1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Modify the interface to the blocking wal-checkpoint functionality.

FossilOrigin-Name: 72787c010c8944e8fcf9c98aa4482f129142d8e9
This commit is contained in:
dan
2010-11-18 12:11:05 +00:00
parent a58f26f93f
commit cdc1f049bf
14 changed files with 236 additions and 93 deletions

View File

@@ -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. C Modify\sthe\sinterface\sto\sthe\sblocking\swal-checkpoint\sfunctionality.
D 2010-11-16T18:56:51 D 2010-11-18T12:11:05
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in e7a59672eaeb04408d1fa8501618d7501a3c5e39 F Makefile.in e7a59672eaeb04408d1fa8501618d7501a3c5e39
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -119,8 +119,8 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c d5b0137bc20327af08c14772227cc35134839c30 F src/backup.c d5b0137bc20327af08c14772227cc35134839c30
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
F src/btree.c 444aae4fc60cc57d6c97615358e1020f6884cca6 F src/btree.c d90149f6e0a6f715b58b272ef1028fa249a2a088
F src/btree.h d1144d38d790a8b7b2e215043f8d068f4f37de07 F src/btree.h 1d62748eb7d129292782cf65b891b85cbfa024d4
F src/btreeInt.h c424f2f131cc61ddf130f9bd736b3df12c8a51f0 F src/btreeInt.h c424f2f131cc61ddf130f9bd736b3df12c8a51f0
F src/build.c 00a327120d81ace6267e714ae8010c997d55de5d F src/build.c 00a327120d81ace6267e714ae8010c997d55de5d
F src/callback.c a1d1b1c9c85415dff013af033e2fed9c8382d33b F src/callback.c a1d1b1c9c85415dff013af033e2fed9c8382d33b
@@ -141,7 +141,7 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
F src/loadext.c 8af9fcc75708d60b88636ccba38b4a7b3c155c3e F src/loadext.c 8af9fcc75708d60b88636ccba38b4a7b3c155c3e
F src/main.c 89c658ae9a610a61ff856a110bda50606e9227d6 F src/main.c 91465f2658911ddb51be89e7b8ee01af8584308f
F src/malloc.c 3d7284cd9346ab6e3945535761e68c23c6cf40ef F src/malloc.c 3d7284cd9346ab6e3945535761e68c23c6cf40ef
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206 F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206
@@ -162,13 +162,13 @@ F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e
F src/os_unix.c de5be4cdbf3d07018059934eaf7e5d8d594a895c F src/os_unix.c de5be4cdbf3d07018059934eaf7e5d8d594a895c
F src/os_win.c 2f90f7bdec714fad51cd31b4ecad3cc1b4bb5aad F src/os_win.c 2f90f7bdec714fad51cd31b4ecad3cc1b4bb5aad
F src/pager.c 7f7587c2f11126d13ee1925ac8960a9e7ab13e8a F src/pager.c b46a78a196d99bc855eec3c602777a1bc8db5122
F src/pager.h ad7d8db0fbcee7546dbc02ffe0d0d44ea868ef52 F src/pager.h e2485f2f2fa5264f2bb68d1783c149d3d57d3637
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58 F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050 F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
F src/pcache1.c e9578a3beac26f229ee558a4e16c863f2498185f F src/pcache1.c e9578a3beac26f229ee558a4e16c863f2498185f
F src/pragma.c 66a8b53d1e74635011fbb0bb54b7ecc402684bae F src/pragma.c f843c877845ddbb911f10eea50c9290bc8354b03
F src/prepare.c c2b318037d626fed27905c9446730b560637217a F src/prepare.c c2b318037d626fed27905c9446730b560637217a
F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506 F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
@@ -176,9 +176,9 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c 550d67688f5e8bc8022faf6d014838afba1415af F src/select.c 550d67688f5e8bc8022faf6d014838afba1415af
F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056 F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
F src/sqlite.h.in f47e09412fc9a129f759fa4d96ef21f4b3d529eb F src/sqlite.h.in 4645a3bddf4481fcc9422ba41acf4e71c1c81e22
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
F src/sqliteInt.h fe1cb073b2707001985f06dee9ee256247e4d0ce F src/sqliteInt.h 4e7045f17606296bc8e7898d69567fc3cd06b761
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44 F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -227,7 +227,7 @@ F src/update.c 227e6cd512108b84f69421fc6c7aa1b83d60d6e0
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685 F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
F src/util.c cd78524566fe45671863eee78685969a4bfd4e4c F src/util.c cd78524566fe45671863eee78685969a4bfd4e4c
F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f
F src/vdbe.c b86b09beb3dcf2e6d5922acee48b8a1c16b68bfd F src/vdbe.c 4bec828e70654c698ef843c29b557bee2c8a0a00
F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2 F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
F src/vdbeInt.h 7f4cf1b2b69bef3a432b1f23dfebef57275436b4 F src/vdbeInt.h 7f4cf1b2b69bef3a432b1f23dfebef57275436b4
F src/vdbeapi.c 5368714fa750270cf6430160287c21adff44582d F src/vdbeapi.c 5368714fa750270cf6430160287c21adff44582d
@@ -236,8 +236,8 @@ F src/vdbeblob.c e0ce3c54cc0c183af2ec67b63a289acf92251df4
F src/vdbemem.c 23723a12cd3ba7ab3099193094cbb2eb78956aa9 F src/vdbemem.c 23723a12cd3ba7ab3099193094cbb2eb78956aa9
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30 F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30
F src/wal.c 400624ce58acce44f0bf0d47ed2f435da290fb04 F src/wal.c 8eca619a28a70a667c913e5927131250836377a2
F src/wal.h d5bbc11242d7fd14e9dc6a74f68d3ccaf01a9e48 F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c d5cc65f51661a038a2c6a663a945d5cf4c277b81 F src/where.c d5cc65f51661a038a2c6a663a945d5cf4c277b81
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -827,7 +827,7 @@ F test/wal.test 70227190e713b3e7eb2a7d5ec3510b66db01f327
F test/wal2.test c794b8b257af54190bb913678ad3984cbf3311b9 F test/wal2.test c794b8b257af54190bb913678ad3984cbf3311b9
F test/wal3.test 957a5f2a8fe8a6ff01de1a15285ecf2f376fcaf8 F test/wal3.test 957a5f2a8fe8a6ff01de1a15285ecf2f376fcaf8
F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30 F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30
F test/wal5.test e0f1abdff4f76d3a8531f5d0f4cb237e5eff891c F test/wal5.test 4e2854d7584dd97a73e7ce0f47bcbbe5c592fe29
F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe
F test/walbak.test 4df1c7369da0301caeb9a48fa45997fd592380e4 F test/walbak.test 4df1c7369da0301caeb9a48fa45997fd592380e4
F test/walbig.test e882bc1d014afffbfa2b6ba36e0f07d30a633ad0 F test/walbig.test e882bc1d014afffbfa2b6ba36e0f07d30a633ad0
@@ -887,10 +887,7 @@ 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 56bbc539246a6dc9f1ae1edb898db7a4f6f6d322 P 7e3fc2c833a5baa08820c499867b6902bdc2ed5a
R 75a04ae738d792c76538f98d6f9ad655 R 1672f1722e4277222ee64bddb8543abf
T *branch * experimental
T *sym-experimental *
T -sym-trunk *
U dan U dan
Z b1cbb492cf90106bd968e524fdd11e16 Z 2e080f5eeb72d6f9662d3b3c376a7b7c

View File

@@ -1 +1 @@
7e3fc2c833a5baa08820c499867b6902bdc2ed5a 72787c010c8944e8fcf9c98aa4482f129142d8e9

View File

@@ -7936,14 +7936,9 @@ int sqlite3BtreeIsInTrans(Btree *p){
** Return SQLITE_LOCKED if this or any other connection has an open ** Return SQLITE_LOCKED if this or any other connection has an open
** transaction on the shared-cache the argument Btree is connected to. ** transaction on the shared-cache the argument Btree is connected to.
** **
** If parameter bBlock is true, then the layers below invoke the ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
** 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){ int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *pnCkpt){
int rc = SQLITE_OK; int rc = SQLITE_OK;
if( p ){ if( p ){
BtShared *pBt = p->pBt; BtShared *pBt = p->pBt;
@@ -7951,7 +7946,7 @@ int sqlite3BtreeCheckpoint(Btree *p, int bBlock){
if( pBt->inTransaction!=TRANS_NONE ){ if( pBt->inTransaction!=TRANS_NONE ){
rc = SQLITE_LOCKED; rc = SQLITE_LOCKED;
}else{ }else{
rc = sqlite3PagerCheckpoint(pBt->pPager, bBlock); rc = sqlite3PagerCheckpoint(pBt->pPager, eMode, pnLog, pnCkpt);
} }
sqlite3BtreeLeave(p); sqlite3BtreeLeave(p);
} }

View File

@@ -207,7 +207,7 @@ void sqlite3BtreeCursorList(Btree*);
#endif #endif
#ifndef SQLITE_OMIT_WAL #ifndef SQLITE_OMIT_WAL
int sqlite3BtreeCheckpoint(Btree*, int); int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
#endif #endif
/* /*

View File

@@ -1340,19 +1340,29 @@ void *sqlite3_wal_hook(
#endif #endif
} }
/* /*
** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points ** Checkpoint database zDb.
** to contains a zero-length string, all attached databases are
** checkpointed.
*/ */
int sqlite3_wal_checkpoint(sqlite3 *db, const char *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 #ifdef SQLITE_OMIT_WAL
return SQLITE_OK; return SQLITE_OK;
#else #else
int rc; /* Return code */ int rc; /* Return code */
int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */ 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); sqlite3_mutex_enter(db->mutex);
if( zDb && zDb[0] ){ if( zDb && zDb[0] ){
iDb = sqlite3FindDbName(db, zDb); iDb = sqlite3FindDbName(db, zDb);
@@ -1361,7 +1371,7 @@ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
sqlite3Error(db, SQLITE_ERROR, "unknown database: %s", zDb); sqlite3Error(db, SQLITE_ERROR, "unknown database: %s", zDb);
}else{ }else{
rc = sqlite3Checkpoint(db, iDb, 0); rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt);
sqlite3Error(db, rc, 0); sqlite3Error(db, rc, 0);
} }
rc = sqlite3ApiExit(db, rc); rc = sqlite3ApiExit(db, rc);
@@ -1370,6 +1380,16 @@ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
#endif #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 #ifndef SQLITE_OMIT_WAL
/* /*
** Run a checkpoint on database iDb. This is a no-op if database iDb is ** 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 - ** checkpointed. If an error is encountered it is returned immediately -
** no attempt is made to checkpoint any remaining databases. ** no attempt is made to checkpoint any remaining databases.
** **
** Parameter bBlock is true for a blocking-checkpoint, false for an ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
** ordinary, non-blocking, checkpoint.
*/ */
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 rc = SQLITE_OK; /* Return code */
int i; /* Used to iterate through attached dbs */ 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++){ for(i=0; i<db->nDb && rc==SQLITE_OK; i++){
if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){ if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){
rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt, bBlock); rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt, eMode, pnLog, pnCkpt);
} }
} }

View File

@@ -6520,17 +6520,16 @@ sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
** "PRAGMA wal_blocking_checkpoint" or calls the sqlite3_wal_checkpoint() ** "PRAGMA wal_blocking_checkpoint" or calls the sqlite3_wal_checkpoint()
** or wal_blocking_checkpoint() API functions. ** or wal_blocking_checkpoint() API functions.
** **
** Parameter bBlock is true for a blocking-checkpoint, false for an ** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
** ordinary, non-blocking, checkpoint.
*/ */
int sqlite3PagerCheckpoint(Pager *pPager, int bBlock){ int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
int rc = SQLITE_OK; int rc = SQLITE_OK;
if( pPager->pWal ){ if( pPager->pWal ){
u8 *zBuf = (u8 *)pPager->pTmpSpace; rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
rc = sqlite3WalCheckpoint(pPager->pWal, pPager->xBusyHandler, pPager->pBusyHandlerArg,
(bBlock ? pPager->xBusyHandler : 0), pPager->pBusyHandlerArg,
(pPager->noSync ? 0 : pPager->sync_flags), (pPager->noSync ? 0 : pPager->sync_flags),
pPager->pageSize, zBuf pPager->pageSize, (u8 *)pPager->pTmpSpace,
pnLog, pnCkpt
); );
} }
return rc; return rc;

View File

@@ -138,7 +138,7 @@ int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
int sqlite3PagerSharedLock(Pager *pPager); int sqlite3PagerSharedLock(Pager *pPager);
int sqlite3PagerCheckpoint(Pager *pPager, int); int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
int sqlite3PagerWalSupported(Pager *pPager); int sqlite3PagerWalSupported(Pager *pPager);
int sqlite3PagerWalCallback(Pager *pPager); int sqlite3PagerWalCallback(Pager *pPager);
int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);

View File

@@ -1393,19 +1393,29 @@ void sqlite3Pragma(
#ifndef SQLITE_OMIT_WAL #ifndef SQLITE_OMIT_WAL
/* /*
** PRAGMA [database.]wal_checkpoint ** PRAGMA [database.]wal_checkpoint = passive|full|restart
** PRAGMA [database.]wal_blocking_checkpoint
** **
** Checkpoint the database. ** Checkpoint the database.
*/ */
if( sqlite3StrICmp(zLeft, "wal_checkpoint")==0 if( sqlite3StrICmp(zLeft, "wal_checkpoint")==0 ){
|| sqlite3StrICmp(zLeft, "wal_blocking_checkpoint")==0
){
int bBlock = (zLeft[14]!=0);
int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED); 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; 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 }else
/* /*

View File

@@ -6145,6 +6145,89 @@ int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
*/ */
int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); 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 ** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support. ** builds on processors without floating point support.

View File

@@ -3036,7 +3036,7 @@ CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
int sqlite3TempInMemory(const sqlite3*); int sqlite3TempInMemory(const sqlite3*);
VTable *sqlite3GetVTable(sqlite3*, Table*); VTable *sqlite3GetVTable(sqlite3*, Table*);
const char *sqlite3JournalModename(int); const char *sqlite3JournalModename(int);
int sqlite3Checkpoint(sqlite3*, int, int); int sqlite3Checkpoint(sqlite3*, int, int, int*, int*);
int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int); int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
/* Declarations for functions in fkey.c. All of these are replaced by /* Declarations for functions in fkey.c. All of these are replaced by

View File

@@ -5216,13 +5216,33 @@ case OP_AggFinal: {
} }
#ifndef SQLITE_OMIT_WAL #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 ** 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: { 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; break;
}; };
#endif #endif

View File

@@ -1576,11 +1576,13 @@ static int walBusyLock(
*/ */
static int walCheckpoint( static int walCheckpoint(
Wal *pWal, /* Wal connection */ Wal *pWal, /* Wal connection */
int eMode, /* One of PASSIVE, FULL or RESTART */
int (*xBusy)(void*), /* Function to call when busy */ int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */ void *pBusyArg, /* Context argument for xBusyHandler */
int sync_flags, /* Flags for OsSync() (or 0) */ int sync_flags, /* Flags for OsSync() (or 0) */
int nBuf, /* Size of zBuf in bytes */ 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 rc; /* Return code */
int szPage; /* Database page-size */ int szPage; /* Database page-size */
@@ -1610,6 +1612,10 @@ static int walCheckpoint(
goto walcheckpoint_out; 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 /* Compute in mxSafeFrame the index of the last frame of the WAL that is
** safe to write into the database. Frames beyond mxSafeFrame might ** safe to write into the database. Frames beyond mxSafeFrame might
** overwrite database pages that are in use by active readers and thus ** overwrite database pages that are in use by active readers and thus
@@ -1617,8 +1623,6 @@ static int walCheckpoint(
*/ */
do { do {
mxSafeFrame = pWal->hdr.mxFrame; mxSafeFrame = pWal->hdr.mxFrame;
mxPage = pWal->hdr.nPage;
pInfo = walCkptInfo(pWal);
for(i=1; i<WAL_NREADER; i++){ for(i=1; i<WAL_NREADER; i++){
u32 y = pInfo->aReadMark[i]; u32 y = pInfo->aReadMark[i];
if( mxSafeFrame>=y ){ 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 if( pInfo->nBackfill<mxSafeFrame
&& (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
@@ -1685,19 +1690,12 @@ static int walCheckpoint(
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
pInfo->nBackfill = mxSafeFrame; pInfo->nBackfill = mxSafeFrame;
if( pnCkpt ) *pnCkpt = mxSafeFrame;
} }
} }
/* Release the reader lock held while backfilling */ /* Release the reader lock held while backfilling */
walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); 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 ){ if( rc==SQLITE_BUSY ){
@@ -1706,6 +1704,17 @@ static int walCheckpoint(
rc = SQLITE_OK; 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: walcheckpoint_out:
walIteratorFree(pIter); walIteratorFree(pIter);
return rc; return rc;
@@ -1737,7 +1746,9 @@ int sqlite3WalClose(
if( pWal->exclusiveMode==WAL_NORMAL_MODE ){ if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
pWal->exclusiveMode = WAL_EXCLUSIVE_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 ){ if( rc==SQLITE_OK ){
isDelete = 1; isDelete = 1;
} }
@@ -2658,11 +2669,14 @@ int sqlite3WalFrames(
*/ */
int sqlite3WalCheckpoint( int sqlite3WalCheckpoint(
Wal *pWal, /* Wal connection */ Wal *pWal, /* Wal connection */
int eMode, /* PASSIVE, FULL or RESTART */
int (*xBusy)(void*), /* Function to call when busy */ int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */ void *pBusyArg, /* Context argument for xBusyHandler */
int sync_flags, /* Flags to sync db file with (or 0) */ int sync_flags, /* Flags to sync db file with (or 0) */
int nBuf, /* Size of temporary buffer */ 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 rc; /* Return code */
int isChanged = 0; /* True if a new wal-index header is loaded */ 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. ** to prevent any writers from running while the checkpoint is underway.
** This has to be done before the call to walIndexReadHdr() below. ** 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); rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
if( rc==SQLITE_OK ) pWal->writeLock = 1; if( rc==SQLITE_OK ) pWal->writeLock = 1;
} }
@@ -2694,7 +2708,9 @@ int sqlite3WalCheckpoint(
rc = walIndexReadHdr(pWal, &isChanged); rc = walIndexReadHdr(pWal, &isChanged);
} }
if( rc==SQLITE_OK ){ 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( 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

View File

@@ -32,7 +32,7 @@
# define sqlite3WalSavepoint(y,z) # define sqlite3WalSavepoint(y,z)
# define sqlite3WalSavepointUndo(y,z) 0 # define sqlite3WalSavepointUndo(y,z) 0
# define sqlite3WalFrames(u,v,w,x,y,z) 0 # define sqlite3WalFrames(u,v,w,x,y,z) 0
# define sqlite3WalCheckpoint(u,v,w,x,y,z) 0 # define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0
# define sqlite3WalCallback(z) 0 # define sqlite3WalCallback(z) 0
# define sqlite3WalExclusiveMode(y,z) 0 # define sqlite3WalExclusiveMode(y,z) 0
# define sqlite3WalHeapMemory(z) 0 # define sqlite3WalHeapMemory(z) 0
@@ -86,11 +86,14 @@ int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
/* Copy pages from the log to the database file */ /* Copy pages from the log to the database file */
int sqlite3WalCheckpoint( int sqlite3WalCheckpoint(
Wal *pWal, /* Write-ahead log connection */ Wal *pWal, /* Write-ahead log connection */
int eMode, /* One of PASSIVE, FULL and RESTART */
int (*xBusy)(void*), /* Function to call when busy */ int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */ void *pBusyArg, /* Context argument for xBusyHandler */
int sync_flags, /* Flags to sync db file with (or 0) */ int sync_flags, /* Flags to sync db file with (or 0) */
int nBuf, /* Size of buffer nBuf */ 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 /* Return the value to pass to a sqlite3_wal_hook callback, the

View File

@@ -82,7 +82,7 @@ do_multiclient_test tn {
# #
set ::busy_handler_script { if {$n==5} { sql2 COMMIT } } set ::busy_handler_script { if {$n==5} { sql2 COMMIT } }
do_test 1.$tn.5 { do_test 1.$tn.5 {
sql1 { PRAGMA wal_blocking_checkpoint } sql1 { PRAGMA wal_checkpoint = RESTART }
list [db_page_count] [wal_page_count] $::nBusyHandler list [db_page_count] [wal_page_count] $::nBusyHandler
} {6 12 6} } {6 12 6}
do_test 1.$tn.6 { do_test 1.$tn.6 {
@@ -109,7 +109,8 @@ do_multiclient_test tn {
if {$n==7} { sql3 COMMIT } if {$n==7} { sql3 COMMIT }
} }
do_test 1.$tn.11 { do_test 1.$tn.11 {
sql1 { PRAGMA wal_blocking_checkpoint } breakpoint
sql1 { PRAGMA wal_checkpoint = RESTART }
list [db_page_count] [wal_page_count] $::nBusyHandler list [db_page_count] [wal_page_count] $::nBusyHandler
} {10 5 8} } {10 5 8}
do_test 1.$tn.12 { set ::db_file_size } 10 do_test 1.$tn.12 { set ::db_file_size } 10