From: dan Date: Mon, 8 Dec 2014 07:50:31 +0000 (+0000) Subject: Update this branch with latest trunk changes. X-Git-Tag: version-3.8.11~252^2~68 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a99e9fb01446941311cab7aa9eec267169c4485;p=thirdparty%2Fsqlite.git Update this branch with latest trunk changes. FossilOrigin-Name: 69a312ad3fe5b39bc394b9ce958cb63d734518c7 --- 0a99e9fb01446941311cab7aa9eec267169c4485 diff --cc manifest index 61039ed68d,2427334a17..96dcf87dd3 --- a/manifest +++ b/manifest @@@ -1,9 -1,9 +1,9 @@@ - C Update\scomments\sin\ssqlite3ota.h\sto\sremove\sthe\s"must\shave\sPRIMARY\sKEY"\srestriction. - D 2014-12-08T07:28:26.753 -C Avoid\saccessing\sa\ssingle\suninitialized\sbyte\swhen\smoving\sa\srare\s3-byte\scell\sfrom\san\sinternal\spage\sto\sa\sleaf.\sThis\swas\snot\sactually\scausing\sa\sproblem,\sjust\sa\svalgrind\swarning. -D 2014-12-06T14:56:49.956 ++C Update\sthis\sbranch\swith\slatest\strunk\schanges. ++D 2014-12-08T07:50:31.222 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f - F Makefile.in a226317fdf3f4c895fb3cfedc355b4d0868ce1fb + F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 - F Makefile.msc 788f1288633a0c3c3cbbe0f3e4827d033f7ba530 + F Makefile.msc 10720782f88648bf2b5dcedf4c1524b067d43e47 F Makefile.vxworks 034289efa9d591b04b1a73598623119c306cbba0 F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8 F VERSION d846487aff892625eb8e75960234e7285f0462fe @@@ -188,7 -173,7 +188,7 @@@ F src/auth.c b56c78ebe40a2110fd361379f7 F src/backup.c 7ddee9c7d505e07e959a575b18498f17c71e53ea F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 - F src/btree.c 1ab82a27ed4f1e8dc640b7ca0ffb074c4233e495 -F src/btree.c 9023963463b0b1876aea1abc6d208d9ffa0228ae ++F src/btree.c 7071995e9ab92173f43e9d1b8560a8db64a31e9a F src/btree.h e31a3a3ebdedb1caf9bda3ad5dbab3db9b780f6e F src/btreeInt.h 3363e18fd76f69a27a870b25221b2345b3fd4d21 F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8 @@@ -196,8 -181,8 +196,8 @@@ F src/callback.c 7b44ce59674338ad48b0e8 F src/complete.c c4ba6e0626bb94bc77a0861735f3382fcf7cc818 F src/ctime.c df19848891c8a553c80e6f5a035e768280952d1a F src/date.c 93594514aae68de117ca4a2a0d6cc63eddf26744 -F src/delete.c 0750b1eb4d96cd3fb2c798599a3a7c85e92f1417 +F src/delete.c 2d2c4ff24bda5d28000d0aeb05960ee2883a2d3a - F src/expr.c 73de4c0da2eed6b149d40a05c589dfeb2c4a87a1 + F src/expr.c 00da3072f362b06f39ce4052baa1d4ce2bb36d1c F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7 F src/func.c 6d3c4ebd72aa7923ce9b110a7dc15f9b8c548430 @@@ -210,7 -195,7 +210,7 @@@ F src/journal.c b4124532212b6952f42eb2c F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994 - F src/main.c cd819123ed552a15c37bd2fd5360db25015dc461 -F src/main.c e50203613fb77e2f28deb51425ee52b3879e85f8 ++F src/main.c eac81ee5cb0f94b496c15f20fcbabe4530b9a8c1 F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f @@@ -231,29 -216,29 +231,29 @@@ F src/os_setup.h c9d4553b5aaa6f73391448 F src/os_unix.c fb587121840f690101336879adfa6d0b2cd0e8c7 F src/os_win.c a9e500dd963fb1f67d7860e58b5772abe6123862 F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21 - F src/pager.c 9fe27a768be53dbe0a818ae10791dc36100a0e76 -F src/pager.c 7a5c5bc0e29b9b16834f5558a9d5d22bbae59a08 -F src/pager.h d1eee3c3f741be247ce6d82752a178515fc8578b ++F src/pager.c 47f13c194a980ed55dd4825f286d40d49c4a7093 +F src/pager.h c6157af66a9999797629968921133f67716f8f9f F src/parse.y 5dfead8aed90cb0c7c1115898ee2266804daff45 F src/pcache.c ace1b67632deeaa84859b4c16c27711dfb7db3d4 F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8 F src/pcache1.c facbdd3ecc09c8f750089d941305694301328e98 - F src/pragma.c 8e0087a5ae6e60ac9ed48df19025cb423e3c8c34 -F src/pragma.c d54cdd40b63d608f2d95b7482c710690e3593a73 ++F src/pragma.c 294c31d79dfcb6f9cea49528b19e5f8b25e3d5ec F src/prepare.c b7b7bf020bd4c962f7c8aed5a3c542c7dfe9f9c7 F src/printf.c 9e75a6a0b55bf61cfff7d7e19d89834a1b938236 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 - F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 + F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e - F src/select.c 428165951748151e87a15295b7357221433e311b - F src/shell.c bc28d5992109717c87804e2eb1a08a7c8cc7a2fd - F src/sqlite.h.in f60a24616a6a7e622266e723ed141f0c6131514e + F src/select.c f377fb8a5c73c10678ea74f3400f7913943e3d75 + F src/shell.c 45d9c9bd7cde07845af957f2d849933b990773cf -F src/sqlite.h.in 6ec654324cb490ea3d8a7be28b8c7d37fe4ad282 ++F src/sqlite.h.in 8f704473c8301f3c9cc044d10020bb3d5955dfc3 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d - F src/sqliteInt.h 32d7becef5cbd9a1118608921ec99f00f96c6e5d -F src/sqliteInt.h 28049b803b74a7f73242a8226915ea00ebb1309f ++F src/sqliteInt.h 9d7b1d5adfcc026971957d440b796f2b26b82d0c F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc -F src/tclsqlite.c 0a874655dd39a9875e39c5d3c464db662171d228 -F src/test1.c ebb8cd3c94a2ac8851b7b0b1349284e73a8b4c7a +F src/tclsqlite.c 8cf7d53aa1e1393b79457e4d49a29c18fa8403bd - F src/test1.c 76b5cbefaac443f48f05d3621f5cedc7b2801c65 ++F src/test1.c fed17ded5498378fea274f2de0fa7b0b89f855f7 F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@@ -310,16 -295,16 +310,16 @@@ F src/vdbe.c 1a9e671c9cfc259e4d2affc71f F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 F src/vdbeapi.c 07acb615d1e4170e71fc1b0d087f3c53a1ad8e83 - F src/vdbeaux.c 5ce4f414147a3bc3cbcf00ec57f2606c25791629 + F src/vdbeaux.c 6f7f39c3fcf0f5923758df8561bb5d843908a553 -F src/vdbeblob.c 4af4bfb71f6df7778397b4a0ebc1879793276778 +F src/vdbeblob.c 317c71482ed73b0966db2d1c4e20839be3e9fe79 F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f - F src/vdbesort.c 87f3923483113d1c95d84640becb4e4946f27d9a + F src/vdbesort.c 42c166f7ca78cb643c7f4e4bdfa83c59d363d1a6 F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010 - F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 - F src/wal.c d5c581b635951cf5513ec9699d118b32323443f3 + F src/vtab.c c08ec66f45919eaa726bf88aa53eb08379d607f9 -F src/wal.c 847692349eb6e1fb8543dbc97e69ddbfa4cc7ea7 -F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 ++F src/wal.c 632d9afe19e11cc49a8b74ff52ec2a415568b958 +F src/wal.h 0d3ba0c3f1b4c25796cb213568a84b9f9063f465 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 - F src/where.c e275cb74731a3351a9da6ba8280bd5054db6192d + F src/where.c e914fdb9159bb36af4a673193bbda08aaf9e5a73 F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@@ -792,7 -779,7 +795,7 @@@ F test/pagesize.test 1dd51367e752e742f5 F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54 - F test/permutations.test 19cc048448340952b08a897167ec7b7bc85142b9 -F test/permutations.test 4e12d43f4639ea8a0e366d9c64e0009afe2eb544 ++F test/permutations.test 7828a776c70fccf83d2e35d0e1efc191b3e0c646 F test/pragma.test 49ac8a73c0daa574824538fed28727d1259fe735 F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 @@@ -1237,7 -1225,7 +1241,7 @@@ F tool/vdbe_profile.tcl 67746953071a9f8 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f - P 46069393b3141ab198f0fcc4f6c05229f06bf1e8 - R 2ff45547a2c264d0b419c476d87c1792 -P dd1dd4451f468599f7a0c2f7b5ee6125db3bb152 -R fd0e43f358120e3c011052c6be23c038 ++P 088a41eb8c18886a260cf53fa0cca3bd1958dc05 6aeece19a235344be2537e66a3fe08b1febfb5a0 ++R 22c55b7623330ec4e5635caf9d27c83c U dan - Z 50a00d12069d2404879b86db79315481 -Z 22968e22e0931f64edb1c44af2aed6b9 ++Z 93c0d69763bbc98aa3e78f69481d4c3f diff --cc manifest.uuid index 85a4152dfb,7af5128636..3420b8955c --- a/manifest.uuid +++ b/manifest.uuid @@@ -1,1 -1,1 +1,1 @@@ - 088a41eb8c18886a260cf53fa0cca3bd1958dc05 -6aeece19a235344be2537e66a3fe08b1febfb5a0 ++69a312ad3fe5b39bc394b9ce958cb63d734518c7 diff --cc src/pager.c index 3508a9f937,a2ae9cc410..a5bba528ee --- a/src/pager.c +++ b/src/pager.c @@@ -7119,9 -7073,10 +7119,10 @@@ void sqlite3PagerClearCache(Pager *pPag */ int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){ int rc = SQLITE_OK; - if( pPager->pWal ){ + if( pPager->pWal && PagerOtaMode(pPager)==0 ){ rc = sqlite3WalCheckpoint(pPager->pWal, eMode, - pPager->xBusyHandler, pPager->pBusyHandlerArg, + (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler), + pPager->pBusyHandlerArg, pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace, pnLog, pnCkpt ); diff --cc src/wal.c index bb8c0f806e,2b80c7a95e..726afbeb2a --- a/src/wal.c +++ b/src/wal.c @@@ -1649,186 -1623,38 +1649,218 @@@ static int walPagesize(Wal *pWal) return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16); } +/* +** Initialize the contents of the WalCkpt object indicated by the final +** argument and begin a checkpoint operation. The CKPT lock must already +** be held when this function is called. +** +** Return SQLITE_OK if successful or an error code otherwise. +*/ +static int walCheckpointStart( + Wal *pWal, /* Wal connection */ + u8 *aBuf, /* Page-sized temporary buffer */ + int nBuf, /* Size of aBuf[] in bytes */ + int (*xBusy)(void*), /* Function to call when busy (or NULL) */ + void *pBusyArg, /* Context argument for xBusyHandler */ + int sync_flags, /* Flags for OsSync() (or 0) */ + WalCkpt *p /* Allocated object to populate */ +){ + int rc; /* Return code */ + int i; /* Iterator variable */ + + memset(p, 0, sizeof(WalCkpt)); + if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ + return SQLITE_CORRUPT_BKPT; + } + + p->szPage = walPagesize(pWal); + p->pWal = pWal; + p->aBuf = aBuf; + p->sync_flags = sync_flags; + testcase( p->szPage<=32768 ); + testcase( p->szPage>=65536 ); + p->pInfo = walCkptInfo(pWal); + if( p->pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK; + + /* Allocate the iterator */ + rc = walIteratorInit(pWal, &p->pIter); + if( rc!=SQLITE_OK ) return rc; + assert( p->pIter ); + + /* Compute in mxSafeFrame the index of the last frame of the WAL that is + ** safe to write into the database. Frames beyond mxSafeFrame might + ** overwrite database pages that are in use by active readers and thus + ** cannot be backfilled from the WAL. + */ + p->mxSafeFrame = pWal->hdr.mxFrame; + p->mxPage = pWal->hdr.nPage; + for(i=1; ipInfo->aReadMark[i]; + if( p->mxSafeFrame>y ){ + assert( y<=pWal->hdr.mxFrame ); + rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); + if( rc==SQLITE_OK ){ + p->pInfo->aReadMark[i] = (i==1 ? p->mxSafeFrame : READMARK_NOT_USED); + walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); + }else if( rc==SQLITE_BUSY ){ + p->mxSafeFrame = y; + xBusy = 0; + }else{ + walIteratorFree(p->pIter); + p->pIter = 0; + return rc; + } + } + } + + if( p->pInfo->nBackfill>=p->mxSafeFrame + || (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))!=SQLITE_OK + ){ + walIteratorFree(p->pIter); + p->pIter = 0; + } + if( rc==SQLITE_BUSY ) rc = SQLITE_OK; + + if( rc==SQLITE_OK && p->pIter ){ + /* Sync the WAL to disk */ + if( sync_flags ){ + rc = sqlite3OsSync(pWal->pWalFd, sync_flags); + } + + /* If the database may grow as a result of this checkpoint, hint + ** about the eventual size of the db file to the VFS layer. */ + if( rc==SQLITE_OK ){ + i64 nSize; /* Current size of database file */ + i64 nReq = ((i64)p->mxPage * p->szPage); + rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); + if( rc==SQLITE_OK && nSizepDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); + } + } + } + + return rc; +} + +/* +** Attempt to copy the next frame from the wal file to the database file. If +** there are no more frames to copy to the database file return SQLITE_DONE. +** If the frame is successfully copied, return SQLITE_OK. Or, if an error +** occurs, return an SQLite error code. +*/ +static int walCheckpointStep(WalCkpt *p){ + u32 iDbpage = 0; /* Next database page to write */ + u32 iFrame = 0; /* Wal frame containing data for iDbpage */ + int rc = SQLITE_DONE; + + assert( p->rc==SQLITE_OK ); + while( p->pIter && 0==walIteratorNext(p->pIter, &iDbpage, &iFrame) ){ + i64 iOffset; + assert( walFramePgno(p->pWal, iFrame)==iDbpage ); + p->nStep++; + if( iFrame<=p->pInfo->nBackfill + || iFrame>p->mxSafeFrame + || iDbpage>p->mxPage + ){ + continue; + } + + iOffset = walFrameOffset(iFrame, p->szPage) + WAL_FRAME_HDRSIZE; + /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ + rc = sqlite3OsRead(p->pWal->pWalFd, p->aBuf, p->szPage, iOffset); + if( rc!=SQLITE_OK ) break; + iOffset = (iDbpage-1)*(i64)p->szPage; + testcase( IS_BIG_INT(iOffset) ); + rc = sqlite3OsWrite(p->pWal->pDbFd, p->aBuf, p->szPage, iOffset); + break; + } + + p->rc = rc; + return rc; +} + +/* +** The current round of checkpointing work using the object indicated by +** the only argument is now finished. If no error occcurred, this function +** saves the results to shared memory (i.e. updates the WalCkptInfo.nBackfill +** variable), and truncates and syncs the database file as required. +** +** All dynamic resources currently held by the WalCkpt object are released. +** It is the responsibility of the caller to delete the WalCkpt itself if +** required. +*/ +static int walCheckpointFinalize(WalCkpt *p){ + if( p->pIter ){ + int rc = p->rc; + Wal *pWal = p->pWal; + + if( rc==SQLITE_DONE ){ + /* If work was completed */ + rc = SQLITE_OK; + if( p->mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ + i64 szDb = pWal->hdr.nPage*(i64)p->szPage; + testcase( IS_BIG_INT(szDb) ); + rc = sqlite3OsTruncate(pWal->pDbFd, szDb); + if( rc==SQLITE_OK && p->sync_flags ){ + rc = sqlite3OsSync(pWal->pDbFd, p->sync_flags); + } + } + if( rc==SQLITE_OK ){ + p->pInfo->nBackfill = p->mxSafeFrame; + } + p->rc = rc; + }else{ +#ifdef SQLITE_ENABLE_OTA + if( rc==SQLITE_OK && p->sync_flags ){ + /* If work was not completed, but no error has occured. */ + p->rc = sqlite3OsSync(pWal->pDbFd, p->sync_flags); + } +#else + assert( rc!=SQLITE_OK ); +#endif + } + + /* Release the reader lock held while backfilling */ + walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); + walIteratorFree(p->pIter); + p->pIter = 0; + } + + return p->rc; +} + + /* + ** The following is guaranteed when this function is called: + ** + ** a) the WRITER lock is held, + ** b) the entire log file has been checkpointed, and + ** c) any existing readers are reading exclusively from the database + ** file - there are no readers that may attempt to read a frame from + ** the log file. + ** + ** This function updates the shared-memory structures so that the next + ** client to write to the database (which may be this one) does so by + ** writing frames into the start of the log file. + ** + ** The value of parameter salt1 is used as the aSalt[1] value in the + ** new wal-index header. It should be passed a pseudo-random value (i.e. + ** one obtained from sqlite3_randomness()). + */ + static void walRestartHdr(Wal *pWal, u32 salt1){ + volatile WalCkptInfo *pInfo = walCkptInfo(pWal); + int i; /* Loop counter */ + u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ + pWal->nCkpt++; + pWal->hdr.mxFrame = 0; + sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); + memcpy(&pWal->hdr.aSalt[1], &salt1, 4); + walIndexWriteHdr(pWal); + pInfo->nBackfill = 0; + pInfo->aReadMark[1] = 0; + for(i=2; iaReadMark[i] = READMARK_NOT_USED; + assert( pInfo->aReadMark[0]==0 ); + } + /* ** Copy as much content as we can from the WAL back into the database file ** in response to an sqlite3_wal_checkpoint() request or the equivalent. @@@ -1863,39 -1689,157 +1895,60 @@@ static int walCheckpoint( Wal *pWal, /* Wal connection */ int eMode, /* One of PASSIVE, FULL or RESTART */ - int (*xBusyCall)(void*), /* Function to call when busy */ + int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ int sync_flags, /* Flags for OsSync() (or 0) */ - u8 *zBuf /* Temporary buffer to use */ + u8 *zBuf, /* Temporary buffer to use */ + int nBuf /* Size of zBuf in bytes */ ){ int rc; /* Return code */ - int (*xBusy)(void*) = 0; /* Function to call when waiting for locks */ - int szPage; /* Database page-size */ - WalIterator *pIter = 0; /* Wal iterator context */ - u32 iDbpage = 0; /* Next database page to write */ - u32 iFrame = 0; /* Wal frame containing data for iDbpage */ - u32 mxSafeFrame; /* Max frame that can be backfilled */ - u32 mxPage; /* Max database page to write */ - int i; /* Loop counter */ - volatile WalCkptInfo *pInfo; /* The checkpoint status information */ - - szPage = walPagesize(pWal); - testcase( szPage<=32768 ); - testcase( szPage>=65536 ); - pInfo = walCkptInfo(pWal); - if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK; - - /* Allocate the iterator */ - rc = walIteratorInit(pWal, &pIter); - if( rc!=SQLITE_OK ){ - return rc; - } - assert( pIter ); + WalCkpt sC; - if( eMode!=SQLITE_CHECKPOINT_PASSIVE ) xBusy = xBusyCall; + /* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked + ** in the SQLITE_CHECKPOINT_PASSIVE mode. */ + assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); + - /* Compute in mxSafeFrame the index of the last frame of the WAL that is - ** safe to write into the database. Frames beyond mxSafeFrame might - ** overwrite database pages that are in use by active readers and thus - ** cannot be backfilled from the WAL. - */ - mxSafeFrame = pWal->hdr.mxFrame; - mxPage = pWal->hdr.nPage; - for(i=1; iaReadMark[i]; - if( mxSafeFrame>y ){ - assert( y<=pWal->hdr.mxFrame ); - rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1); - if( rc==SQLITE_OK ){ - pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED); - walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); - }else if( rc==SQLITE_BUSY ){ - mxSafeFrame = y; - xBusy = 0; - }else{ - goto walcheckpoint_out; - } - } - } - - if( pInfo->nBackfillnBackfill; - - /* Sync the WAL to disk */ - if( sync_flags ){ - rc = sqlite3OsSync(pWal->pWalFd, sync_flags); - } - - /* If the database may grow as a result of this checkpoint, hint - ** about the eventual size of the db file to the VFS layer. - */ - if( rc==SQLITE_OK ){ - i64 nReq = ((i64)mxPage * szPage); - rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); - if( rc==SQLITE_OK && nSizepDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); - } - } - + rc = walCheckpointStart(pWal, zBuf, nBuf, xBusy, pBusyArg, sync_flags, &sC); + if( sC.pIter==0 ) goto walcheckpoint_out; + assert( rc==SQLITE_OK ); - /* Iterate through the contents of the WAL, copying data to the db file. */ - while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ - i64 iOffset; - assert( walFramePgno(pWal, iFrame)==iDbpage ); - if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue; - iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; - /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ - rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); - if( rc!=SQLITE_OK ) break; - iOffset = (iDbpage-1)*(i64)szPage; - testcase( IS_BIG_INT(iOffset) ); - rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); - if( rc!=SQLITE_OK ) break; - } - - /* If work was actually accomplished... */ - if( rc==SQLITE_OK ){ - if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ - i64 szDb = pWal->hdr.nPage*(i64)szPage; - testcase( IS_BIG_INT(szDb) ); - rc = sqlite3OsTruncate(pWal->pDbFd, szDb); - if( rc==SQLITE_OK && sync_flags ){ - rc = sqlite3OsSync(pWal->pDbFd, sync_flags); - } - } - if( rc==SQLITE_OK ){ - pInfo->nBackfill = mxSafeFrame; - } - } - - /* Release the reader lock held while backfilling */ - walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); - } - - if( rc==SQLITE_BUSY ){ - /* Reset the return code so as not to report a checkpoint failure - ** just because there are active readers. */ - rc = SQLITE_OK; - } + /* Step the checkpoint object until it reports something other than + ** SQLITE_OK. */ + while( SQLITE_OK==(rc = walCheckpointStep(&sC)) ); + rc = walCheckpointFinalize(&sC); - /* If this is an SQLITE_CHECKPOINT_RESTART operation, and the entire wal - ** file has been copied into the database file, then block until all - ** readers have finished using the wal file. This ensures that the next - ** process to write to the database restarts the wal file. + /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the + ** entire wal file has been copied into the database file, then block + ** until all readers have finished using the wal file. This ensures that + ** the next process to write to the database restarts the wal file. */ if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){ assert( pWal->writeLock ); - if( pInfo->nBackfillhdr.mxFrame ){ + if( sC.pInfo->nBackfillhdr.mxFrame ){ rc = SQLITE_BUSY; - }else if( eMode==SQLITE_CHECKPOINT_RESTART ){ + }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){ + u32 salt1; + sqlite3_randomness(4, &salt1); - assert( mxSafeFrame==pWal->hdr.mxFrame ); + assert( sC.mxSafeFrame==pWal->hdr.mxFrame ); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1); if( rc==SQLITE_OK ){ + if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){ + /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as + ** SQLITE_CHECKPOINT_RESTART with the addition that it also + ** truncates the log file to zero bytes just prior to a + ** successful return. + ** + ** In theory, it might be safe to do this without updating the + ** wal-index header in shared memory, as all subsequent reader or + ** writer clients should see that the entire log file has been + ** checkpointed and behave accordingly. This seems unsafe though, + ** as it would leave the system in a state where the contents of + ** the wal-index header do not match the contents of the + ** file-system. To avoid this, update the wal-index header to + ** indicate that the log file contains zero valid frames. */ + walRestartHdr(pWal, salt1); + rc = sqlite3OsTruncate(pWal->pWalFd, 0); + } walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); } } @@@ -3081,7 -3016,11 +3135,7 @@@ int sqlite3WalCheckpoint /* Copy data from the log to the database file. */ if( rc==SQLITE_OK ){ - rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf, nBuf); - if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ - rc = SQLITE_CORRUPT_BKPT; - }else{ - rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf); - } ++ rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf, nBuf); /* If no error occurred, set the output variables. */ if( rc==SQLITE_OK || rc==SQLITE_BUSY ){