From: dan Date: Thu, 18 Nov 2010 12:11:05 +0000 (+0000) Subject: Modify the interface to the blocking wal-checkpoint functionality. X-Git-Tag: version-3.7.6~174^2~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cdc1f049bf19766b4847cb59ec87b680e2982671;p=thirdparty%2Fsqlite.git Modify the interface to the blocking wal-checkpoint functionality. FossilOrigin-Name: 72787c010c8944e8fcf9c98aa4482f129142d8e9 --- diff --git a/manifest b/manifest index a133dac267..7dd2eb66e6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sexperimental\scommand\s"PRAGMA\swal_blocking_checkpoint",\swhich\suses\sthe\sbusy-handler\sto\sblock\suntil\sall\sreaders\shave\sfinished\sin\sorder\sto\sensure\sthe\snext\swriter\swill\sbe\sable\sto\swrap\saround\sto\sthe\sstart\sof\sthe\slog\sfile. -D 2010-11-16T18:56:51 +C Modify\sthe\sinterface\sto\sthe\sblocking\swal-checkpoint\sfunctionality. +D 2010-11-18T12:11:05 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in e7a59672eaeb04408d1fa8501618d7501a3c5e39 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -119,8 +119,8 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c d5b0137bc20327af08c14772227cc35134839c30 F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff -F src/btree.c 444aae4fc60cc57d6c97615358e1020f6884cca6 -F src/btree.h d1144d38d790a8b7b2e215043f8d068f4f37de07 +F src/btree.c d90149f6e0a6f715b58b272ef1028fa249a2a088 +F src/btree.h 1d62748eb7d129292782cf65b891b85cbfa024d4 F src/btreeInt.h c424f2f131cc61ddf130f9bd736b3df12c8a51f0 F src/build.c 00a327120d81ace6267e714ae8010c997d55de5d F src/callback.c a1d1b1c9c85415dff013af033e2fed9c8382d33b @@ -141,7 +141,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e F src/loadext.c 8af9fcc75708d60b88636ccba38b4a7b3c155c3e -F src/main.c 89c658ae9a610a61ff856a110bda50606e9227d6 +F src/main.c 91465f2658911ddb51be89e7b8ee01af8584308f F src/malloc.c 3d7284cd9346ab6e3945535761e68c23c6cf40ef F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206 @@ -162,13 +162,13 @@ F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e F src/os_unix.c de5be4cdbf3d07018059934eaf7e5d8d594a895c F src/os_win.c 2f90f7bdec714fad51cd31b4ecad3cc1b4bb5aad -F src/pager.c 7f7587c2f11126d13ee1925ac8960a9e7ab13e8a -F src/pager.h ad7d8db0fbcee7546dbc02ffe0d0d44ea868ef52 +F src/pager.c b46a78a196d99bc855eec3c602777a1bc8db5122 +F src/pager.h e2485f2f2fa5264f2bb68d1783c149d3d57d3637 F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58 F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050 F src/pcache1.c e9578a3beac26f229ee558a4e16c863f2498185f -F src/pragma.c 66a8b53d1e74635011fbb0bb54b7ecc402684bae +F src/pragma.c f843c877845ddbb911f10eea50c9290bc8354b03 F src/prepare.c c2b318037d626fed27905c9446730b560637217a F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 @@ -176,9 +176,9 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/select.c 550d67688f5e8bc8022faf6d014838afba1415af F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056 -F src/sqlite.h.in f47e09412fc9a129f759fa4d96ef21f4b3d529eb +F src/sqlite.h.in 4645a3bddf4481fcc9422ba41acf4e71c1c81e22 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 -F src/sqliteInt.h fe1cb073b2707001985f06dee9ee256247e4d0ce +F src/sqliteInt.h 4e7045f17606296bc8e7898d69567fc3cd06b761 F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44 F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -227,7 +227,7 @@ F src/update.c 227e6cd512108b84f69421fc6c7aa1b83d60d6e0 F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685 F src/util.c cd78524566fe45671863eee78685969a4bfd4e4c F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f -F src/vdbe.c b86b09beb3dcf2e6d5922acee48b8a1c16b68bfd +F src/vdbe.c 4bec828e70654c698ef843c29b557bee2c8a0a00 F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2 F src/vdbeInt.h 7f4cf1b2b69bef3a432b1f23dfebef57275436b4 F src/vdbeapi.c 5368714fa750270cf6430160287c21adff44582d @@ -236,8 +236,8 @@ F src/vdbeblob.c e0ce3c54cc0c183af2ec67b63a289acf92251df4 F src/vdbemem.c 23723a12cd3ba7ab3099193094cbb2eb78956aa9 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2 F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30 -F src/wal.c 400624ce58acce44f0bf0d47ed2f435da290fb04 -F src/wal.h d5bbc11242d7fd14e9dc6a74f68d3ccaf01a9e48 +F src/wal.c 8eca619a28a70a667c913e5927131250836377a2 +F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/where.c d5cc65f51661a038a2c6a663a945d5cf4c277b81 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -827,7 +827,7 @@ F test/wal.test 70227190e713b3e7eb2a7d5ec3510b66db01f327 F test/wal2.test c794b8b257af54190bb913678ad3984cbf3311b9 F test/wal3.test 957a5f2a8fe8a6ff01de1a15285ecf2f376fcaf8 F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30 -F test/wal5.test e0f1abdff4f76d3a8531f5d0f4cb237e5eff891c +F test/wal5.test 4e2854d7584dd97a73e7ce0f47bcbbe5c592fe29 F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe F test/walbak.test 4df1c7369da0301caeb9a48fa45997fd592380e4 F test/walbig.test e882bc1d014afffbfa2b6ba36e0f07d30a633ad0 @@ -887,10 +887,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 56bbc539246a6dc9f1ae1edb898db7a4f6f6d322 -R 75a04ae738d792c76538f98d6f9ad655 -T *branch * experimental -T *sym-experimental * -T -sym-trunk * +P 7e3fc2c833a5baa08820c499867b6902bdc2ed5a +R 1672f1722e4277222ee64bddb8543abf U dan -Z b1cbb492cf90106bd968e524fdd11e16 +Z 2e080f5eeb72d6f9662d3b3c376a7b7c diff --git a/manifest.uuid b/manifest.uuid index 936ce08f7a..3807e38807 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7e3fc2c833a5baa08820c499867b6902bdc2ed5a \ No newline at end of file +72787c010c8944e8fcf9c98aa4482f129142d8e9 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 94100f48fc..f354b43558 100644 --- a/src/btree.c +++ b/src/btree.c @@ -7936,14 +7936,9 @@ int sqlite3BtreeIsInTrans(Btree *p){ ** Return SQLITE_LOCKED if this or any other connection has an open ** transaction on the shared-cache the argument Btree is connected to. ** -** If parameter bBlock is true, then the layers below invoke the -** busy-handler callback while waiting for readers to release locks so -** that the entire WAL can be checkpointed. If it is false, then as -** much as possible of the WAL is checkpointed without waiting for readers -** to finish. bBlock is true for "PRAGMA wal_blocking_checkpoint" and false -** for "PRAGMA wal_checkpoint". -*/ -int sqlite3BtreeCheckpoint(Btree *p, int bBlock){ +** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. +*/ +int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *pnCkpt){ int rc = SQLITE_OK; if( p ){ BtShared *pBt = p->pBt; @@ -7951,7 +7946,7 @@ int sqlite3BtreeCheckpoint(Btree *p, int bBlock){ if( pBt->inTransaction!=TRANS_NONE ){ rc = SQLITE_LOCKED; }else{ - rc = sqlite3PagerCheckpoint(pBt->pPager, bBlock); + rc = sqlite3PagerCheckpoint(pBt->pPager, eMode, pnLog, pnCkpt); } sqlite3BtreeLeave(p); } diff --git a/src/btree.h b/src/btree.h index ce86cdabb1..4bfc130ef1 100644 --- a/src/btree.h +++ b/src/btree.h @@ -207,7 +207,7 @@ void sqlite3BtreeCursorList(Btree*); #endif #ifndef SQLITE_OMIT_WAL - int sqlite3BtreeCheckpoint(Btree*, int); + int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); #endif /* diff --git a/src/main.c b/src/main.c index 7ce43aec5c..4333a5873b 100644 --- a/src/main.c +++ b/src/main.c @@ -1340,19 +1340,29 @@ void *sqlite3_wal_hook( #endif } - /* -** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points -** to contains a zero-length string, all attached databases are -** checkpointed. -*/ -int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ +** Checkpoint database zDb. +*/ +int sqlite3_wal_checkpoint_v2( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of attached database (or NULL) */ + int eMode, /* SQLITE_CHECKPOINT_* value */ + int *pnLog, /* OUT: Size of WAL log in frames */ + int *pnCkpt /* OUT: Total number of frames checkpointed */ +){ #ifdef SQLITE_OMIT_WAL return SQLITE_OK; #else int rc; /* Return code */ int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */ + if( eMode!=SQLITE_CHECKPOINT_PASSIVE + && eMode!=SQLITE_CHECKPOINT_FULL + && eMode!=SQLITE_CHECKPOINT_RESTART + ){ + return SQLITE_MISUSE; + } + sqlite3_mutex_enter(db->mutex); if( zDb && zDb[0] ){ iDb = sqlite3FindDbName(db, zDb); @@ -1361,7 +1371,7 @@ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ rc = SQLITE_ERROR; sqlite3Error(db, SQLITE_ERROR, "unknown database: %s", zDb); }else{ - rc = sqlite3Checkpoint(db, iDb, 0); + rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt); sqlite3Error(db, rc, 0); } rc = sqlite3ApiExit(db, rc); @@ -1370,6 +1380,16 @@ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ #endif } + +/* +** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points +** to contains a zero-length string, all attached databases are +** checkpointed. +*/ +int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ + return sqlite3_wal_checkpoint_v2(db, zDb, SQLITE_CHECKPOINT_PASSIVE, 0, 0); +} + #ifndef SQLITE_OMIT_WAL /* ** Run a checkpoint on database iDb. This is a no-op if database iDb is @@ -1388,10 +1408,9 @@ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){ ** checkpointed. If an error is encountered it is returned immediately - ** no attempt is made to checkpoint any remaining databases. ** -** Parameter bBlock is true for a blocking-checkpoint, false for an -** ordinary, non-blocking, checkpoint. +** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. */ -int sqlite3Checkpoint(sqlite3 *db, int iDb, int bBlock){ +int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){ int rc = SQLITE_OK; /* Return code */ int i; /* Used to iterate through attached dbs */ @@ -1399,7 +1418,7 @@ int sqlite3Checkpoint(sqlite3 *db, int iDb, int bBlock){ for(i=0; inDb && rc==SQLITE_OK; i++){ if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){ - rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt, bBlock); + rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt, eMode, pnLog, pnCkpt); } } diff --git a/src/pager.c b/src/pager.c index 29f3bf1eb1..bb9f6ddf02 100644 --- a/src/pager.c +++ b/src/pager.c @@ -6520,17 +6520,16 @@ sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){ ** "PRAGMA wal_blocking_checkpoint" or calls the sqlite3_wal_checkpoint() ** or wal_blocking_checkpoint() API functions. ** -** Parameter bBlock is true for a blocking-checkpoint, false for an -** ordinary, non-blocking, checkpoint. +** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART. */ -int sqlite3PagerCheckpoint(Pager *pPager, int bBlock){ +int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){ int rc = SQLITE_OK; if( pPager->pWal ){ - u8 *zBuf = (u8 *)pPager->pTmpSpace; - rc = sqlite3WalCheckpoint(pPager->pWal, - (bBlock ? pPager->xBusyHandler : 0), pPager->pBusyHandlerArg, + rc = sqlite3WalCheckpoint(pPager->pWal, eMode, + pPager->xBusyHandler, pPager->pBusyHandlerArg, (pPager->noSync ? 0 : pPager->sync_flags), - pPager->pageSize, zBuf + pPager->pageSize, (u8 *)pPager->pTmpSpace, + pnLog, pnCkpt ); } return rc; diff --git a/src/pager.h b/src/pager.h index e0396e99aa..27524f0217 100644 --- a/src/pager.h +++ b/src/pager.h @@ -138,7 +138,7 @@ int sqlite3PagerOpenSavepoint(Pager *pPager, int n); int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); int sqlite3PagerSharedLock(Pager *pPager); -int sqlite3PagerCheckpoint(Pager *pPager, int); +int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*); int sqlite3PagerWalSupported(Pager *pPager); int sqlite3PagerWalCallback(Pager *pPager); int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); diff --git a/src/pragma.c b/src/pragma.c index 7324e1bde8..fb7fe2c920 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1393,19 +1393,29 @@ void sqlite3Pragma( #ifndef SQLITE_OMIT_WAL /* - ** PRAGMA [database.]wal_checkpoint - ** PRAGMA [database.]wal_blocking_checkpoint + ** PRAGMA [database.]wal_checkpoint = passive|full|restart ** ** Checkpoint the database. */ - if( sqlite3StrICmp(zLeft, "wal_checkpoint")==0 - || sqlite3StrICmp(zLeft, "wal_blocking_checkpoint")==0 - ){ - int bBlock = (zLeft[14]!=0); + if( sqlite3StrICmp(zLeft, "wal_checkpoint")==0 ){ int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED); - assert( bBlock==(sqlite3StrICmp(zLeft, "wal_checkpoint")!=0) ); + int eMode = SQLITE_CHECKPOINT_PASSIVE; + if( zRight ){ + if( sqlite3StrICmp(zRight, "full")==0 ){ + eMode = SQLITE_CHECKPOINT_FULL; + }else if( sqlite3StrICmp(zRight, "restart")==0 ){ + eMode = SQLITE_CHECKPOINT_RESTART; + } + } if( sqlite3ReadSchema(pParse) ) goto pragma_out; - sqlite3VdbeAddOp2(v, OP_Checkpoint, iBt, bBlock); + sqlite3VdbeSetNumCols(v, 3); + pParse->nMem = 3; + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "busy", SQLITE_STATIC); + sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "log", SQLITE_STATIC); + sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "checkpointed", SQLITE_STATIC); + + sqlite3VdbeAddOp2(v, OP_Checkpoint, iBt, eMode); + sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); }else /* diff --git a/src/sqlite.h.in b/src/sqlite.h.in index e08d5ce596..8baf9ae029 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6145,6 +6145,89 @@ int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); */ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); +/* +** +** CAPI3REF: Checkpoint a database +** +** Run a checkpoint operation on WAL database zDb attached to database +** handle db. The specific operation is determined by the value of the +** eMode parameter: +** +**
+**
SQLITE_CHECKPOINT_PASSIVE
+** Checkpoint as many frames as possible without waiting for any database +** readers or writers to finish. Sync the db file if all frames in the log +** are checkpointed. This mode is the same as calling +** sqlite3_wal_checkpoint(). The busy-handler callback is never invoked. +** +**
SQLITE_CHECKPOINT_FULL
+** This mode blocks (calls the busy-handler callback) until there is no +** database writer and all readers are reading from the most recent database +** snapshot. It then checkpoints all frames in the log file and syncs the +** database file. This call blocks database writers while it is running, +** but not database readers. +** +**
SQLITE_CHECKPOINT_RESTART
+** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after +** checkpointing the log file it blocks (calls the busy-handler callback) +** until all readers are reading from the database file only. This ensures +** that the next client to write to the database file restarts the log file +** from the beginning. This call blocks database writers while it is running, +** but not database readers. +**
+** +** If pnLog is not NULL, then *pnLog is set to the total number of frames in +** the log file before returning. If pnCkpt is not NULL, then *pnCkpt is set to +** the total number of checkpointed frames (including any that were already +** checkpointed when this function is called). *pnLog and *pnCkpt may be +** populated even if sqlite3_wal_checkpoint_v2() returns other than SQLITE_OK. +** If no values are available because of an error, they are both set to -1 +** before returning to communicate this to the caller. +** +** All calls obtain an exclusive "checkpoint" lock on the database file. If +** any other process is running a checkpoint operation at the same time, the +** lock cannot be obtained and SQLITE_BUSY is returned. Even if there is a +** busy-handler configured, it will not be invoked in this case. +** +** The SQLITE_CHECKPOINT_FULL and RESTART modes also obtain the exclusive +** "writer" lock on the database file. If the writer lock cannot be obtained +** immediately, and a busy-handler is configured, it is invoked and the writer +** lock retried until either the busy-handler returns 0 or the lock is +** successfully obtained. The busy-handler is also invoked while waiting for +** database readers as described above. If the busy-handler returns 0 before +** the writer lock is obtained or while waiting for database readers, the +** checkpoint operation proceeds from that point in the same way as +** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible +** without blocking any further. SQLITE_BUSY is returned in this case. +** +** If parameter zDb is NULL or points to a zero length string, then the +** specified operation is attempted on all WAL databases. In this case the +** values written to output parameters *pnLog and *pnCkpt are undefined. If +** an SQLITE_BUSY error is encountered when processing one or more of the +** attached WAL databases, the operation is still attempted on any remaining +** attached databases and SQLITE_BUSY is returned to the caller. If any other +** error occurs while processing an attached database, processing is abandoned +** and the error code returned to the caller immediately. If no error +** (SQLITE_BUSY or otherwise) is encountered while processing the attached +** databases, SQLITE_OK is returned. +** +** If database zDb is the name of an attached database that is not in WAL +** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. If +** zDb is not NULL (or a zero length string) and is not the name of any +** attached database, SQLITE_ERROR is returned to the caller. +*/ +int sqlite3_wal_checkpoint_v2( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of attached database (or NULL) */ + int eMode, /* SQLITE_CHECKPOINT_* value */ + int *pnLog, /* OUT: Size of WAL log in frames */ + int *pnCkpt /* OUT: Total number of frames checkpointed */ +); +#define SQLITE_CHECKPOINT_PASSIVE 0 +#define SQLITE_CHECKPOINT_FULL 1 +#define SQLITE_CHECKPOINT_RESTART 2 + + /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 8b4fe599eb..c6e7f6e67a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3036,7 +3036,7 @@ CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); int sqlite3TempInMemory(const sqlite3*); VTable *sqlite3GetVTable(sqlite3*, Table*); const char *sqlite3JournalModename(int); -int sqlite3Checkpoint(sqlite3*, int, int); +int sqlite3Checkpoint(sqlite3*, int, int, int*, int*); int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int); /* Declarations for functions in fkey.c. All of these are replaced by diff --git a/src/vdbe.c b/src/vdbe.c index dcff83f17a..0e9f27d101 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -5216,13 +5216,33 @@ case OP_AggFinal: { } #ifndef SQLITE_OMIT_WAL -/* Opcode: Checkpoint P1 P2 * * * +/* Opcode: Checkpoint P1 P2 P3 * * ** ** Checkpoint database P1. This is a no-op if P1 is not currently in -** WAL mode. If P2 is non-zero, this is a blocking checkpoint. +** WAL mode. Parameter P2 is one of SQLITE_CHECKPOINT_PASSIVE, FULL +** or RESTART. */ case OP_Checkpoint: { - rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2); + int nLog = -1; /* Number of pages in WAL log */ + int nCkpt = -1; /* Number of checkpointed pages */ + int bBusy = 0; + assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE + || pOp->p2==SQLITE_CHECKPOINT_FULL + || pOp->p2==SQLITE_CHECKPOINT_RESTART + ); + rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &nLog, &nCkpt); + if( rc==SQLITE_BUSY ){ + rc = SQLITE_OK; + bBusy = 1; + } + + aMem[1].u.i = bBusy; + aMem[2].u.i = nLog; + aMem[3].u.i = nCkpt; + MemSetTypeFlag(&aMem[1], MEM_Int); + MemSetTypeFlag(&aMem[2], MEM_Int); + MemSetTypeFlag(&aMem[3], MEM_Int); + break; }; #endif diff --git a/src/wal.c b/src/wal.c index 5ff9f227e0..0619822434 100644 --- a/src/wal.c +++ b/src/wal.c @@ -1576,11 +1576,13 @@ static int walBusyLock( */ static int walCheckpoint( Wal *pWal, /* Wal connection */ + int eMode, /* One of PASSIVE, FULL or RESTART */ int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ int sync_flags, /* Flags for OsSync() (or 0) */ int nBuf, /* Size of zBuf in bytes */ - u8 *zBuf /* Temporary buffer to use */ + u8 *zBuf, /* Temporary buffer to use */ + int *pnCkpt /* Total frames checkpointed */ ){ int rc; /* Return code */ int szPage; /* Database page-size */ @@ -1610,6 +1612,10 @@ static int walCheckpoint( goto walcheckpoint_out; } + pInfo = walCkptInfo(pWal); + mxPage = pWal->hdr.nPage; + if( pnCkpt ) *pnCkpt = pInfo->nBackfill; + /* 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 @@ -1617,8 +1623,6 @@ static int walCheckpoint( */ do { mxSafeFrame = pWal->hdr.mxFrame; - mxPage = pWal->hdr.nPage; - pInfo = walCkptInfo(pWal); for(i=1; iaReadMark[i]; if( mxSafeFrame>=y ){ @@ -1634,7 +1638,8 @@ static int walCheckpoint( } } } - }while( xBusy && mxSafeFramehdr.mxFrame && xBusy(pBusyArg) ); + }while( eMode!=SQLITE_CHECKPOINT_PASSIVE + && xBusy && mxSafeFramehdr.mxFrame && xBusy(pBusyArg) ); if( pInfo->nBackfillnBackfill = mxSafeFrame; + if( pnCkpt ) *pnCkpt = mxSafeFrame; } } /* Release the reader lock held while backfilling */ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); - - if( xBusy && rc==SQLITE_OK && pWal->hdr.mxFrame==mxSafeFrame ){ - assert( pWal->writeLock ); - rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1); - if( rc==SQLITE_OK ){ - walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); - } - } } if( rc==SQLITE_BUSY ){ @@ -1706,6 +1704,17 @@ static int walCheckpoint( rc = SQLITE_OK; } + if( rc==SQLITE_OK + && eMode==SQLITE_CHECKPOINT_RESTART + && pWal->hdr.mxFrame==mxSafeFrame + ){ + assert( pWal->writeLock ); + rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1); + if( rc==SQLITE_OK ){ + walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); + } + } + walcheckpoint_out: walIteratorFree(pIter); return rc; @@ -1737,7 +1746,9 @@ int sqlite3WalClose( if( pWal->exclusiveMode==WAL_NORMAL_MODE ){ pWal->exclusiveMode = WAL_EXCLUSIVE_MODE; } - rc = sqlite3WalCheckpoint(pWal, 0, 0, sync_flags, nBuf, zBuf); + rc = sqlite3WalCheckpoint( + pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0 + ); if( rc==SQLITE_OK ){ isDelete = 1; } @@ -2658,11 +2669,14 @@ int sqlite3WalFrames( */ int sqlite3WalCheckpoint( Wal *pWal, /* Wal connection */ + int eMode, /* PASSIVE, FULL or RESTART */ int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ int sync_flags, /* Flags to sync db file with (or 0) */ int nBuf, /* Size of temporary buffer */ - u8 *zBuf /* Temporary buffer to use */ + u8 *zBuf, /* Temporary buffer to use */ + int *pnLog, /* OUT: Number of frames in WAL */ + int *pnCkpt /* OUT: Number of backfilled frames in WAL */ ){ int rc; /* Return code */ int isChanged = 0; /* True if a new wal-index header is loaded */ @@ -2684,7 +2698,7 @@ int sqlite3WalCheckpoint( ** to prevent any writers from running while the checkpoint is underway. ** This has to be done before the call to walIndexReadHdr() below. */ - if( xBusy ){ + if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1); if( rc==SQLITE_OK ) pWal->writeLock = 1; } @@ -2694,7 +2708,9 @@ int sqlite3WalCheckpoint( rc = walIndexReadHdr(pWal, &isChanged); } if( rc==SQLITE_OK ){ - rc = walCheckpoint(pWal, xBusy, pBusyArg, sync_flags, nBuf, zBuf); + if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame; + rc = walCheckpoint( + pWal, eMode, xBusy, pBusyArg, sync_flags, nBuf, zBuf, pnCkpt); } if( isChanged ){ /* If a new wal-index header was loaded before the checkpoint was diff --git a/src/wal.h b/src/wal.h index e9c614fe85..2039c701cf 100644 --- a/src/wal.h +++ b/src/wal.h @@ -20,22 +20,22 @@ #include "sqliteInt.h" #ifdef SQLITE_OMIT_WAL -# define sqlite3WalOpen(x,y,z) 0 -# define sqlite3WalClose(w,x,y,z) 0 -# define sqlite3WalBeginReadTransaction(y,z) 0 +# define sqlite3WalOpen(x,y,z) 0 +# define sqlite3WalClose(w,x,y,z) 0 +# define sqlite3WalBeginReadTransaction(y,z) 0 # define sqlite3WalEndReadTransaction(z) -# define sqlite3WalRead(v,w,x,y,z) 0 -# define sqlite3WalDbsize(y) 0 -# define sqlite3WalBeginWriteTransaction(y) 0 -# define sqlite3WalEndWriteTransaction(x) 0 -# define sqlite3WalUndo(x,y,z) 0 +# define sqlite3WalRead(v,w,x,y,z) 0 +# define sqlite3WalDbsize(y) 0 +# define sqlite3WalBeginWriteTransaction(y) 0 +# define sqlite3WalEndWriteTransaction(x) 0 +# define sqlite3WalUndo(x,y,z) 0 # define sqlite3WalSavepoint(y,z) -# define sqlite3WalSavepointUndo(y,z) 0 -# define sqlite3WalFrames(u,v,w,x,y,z) 0 -# define sqlite3WalCheckpoint(u,v,w,x,y,z) 0 -# define sqlite3WalCallback(z) 0 -# define sqlite3WalExclusiveMode(y,z) 0 -# define sqlite3WalHeapMemory(z) 0 +# define sqlite3WalSavepointUndo(y,z) 0 +# define sqlite3WalFrames(u,v,w,x,y,z) 0 +# define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0 +# define sqlite3WalCallback(z) 0 +# define sqlite3WalExclusiveMode(y,z) 0 +# define sqlite3WalHeapMemory(z) 0 #else #define WAL_SAVEPOINT_NDATA 4 @@ -86,11 +86,14 @@ int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int); /* Copy pages from the log to the database file */ int sqlite3WalCheckpoint( Wal *pWal, /* Write-ahead log connection */ + int eMode, /* One of PASSIVE, FULL and RESTART */ int (*xBusy)(void*), /* Function to call when busy */ void *pBusyArg, /* Context argument for xBusyHandler */ int sync_flags, /* Flags to sync db file with (or 0) */ int nBuf, /* Size of buffer nBuf */ - u8 *zBuf /* Temporary buffer to use */ + u8 *zBuf, /* Temporary buffer to use */ + int *pnLog, /* OUT: Number of frames in WAL */ + int *pnCkpt /* OUT: Number of backfilled frames in WAL */ ); /* Return the value to pass to a sqlite3_wal_hook callback, the diff --git a/test/wal5.test b/test/wal5.test index 24d6353a62..aa2014760c 100644 --- a/test/wal5.test +++ b/test/wal5.test @@ -82,7 +82,7 @@ do_multiclient_test tn { # set ::busy_handler_script { if {$n==5} { sql2 COMMIT } } do_test 1.$tn.5 { - sql1 { PRAGMA wal_blocking_checkpoint } + sql1 { PRAGMA wal_checkpoint = RESTART } list [db_page_count] [wal_page_count] $::nBusyHandler } {6 12 6} do_test 1.$tn.6 { @@ -109,7 +109,8 @@ do_multiclient_test tn { if {$n==7} { sql3 COMMIT } } do_test 1.$tn.11 { - sql1 { PRAGMA wal_blocking_checkpoint } +breakpoint + sql1 { PRAGMA wal_checkpoint = RESTART } list [db_page_count] [wal_page_count] $::nBusyHandler } {10 5 8} do_test 1.$tn.12 { set ::db_file_size } 10