------BEGIN PGP SIGNED MESSAGE-----
-Hash: SHA1
-
-C Use\sthe\sestimated\snumber\sof\srows\scomputed\sfor\ssubqueries\sin\sthe\scost\ncomputations\sfor\souter\squeries.
-D 2010-11-16T02:49:16
+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
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in e7a59672eaeb04408d1fa8501618d7501a3c5e39
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F src/backup.c d5b0137bc20327af08c14772227cc35134839c30
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
-F src/btree.c 3edab36d03d86c200cb9551467410f975d510aa9
-F src/btree.h 2d1a83ad509047e8cc314fda7e054f99ff52414d
+F src/btree.c 444aae4fc60cc57d6c97615358e1020f6884cca6
+F src/btree.h d1144d38d790a8b7b2e215043f8d068f4f37de07
F src/btreeInt.h c424f2f131cc61ddf130f9bd736b3df12c8a51f0
F src/build.c 00a327120d81ace6267e714ae8010c997d55de5d
F src/callback.c a1d1b1c9c85415dff013af033e2fed9c8382d33b
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
F src/loadext.c 8af9fcc75708d60b88636ccba38b4a7b3c155c3e
-F src/main.c 335d2c7ecb093db7b662d9325fe68fb9087a4814
+F src/main.c 89c658ae9a610a61ff856a110bda50606e9227d6
F src/malloc.c 3d7284cd9346ab6e3945535761e68c23c6cf40ef
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206
F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e
F src/os_unix.c de5be4cdbf3d07018059934eaf7e5d8d594a895c
F src/os_win.c 2f90f7bdec714fad51cd31b4ecad3cc1b4bb5aad
-F src/pager.c 067ae23d7a370eea6bd529848331c63879570adc
-F src/pager.h 8167a1e720d0b7a2790079007128e594010220ad
+F src/pager.c 7f7587c2f11126d13ee1925ac8960a9e7ab13e8a
+F src/pager.h ad7d8db0fbcee7546dbc02ffe0d0d44ea868ef52
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
F src/pcache1.c e9578a3beac26f229ee558a4e16c863f2498185f
-F src/pragma.c 216d12e4546e65ca6cfcd3221e64573889ae8f34
+F src/pragma.c 66a8b53d1e74635011fbb0bb54b7ecc402684bae
F src/prepare.c c2b318037d626fed27905c9446730b560637217a
F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
F src/sqlite.h.in f47e09412fc9a129f759fa4d96ef21f4b3d529eb
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
-F src/sqliteInt.h dd28f6138c74cf4833e032a989b6ff7885798cf6
+F src/sqliteInt.h fe1cb073b2707001985f06dee9ee256247e4d0ce
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
F src/util.c cd78524566fe45671863eee78685969a4bfd4e4c
F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f
-F src/vdbe.c e1aa917961e69f71c80f46ce231b496d3c841ae1
+F src/vdbe.c b86b09beb3dcf2e6d5922acee48b8a1c16b68bfd
F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
F src/vdbeInt.h 7f4cf1b2b69bef3a432b1f23dfebef57275436b4
F src/vdbeapi.c 5368714fa750270cf6430160287c21adff44582d
F src/vdbemem.c 23723a12cd3ba7ab3099193094cbb2eb78956aa9
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30
-F src/wal.c f26b8d297bd11cb792e609917f9d4c6718ac8e0e
-F src/wal.h c1aac6593a0b02b15dc625987e619edeab39292e
+F src/wal.c 400624ce58acce44f0bf0d47ed2f435da290fb04
+F src/wal.h d5bbc11242d7fd14e9dc6a74f68d3ccaf01a9e48
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c d5cc65f51661a038a2c6a663a945d5cf4c277b81
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/wal2.test c794b8b257af54190bb913678ad3984cbf3311b9
F test/wal3.test 957a5f2a8fe8a6ff01de1a15285ecf2f376fcaf8
F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30
-F test/wal_common.tcl 895d76138043b86bdccf36494054bdabcf65837b
+F test/wal5.test e0f1abdff4f76d3a8531f5d0f4cb237e5eff891c
+F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe
F test/walbak.test 4df1c7369da0301caeb9a48fa45997fd592380e4
F test/walbig.test e882bc1d014afffbfa2b6ba36e0f07d30a633ad0
F test/walcksum.test a37b36375c595e61bdb7e1ec49b5f0979b6fc7ce
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P d52b593978aa1776af7aeb957c4f8df0c5cb7e43
-R d49dbce342d6074d2c08ca15a1061dc2
-U drh
-Z 1d0a2a683be8d99ef69f89af3e0fc4c3
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.6 (GNU/Linux)
-
-iD8DBQFM4fEvoxKgR168RlERAtLBAJ0duCZxNY8VlhlVLo/NezKrqI5noACdE3GU
-LDKZgeEbRVz6H1/mucVVNUQ=
-=B2su
------END PGP SIGNATURE-----
+P 56bbc539246a6dc9f1ae1edb898db7a4f6f6d322
+R 75a04ae738d792c76538f98d6f9ad655
+T *branch * experimental
+T *sym-experimental *
+T -sym-trunk *
+U dan
+Z b1cbb492cf90106bd968e524fdd11e16
-56bbc539246a6dc9f1ae1edb898db7a4f6f6d322
\ No newline at end of file
+7e3fc2c833a5baa08820c499867b6902bdc2ed5a
\ No newline at end of file
**
** 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 sqlite3BtreeCheckpoint(Btree *p, int bBlock){
int rc = SQLITE_OK;
if( p ){
BtShared *pBt = p->pBt;
if( pBt->inTransaction!=TRANS_NONE ){
rc = SQLITE_LOCKED;
}else{
- rc = sqlite3PagerCheckpoint(pBt->pPager);
+ rc = sqlite3PagerCheckpoint(pBt->pPager, bBlock);
}
sqlite3BtreeLeave(p);
}
#endif
#ifndef SQLITE_OMIT_WAL
- int sqlite3BtreeCheckpoint(Btree*);
+ int sqlite3BtreeCheckpoint(Btree*, int);
#endif
/*
rc = SQLITE_ERROR;
sqlite3Error(db, SQLITE_ERROR, "unknown database: %s", zDb);
}else{
- rc = sqlite3Checkpoint(db, iDb);
+ rc = sqlite3Checkpoint(db, iDb, 0);
sqlite3Error(db, rc, 0);
}
rc = sqlite3ApiExit(db, rc);
** If iDb is passed SQLITE_MAX_ATTACHED, then all attached databases are
** 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.
*/
-int sqlite3Checkpoint(sqlite3 *db, int iDb){
+int sqlite3Checkpoint(sqlite3 *db, int iDb, int bBlock){
int rc = SQLITE_OK; /* Return code */
int i; /* Used to iterate through attached dbs */
for(i=0; i<db->nDb && rc==SQLITE_OK; i++){
if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){
- rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt);
+ rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt, bBlock);
}
}
#ifndef SQLITE_OMIT_WAL
/*
-** This function is called when the user invokes "PRAGMA checkpoint".
+** This function is called when the user invokes "PRAGMA wal_checkpoint",
+** "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.
*/
-int sqlite3PagerCheckpoint(Pager *pPager){
+int sqlite3PagerCheckpoint(Pager *pPager, int bBlock){
int rc = SQLITE_OK;
if( pPager->pWal ){
u8 *zBuf = (u8 *)pPager->pTmpSpace;
rc = sqlite3WalCheckpoint(pPager->pWal,
+ (bBlock ? pPager->xBusyHandler : 0), pPager->pBusyHandlerArg,
(pPager->noSync ? 0 : pPager->sync_flags),
pPager->pageSize, zBuf
);
int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
int sqlite3PagerSharedLock(Pager *pPager);
-int sqlite3PagerCheckpoint(Pager *pPager);
+int sqlite3PagerCheckpoint(Pager *pPager, int);
int sqlite3PagerWalSupported(Pager *pPager);
int sqlite3PagerWalCallback(Pager *pPager);
int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
#ifndef SQLITE_OMIT_WAL
/*
** PRAGMA [database.]wal_checkpoint
+ ** PRAGMA [database.]wal_blocking_checkpoint
**
** 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);
+ assert( bBlock==(sqlite3StrICmp(zLeft, "wal_checkpoint")!=0) );
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
- sqlite3VdbeAddOp3(v, OP_Checkpoint, pId2->z?iDb:SQLITE_MAX_ATTACHED, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Checkpoint, iBt, bBlock);
}else
/*
int sqlite3TempInMemory(const sqlite3*);
VTable *sqlite3GetVTable(sqlite3*, Table*);
const char *sqlite3JournalModename(int);
-int sqlite3Checkpoint(sqlite3*, int);
+int sqlite3Checkpoint(sqlite3*, int, int);
int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
/* Declarations for functions in fkey.c. All of these are replaced by
}
#ifndef SQLITE_OMIT_WAL
-/* Opcode: Checkpoint P1 * * * *
+/* Opcode: Checkpoint P1 P2 * * *
**
** Checkpoint database P1. This is a no-op if P1 is not currently in
-** WAL mode.
+** WAL mode. If P2 is non-zero, this is a blocking checkpoint.
*/
case OP_Checkpoint: {
- rc = sqlite3Checkpoint(db, pOp->p1);
+ rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2);
break;
};
#endif
return rc;
}
+/*
+** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
+** n. If the attempt fails and parameter xBusy is not NULL, then it is a
+** busy-handler function. Invoke it and retry the lock until either the
+** lock is successfully obtained or the busy-handler returns 0.
+*/
+static int walBusyLock(
+ Wal *pWal, /* WAL connection */
+ int (*xBusy)(void*), /* Function to call when busy */
+ void *pBusyArg, /* Context argument for xBusyHandler */
+ int lockIdx, /* Offset of first byte to lock */
+ int n /* Number of bytes to lock */
+){
+ int rc;
+ do {
+ rc = walLockExclusive(pWal, lockIdx, n);
+ }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
+ return rc;
+}
+
/*
** 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.
*/
static int walCheckpoint(
Wal *pWal, /* Wal connection */
+ 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 */
** 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;
- pInfo = walCkptInfo(pWal);
- for(i=1; i<WAL_NREADER; i++){
- u32 y = pInfo->aReadMark[i];
- if( mxSafeFrame>=y ){
- assert( y<=pWal->hdr.mxFrame );
- rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
- if( rc==SQLITE_OK ){
- pInfo->aReadMark[i] = READMARK_NOT_USED;
- walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
- }else if( rc==SQLITE_BUSY ){
- mxSafeFrame = y;
- }else{
- goto walcheckpoint_out;
+ 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 ){
+ assert( y<=pWal->hdr.mxFrame );
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ if( rc==SQLITE_OK ){
+ pInfo->aReadMark[i] = READMARK_NOT_USED;
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ }else if( rc==SQLITE_BUSY ){
+ mxSafeFrame = y;
+ }else{
+ goto walcheckpoint_out;
+ }
}
}
- }
+ }while( xBusy && mxSafeFrame<pWal->hdr.mxFrame && xBusy(pBusyArg) );
if( pInfo->nBackfill<mxSafeFrame
- && (rc = walLockExclusive(pWal, WAL_READ_LOCK(0), 1))==SQLITE_OK
+ && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
){
i64 nSize; /* Current size of database file */
u32 nBackfill = pInfo->nBackfill;
/* Release the reader lock held while backfilling */
walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
- }else if( rc==SQLITE_BUSY ){
+
+ 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 ){
/* Reset the return code so as not to report a checkpoint failure
- ** just because active readers prevent any backfill.
- */
+ ** just because there are active readers. */
rc = SQLITE_OK;
}
if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
}
- rc = sqlite3WalCheckpoint(pWal, sync_flags, nBuf, zBuf);
+ rc = sqlite3WalCheckpoint(pWal, 0, 0, sync_flags, nBuf, zBuf);
if( rc==SQLITE_OK ){
isDelete = 1;
}
**
** Obtain a CHECKPOINT lock and then backfill as much information as
** we can from WAL into the database.
+**
+** If parameter xBusy is not NULL, it is a pointer to a busy-handler
+** callback. In this case this function runs a blocking checkpoint.
*/
int sqlite3WalCheckpoint(
Wal *pWal, /* Wal connection */
+ 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 */
int isChanged = 0; /* True if a new wal-index header is loaded */
assert( pWal->ckptLock==0 );
+ assert( pWal->writeLock==0 );
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
}
pWal->ckptLock = 1;
+ /* If this is a blocking-checkpoint, then obtain the write-lock as well
+ ** to prevent any writers from running while the checkpoint is underway.
+ ** This has to be done before the call to walIndexReadHdr() below.
+ */
+ if( xBusy ){
+ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
+ if( rc==SQLITE_OK ) pWal->writeLock = 1;
+ }
+
/* Copy data from the log to the database file. */
- rc = walIndexReadHdr(pWal, &isChanged);
if( rc==SQLITE_OK ){
- rc = walCheckpoint(pWal, sync_flags, nBuf, zBuf);
+ rc = walIndexReadHdr(pWal, &isChanged);
+ }
+ if( rc==SQLITE_OK ){
+ rc = walCheckpoint(pWal, xBusy, pBusyArg, sync_flags, nBuf, zBuf);
}
if( isChanged ){
/* If a new wal-index header was loaded before the checkpoint was
}
/* Release the locks. */
+ sqlite3WalEndWriteTransaction(pWal);
walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
pWal->ckptLock = 0;
WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
# define sqlite3WalSavepoint(y,z)
# define sqlite3WalSavepointUndo(y,z) 0
# define sqlite3WalFrames(u,v,w,x,y,z) 0
-# define sqlite3WalCheckpoint(u,v,w,x) 0
+# define sqlite3WalCheckpoint(u,v,w,x,y,z) 0
# define sqlite3WalCallback(z) 0
# define sqlite3WalExclusiveMode(y,z) 0
# define sqlite3WalHeapMemory(z) 0
/* Copy pages from the log to the database file */
int sqlite3WalCheckpoint(
Wal *pWal, /* Write-ahead log connection */
+ 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 */
--- /dev/null
+# 2010 April 13
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library. The
+# focus of this file is testing the operation of "blocking-checkpoint"
+# operations.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+source $testdir/wal_common.tcl
+ifcapable !wal {finish_test ; return }
+
+set testprefix wal5
+
+do_multiclient_test tn {
+
+ proc db_page_count {} { expr [file size test.db] / 1024 }
+ proc wal_page_count {} { wal_frame_count test.db-wal 1024 }
+
+ set ::nBusyHandler 0
+ set ::busy_handler_script ""
+ proc busyhandler {n} {
+ incr ::nBusyHandler
+ eval $::busy_handler_script
+ return 0
+ }
+
+ proc reopen_all {} {
+ code1 {db close}
+ code2 {db2 close}
+ code3 {db3 close}
+ code1 {sqlite3 db test.db}
+ code2 {sqlite3 db2 test.db}
+ code3 {sqlite3 db3 test.db}
+ sql1 { PRAGMA synchronous = NORMAL }
+ code1 { db busy busyhandler }
+ }
+
+ do_test 1.$tn.1 {
+ reopen_all
+ sql1 {
+ PRAGMA page_size = 1024;
+ PRAGMA auto_vacuum = 0;
+ CREATE TABLE t1(x, y);
+ PRAGMA journal_mode = WAL;
+ INSERT INTO t1 VALUES(1, zeroblob(1200));
+ INSERT INTO t1 VALUES(2, zeroblob(1200));
+ INSERT INTO t1 VALUES(3, zeroblob(1200));
+ }
+ expr [file size test.db] / 1024
+ } {2}
+
+ # Have connection 2 grab a read-lock on the current snapshot.
+ do_test 1.$tn.2 { sql2 { BEGIN; SELECT x FROM t1 } } {1 2 3}
+
+ # Attempt a checkpoint.
+ do_test 1.$tn.3 {
+ sql1 { PRAGMA wal_checkpoint }
+ list [db_page_count] [wal_page_count]
+ } {5 9}
+
+ # Write to the db again. The log cannot wrap because of the lock still
+ # held by connection 2. The busy-handler has not yet been invoked.
+ do_test 1.$tn.4 {
+ sql1 { INSERT INTO t1 VALUES(4, zeroblob(1200)) }
+ list [db_page_count] [wal_page_count] $::nBusyHandler
+ } {5 12 0}
+
+ # Now do a blocking-checkpoint. Set the busy-handler up so that connection
+ # 2 releases its lock on the 6th invocation. The checkpointer should then
+ # proceed to checkpoint the entire log file. Next write should go to the
+ # start of the log file.
+ #
+ set ::busy_handler_script { if {$n==5} { sql2 COMMIT } }
+ do_test 1.$tn.5 {
+ sql1 { PRAGMA wal_blocking_checkpoint }
+ list [db_page_count] [wal_page_count] $::nBusyHandler
+ } {6 12 6}
+ do_test 1.$tn.6 {
+ set ::nBusyHandler 0
+ sql1 { INSERT INTO t1 VALUES(5, zeroblob(1200)) }
+ list [db_page_count] [wal_page_count] $::nBusyHandler
+ } {6 12 0}
+
+ do_test 1.$tn.7 {
+ reopen_all
+ list [db_page_count] [wal_page_count] $::nBusyHandler
+ } {7 0 0}
+
+ do_test 1.$tn.8 { sql2 { BEGIN ; SELECT x FROM t1 } } {1 2 3 4 5}
+ do_test 1.$tn.9 {
+ sql1 { INSERT INTO t1 VALUES(6, zeroblob(1200)) }
+ list [db_page_count] [wal_page_count] $::nBusyHandler
+ } {7 5 0}
+ do_test 1.$tn.10 { sql3 { BEGIN ; SELECT x FROM t1 } } {1 2 3 4 5 6}
+
+ set ::busy_handler_script {
+ if {$n==5} { sql2 COMMIT }
+ if {$n==6} { set ::db_file_size [db_page_count] }
+ if {$n==7} { sql3 COMMIT }
+ }
+ do_test 1.$tn.11 {
+ sql1 { PRAGMA wal_blocking_checkpoint }
+ list [db_page_count] [wal_page_count] $::nBusyHandler
+ } {10 5 8}
+ do_test 1.$tn.12 { set ::db_file_size } 10
+}
+
+finish_test
}
proc wal_frame_count {zFile pgsz} {
+ if {[file exists $zFile]==0} { return 0 }
set f [file size $zFile]
+ if {$f < 32} { return 0 }
expr {($f - 32) / ($pgsz+24)}
}