Make use of the extra information in the WAL header and frame header to

enhance robustness.

FossilOrigin-Name: 9580ecb7e3beb1949a71784a3dcd1823a88e4a9d
This commit is contained in:
drh 2010-05-20 21:21:09 +00:00
parent 23ea97b641
commit 7e263728f2
5 changed files with 143 additions and 159 deletions

View File

@ -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-----

View File

@ -1 +1 @@
669706431f186f92fdc0856a6206419a1e843f46
9580ecb7e3beb1949a71784a3dcd1823a88e4a9d

258
src/wal.c
View File

@ -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;
}
}

View File

@ -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

View File

@ -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