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-----
|
-----BEGIN PGP SIGNED MESSAGE-----
|
||||||
Hash: SHA1
|
Hash: SHA1
|
||||||
|
|
||||||
C Mark\sthe\sshared-memory\sin\sthe\sWAL\simplementation\sas\svolatile.
|
C Refactoring\sof\sthe\sWalIterator\simplementation.
|
||||||
D 2010-05-18T13:27:13
|
D 2010-05-18T18:01:09
|
||||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||||
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
|
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -227,7 +227,7 @@ F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
|
|||||||
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
|
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
|
||||||
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
|
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
|
||||||
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
|
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
|
||||||
F src/wal.c 03c150ff23332a58dd0cf313c7b7defdd9ec6275
|
F src/wal.c cfbb818b50bec82675aa5322d7ee0e2b2c2a7386
|
||||||
F src/wal.h 434f76f51225bb614e43ccb6bd2341541ba6a06e
|
F src/wal.h 434f76f51225bb614e43ccb6bd2341541ba6a06e
|
||||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||||
F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356
|
F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356
|
||||||
@@ -816,14 +816,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
|||||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||||
P a029be10172e2e6a2ef4e3eb2ea1bd0ca85b16ed
|
P 0a6787908e989bd5e6af25acbdc59ebc8fa61d6d
|
||||||
R c3edbc896fce7d9f6c83f7337ac02298
|
R 70b31773a620515609c56c14086245f3
|
||||||
U drh
|
U drh
|
||||||
Z 88ded0b14b6354cb7517528585f793ca
|
Z 7b37c77bed71cbc8c1a6f26dcf7b1090
|
||||||
-----BEGIN PGP SIGNATURE-----
|
-----BEGIN PGP SIGNATURE-----
|
||||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||||
|
|
||||||
iD8DBQFL8pW0oxKgR168RlERAoCBAJ9VXFufUgFrlJ8vv69PNeEYGWy/IgCcD99s
|
iD8DBQFL8tXooxKgR168RlERAkToAJ4sc1mZ1q5W9au06n2/yU3i2HlYxwCdEuup
|
||||||
/C+oicnjvVyzr2OBGGMkk9c=
|
sJTTs22gXenKu7GRNzIKGS0=
|
||||||
=CSoB
|
=4glP
|
||||||
-----END PGP SIGNATURE-----
|
-----END PGP SIGNATURE-----
|
||||||
|
@@ -1 +1 @@
|
|||||||
0a6787908e989bd5e6af25acbdc59ebc8fa61d6d
|
b5b60fdcc5dcf41f2c79912075ac241f7ce220d6
|
325
src/wal.c
325
src/wal.c
@@ -44,7 +44,7 @@
|
|||||||
/*
|
/*
|
||||||
** WAL-INDEX FILE FORMAT
|
** 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
|
** 8-byte region that contains no useful data (used to apply byte-range locks
|
||||||
** in some implementations), followed by the data region.
|
** 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
|
** This structure is used to implement an iterator that loops through
|
||||||
** all frames in the log in database page order. Where two or more frames
|
** 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
|
** 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:
|
** 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()).
|
** This functionality is used by the checkpoint code (see walCheckpoint()).
|
||||||
*/
|
*/
|
||||||
struct WalIterator {
|
struct WalIterator {
|
||||||
int nSegment; /* Size of WalIterator.aSegment[] array */
|
int iPrior; /* Last result returned from the iterator */
|
||||||
int nFinal; /* Elements in segment nSegment-1 */
|
int nSegment; /* Size of the aSegment[] array */
|
||||||
|
int nFinal; /* Elements in aSegment[nSegment-1] */
|
||||||
struct WalSegment {
|
struct WalSegment {
|
||||||
int iNext; /* Next aIndex index */
|
int iNext; /* Next slot in aIndex[] not previously returned */
|
||||||
u8 *aIndex; /* Pointer to index array */
|
u8 *aIndex; /* i0, i1, i2... such that aPgno[iN] ascending */
|
||||||
u32 *aDbPage; /* Pointer to db page array */
|
u32 *aPgno; /* 256 page numbers. Pointer to Wal.pWiData */
|
||||||
} aSegment[1];
|
} aSegment[1]; /* One for every 256 entries in the WAL */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -302,59 +304,6 @@ static int walDecodeFrame(
|
|||||||
return 1;
|
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
|
** 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
|
** 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)
|
#define HASHTABLE_NBYTE (sizeof(HASHTABLE_DATATYPE)*HASHTABLE_NSLOT)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return the index in the WalIndex.aData array that corresponds to
|
** Return the index in the Wal.pWiData array that corresponds to
|
||||||
** frame iFrame. The wal-index file consists of a header, followed by
|
** frame iFrame.
|
||||||
** alternating "map" and "index" blocks.
|
**
|
||||||
|
** 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){
|
static int walIndexEntry(u32 iFrame){
|
||||||
return (
|
return (
|
||||||
@@ -715,20 +673,32 @@ int sqlite3WalOpen(
|
|||||||
return rc;
|
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(
|
static int walIteratorNext(
|
||||||
WalIterator *p, /* Iterator */
|
WalIterator *p, /* Iterator */
|
||||||
u32 *piPage, /* OUT: Next db page to write */
|
u32 *piPage, /* OUT: The page number of the next page */
|
||||||
u32 *piFrame /* OUT: Wal frame to read from */
|
u32 *piFrame /* OUT: Wal frame index of next page */
|
||||||
){
|
){
|
||||||
u32 iMin = *piPage;
|
u32 iMin; /* Result pgno must be greater than iMin */
|
||||||
u32 iRet = 0xFFFFFFFF;
|
u32 iRet = 0xFFFFFFFF; /* 0xffffffff is never a valid page number */
|
||||||
int i;
|
int i; /* For looping through segments */
|
||||||
int nBlock = p->nFinal;
|
int nBlock = p->nFinal; /* Number of entries in current segment */
|
||||||
|
|
||||||
|
iMin = p->iPrior;
|
||||||
|
assert( iMin<0xffffffff );
|
||||||
for(i=p->nSegment-1; i>=0; i--){
|
for(i=p->nSegment-1; i>=0; i--){
|
||||||
struct WalSegment *pSegment = &p->aSegment[i];
|
struct WalSegment *pSegment = &p->aSegment[i];
|
||||||
while( pSegment->iNext<nBlock ){
|
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>iMin ){
|
||||||
if( iPg<iRet ){
|
if( iPg<iRet ){
|
||||||
iRet = iPg;
|
iRet = iPg;
|
||||||
@@ -741,62 +711,143 @@ static int walIteratorNext(
|
|||||||
nBlock = 256;
|
nBlock = 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
*piPage = iRet;
|
*piPage = p->iPrior = iRet;
|
||||||
return (iRet==0xFFFFFFFF);
|
return (iRet==0xFFFFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int walIteratorInit(Wal *pWal, WalIterator **pp){
|
|
||||||
u32 *aData; /* Content of the wal-index file */
|
|
||||||
WalIterator *p; /* Return value */
|
|
||||||
int nSegment; /* Number of segments to merge */
|
|
||||||
u32 iLast; /* Last frame in log */
|
|
||||||
int nByte; /* Number of bytes to allocate */
|
|
||||||
int i; /* Iterator variable */
|
|
||||||
int nFinal; /* Number of unindexed entries */
|
|
||||||
u8 *aTmp; /* Temp space used by merge-sort */
|
|
||||||
int rc; /* Return code of walIndexMap() */
|
|
||||||
|
|
||||||
|
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 */
|
||||||
|
int nSegment; /* Number of segments to merge */
|
||||||
|
u32 iLast; /* Last frame in log */
|
||||||
|
int nByte; /* Number of bytes to allocate */
|
||||||
|
int i; /* Iterator variable */
|
||||||
|
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));
|
rc = walIndexMap(pWal, walMappingSize(pWal->hdr.iLastPg));
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
return rc;
|
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;
|
aData = (u32*)pWal->pWiData;
|
||||||
|
|
||||||
|
/* Allocate space for the WalIterator object */
|
||||||
iLast = pWal->hdr.iLastPg;
|
iLast = pWal->hdr.iLastPg;
|
||||||
nSegment = (iLast >> 8) + 1;
|
nSegment = (iLast >> 8) + 1;
|
||||||
nFinal = (iLast & 0x000000FF);
|
nFinal = (iLast & 0x000000FF);
|
||||||
|
|
||||||
nByte = sizeof(WalIterator) + (nSegment+1)*(sizeof(struct WalSegment)+256);
|
nByte = sizeof(WalIterator) + (nSegment+1)*(sizeof(struct WalSegment)+256);
|
||||||
p = (WalIterator *)sqlite3_malloc(nByte);
|
p = (WalIterator *)sqlite3_malloc(nByte);
|
||||||
if( !p ){
|
if( !p ){
|
||||||
rc = SQLITE_NOMEM;
|
return SQLITE_NOMEM;
|
||||||
}else{
|
}
|
||||||
u8 *aSpace;
|
memset(p, 0, nByte);
|
||||||
memset(p, 0, nByte);
|
|
||||||
p->nSegment = nSegment;
|
|
||||||
|
|
||||||
aSpace = (u8 *)&p->aSegment[nSegment];
|
/* Initialize the WalIterator object. Each 256-entry segment is
|
||||||
aTmp = &aSpace[nSegment*256];
|
** presorted in order to make iterating through all entries much
|
||||||
for(i=0; i<nSegment; i++){
|
** faster.
|
||||||
int j;
|
*/
|
||||||
int nIndex = (i==nSegment-1) ? nFinal : 256;
|
p->nSegment = nSegment;
|
||||||
p->aSegment[i].aDbPage = &aData[walIndexEntry(i*256+1)];
|
aSpace = (u8 *)&p->aSegment[nSegment];
|
||||||
p->aSegment[i].aIndex = aSpace;
|
aTmp = &aSpace[nSegment*256];
|
||||||
for(j=0; j<nIndex; j++){
|
for(i=0; i<nSegment; i++){
|
||||||
aSpace[j] = j;
|
int j;
|
||||||
}
|
int nIndex = (i==nSegment-1) ? nFinal : 256;
|
||||||
walMergesort8(p->aSegment[i].aDbPage, aTmp, aSpace, &nIndex);
|
p->aSegment[i].aPgno = &aData[walIndexEntry(i*256+1)];
|
||||||
memset(&aSpace[nIndex], aSpace[nIndex-1], 256-nIndex);
|
p->aSegment[i].aIndex = aSpace;
|
||||||
aSpace += 256;
|
for(j=0; j<nIndex; j++){
|
||||||
p->nFinal = nIndex;
|
aSpace[j] = j;
|
||||||
}
|
}
|
||||||
|
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;
|
*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){
|
static void walIteratorFree(WalIterator *p){
|
||||||
sqlite3_free(p);
|
sqlite3_free(p);
|
||||||
@@ -924,16 +975,24 @@ int sqlite3WalClose(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Try to read the wal-index header. Attempt to verify the header
|
** Try to read the wal-index header. Return 0 on success and 1 if
|
||||||
** checksum. If the checksum can be verified, copy the wal-index
|
** there is a problem.
|
||||||
** header into structure pWal->hdr. If the contents of pWal->hdr are
|
**
|
||||||
** modified by this and pChanged is not NULL, set *pChanged to 1.
|
** The wal-index is in shared memory. Another thread or process might
|
||||||
** Otherwise leave *pChanged unmodified.
|
** 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
|
** If the checksum cannot be verified return non-zero. If the header
|
||||||
** is read successfully and the checksum verified, return zero.
|
** is read successfully and the checksum verified, return zero.
|
||||||
*/
|
*/
|
||||||
int walIndexTryHdr(Wal *pWal, int *pChanged){
|
int walIndexTryHdr(Wal *pWal, int *pChanged){
|
||||||
|
int i;
|
||||||
|
volatile u32 *aWiData;
|
||||||
u32 aCksum[2] = {1, 1};
|
u32 aCksum[2] = {1, 1};
|
||||||
u32 aHdr[WALINDEX_HDR_NFIELD+2];
|
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
|
** file, meaning it is possible that an inconsistent snapshot is read
|
||||||
** from the file. If this happens, return non-zero.
|
** 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);
|
walChecksumBytes((u8*)aHdr, sizeof(u32)*WALINDEX_HDR_NFIELD, aCksum);
|
||||||
if( aCksum[0]!=aHdr[WALINDEX_HDR_NFIELD]
|
if( aCksum[0]!=aHdr[WALINDEX_HDR_NFIELD]
|
||||||
|| aCksum[1]!=aHdr[WALINDEX_HDR_NFIELD+1]
|
|| 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
|
** Read the wal-index header from the wal-index and into pWal->hdr.
|
||||||
** pWal->hdr. If attempting to verify the header checksum fails, try
|
** If the wal-header appears to be corrupt, try to recover the log
|
||||||
** to recover the log before returning.
|
** 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.
|
** If the wal-index header is successfully read, return SQLITE_OK.
|
||||||
** Otherwise an SQLite error code.
|
** 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
|
** 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
|
** 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->lockState==SQLITE_SHM_WRITE );
|
||||||
assert( pWal->pWiData==0 );
|
assert( pWal->pWiData==0 );
|
||||||
|
|
||||||
/* If this is the first frame written into the log, write the log
|
/* If this is the first frame written into the log, write the WAL
|
||||||
** header to the start of the log file. See comments at the top of
|
** header to the start of the WAL file. See comments at the top of
|
||||||
** this file for a description of the log-header format.
|
** this source file for a description of the WAL header format.
|
||||||
*/
|
*/
|
||||||
assert( WAL_FRAME_HDRSIZE>=WAL_HDRSIZE );
|
assert( WAL_FRAME_HDRSIZE>=WAL_HDRSIZE );
|
||||||
iFrame = pWal->hdr.iLastPg;
|
iFrame = pWal->hdr.iLastPg;
|
||||||
@@ -1355,7 +1436,7 @@ int sqlite3WalFrames(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write the page data */
|
/* 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 ){
|
if( rc!=SQLITE_OK ){
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -1392,7 +1473,7 @@ int sqlite3WalFrames(
|
|||||||
assert( pWal->pWiData==0 );
|
assert( pWal->pWiData==0 );
|
||||||
|
|
||||||
/* Append data to the wal-index. It is not necessary to lock the
|
/* 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
|
** guarantees that there are no other writers, and no data that may
|
||||||
** be in use by existing readers is being overwritten.
|
** be in use by existing readers is being overwritten.
|
||||||
*/
|
*/
|
||||||
@@ -1476,7 +1557,7 @@ int sqlite3WalCheckpoint(
|
|||||||
}
|
}
|
||||||
if( isChanged ){
|
if( isChanged ){
|
||||||
/* If a new wal-index header was loaded before the checkpoint was
|
/* 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
|
** 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
|
** next time the pager opens a snapshot on this database it knows that
|
||||||
** the cache needs to be reset.
|
** the cache needs to be reset.
|
||||||
|
Reference in New Issue
Block a user