]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Modify the interface to the blocking wal-checkpoint functionality.
authordan <dan@noemail.net>
Thu, 18 Nov 2010 12:11:05 +0000 (12:11 +0000)
committerdan <dan@noemail.net>
Thu, 18 Nov 2010 12:11:05 +0000 (12:11 +0000)
FossilOrigin-Name: 72787c010c8944e8fcf9c98aa4482f129142d8e9

14 files changed:
manifest
manifest.uuid
src/btree.c
src/btree.h
src/main.c
src/pager.c
src/pager.h
src/pragma.c
src/sqlite.h.in
src/sqliteInt.h
src/vdbe.c
src/wal.c
src/wal.h
test/wal5.test

index a133dac267c2b887d6fb54236530dedf9f0f0341..7dd2eb66e6a68066f14b38485370371c7ffb3746 100644 (file)
--- 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
index 936ce08f7ace12207c16618fb7c261d78c5a3b48..3807e3880746accbe92ba5458850630fd47b8372 100644 (file)
@@ -1 +1 @@
-7e3fc2c833a5baa08820c499867b6902bdc2ed5a
\ No newline at end of file
+72787c010c8944e8fcf9c98aa4482f129142d8e9
\ No newline at end of file
index 94100f48fc2001c01bc6030525c3ef92d6cf8cd1..f354b4355861dfd261c909b26d7e1e1a13938610 100644 (file)
@@ -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);
   }
index ce86cdabb159ba4b76f591e2a82fda560dcbf036..4bfc130ef12d6f4507147858e9d4333e831d22b6 100644 (file)
@@ -207,7 +207,7 @@ void sqlite3BtreeCursorList(Btree*);
 #endif
 
 #ifndef SQLITE_OMIT_WAL
-  int sqlite3BtreeCheckpoint(Btree*, int);
+  int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
 #endif
 
 /*
index 7ce43aec5cb397b7f187139c1cbbdeba5aaa16aa..4333a5873b6f503a454ded77beacfee745e0c12e 100644 (file)
@@ -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; i<db->nDb && 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);
     }
   }
 
index 29f3bf1eb156575f2ec927bf5732cf4b72cc5c87..bb9f6ddf02f7cd623c2618bd872eeb440dacee4a 100644 (file)
@@ -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;
index e0396e99aa12aabfd1db539cecae822316cbc595..27524f0217ec56c63dc5d86c2795ebd1c479c454 100644 (file)
@@ -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);
index 7324e1bde8fda977419b7042b3e0e1575382fdaa..fb7fe2c92061f4d44fa048b010f69e2d8e052fff 100644 (file)
@@ -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
 
   /*
index e08d5ce5965603c4a87bab69c4eb3ad50cfebe11..8baf9ae029c6b3d3d73431da40dfcbe335841f80 100644 (file)
@@ -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:
+**
+** <dl>
+** <dt>SQLITE_CHECKPOINT_PASSIVE<dd>
+**   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.
+**
+** <dt>SQLITE_CHECKPOINT_FULL<dd>
+**   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.
+**
+** <dt>SQLITE_CHECKPOINT_RESTART<dd>
+**   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.
+** </dl>
+**
+** 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.
index 8b4fe599eb8828df8fb2c19209d2a9d7db8d2370..c6e7f6e67a32f331aa8dd5bcbcfd70b4158c9ec2 100644 (file)
@@ -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
index dcff83f17ad8cbc37d9925d0576821043b0a4bc9..0e9f27d1010d799620d4bc972c77bb81ea88579d 100644 (file)
@@ -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
index 5ff9f227e0f9d63d811c7410d8cd7a267a117b48..0619822434bd46afbeeac202077ca0db04f52ad2 100644 (file)
--- 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; i<WAL_NREADER; i++){
       u32 y = pInfo->aReadMark[i];
       if( mxSafeFrame>=y ){
@@ -1634,7 +1638,8 @@ static int walCheckpoint(
         }
       }
     }
-  }while( xBusy && mxSafeFrame<pWal->hdr.mxFrame && xBusy(pBusyArg) );
+  }while( eMode!=SQLITE_CHECKPOINT_PASSIVE 
+       && xBusy && mxSafeFrame<pWal->hdr.mxFrame && xBusy(pBusyArg) );
 
   if( pInfo->nBackfill<mxSafeFrame
    && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
@@ -1685,19 +1690,12 @@ static int walCheckpoint(
       }
       if( rc==SQLITE_OK ){
         pInfo->nBackfill = 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 
index e9c614fe85eb88d30b43af75e72fdef8ee3ad4c1..2039c701cf29bae49a7e984c4b1d59aa76683040 100644 (file)
--- a/src/wal.h
+++ b/src/wal.h
 #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
index 24d6353a62e7309575c6cb59f4ed468521d5447f..aa2014760c23ec763d57a9d04e6b0da9795e160d 100644 (file)
@@ -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