]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Experiment with using an atomic CPU primitive instead of a mutex for
authordan <dan@noemail.net>
Thu, 6 Dec 2018 18:58:58 +0000 (18:58 +0000)
committerdan <dan@noemail.net>
Thu, 6 Dec 2018 18:58:58 +0000 (18:58 +0000)
intra-process locking with the unix-excl VFS.

FossilOrigin-Name: 8f4cb9dd3396bcaaf85dcdb4e3ae3c96f28a4d71d72665c4abf7c221370be626

manifest
manifest.uuid
src/os_unix.c
src/test_vfs.c
test/lock_common.tcl
test/permutations.test
test/shmlock.test [new file with mode: 0644]
test/wal.test

index 720ed6ca6bf0c3339cb7c605671460d289e52a68..f8b2c4a2474aa08866a6805fd1940fa3bad6b7bf 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Invoking\sthe\ssqlite3_trace()\sor\ssqlite3_trace_v2()\sinterfaces\scancels\nany\ssqlite3_profile()\sthat\sis\srunning.
-D 2018-12-06T03:59:25.918
+C Experiment\swith\susing\san\satomic\sCPU\sprimitive\sinstead\sof\sa\smutex\sfor\nintra-process\slocking\swith\sthe\sunix-excl\sVFS.
+D 2018-12-06T18:58:58.578
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in 68d0ba0f0b533d5bc84c78c13a6ce84ee81183a67014caa47a969e67f028fa1c
@@ -491,7 +491,7 @@ F src/os.c 8aeb0b0f40f8f5b0da03fe49706695adaf42d2f516ab95abc72e86c245e119de
 F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
 F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
 F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
-F src/os_unix.c f6e91b8fd82af7afbfd073c4974ad6cdb8e62d9f65ceddb45167835a0567fdc0
+F src/os_unix.c dcf08ca4f7092507015391b078f9ab866e8fcc6fba22560086fe1eec031edd18
 F src/os_win.c 85d9e532d0444ab6c16d7431490c2e279e282aa0917b0e988996b1ae0de5c5a0
 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
 F src/pager.c 75e0f3cfa3962c714f519f8a3d1e67ecca1c91de0e010a036b988e40ce9e4c73
@@ -563,7 +563,7 @@ F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
 F src/test_tclsh.c 06317648b0d85a85fd823f7973b55535c59a3156c1ef59394fe511f932cfa78d
 F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
 F src/test_thread.c 911d15fb14e19c0c542bdc8aabf981c2f10a4858
-F src/test_vfs.c 112f1f9271c33c211812e0e681830a84262dac065da58579ff49f9cefec97d4f
+F src/test_vfs.c 194b8e78e9b4279bc69693cb5cfc343e0a08482c430a571ec96d80440e337a44
 F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
 F src/test_windirent.c a895e2c068a06644eef91a7f0a32182445a893b9a0f33d0cdb4283dca2486ac1
 F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a90484215
@@ -1078,7 +1078,7 @@ F test/lock4.test 27143363eda1622f03c133efc8db808fc331afd973486cb571ea71cd717d37
 F test/lock5.test c6c5e0ebcb21c61a572870cc86c0cb9f14cede38
 F test/lock6.test ad5b387a3a8096afd3c68a55b9535056431b0cf5
 F test/lock7.test 49f1eaff1cdc491cc5dee3669f3c671d9f172431
-F test/lock_common.tcl 7ffb45accf6ee91c736df9bafe0806a44358f035
+F test/lock_common.tcl 2f3f7f2e9637f93ccf609df48ef5b27a50278b6b1cd752b445d52262e5841413
 F test/lookaside.test 5a828e7256f1ee4da8e1bdaa03373a3ccdb0f1ff98dfa82e9b76cb41a45b1083
 F test/main.test 6bbb3999fd461eb8fb335cbab97409a3d7f91bbb8da60635e8be3e4a04a77772
 F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
@@ -1181,7 +1181,7 @@ F test/parser1.test 6ccdf5e459a5dc4673d3273dc311a7e9742ca952dd0551a6a6320d27035c
 F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
 F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
 F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
-F test/permutations.test cf0b4e498db1d0143c19641d4420df7cc27fab2c95ed0abd2c7c5753beab25b8
+F test/permutations.test c2e5f618a71d1a7e50216325dd056f6ec16439b3c98d87bcd2df381297e5dc97
 F test/pg_common.tcl 301ac19c1a52fd55166d26db929b3b89165c634d52b5f8ad76ea8cb06960db30
 F test/pragma.test c267bf02742c823a191960895b3d52933cebd7beee26757d1ed694f213fcd867
 F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
@@ -1285,6 +1285,7 @@ F test/shell5.test 23939a4c51f0421330ea61dbd3c74f9c215f5f8d3d1a94846da6ffc777a35
 F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
 F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
 F test/shell8.test 96be02ea0c21f05b24c1883d7b711a1fa8525a68ab7b636aacf6057876941013
+F test/shmlock.test 2d8d2401fb001414a817d61b2c4983215d546c71d48da517a0a5015422997628
 F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
 F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
 F test/shrink.test 1b4330b1fd9e818c04726d45cb28db73087535ce
@@ -1592,7 +1593,7 @@ F test/vtabJ.test d7b73675708cf63cfcb9d443bb451fc01a028347275b7311e51f9fdf3ca675
 F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c3784c6783
 F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65
 F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
-F test/wal.test 613efec03e517e1775d86b993a54877d2e29a477
+F test/wal.test cdf0ca6cc0447520d19ef1c83287824ebeb3e82d75af856511ba96841a79fc9b
 F test/wal2.test 155b9efa999bdb38ce1cd729b9a4fcdbffd6b88be27f039bad1d2929d287d918
 F test/wal3.test 2a93004bc0fb2b5c29888964024695bade278ab2
 F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
@@ -1782,7 +1783,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 3a2c047989facc3461c63a2f9eed412014c951035a80da47c52a70139fb552de
-R e33573679d2b83476b49b39d100df865
-U drh
-Z 9b63335dca170db3a75ac781c84ad8b2
+P ec63d3506bd429560077f82a4c5ed9d189780789fe1c134fff4f3b8733be1a3f
+R 421ea33fec1ec5096b7fb80f863def19
+T *branch * mutexfree-shmlock
+T *sym-mutexfree-shmlock *
+T -sym-trunk *
+U dan
+Z 737072d87778273578811397782f507c
index 787485caf52b78182969958eaf19ca5b922e8c05..f3e776b8e79e9fc258ae47213343eee8de82dd44 100644 (file)
@@ -1 +1 @@
-ec63d3506bd429560077f82a4c5ed9d189780789fe1c134fff4f3b8733be1a3f
\ No newline at end of file
+8f4cb9dd3396bcaaf85dcdb4e3ae3c96f28a4d71d72665c4abf7c221370be626
\ No newline at end of file
index f20763e5b0bc96dbdb7947ec6f919081d946c845..946c5d3d6577266da32d8e89c9e6f2e8401dad8e 100644 (file)
@@ -46,6 +46,9 @@
 #include "sqliteInt.h"
 #if SQLITE_OS_UNIX              /* This file is used on unix only */
 
+/* Turn this feature on in all builds for now */
+#define SQLITE_MUTEXFREE_SHMLOCK 1
+
 /*
 ** There are various methods for file locking used for concurrency
 ** control:
@@ -4239,8 +4242,38 @@ struct unixShmNode {
   u8 sharedMask;             /* Mask of shared locks held */
   u8 nextShmId;              /* Next available unixShm.id value */
 #endif
+
+#ifdef SQLITE_MUTEXFREE_SHMLOCK
+  /* In unix-excl mode, if SQLITE_MUTEXFREE_SHMLOCK is defined, all locks
+  ** are stored in the following 64-bit value. There are in total 8 
+  ** shm-locking slots, each of which are assigned 8-bits from the 64-bit
+  ** value. The least-significant 8 bits correspond to shm-locking slot
+  ** 0, and so on.
+  **
+  ** If the 8-bits corresponding to a shm-locking locking slot are set to
+  ** 0xFF, then a write-lock is held on the slot. Or, if they are set to
+  ** a non-zero value smaller than 0xFF, then they represent the total 
+  ** number of read-locks held on the slot. There is no way to distinguish
+  ** between a write-lock and 255 read-locks.  */
+  u64 lockmask;
+#endif
 };
 
+/*
+** Atomic CAS primitive used in multi-process mode. Equivalent to:
+** 
+**   int unixCompareAndSwap(u32 *ptr, u32 oldval, u32 newval){
+**     if( *ptr==oldval ){
+**       *ptr = newval;
+**       return 1;
+**     }
+**     return 0;
+**   }
+*/
+#define unixCompareAndSwap(ptr,oldval,newval) \
+    __sync_bool_compare_and_swap(ptr,oldval,newval)
+
+
 /*
 ** Structure used internally by this VFS to record the state of an
 ** open shared memory connection.
@@ -4800,6 +4833,58 @@ static int unixShmLock(
 
   mask = (1<<(ofst+n)) - (1<<ofst);
   assert( n>1 || mask==(1<<ofst) );
+
+#ifdef SQLITE_MUTEXFREE_SHMLOCK
+  if( pDbFd->pInode->bProcessLock ){
+
+    while( 1 ){
+      u64 lockmask = pShmNode->lockmask;
+      u64 newmask = lockmask;
+      int i;
+      for(i=ofst; i<n+ofst; i++){
+        int ix8 = i*8;
+        u8 v = (lockmask >> (ix8)) & 0xFF;
+        if( flags & SQLITE_SHM_UNLOCK ){
+          if( flags & SQLITE_SHM_EXCLUSIVE ){
+            if( p->exclMask & (1 << i) ){
+              newmask = newmask & ~((u64)0xFF<<ix8);
+            }
+          }else{
+            if( p->sharedMask & (1 << i) ){
+              newmask = newmask & ~((u64)0xFF<<ix8) | ((u64)(v-1)<<ix8);
+            }
+          }
+        }else{
+          if( flags & SQLITE_SHM_EXCLUSIVE ){
+            if( v ) return SQLITE_BUSY;
+            if( (p->exclMask & (1 << i))==0 ){
+              newmask = newmask | ((u64)0xFF<<ix8);
+            }
+          }else{
+            if( v==0xFF ) return SQLITE_BUSY;
+            if( (p->sharedMask & (1 << i))==0 ){
+              newmask = newmask & ~((u64)0xFF<<ix8) | ((u64)(v+1)<<ix8);
+            }
+          }
+        }
+      }
+
+      if( unixCompareAndSwap(&pShmNode->lockmask, lockmask, newmask) ) break;
+    }
+
+    if( flags & SQLITE_SHM_UNLOCK ){
+      p->sharedMask &= ~mask;
+      p->exclMask &= ~mask;
+    }else if( flags & SQLITE_SHM_EXCLUSIVE ){
+      p->exclMask |= mask;
+    }else{
+      p->sharedMask |= mask;
+    }
+
+    return SQLITE_OK;
+  }
+#endif
+
   sqlite3_mutex_enter(pShmNode->pShmMutex);
   if( flags & SQLITE_SHM_UNLOCK ){
     u16 allMask = 0; /* Mask of locks held by siblings */
index 4a98ac214ce005371b6f2a81a13d9591eea6b669..645b1447c2ee410ff72dc060a7f33f5944a9b3d6 100644 (file)
@@ -1563,8 +1563,62 @@ static int SQLITE_TCLAPI testvfs_cmd(
   return TCL_ERROR;
 }
 
+extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
+extern const char *sqlite3ErrName(int);
+
+/*
+** tclcmd: vfs_shmlock DB DBNAME (shared|exclusive) (lock|unlock) OFFSET N
+*/
+static int SQLITE_TCLAPI test_vfs_shmlock(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  const char *azArg1[] = {"shared", "exclusive", 0};
+  const char *azArg2[] = {"lock", "unlock", 0};
+  sqlite3 *db = 0;
+  int rc = SQLITE_OK;
+  const char *zDbname = 0;
+  int iArg1 = 0;
+  int iArg2 = 0;
+  int iOffset = 0;
+  int n = 0;
+  sqlite3_file *pFd;
+
+  if( objc!=7 ){
+    Tcl_WrongNumArgs(interp, 1, objv, 
+        "DB DBNAME (shared|exclusive) (lock|unlock) OFFSET N"
+    );
+    return TCL_ERROR;
+  }
+
+  zDbname = Tcl_GetString(objv[2]);
+  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) 
+   || Tcl_GetIndexFromObj(interp, objv[3], azArg1, "ARG", 0, &iArg1) 
+   || Tcl_GetIndexFromObj(interp, objv[4], azArg2, "ARG", 0, &iArg2) 
+   || Tcl_GetIntFromObj(interp, objv[5], &iOffset)
+   || Tcl_GetIntFromObj(interp, objv[6], &n)
+  ){
+    return TCL_ERROR;
+  }
+
+  sqlite3_file_control(db, zDbname, SQLITE_FCNTL_FILE_POINTER, (void*)&pFd);
+  if( pFd==0 ){
+    return TCL_ERROR;
+  }
+  rc = pFd->pMethods->xShmLock(pFd, iOffset, n, 
+      (iArg1==0 ? SQLITE_SHM_SHARED : SQLITE_SHM_EXCLUSIVE)
+    | (iArg2==0 ? SQLITE_SHM_LOCK : SQLITE_SHM_UNLOCK)
+  );
+  Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
+  return TCL_OK;
+}
+
+
 int Sqlitetestvfs_Init(Tcl_Interp *interp){
   Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0);
+  Tcl_CreateObjCommand(interp, "vfs_shmlock", test_vfs_shmlock, 0, 0);
   return TCL_OK;
 }
 
index a758e7af2e4d506301378ce86bcca155551483b1..3e1821bab0b5d4de72ff8f75afbc3313104ce482 100644 (file)
 
 proc do_multiclient_test {varname script} {
 
-  foreach code [list {
+  foreach {tn code} [list 1 {
     if {[info exists ::G(valgrind)]} { db close ; continue }
     set ::code2_chan [launch_testfixture]
     set ::code3_chan [launch_testfixture]
     proc code2 {tcl} { testfixture $::code2_chan $tcl }
     proc code3 {tcl} { testfixture $::code3_chan $tcl }
-    set tn 1
-  } {
+  } 2 {
     proc code2 {tcl} { uplevel #0 $tcl }
     proc code3 {tcl} { uplevel #0 $tcl }
-    set tn 2
   }] {
+    # Do not run multi-process tests with the unix-excl VFS.
+    #
+    if {$tn==1 && [permutation]=="unix-excl"} continue
+
     faultsim_delete_and_reopen
 
     proc code1 {tcl} { uplevel #0 $tcl }
index 6aa812e8af55fd0cf1394e83292ddc97a0d68a53..a4c21e67d816904db148c9c3948b6a28ddc1dea2 100644 (file)
@@ -607,6 +607,16 @@ test_suite "onefile" -description {
   rollback.test  select1.test  select2.test  select3.test
 }
 
+# Run some tests using the "unix-excl" VFS.
+#
+test_suite "unix-excl" -description {
+  Run some tests using the "unix-excl" VFS
+} -initialize {
+  set ::G(perm:sqlite3_args) [list -vfs unix-excl]
+} -files {
+  shmlock.test
+}
+
 # Run some tests using UTF-16 databases.
 #
 test_suite "utf16" -description {
diff --git a/test/shmlock.test b/test/shmlock.test
new file mode 100644 (file)
index 0000000..ac79ac4
--- /dev/null
@@ -0,0 +1,111 @@
+# 2018 December 6
+#
+# 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.
+#
+#***********************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+set testprefix shmlock
+
+ifcapable !wal {finish_test ; return }
+
+sqlite3 db2 test.db
+sqlite3 db3 test.db
+
+do_execsql_test 1.0 {
+  PRAGMA journal_mode = wal;
+  CREATE TABLE t1(a, b);
+  INSERT INTO t1 VALUES(1, 2);
+} {wal}
+do_test 1.1 { execsql { SELECT * FROM t1 } db2 } {1 2}
+do_test 1.2 { execsql { SELECT * FROM t1 } db3 } {1 2}
+
+foreach {tn dbhandle cmd res} {
+  1    db  {shared    lock   7 1}    OK
+  2    db2 {exclusive lock   7 1}    BUSY
+  3    db  {shared    unlock 7 1}    OK
+  4    db2 {exclusive lock   7 1}    OK
+  5    db  {shared    lock   7 1}    BUSY
+  6    db  {exclusive lock   7 1}    BUSY
+  7    db2 {exclusive unlock 7 1}    OK
+
+  8    db  {exclusive lock   0 8}    OK
+  9    db  {exclusive unlock 0 8}    OK
+  10   db2 {exclusive lock   0 8}    OK
+  11   db2 {exclusive unlock 0 8}    OK
+
+  12   db  {shared    lock   0 1}    OK
+  13   db2 {shared    lock   0 1}    OK
+  14   db3 {shared    lock   0 1}    OK
+  15   db3 {shared    unlock 0 1}    OK
+  16   db3 {exclusive lock   0 1}    BUSY
+  17   db2 {shared    unlock 0 1}    OK
+  18   db3 {exclusive lock   0 1}    BUSY
+  19   db  {shared    unlock 0 1}    OK
+  20   db3 {exclusive lock   0 1}    OK
+  21   db3 {exclusive unlock 0 1}    OK
+
+  22   db  {shared    lock   3 1}    OK
+  23   db2 {exclusive lock   2 2}    BUSY
+  24   db  {shared    lock   2 1}    OK
+  25   db2 {exclusive lock   0 5}    BUSY
+  26   db2 {exclusive lock   0 4}    BUSY
+  27   db2 {exclusive lock   0 3}    BUSY
+  28   db  {shared    unlock 3 1}    OK
+  29   db2 {exclusive lock   2 2}    BUSY
+  28   db  {shared    unlock 2 1}    OK
+  29   db2 {exclusive lock   2 2}    OK
+  29   db2 {exclusive unlock 2 2}    OK
+} {
+  do_test 1.3.$tn [list vfs_shmlock $dbhandle main {*}$cmd] "SQLITE_$res"
+}
+
+db  close
+db2 close
+db3 close
+
+if {[permutation]=="unix-excl"} {
+  do_test 2.0 {
+    for {set i 0} {$i < 256} {incr i} { 
+      sqlite3 db$i test.db 
+      execsql { SELECT * FROM t1 } db$i
+    }
+    for {set i 0} {$i < 255} {incr i} { 
+      set rc [vfs_shmlock db$i main shared lock 4 1]
+      if {$rc != "SQLITE_OK"} { error $rc }
+    }
+
+    vfs_shmlock db255 main shared lock 4 1
+  } {SQLITE_BUSY}
+
+  do_test 2.1 { vfs_shmlock db255 main exclusive lock   4 1 } SQLITE_BUSY
+  do_test 2.2 { vfs_shmlock db0   main shared    unlock 4 1 } SQLITE_OK
+  do_test 2.3 { vfs_shmlock db255 main shared    lock   4 1 } SQLITE_OK
+  do_test 2.4 { vfs_shmlock db255 main shared    unlock 4 1 } SQLITE_OK
+  do_test 2.5 { vfs_shmlock db255 main exclusive lock   4 1 } SQLITE_BUSY
+
+  do_test 2.6 {
+    for {set i 1} {$i < 255} {incr i} { 
+      set rc [vfs_shmlock db255 main exclusive lock 4 1]
+      if {$rc != "SQLITE_BUSY"} { error $rc }
+      set rc [vfs_shmlock db$i main shared unlock 4 1]
+      if {$rc != "SQLITE_OK"} { error $rc }
+    }
+
+    vfs_shmlock db255 main exclusive lock 4 1
+  } {SQLITE_OK}
+
+  vfs_shmlock db255 main exclusive unlock 4 1
+}
+
+finish_test
+
+
index bb164bb76ad1aa38a4e5d4203e608679e1001e50..a003b6ad20abd62c443d49512682e26a5bc17622 100644 (file)
@@ -1297,51 +1297,53 @@ do_test wal-19.4 {
 # At one point, SQLite was failing to grow the mapping of the wal-index
 # file in step 3 and the checkpoint was corrupting the database file.
 #
-do_test wal-20.1 {
-  catch {db close}
-  forcedelete test.db test.db-wal test.db-journal
-  sqlite3 db test.db
-  execsql {
-    PRAGMA journal_mode = WAL;
-    CREATE TABLE t1(x);
-    INSERT INTO t1 VALUES(randomblob(900));
-    SELECT count(*) FROM t1;
-  }
-} {wal 1}
-do_test wal-20.2 {
-  set ::buddy [launch_testfixture]
-  testfixture $::buddy {
+if {[permutation]!="unix-excl"} {
+  do_test wal-20.1 {
+    catch {db close}
+    forcedelete test.db test.db-wal test.db-journal
     sqlite3 db test.db
-    db transaction { db eval {
-      PRAGMA wal_autocheckpoint = 0;
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 2 */
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 4 */
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 8 */
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 16 */
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 32 */
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 64 */
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 128 */
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 256 */
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 512 */
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 1024 */
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 2048 */
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 4096 */
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 8192 */
-      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 16384 */
-    } }
-  }
-} {0}
-do_test wal-20.3 {
-  close $::buddy
-  execsql { PRAGMA wal_checkpoint }
-  execsql { SELECT count(*) FROM t1 }
-} {16384}
-do_test wal-20.4 {
-  db close
-  sqlite3 db test.db
-  execsql { SELECT count(*) FROM t1 }
-} {16384}
-integrity_check wal-20.5
+    execsql {
+      PRAGMA journal_mode = WAL;
+      CREATE TABLE t1(x);
+      INSERT INTO t1 VALUES(randomblob(900));
+      SELECT count(*) FROM t1;
+    }
+  } {wal 1}
+  do_test wal-20.2 {
+    set ::buddy [launch_testfixture]
+    testfixture $::buddy {
+      sqlite3 db test.db
+      db transaction { db eval {
+        PRAGMA wal_autocheckpoint = 0;
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 2 */
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 4 */
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 8 */
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 16 */
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 32 */
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 64 */
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 128 */
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 256 */
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 512 */
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 1024 */
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 2048 */
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 4096 */
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 8192 */
+        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 16384 */
+      } }
+    }
+  } {0}
+  do_test wal-20.3 {
+    close $::buddy
+    execsql { PRAGMA wal_checkpoint }
+    execsql { SELECT count(*) FROM t1 }
+  } {16384}
+  do_test wal-20.4 {
+    db close
+    sqlite3 db test.db
+    execsql { SELECT count(*) FROM t1 }
+  } {16384}
+  integrity_check wal-20.5
+}
 
 catch { db2 close }
 catch { db close }