Make use of the extra information in the WAL header and frame header to
enhance robustness. FossilOrigin-Name: 9580ecb7e3beb1949a71784a3dcd1823a88e4a9d
This commit is contained in:
parent
23ea97b641
commit
7e263728f2
22
manifest
22
manifest
@ -1,8 +1,8 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C Convert\sthe\swal-header\sand\sframe-header\sto\s24\sbytes.\s\sExtra\sinformation\sin\nboth\sheaders\sis\sdesigned\sto\senhance\srobustness\safter\scrashes,\sthough\sthe\nextra\sinformation\sis\scurrently\sunused.\s\sThis\sis\sa\ssnapshot\sof\sa\swork\sin\nprogress.
|
||||
D 2010-05-20T16:45:59
|
||||
C Make\suse\sof\sthe\sextra\sinformation\sin\sthe\sWAL\sheader\sand\sframe\sheader\sto\nenhance\srobustness.
|
||||
D 2010-05-20T21:21:10
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@ -227,7 +227,7 @@ F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
|
||||
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
|
||||
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
|
||||
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
|
||||
F src/wal.c 25969e598b3ce8748295801826cda538232d9200
|
||||
F src/wal.c fd4377f7fe58cd5063b547b7f0f9a220d68335de
|
||||
F src/wal.h 434f76f51225bb614e43ccb6bd2341541ba6a06e
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356
|
||||
@ -764,8 +764,8 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
|
||||
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
|
||||
F test/wal.test 1ea87f3bc6c597ea6ca10e9f5f819c0e6c0ce2f8
|
||||
F test/wal2.test 03059bc4d450c37f4b53278ddc3e2c7d53ac2d3f
|
||||
F test/wal.test 90afd254ece957a716751b1c35fac02d6353c2a7
|
||||
F test/wal2.test ed0d505726343408b8f88b281dadc95ba0a00ba2
|
||||
F test/walbak.test e7650a26eb4b8abeca9b145b1af1e63026dde432
|
||||
F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
|
||||
F test/walfault.test 98df47444944a6db2161eed5cef71d6c00bcb8c3
|
||||
@ -816,14 +816,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 43377663fc3569c361867cdea19e8abaf91a163f
|
||||
R 47b0032c37d93d195eb69ddfe3dd9d8c
|
||||
P 669706431f186f92fdc0856a6206419a1e843f46
|
||||
R 7ce0bc2b62787cca31ab42b34ac1e9ef
|
||||
U drh
|
||||
Z bc14d892f085709c56913a5ad734eeb0
|
||||
Z 335bcf01b684b4b622e461b91e26e309
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFL9WdKoxKgR168RlERAjyUAJ9c2KtaS5H2pdO1uUyrfgizw26dywCffxrC
|
||||
bcVcl+tQYJI9XMFw4UKZNxs=
|
||||
=Bxmw
|
||||
iD8DBQFL9afIoxKgR168RlERAma7AJ9zhPYbudAO43Ry1pxCArWXbiP7QwCffSB2
|
||||
UDhUaZ/h1EszzPxcYgfA5bo=
|
||||
=RESX
|
||||
-----END PGP SIGNATURE-----
|
||||
|
@ -1 +1 @@
|
||||
669706431f186f92fdc0856a6206419a1e843f46
|
||||
9580ecb7e3beb1949a71784a3dcd1823a88e4a9d
|
258
src/wal.c
258
src/wal.c
@ -15,7 +15,7 @@
|
||||
**
|
||||
** WRITE-AHEAD LOG (WAL) FILE FORMAT
|
||||
**
|
||||
** A wal file consists of a header followed by zero or more "frames".
|
||||
** A WAL file consists of a header followed by zero or more "frames".
|
||||
** Each frame records the revised content of a single page from the
|
||||
** database file. All changes to the database are recorded by writing
|
||||
** frames into the WAL. Transactions commit when a frame is written that
|
||||
@ -38,8 +38,8 @@
|
||||
** 4: File format version. Currently 3007000
|
||||
** 8: Database page size. Example: 1024
|
||||
** 12: Checkpoint sequence number
|
||||
** 16: Salt-1, random integer that changes with each checkpoint
|
||||
** 20: Salt-2, a different random integer changing with salt-1
|
||||
** 16: Salt-1, random integer incremented with each checkpoint
|
||||
** 20: Salt-2, a different random integer changing with each ckpt
|
||||
**
|
||||
** Immediately following the wal-header are zero or more frames. Each
|
||||
** frame consists of a 24-byte frame-header followed by a <page-size> bytes
|
||||
@ -49,11 +49,33 @@
|
||||
** 0: Page number.
|
||||
** 4: For commit records, the size of the database image in pages
|
||||
** after the commit. For all other records, zero.
|
||||
** 8: Checkpoint sequence number (copied from the header)
|
||||
** 12: Salt-1 (copied from the header)
|
||||
** 8: Salt-1 (copied from the header)
|
||||
** 12: Salt-2 (copied from the header)
|
||||
** 16: Checksum-1.
|
||||
** 20: Checksum-2.
|
||||
**
|
||||
** A frame is considered valid if and only if the following conditions are
|
||||
** true:
|
||||
**
|
||||
** (1) The salt-1 and salt-2 values in the frame-header match
|
||||
** salt values in the wal-header
|
||||
**
|
||||
** (2) The checksum values in the final 8 bytes of the frame-header
|
||||
** exactly match the checksum computed consecutively on
|
||||
** (a) the first 16 bytes of the frame-header, and
|
||||
** (b) the frame data.
|
||||
**
|
||||
** On a checkpoint, the WAL is first VFS.xSync-ed, then valid content of the
|
||||
** WAL is transferred into the database, then the database is VFS.xSync-ed.
|
||||
** The VFS.xSync operations server as write barriers - all writes launched
|
||||
** before the xSync must complete before any write that launches after the
|
||||
** xSync begins.
|
||||
**
|
||||
** After each checkpoint, the salt-1 value is incremented and the salt-2
|
||||
** value is randomized. This prevents old and new frames in the WAL from
|
||||
** being considered valid at the same time and being checkpointing together
|
||||
** following a crash.
|
||||
**
|
||||
** READER ALGORITHM
|
||||
**
|
||||
** To read a page from the database (call it page number P), a reader
|
||||
@ -185,32 +207,23 @@ typedef struct WalIterator WalIterator;
|
||||
|
||||
|
||||
/*
|
||||
** The following object stores information from the wal-index header.
|
||||
**
|
||||
** This object is *not* a copy of the wal-index header.
|
||||
**
|
||||
** Member variables iCheck1 and iCheck2 contain the checksum for the
|
||||
** last frame written to the wal, or 2 and 3 respectively if the log
|
||||
** is currently empty.
|
||||
** The following object holds an exact copy of the wal-index header.
|
||||
*/
|
||||
struct WalIndexHdr {
|
||||
u32 iChange; /* Counter incremented each transaction */
|
||||
u32 szPage; /* Database page size in bytes */
|
||||
u32 mxFrame; /* Index of last valid frame in the WAL */
|
||||
u32 nPage; /* Size of database in pages */
|
||||
u32 iCheck1; /* Checksum value 1 */
|
||||
u32 iCheck2; /* Checksum value 2 */
|
||||
u32 iChange; /* Counter incremented each transaction */
|
||||
u32 szPage; /* Database page size in bytes */
|
||||
u32 mxFrame; /* Index of last valid frame in the WAL */
|
||||
u32 nPage; /* Size of database in pages */
|
||||
u32 aSalt[2]; /* Salt-1 and salt-2 values copied from WAL header */
|
||||
u32 aCksum[2]; /* Checksum over all prior fields */
|
||||
};
|
||||
|
||||
/* Size of serialized WalIndexHdr object. */
|
||||
#define WALINDEX_HDR_NFIELD (sizeof(WalIndexHdr) / sizeof(u32))
|
||||
|
||||
/* A block of 16 bytes beginning at WALINDEX_LOCK_OFFSET is reserved
|
||||
** for locks. Since some systems only feature mandatory file-locks, we
|
||||
** do not read or write data from the region of the file on which locks
|
||||
** are applied.
|
||||
/* A block of WALINDEX_LOCK_RESERVED bytes beginning at
|
||||
** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems
|
||||
** only support mandatory file-locks, we do not read or write data
|
||||
** from the region of the file on which locks are applied.
|
||||
*/
|
||||
#define WALINDEX_LOCK_OFFSET ((sizeof(WalIndexHdr))+2*sizeof(u32))
|
||||
#define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr))
|
||||
#define WALINDEX_LOCK_RESERVED 8
|
||||
|
||||
/* Size of header before each frame in wal */
|
||||
@ -245,8 +258,8 @@ struct Wal {
|
||||
u8 isWindexOpen; /* True if ShmOpen() called on pDbFd */
|
||||
WalIndexHdr hdr; /* Wal-index for current snapshot */
|
||||
char *zWalName; /* Name of WAL file */
|
||||
u32 nCkpt; /* Checkpoint sequence number */
|
||||
u32 iSalt1, iSalt2; /* Two random salt values */
|
||||
int szPage; /* Database page size */
|
||||
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
|
||||
};
|
||||
|
||||
|
||||
@ -278,13 +291,27 @@ struct WalIterator {
|
||||
|
||||
|
||||
/*
|
||||
** Generate an 8 byte checksum based on the data in array aByte[] and the
|
||||
** initial values of aCksum[0] and aCksum[1]. The checksum is written
|
||||
** back into aCksum[] before returning.
|
||||
** Generate or extend an 8 byte checksum based on the data in
|
||||
** array aByte[] and the initial values of aIn[0] and aIn[1] (or
|
||||
** initial values of 0 and 0 if aIn==NULL).
|
||||
**
|
||||
** The checksum is written back into aOut[] before returning.
|
||||
**
|
||||
** nByte must be a positive multiple of 8.
|
||||
*/
|
||||
static void walChecksumBytes(u8 *a, int nByte, u32 *aCksum){
|
||||
u32 s1 = aCksum[0];
|
||||
u32 s2 = aCksum[1];
|
||||
static void walChecksumBytes(
|
||||
u8 *a, /* Content to be checksummed */
|
||||
int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */
|
||||
const u32 *aIn, /* Initial checksum value input */
|
||||
u32 *aOut /* OUT: Final checksum value output */
|
||||
){
|
||||
u32 s1, s2;
|
||||
if( aIn ){
|
||||
s1 = aIn[0];
|
||||
s2 = aIn[1];
|
||||
}else{
|
||||
s1 = s2 = 0;
|
||||
}
|
||||
u8 *aEnd = (u8*)&a[nByte];
|
||||
|
||||
assert( nByte>=8 );
|
||||
@ -295,8 +322,8 @@ static void walChecksumBytes(u8 *a, int nByte, u32 *aCksum){
|
||||
s2 += (a[4]<<24) + (a[5]<<16) + (a[6]<<8) + a[7] + s1;
|
||||
a += 8;
|
||||
}while( a<aEnd );
|
||||
aCksum[0] = s1;
|
||||
aCksum[1] = s2;
|
||||
aOut[0] = s1;
|
||||
aOut[1] = s2;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -323,17 +350,15 @@ static int walSetLock(Wal *pWal, int desiredStatus){
|
||||
}
|
||||
|
||||
/*
|
||||
** Update the header of the wal-index file.
|
||||
** Write the header information in pWal->hdr into the wal-index.
|
||||
**
|
||||
** The checksum on pWal->hdr is updated before it is written.
|
||||
*/
|
||||
static void walIndexWriteHdr(Wal *pWal, WalIndexHdr *pHdr){
|
||||
volatile u32 *aHdr = pWal->pWiData; /* Write header here */
|
||||
volatile u32 *aCksum = &aHdr[WALINDEX_HDR_NFIELD]; /* Write cksum here */
|
||||
|
||||
assert( WALINDEX_HDR_NFIELD==sizeof(WalIndexHdr)/4 );
|
||||
assert( aHdr!=0 );
|
||||
memcpy((void*)aHdr, pHdr, sizeof(WalIndexHdr));
|
||||
aCksum[0] = aCksum[1] = 1;
|
||||
walChecksumBytes((u8*)aHdr, sizeof(WalIndexHdr), (u32*)aCksum);
|
||||
static void walIndexWriteHdr(Wal *pWal){
|
||||
walChecksumBytes((u8*)&pWal->hdr,
|
||||
sizeof(pWal->hdr) - sizeof(pWal->hdr.aCksum),
|
||||
0, pWal->hdr.aCksum);
|
||||
memcpy((void*)pWal->pWiData, &pWal->hdr, sizeof(pWal->hdr));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -344,60 +369,59 @@ static void walIndexWriteHdr(Wal *pWal, WalIndexHdr *pHdr){
|
||||
** 0: Page number.
|
||||
** 4: For commit records, the size of the database image in pages
|
||||
** after the commit. For all other records, zero.
|
||||
** 8: Checkpoint sequence number (copied from the header)
|
||||
** 12: Salt-1 (copied from the header)
|
||||
** 8: Salt-1 (copied from the wal-header)
|
||||
** 12: Salt-2 (copied from the wal-header)
|
||||
** 16: Checksum-1.
|
||||
** 20: Checksum-2.
|
||||
*/
|
||||
static void walEncodeFrame(
|
||||
Wal *pWal, /* The write-ahead log */
|
||||
u32 *aCksum, /* IN/OUT: Checksum values */
|
||||
u32 iPage, /* Database page number for frame */
|
||||
u32 nTruncate, /* New db size (or 0 for non-commit frames) */
|
||||
int nData, /* Database page size (size of aData[]) */
|
||||
u8 *aData, /* Pointer to page data (for checksum) */
|
||||
u8 *aData, /* Pointer to page data */
|
||||
u8 *aFrame /* OUT: Write encoded frame here */
|
||||
){
|
||||
u32 aCksum[2];
|
||||
assert( WAL_FRAME_HDRSIZE==24 );
|
||||
|
||||
sqlite3Put4byte(&aFrame[0], iPage);
|
||||
sqlite3Put4byte(&aFrame[4], nTruncate);
|
||||
sqlite3Put4byte(&aFrame[8], pWal->nCkpt);
|
||||
sqlite3Put4byte(&aFrame[12], pWal->iSalt1);
|
||||
memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
|
||||
|
||||
walChecksumBytes(aFrame, 8, aCksum);
|
||||
walChecksumBytes(aData, nData, aCksum);
|
||||
walChecksumBytes(aFrame, 16, 0, aCksum);
|
||||
walChecksumBytes(aData, pWal->szPage, aCksum, aCksum);
|
||||
|
||||
sqlite3Put4byte(&aFrame[16], aCksum[0]);
|
||||
sqlite3Put4byte(&aFrame[20], aCksum[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return 1 and populate *piPage, *pnTruncate and aCksum if the
|
||||
** frame checksum looks Ok. Otherwise return 0.
|
||||
** Check to see if the frame with header in aFrame[] and content
|
||||
** in aData[] is valid. If it is a valid frame, fill *piPage and
|
||||
** *pnTruncate and return true. Return if the frame is not valid.
|
||||
*/
|
||||
static int walDecodeFrame(
|
||||
Wal *pWal, /* The write-ahead log */
|
||||
u32 *aCksum, /* IN/OUT: Checksum values */
|
||||
u32 *piPage, /* OUT: Database page number for frame */
|
||||
u32 *pnTruncate, /* OUT: New db size (or 0 if not commit) */
|
||||
int nData, /* Database page size (size of aData[]) */
|
||||
u8 *aData, /* Pointer to page data (for checksum) */
|
||||
u8 *aFrame /* Frame data */
|
||||
){
|
||||
u32 aCksum[2];
|
||||
assert( WAL_FRAME_HDRSIZE==24 );
|
||||
|
||||
#if 0
|
||||
if( pWal->nCkpt!=sqlite3Get4byte(&aFrame[8]) ){
|
||||
/* A frame is only valid if the salt values in the frame-header
|
||||
** match the salt values in the wal-header.
|
||||
*/
|
||||
if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){
|
||||
return 0;
|
||||
}
|
||||
if( pWal->iSalt1!=sqlite3Get4byte(&aFrame[12]) ){
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
walChecksumBytes(aFrame, 8, aCksum);
|
||||
walChecksumBytes(aData, nData, aCksum);
|
||||
/* A frame is only valid if a checksum of the first 16 bytes
|
||||
** of the frame-header, and the frame-data matches
|
||||
** the checksum in the last 8 bytes of the frame-header.
|
||||
*/
|
||||
walChecksumBytes(aFrame, 16, 0, aCksum);
|
||||
walChecksumBytes(aData, pWal->szPage, aCksum, aCksum);
|
||||
if( aCksum[0]!=sqlite3Get4byte(&aFrame[16])
|
||||
|| aCksum[1]!=sqlite3Get4byte(&aFrame[20])
|
||||
){
|
||||
@ -405,6 +429,9 @@ static int walDecodeFrame(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we reach this point, the frame is valid. Return the page number
|
||||
** and the new database size.
|
||||
*/
|
||||
*piPage = sqlite3Get4byte(&aFrame[0]);
|
||||
*pnTruncate = sqlite3Get4byte(&aFrame[4]);
|
||||
return 1;
|
||||
@ -648,7 +675,6 @@ static int walIndexRecover(Wal *pWal){
|
||||
int iFrame; /* Index of last frame read */
|
||||
i64 iOffset; /* Next offset to read from log file */
|
||||
int szPage; /* Page size according to the log */
|
||||
u32 aCksum[2]; /* Running checksum */
|
||||
|
||||
/* Read in the first frame header in the file (to determine the
|
||||
** database page size).
|
||||
@ -665,9 +691,9 @@ static int walIndexRecover(Wal *pWal){
|
||||
if( szPage&(szPage-1) || szPage>SQLITE_MAX_PAGE_SIZE || szPage<512 ){
|
||||
goto finished;
|
||||
}
|
||||
pWal->szPage = szPage;
|
||||
pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
|
||||
aCksum[0] = sqlite3Get4byte(&aBuf[16]);
|
||||
aCksum[1] = sqlite3Get4byte(&aBuf[20]);
|
||||
memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
|
||||
|
||||
/* Malloc a buffer to read frames into. */
|
||||
szFrame = szPage + WAL_FRAME_HDRSIZE;
|
||||
@ -687,16 +713,13 @@ static int walIndexRecover(Wal *pWal){
|
||||
/* Read and decode the next log frame. */
|
||||
rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
isValid = walDecodeFrame(pWal, aCksum, &pgno, &nTruncate, szPage,
|
||||
aData, aFrame);
|
||||
isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
|
||||
if( !isValid ) break;
|
||||
rc = walIndexAppend(pWal, ++iFrame, pgno);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
|
||||
/* If nTruncate is non-zero, this is a commit record. */
|
||||
if( nTruncate ){
|
||||
hdr.iCheck1 = aCksum[0];
|
||||
hdr.iCheck2 = aCksum[1];
|
||||
hdr.mxFrame = iFrame;
|
||||
hdr.nPage = nTruncate;
|
||||
hdr.szPage = szPage;
|
||||
@ -705,8 +728,7 @@ static int walIndexRecover(Wal *pWal){
|
||||
|
||||
sqlite3_free(aFrame);
|
||||
}else{
|
||||
hdr.iCheck1 = 2;
|
||||
hdr.iCheck2 = 3;
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
}
|
||||
|
||||
finished:
|
||||
@ -714,8 +736,8 @@ finished:
|
||||
rc = walIndexRemap(pWal, WALINDEX_MMAP_INCREMENT);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
walIndexWriteHdr(pWal, &hdr);
|
||||
memcpy(&pWal->hdr, &hdr, sizeof(hdr));
|
||||
walIndexWriteHdr(pWal);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -774,6 +796,7 @@ int sqlite3WalOpen(
|
||||
pRet->pVfs = pVfs;
|
||||
pRet->pWalFd = (sqlite3_file *)&pRet[1];
|
||||
pRet->pDbFd = pDbFd;
|
||||
sqlite3_randomness(8, &pRet->hdr.aSalt);
|
||||
pRet->zWalName = zWal = pVfs->szOsFile + (char*)pRet->pWalFd;
|
||||
sqlite3_snprintf(nWal, zWal, "%s-wal", zDbName);
|
||||
rc = sqlite3OsShmOpen(pDbFd);
|
||||
@ -1027,30 +1050,11 @@ static int walCheckpoint(
|
||||
if( rc!=SQLITE_OK ) goto out;
|
||||
}
|
||||
pWal->hdr.mxFrame = 0;
|
||||
pWal->hdr.iCheck1 = 2;
|
||||
pWal->hdr.iCheck2 = 3;
|
||||
walIndexWriteHdr(pWal, &pWal->hdr);
|
||||
pWal->nCkpt++;
|
||||
|
||||
/* TODO: If a crash occurs and the current log is copied into the
|
||||
** database there is no problem. However, if a crash occurs while
|
||||
** writing the next transaction into the start of the log, such that:
|
||||
**
|
||||
** * The first transaction currently in the log is left intact, but
|
||||
** * The second (or subsequent) transaction is damaged,
|
||||
**
|
||||
** then the database could become corrupt.
|
||||
**
|
||||
** The easiest thing to do would be to write and sync a dummy header
|
||||
** into the log at this point. Unfortunately, that turns out to be
|
||||
** an unwelcome performance hit. Alternatives are...
|
||||
*/
|
||||
#if 0
|
||||
memset(zBuf, 0, WAL_FRAME_HDRSIZE);
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, zBuf, WAL_FRAME_HDRSIZE, 0);
|
||||
if( rc!=SQLITE_OK ) goto out;
|
||||
rc = sqlite3OsSync(pWal->pWalFd, pWal->sync_flags);
|
||||
#endif
|
||||
sqlite3Put4byte((u8*)pWal->hdr.aSalt,
|
||||
1 + sqlite3Get4byte((u8*)pWal->hdr.aSalt));
|
||||
sqlite3_randomness(4, &pWal->hdr.aSalt[1]);
|
||||
walIndexWriteHdr(pWal);
|
||||
|
||||
out:
|
||||
walIteratorFree(pIter);
|
||||
@ -1114,10 +1118,8 @@ int sqlite3WalClose(
|
||||
** is read successfully and the checksum verified, return zero.
|
||||
*/
|
||||
int walIndexTryHdr(Wal *pWal, int *pChanged){
|
||||
int i;
|
||||
volatile u32 *aWiData;
|
||||
u32 aCksum[2] = {1, 1};
|
||||
u32 aHdr[WALINDEX_HDR_NFIELD+2];
|
||||
u32 aCksum[2];
|
||||
WalIndexHdr hdr;
|
||||
|
||||
assert( pWal->pWiData );
|
||||
if( pWal->szWIndex==0 ){
|
||||
@ -1133,20 +1135,16 @@ int walIndexTryHdr(Wal *pWal, int *pChanged){
|
||||
** file, meaning it is possible that an inconsistent snapshot is read
|
||||
** from the file. If this happens, return non-zero.
|
||||
*/
|
||||
aWiData = pWal->pWiData;
|
||||
for(i=0; i<WALINDEX_HDR_NFIELD+2; i++){
|
||||
aHdr[i] = aWiData[i];
|
||||
}
|
||||
walChecksumBytes((u8*)aHdr, sizeof(u32)*WALINDEX_HDR_NFIELD, aCksum);
|
||||
if( aCksum[0]!=aHdr[WALINDEX_HDR_NFIELD]
|
||||
|| aCksum[1]!=aHdr[WALINDEX_HDR_NFIELD+1]
|
||||
){
|
||||
memcpy(&hdr, (void*)pWal->pWiData, sizeof(hdr));
|
||||
walChecksumBytes((u8*)&hdr, sizeof(hdr)-sizeof(hdr.aCksum), 0, aCksum);
|
||||
if( aCksum[0]!=hdr.aCksum[0] || aCksum[1]!=hdr.aCksum[1] ){
|
||||
return 1;
|
||||
}
|
||||
|
||||
if( memcmp(&pWal->hdr, aHdr, sizeof(WalIndexHdr)) ){
|
||||
if( memcmp(&pWal->hdr, &hdr, sizeof(WalIndexHdr)) ){
|
||||
*pChanged = 1;
|
||||
memcpy(&pWal->hdr, aHdr, sizeof(WalIndexHdr));
|
||||
memcpy(&pWal->hdr, &hdr, sizeof(WalIndexHdr));
|
||||
pWal->szPage = pWal->hdr.szPage;
|
||||
}
|
||||
|
||||
/* The header was successfully read. Return zero. */
|
||||
@ -1487,17 +1485,9 @@ u32 sqlite3WalSavepoint(Wal *pWal){
|
||||
*/
|
||||
int sqlite3WalSavepointUndo(Wal *pWal, u32 iFrame){
|
||||
int rc = SQLITE_OK;
|
||||
u8 aCksum[8];
|
||||
assert( pWal->lockState==SQLITE_SHM_WRITE );
|
||||
|
||||
pWal->hdr.mxFrame = iFrame;
|
||||
if( iFrame>0 ){
|
||||
i64 iOffset = walFrameOffset(iFrame, pWal->hdr.szPage) + sizeof(u32)*4;
|
||||
rc = sqlite3OsRead(pWal->pWalFd, aCksum, sizeof(aCksum), iOffset);
|
||||
pWal->hdr.iCheck1 = sqlite3Get4byte(&aCksum[0]);
|
||||
pWal->hdr.iCheck2 = sqlite3Get4byte(&aCksum[4]);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1517,7 +1507,6 @@ int sqlite3WalFrames(
|
||||
u32 iFrame; /* Next frame address */
|
||||
u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
|
||||
PgHdr *p; /* Iterator to run through pList with. */
|
||||
u32 aCksum[2]; /* Checksums */
|
||||
PgHdr *pLast = 0; /* Last frame in list */
|
||||
int nLast = 0; /* Number of extra copies of last page */
|
||||
|
||||
@ -1535,20 +1524,17 @@ int sqlite3WalFrames(
|
||||
sqlite3Put4byte(&aWalHdr[0], 0x377f0682);
|
||||
sqlite3Put4byte(&aWalHdr[4], 3007000);
|
||||
sqlite3Put4byte(&aWalHdr[8], szPage);
|
||||
pWal->szPage = szPage;
|
||||
sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
|
||||
sqlite3_randomness(8, &aWalHdr[16]);
|
||||
pWal->hdr.iCheck1 = pWal->iSalt1 = sqlite3Get4byte(&aWalHdr[16]);
|
||||
pWal->hdr.iCheck2 = pWal->iSalt2 = sqlite3Get4byte(&aWalHdr[20]);
|
||||
memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8);
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
assert( pWal->szPage==szPage );
|
||||
|
||||
aCksum[0] = pWal->hdr.iCheck1;
|
||||
aCksum[1] = pWal->hdr.iCheck2;
|
||||
|
||||
/* Write the log file. */
|
||||
/* Write the log file. */
|
||||
for(p=pList; p; p=p->pDirty){
|
||||
u32 nDbsize; /* Db-size field for frame header */
|
||||
i64 iOffset; /* Write offset in log file */
|
||||
@ -1557,7 +1543,7 @@ int sqlite3WalFrames(
|
||||
|
||||
/* Populate and write the frame header */
|
||||
nDbsize = (isCommit && p->pDirty==0) ? nTruncate : 0;
|
||||
walEncodeFrame(pWal, aCksum, p->pgno, nDbsize, szPage, p->pData, aFrame);
|
||||
walEncodeFrame(pWal, p->pgno, nDbsize, p->pData, aFrame);
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
@ -1581,8 +1567,7 @@ int sqlite3WalFrames(
|
||||
|
||||
iSegment = (((iOffset+iSegment-1)/iSegment) * iSegment);
|
||||
while( iOffset<iSegment ){
|
||||
walEncodeFrame(pWal, aCksum, pLast->pgno, nTruncate, szPage,
|
||||
pLast->pData, aFrame);
|
||||
walEncodeFrame(pWal, pLast->pgno, nTruncate, pLast->pData, aFrame);
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
@ -1625,12 +1610,9 @@ int sqlite3WalFrames(
|
||||
pWal->hdr.iChange++;
|
||||
pWal->hdr.nPage = nTruncate;
|
||||
}
|
||||
pWal->hdr.iCheck1 = aCksum[0];
|
||||
pWal->hdr.iCheck2 = aCksum[1];
|
||||
|
||||
/* If this is a commit, update the wal-index header too. */
|
||||
if( isCommit ){
|
||||
walIndexWriteHdr(pWal, &pWal->hdr);
|
||||
walIndexWriteHdr(pWal);
|
||||
pWal->iCallback = iFrame;
|
||||
}
|
||||
}
|
||||
|
@ -556,7 +556,10 @@ foreach code [list {
|
||||
catchsql { INSERT INTO t1 VALUES(9, 10) }
|
||||
} {1 {database is locked}}
|
||||
do_test wal-10.$tn.10 {
|
||||
execsql { COMMIT; BEGIN; INSERT INTO t1 VALUES(9, 10); COMMIT; }
|
||||
execsql { COMMIT }
|
||||
execsql { BEGIN }
|
||||
execsql { INSERT INTO t1 VALUES(9, 10) }
|
||||
execsql { COMMIT }
|
||||
execsql { SELECT * FROM t1 }
|
||||
} {1 2 3 4 5 6 7 8 9 10}
|
||||
|
||||
@ -1336,15 +1339,14 @@ foreach {tn pgsz works} {
|
||||
# or too large), the db will not be corrupt as the log file will
|
||||
# be ignored.
|
||||
#
|
||||
set c1 22
|
||||
set c2 23
|
||||
set walhdr [binary format IIIIII 931071618 3007000 $pgsz 1234 $c1 $c2]
|
||||
set salt1 $c1
|
||||
set walhdr [binary format IIIIII 931071618 3007000 $pgsz 1234 22 23]
|
||||
set framebody [randomblob $pgsz]
|
||||
set framehdr [binary format II $pg 5]
|
||||
set framehdr [binary format IIII $pg 5 22 23]
|
||||
set c1 0
|
||||
set c2 0
|
||||
logcksum c1 c2 $framehdr
|
||||
logcksum c1 c2 $framebody
|
||||
set framehdr [binary format IIIIII $pg 5 1234 $salt1 $c1 $c2]
|
||||
set framehdr [binary format IIIIII $pg 5 22 23 $c1 $c2]
|
||||
set fd [open test.db-wal w]
|
||||
fconfigure $fd -encoding binary -translation binary
|
||||
puts -nonewline $fd $walhdr
|
||||
|
@ -115,6 +115,7 @@ foreach {tn iInsert res wal_index_hdr_mod wal_locks} {
|
||||
return SQLITE_OK
|
||||
}
|
||||
|
||||
breakpoint
|
||||
execsql { SELECT count(a), sum(a) FROM t1 } db2
|
||||
} $res
|
||||
|
||||
@ -178,7 +179,7 @@ foreach {tn iInsert res0 res1 wal_index_hdr_mod} {
|
||||
8 11 {10 55} {11 66} 6
|
||||
9 12 {11 66} {12 78} 7
|
||||
} {
|
||||
do_test wal2-1.$tn.1 {
|
||||
do_test wal2-2.$tn.1 {
|
||||
set oldhdr [set_tvfs_hdr $::shm_file]
|
||||
execsql { INSERT INTO t1 VALUES($iInsert) }
|
||||
execsql { SELECT count(a), sum(a) FROM t1 }
|
||||
@ -603,4 +604,3 @@ do_test wal2-6.5.3 {
|
||||
db close
|
||||
|
||||
finish_test
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user