mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Refactoring of the WalIterator implementation.
FossilOrigin-Name: b5b60fdcc5dcf41f2c79912075ac241f7ce220d6
This commit is contained in:
18
manifest
18
manifest
@@ -1,8 +1,8 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C Mark\sthe\sshared-memory\sin\sthe\sWAL\simplementation\sas\svolatile.
|
||||
D 2010-05-18T13:27:13
|
||||
C Refactoring\sof\sthe\sWalIterator\simplementation.
|
||||
D 2010-05-18T18:01:09
|
||||
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 03c150ff23332a58dd0cf313c7b7defdd9ec6275
|
||||
F src/wal.c cfbb818b50bec82675aa5322d7ee0e2b2c2a7386
|
||||
F src/wal.h 434f76f51225bb614e43ccb6bd2341541ba6a06e
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356
|
||||
@@ -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 a029be10172e2e6a2ef4e3eb2ea1bd0ca85b16ed
|
||||
R c3edbc896fce7d9f6c83f7337ac02298
|
||||
P 0a6787908e989bd5e6af25acbdc59ebc8fa61d6d
|
||||
R 70b31773a620515609c56c14086245f3
|
||||
U drh
|
||||
Z 88ded0b14b6354cb7517528585f793ca
|
||||
Z 7b37c77bed71cbc8c1a6f26dcf7b1090
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFL8pW0oxKgR168RlERAoCBAJ9VXFufUgFrlJ8vv69PNeEYGWy/IgCcD99s
|
||||
/C+oicnjvVyzr2OBGGMkk9c=
|
||||
=CSoB
|
||||
iD8DBQFL8tXooxKgR168RlERAkToAJ4sc1mZ1q5W9au06n2/yU3i2HlYxwCdEuup
|
||||
sJTTs22gXenKu7GRNzIKGS0=
|
||||
=4glP
|
||||
-----END PGP SIGNATURE-----
|
||||
|
@@ -1 +1 @@
|
||||
0a6787908e989bd5e6af25acbdc59ebc8fa61d6d
|
||||
b5b60fdcc5dcf41f2c79912075ac241f7ce220d6
|
281
src/wal.c
281
src/wal.c
@@ -44,7 +44,7 @@
|
||||
/*
|
||||
** WAL-INDEX FILE FORMAT
|
||||
**
|
||||
** The wal-index consists of a 32-byte header region, followed by an
|
||||
** The wal-index consists of a header region, followed by an
|
||||
** 8-byte region that contains no useful data (used to apply byte-range locks
|
||||
** in some implementations), followed by the data region.
|
||||
**
|
||||
@@ -134,10 +134,11 @@ struct Wal {
|
||||
|
||||
|
||||
/*
|
||||
** This structure is used to implement an iterator that iterates through
|
||||
** all frames in the log in database page order. Where two or more frames
|
||||
** This structure is used to implement an iterator that loops through
|
||||
** all frames in the WAL in database page order. Where two or more frames
|
||||
** correspond to the same database page, the iterator visits only the
|
||||
** frame most recently written to the log.
|
||||
** frame most recently written to the WAL (in other words, the frame with
|
||||
** the largest index).
|
||||
**
|
||||
** The internals of this structure are only accessed by:
|
||||
**
|
||||
@@ -148,13 +149,14 @@ struct Wal {
|
||||
** This functionality is used by the checkpoint code (see walCheckpoint()).
|
||||
*/
|
||||
struct WalIterator {
|
||||
int nSegment; /* Size of WalIterator.aSegment[] array */
|
||||
int nFinal; /* Elements in segment nSegment-1 */
|
||||
int iPrior; /* Last result returned from the iterator */
|
||||
int nSegment; /* Size of the aSegment[] array */
|
||||
int nFinal; /* Elements in aSegment[nSegment-1] */
|
||||
struct WalSegment {
|
||||
int iNext; /* Next aIndex index */
|
||||
u8 *aIndex; /* Pointer to index array */
|
||||
u32 *aDbPage; /* Pointer to db page array */
|
||||
} aSegment[1];
|
||||
int iNext; /* Next slot in aIndex[] not previously returned */
|
||||
u8 *aIndex; /* i0, i1, i2... such that aPgno[iN] ascending */
|
||||
u32 *aPgno; /* 256 page numbers. Pointer to Wal.pWiData */
|
||||
} aSegment[1]; /* One for every 256 entries in the WAL */
|
||||
};
|
||||
|
||||
|
||||
@@ -302,59 +304,6 @@ static int walDecodeFrame(
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void walMergesort8(
|
||||
Pgno *aContent, /* Pages in wal */
|
||||
u8 *aBuffer, /* Buffer of at least *pnList items to use */
|
||||
u8 *aList, /* IN/OUT: List to sort */
|
||||
int *pnList /* IN/OUT: Number of elements in aList[] */
|
||||
){
|
||||
int nList = *pnList;
|
||||
if( nList>1 ){
|
||||
int nLeft = nList / 2; /* Elements in left list */
|
||||
int nRight = nList - nLeft; /* Elements in right list */
|
||||
u8 *aLeft = aList; /* Left list */
|
||||
u8 *aRight = &aList[nLeft]; /* Right list */
|
||||
int iLeft = 0; /* Current index in aLeft */
|
||||
int iRight = 0; /* Current index in aright */
|
||||
int iOut = 0; /* Current index in output buffer */
|
||||
|
||||
/* TODO: Change to non-recursive version. */
|
||||
walMergesort8(aContent, aBuffer, aLeft, &nLeft);
|
||||
walMergesort8(aContent, aBuffer, aRight, &nRight);
|
||||
|
||||
while( iRight<nRight || iLeft<nLeft ){
|
||||
u8 logpage;
|
||||
Pgno dbpage;
|
||||
|
||||
if( (iLeft<nLeft)
|
||||
&& (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
|
||||
){
|
||||
logpage = aLeft[iLeft++];
|
||||
}else{
|
||||
logpage = aRight[iRight++];
|
||||
}
|
||||
dbpage = aContent[logpage];
|
||||
|
||||
aBuffer[iOut++] = logpage;
|
||||
if( iLeft<nLeft && aContent[aLeft[iLeft]]==dbpage ) iLeft++;
|
||||
|
||||
assert( iLeft>=nLeft || aContent[aLeft[iLeft]]>dbpage );
|
||||
assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage );
|
||||
}
|
||||
memcpy(aList, aBuffer, sizeof(aList[0])*iOut);
|
||||
*pnList = iOut;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
{
|
||||
int i;
|
||||
for(i=1; i<*pnList; i++){
|
||||
assert( aContent[aList[i]] > aContent[aList[i-1]] );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Define the size of the hash tables in the wal-index file. There
|
||||
** is a hash-table following every HASHTABLE_NPAGE page numbers in the
|
||||
@@ -367,9 +316,18 @@ static void walMergesort8(
|
||||
#define HASHTABLE_NBYTE (sizeof(HASHTABLE_DATATYPE)*HASHTABLE_NSLOT)
|
||||
|
||||
/*
|
||||
** Return the index in the WalIndex.aData array that corresponds to
|
||||
** frame iFrame. The wal-index file consists of a header, followed by
|
||||
** alternating "map" and "index" blocks.
|
||||
** Return the index in the Wal.pWiData array that corresponds to
|
||||
** frame iFrame.
|
||||
**
|
||||
** Wal.pWiData is an array of u32 elements that is the wal-index.
|
||||
** The array begins with a header and is then followed by alternating
|
||||
** "map" and "hash-table" blocks. Each "map" block consists of
|
||||
** HASHTABLE_NPAGE u32 elements which are page numbers corresponding
|
||||
** to frames in the WAL file.
|
||||
**
|
||||
** This routine returns an index X such that Wal.pWiData[X] is part
|
||||
** of a "map" block that contains the page number of the iFrame-th
|
||||
** frame in the WAL file.
|
||||
*/
|
||||
static int walIndexEntry(u32 iFrame){
|
||||
return (
|
||||
@@ -715,20 +673,32 @@ int sqlite3WalOpen(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Find the smallest page number out of all pages held in the WAL that
|
||||
** has not been returned by any prior invocation of this method on the
|
||||
** same WalIterator object. Write into *piFrame the frame index where
|
||||
** that page was last written into the WAL. Write into *piPage the page
|
||||
** number.
|
||||
**
|
||||
** Return 0 on success. If there are no pages in the WAL with a page
|
||||
** number larger than *piPage, then return 1.
|
||||
*/
|
||||
static int walIteratorNext(
|
||||
WalIterator *p, /* Iterator */
|
||||
u32 *piPage, /* OUT: Next db page to write */
|
||||
u32 *piFrame /* OUT: Wal frame to read from */
|
||||
u32 *piPage, /* OUT: The page number of the next page */
|
||||
u32 *piFrame /* OUT: Wal frame index of next page */
|
||||
){
|
||||
u32 iMin = *piPage;
|
||||
u32 iRet = 0xFFFFFFFF;
|
||||
int i;
|
||||
int nBlock = p->nFinal;
|
||||
u32 iMin; /* Result pgno must be greater than iMin */
|
||||
u32 iRet = 0xFFFFFFFF; /* 0xffffffff is never a valid page number */
|
||||
int i; /* For looping through segments */
|
||||
int nBlock = p->nFinal; /* Number of entries in current segment */
|
||||
|
||||
iMin = p->iPrior;
|
||||
assert( iMin<0xffffffff );
|
||||
for(i=p->nSegment-1; i>=0; i--){
|
||||
struct WalSegment *pSegment = &p->aSegment[i];
|
||||
while( pSegment->iNext<nBlock ){
|
||||
u32 iPg = pSegment->aDbPage[pSegment->aIndex[pSegment->iNext]];
|
||||
u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]];
|
||||
if( iPg>iMin ){
|
||||
if( iPg<iRet ){
|
||||
iRet = iPg;
|
||||
@@ -741,10 +711,78 @@ static int walIteratorNext(
|
||||
nBlock = 256;
|
||||
}
|
||||
|
||||
*piPage = iRet;
|
||||
*piPage = p->iPrior = iRet;
|
||||
return (iRet==0xFFFFFFFF);
|
||||
}
|
||||
|
||||
|
||||
static void walMergesort8(
|
||||
Pgno *aContent, /* Pages in wal */
|
||||
u8 *aBuffer, /* Buffer of at least *pnList items to use */
|
||||
u8 *aList, /* IN/OUT: List to sort */
|
||||
int *pnList /* IN/OUT: Number of elements in aList[] */
|
||||
){
|
||||
int nList = *pnList;
|
||||
if( nList>1 ){
|
||||
int nLeft = nList / 2; /* Elements in left list */
|
||||
int nRight = nList - nLeft; /* Elements in right list */
|
||||
u8 *aLeft = aList; /* Left list */
|
||||
u8 *aRight = &aList[nLeft]; /* Right list */
|
||||
int iLeft = 0; /* Current index in aLeft */
|
||||
int iRight = 0; /* Current index in aright */
|
||||
int iOut = 0; /* Current index in output buffer */
|
||||
|
||||
/* TODO: Change to non-recursive version. */
|
||||
walMergesort8(aContent, aBuffer, aLeft, &nLeft);
|
||||
walMergesort8(aContent, aBuffer, aRight, &nRight);
|
||||
|
||||
while( iRight<nRight || iLeft<nLeft ){
|
||||
u8 logpage;
|
||||
Pgno dbpage;
|
||||
|
||||
if( (iLeft<nLeft)
|
||||
&& (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
|
||||
){
|
||||
logpage = aLeft[iLeft++];
|
||||
}else{
|
||||
logpage = aRight[iRight++];
|
||||
}
|
||||
dbpage = aContent[logpage];
|
||||
|
||||
aBuffer[iOut++] = logpage;
|
||||
if( iLeft<nLeft && aContent[aLeft[iLeft]]==dbpage ) iLeft++;
|
||||
|
||||
assert( iLeft>=nLeft || aContent[aLeft[iLeft]]>dbpage );
|
||||
assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage );
|
||||
}
|
||||
memcpy(aList, aBuffer, sizeof(aList[0])*iOut);
|
||||
*pnList = iOut;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
{
|
||||
int i;
|
||||
for(i=1; i<*pnList; i++){
|
||||
assert( aContent[aList[i]] > aContent[aList[i-1]] );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Map the wal-index into memory owned by this thread, if it is not
|
||||
** mapped already. Then construct a WalInterator object that can be
|
||||
** used to loop over all pages in the WAL in ascending order.
|
||||
**
|
||||
** On success, make *pp point to the newly allocated WalInterator object
|
||||
** return SQLITE_OK. Otherwise, leave *pp unchanged and return an error
|
||||
** code.
|
||||
**
|
||||
** The calling routine should invoke walIteratorFree() to destroy the
|
||||
** WalIterator object when it has finished with it. The caller must
|
||||
** also unmap the wal-index. But the wal-index must not be unmapped
|
||||
** prior to the WalIterator object being destroyed.
|
||||
*/
|
||||
static int walIteratorInit(Wal *pWal, WalIterator **pp){
|
||||
u32 *aData; /* Content of the wal-index file */
|
||||
WalIterator *p; /* Return value */
|
||||
@@ -755,48 +793,61 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
|
||||
int nFinal; /* Number of unindexed entries */
|
||||
u8 *aTmp; /* Temp space used by merge-sort */
|
||||
int rc; /* Return code of walIndexMap() */
|
||||
u8 *aSpace; /* Surplus space on the end of the allocation */
|
||||
|
||||
/* Make sure the wal-index is mapped into local memory */
|
||||
rc = walIndexMap(pWal, walMappingSize(pWal->hdr.iLastPg));
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* This routine only runs while holding SQLITE_SHM_CHECKPOINT. No other
|
||||
** thread is able to write to shared memory while this routine is
|
||||
** running (or, indeed, while the WalIterator object exists). Hence,
|
||||
** we can cast off the volatile qualifacation from shared memory
|
||||
*/
|
||||
assert( pWal->lockState==SQLITE_SHM_CHECKPOINT );
|
||||
aData = (u32*)pWal->pWiData;
|
||||
|
||||
/* Allocate space for the WalIterator object */
|
||||
iLast = pWal->hdr.iLastPg;
|
||||
nSegment = (iLast >> 8) + 1;
|
||||
nFinal = (iLast & 0x000000FF);
|
||||
|
||||
nByte = sizeof(WalIterator) + (nSegment+1)*(sizeof(struct WalSegment)+256);
|
||||
p = (WalIterator *)sqlite3_malloc(nByte);
|
||||
if( !p ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
u8 *aSpace;
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
memset(p, 0, nByte);
|
||||
p->nSegment = nSegment;
|
||||
|
||||
/* Initialize the WalIterator object. Each 256-entry segment is
|
||||
** presorted in order to make iterating through all entries much
|
||||
** faster.
|
||||
*/
|
||||
p->nSegment = nSegment;
|
||||
aSpace = (u8 *)&p->aSegment[nSegment];
|
||||
aTmp = &aSpace[nSegment*256];
|
||||
for(i=0; i<nSegment; i++){
|
||||
int j;
|
||||
int nIndex = (i==nSegment-1) ? nFinal : 256;
|
||||
p->aSegment[i].aDbPage = &aData[walIndexEntry(i*256+1)];
|
||||
p->aSegment[i].aPgno = &aData[walIndexEntry(i*256+1)];
|
||||
p->aSegment[i].aIndex = aSpace;
|
||||
for(j=0; j<nIndex; j++){
|
||||
aSpace[j] = j;
|
||||
}
|
||||
walMergesort8(p->aSegment[i].aDbPage, aTmp, aSpace, &nIndex);
|
||||
walMergesort8(p->aSegment[i].aPgno, aTmp, aSpace, &nIndex);
|
||||
memset(&aSpace[nIndex], aSpace[nIndex-1], 256-nIndex);
|
||||
aSpace += 256;
|
||||
p->nFinal = nIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the fully initializd WalIterator object */
|
||||
*pp = p;
|
||||
return rc;
|
||||
return SQLITE_OK ;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free a log iterator allocated by walIteratorInit().
|
||||
** Free an iterator allocated by walIteratorInit().
|
||||
*/
|
||||
static void walIteratorFree(WalIterator *p){
|
||||
sqlite3_free(p);
|
||||
@@ -924,16 +975,24 @@ int sqlite3WalClose(
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to read the wal-index header. Attempt to verify the header
|
||||
** checksum. If the checksum can be verified, copy the wal-index
|
||||
** header into structure pWal->hdr. If the contents of pWal->hdr are
|
||||
** modified by this and pChanged is not NULL, set *pChanged to 1.
|
||||
** Otherwise leave *pChanged unmodified.
|
||||
** Try to read the wal-index header. Return 0 on success and 1 if
|
||||
** there is a problem.
|
||||
**
|
||||
** The wal-index is in shared memory. Another thread or process might
|
||||
** be writing the header at the same time this procedure is trying to
|
||||
** read it, which might result in inconsistency. A dirty read is detected
|
||||
** by verifying a checksum on the header.
|
||||
**
|
||||
** If and only if the read is consistent and the header is different from
|
||||
** pWal->hdr, then pWal->hdr is updated to the content of the new header
|
||||
** and *pChanged is set to 1.
|
||||
**
|
||||
** If the checksum cannot be verified return non-zero. If the header
|
||||
** 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];
|
||||
|
||||
@@ -951,7 +1010,10 @@ 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.
|
||||
*/
|
||||
memcpy(aHdr, (void*)pWal->pWiData, sizeof(aHdr));
|
||||
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]
|
||||
@@ -969,9 +1031,19 @@ int walIndexTryHdr(Wal *pWal, int *pChanged){
|
||||
}
|
||||
|
||||
/*
|
||||
** Read the wal-index header from the wal-index file into structure
|
||||
** pWal->hdr. If attempting to verify the header checksum fails, try
|
||||
** to recover the log before returning.
|
||||
** Read the wal-index header from the wal-index and into pWal->hdr.
|
||||
** If the wal-header appears to be corrupt, try to recover the log
|
||||
** before returning.
|
||||
**
|
||||
** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
|
||||
** changed by this opertion. If pWal->hdr is unchanged, set *pChanged
|
||||
** to 0.
|
||||
**
|
||||
** This routine also maps the wal-index content into memory and assigns
|
||||
** ownership of that mapping to the current thread. In some implementations,
|
||||
** only one thread at a time can hold a mapping of the wal-index. Hence,
|
||||
** the caller should strive to invoke walIndexUnmap() as soon as possible
|
||||
** after this routine returns.
|
||||
**
|
||||
** If the wal-index header is successfully read, return SQLITE_OK.
|
||||
** Otherwise an SQLite error code.
|
||||
@@ -1032,7 +1104,16 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
||||
}
|
||||
|
||||
/*
|
||||
** Lock a snapshot.
|
||||
** Take a snapshot of the state of the WAL and wal-index for the current
|
||||
** instant in time. The current thread will continue to use this snapshot.
|
||||
** Other threads might containing appending to the WAL and wal-index but
|
||||
** the extra content appended will be ignored by the current thread.
|
||||
**
|
||||
** A snapshot is like a read transaction.
|
||||
**
|
||||
** No other threads are allowed to run a checkpoint while this thread is
|
||||
** holding the snapshot since a checkpoint would remove data out from under
|
||||
** this thread.
|
||||
**
|
||||
** If this call obtains a new read-lock and the database contents have been
|
||||
** modified since the most recent call to WalCloseSnapshot() on this Wal
|
||||
@@ -1319,9 +1400,9 @@ int sqlite3WalFrames(
|
||||
assert( pWal->lockState==SQLITE_SHM_WRITE );
|
||||
assert( pWal->pWiData==0 );
|
||||
|
||||
/* If this is the first frame written into the log, write the log
|
||||
** header to the start of the log file. See comments at the top of
|
||||
** this file for a description of the log-header format.
|
||||
/* If this is the first frame written into the log, write the WAL
|
||||
** header to the start of the WAL file. See comments at the top of
|
||||
** this source file for a description of the WAL header format.
|
||||
*/
|
||||
assert( WAL_FRAME_HDRSIZE>=WAL_HDRSIZE );
|
||||
iFrame = pWal->hdr.iLastPg;
|
||||
@@ -1355,7 +1436,7 @@ int sqlite3WalFrames(
|
||||
}
|
||||
|
||||
/* Write the page data */
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, p->pData, nPgsz, iOffset + sizeof(aFrame));
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, p->pData, nPgsz, iOffset+sizeof(aFrame));
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
@@ -1392,7 +1473,7 @@ int sqlite3WalFrames(
|
||||
assert( pWal->pWiData==0 );
|
||||
|
||||
/* Append data to the wal-index. It is not necessary to lock the
|
||||
** wal-index to do this as the RESERVED lock held on the db file
|
||||
** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
|
||||
** guarantees that there are no other writers, and no data that may
|
||||
** be in use by existing readers is being overwritten.
|
||||
*/
|
||||
@@ -1476,7 +1557,7 @@ int sqlite3WalCheckpoint(
|
||||
}
|
||||
if( isChanged ){
|
||||
/* If a new wal-index header was loaded before the checkpoint was
|
||||
** performed, then the pager-cache associated with log pWal is now
|
||||
** performed, then the pager-cache associated with pWal is now
|
||||
** out of date. So zero the cached wal-index header to ensure that
|
||||
** next time the pager opens a snapshot on this database it knows that
|
||||
** the cache needs to be reset.
|
||||
|
Reference in New Issue
Block a user