/ Check-in [8f4cb9dd]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Experiment with using an atomic CPU primitive instead of a mutex for intra-process locking with the unix-excl VFS.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | mutexfree-shmlock
Files: files | file ages | folders
SHA3-256: 8f4cb9dd3396bcaaf85dcdb4e3ae3c96f28a4d71d72665c4abf7c221370be626
User & Date: dan 2018-12-06 18:58:58
Context
2018-12-10
09:45
Avoid a mutex in-and-out in unixShmBarrier() on this branch. Use __sync_synchronize() instead. check-in: a8c5fd86 user: dan tags: mutexfree-shmlock
2018-12-06
20:26
Add the mutexfree-shmlock experiment to the begin-concurrent-pnu branch. check-in: 3aead209 user: dan tags: begin-concurrent-pnu-mutexfree-shmlock
18:58
Experiment with using an atomic CPU primitive instead of a mutex for intra-process locking with the unix-excl VFS. check-in: 8f4cb9dd user: dan tags: mutexfree-shmlock
03:59
Invoking the sqlite3_trace() or sqlite3_trace_v2() interfaces cancels any sqlite3_profile() that is running. check-in: ec63d350 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

    42     42   **   *  Locking primitives for the proxy uber-locking-method. (MacOSX only)
    43     43   **   *  Definitions of sqlite3_vfs objects for all locking methods
    44     44   **      plus implementations of sqlite3_os_init() and sqlite3_os_end().
    45     45   */
    46     46   #include "sqliteInt.h"
    47     47   #if SQLITE_OS_UNIX              /* This file is used on unix only */
    48     48   
           49  +/* Turn this feature on in all builds for now */
           50  +#define SQLITE_MUTEXFREE_SHMLOCK 1
           51  +
    49     52   /*
    50     53   ** There are various methods for file locking used for concurrency
    51     54   ** control:
    52     55   **
    53     56   **   1. POSIX locking (the default),
    54     57   **   2. No locking,
    55     58   **   3. Dot-file locking,
................................................................................
  4235   4238     int nRef;                  /* Number of unixShm objects pointing to this */
  4236   4239     unixShm *pFirst;           /* All unixShm objects pointing to this */
  4237   4240   #ifdef SQLITE_DEBUG
  4238   4241     u8 exclMask;               /* Mask of exclusive locks held */
  4239   4242     u8 sharedMask;             /* Mask of shared locks held */
  4240   4243     u8 nextShmId;              /* Next available unixShm.id value */
  4241   4244   #endif
         4245  +
         4246  +#ifdef SQLITE_MUTEXFREE_SHMLOCK
         4247  +  /* In unix-excl mode, if SQLITE_MUTEXFREE_SHMLOCK is defined, all locks
         4248  +  ** are stored in the following 64-bit value. There are in total 8 
         4249  +  ** shm-locking slots, each of which are assigned 8-bits from the 64-bit
         4250  +  ** value. The least-significant 8 bits correspond to shm-locking slot
         4251  +  ** 0, and so on.
         4252  +  **
         4253  +  ** If the 8-bits corresponding to a shm-locking locking slot are set to
         4254  +  ** 0xFF, then a write-lock is held on the slot. Or, if they are set to
         4255  +  ** a non-zero value smaller than 0xFF, then they represent the total 
         4256  +  ** number of read-locks held on the slot. There is no way to distinguish
         4257  +  ** between a write-lock and 255 read-locks.  */
         4258  +  u64 lockmask;
         4259  +#endif
  4242   4260   };
         4261  +
         4262  +/*
         4263  +** Atomic CAS primitive used in multi-process mode. Equivalent to:
         4264  +** 
         4265  +**   int unixCompareAndSwap(u32 *ptr, u32 oldval, u32 newval){
         4266  +**     if( *ptr==oldval ){
         4267  +**       *ptr = newval;
         4268  +**       return 1;
         4269  +**     }
         4270  +**     return 0;
         4271  +**   }
         4272  +*/
         4273  +#define unixCompareAndSwap(ptr,oldval,newval) \
         4274  +    __sync_bool_compare_and_swap(ptr,oldval,newval)
         4275  +
  4243   4276   
  4244   4277   /*
  4245   4278   ** Structure used internally by this VFS to record the state of an
  4246   4279   ** open shared memory connection.
  4247   4280   **
  4248   4281   ** The following fields are initialized when this object is created and
  4249   4282   ** are read-only thereafter:
................................................................................
  4796   4829          || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
  4797   4830     assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
  4798   4831     assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
  4799   4832     assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
  4800   4833   
  4801   4834     mask = (1<<(ofst+n)) - (1<<ofst);
  4802   4835     assert( n>1 || mask==(1<<ofst) );
         4836  +
         4837  +#ifdef SQLITE_MUTEXFREE_SHMLOCK
         4838  +  if( pDbFd->pInode->bProcessLock ){
         4839  +
         4840  +    while( 1 ){
         4841  +      u64 lockmask = pShmNode->lockmask;
         4842  +      u64 newmask = lockmask;
         4843  +      int i;
         4844  +      for(i=ofst; i<n+ofst; i++){
         4845  +        int ix8 = i*8;
         4846  +        u8 v = (lockmask >> (ix8)) & 0xFF;
         4847  +        if( flags & SQLITE_SHM_UNLOCK ){
         4848  +          if( flags & SQLITE_SHM_EXCLUSIVE ){
         4849  +            if( p->exclMask & (1 << i) ){
         4850  +              newmask = newmask & ~((u64)0xFF<<ix8);
         4851  +            }
         4852  +          }else{
         4853  +            if( p->sharedMask & (1 << i) ){
         4854  +              newmask = newmask & ~((u64)0xFF<<ix8) | ((u64)(v-1)<<ix8);
         4855  +            }
         4856  +          }
         4857  +        }else{
         4858  +          if( flags & SQLITE_SHM_EXCLUSIVE ){
         4859  +            if( v ) return SQLITE_BUSY;
         4860  +            if( (p->exclMask & (1 << i))==0 ){
         4861  +              newmask = newmask | ((u64)0xFF<<ix8);
         4862  +            }
         4863  +          }else{
         4864  +            if( v==0xFF ) return SQLITE_BUSY;
         4865  +            if( (p->sharedMask & (1 << i))==0 ){
         4866  +              newmask = newmask & ~((u64)0xFF<<ix8) | ((u64)(v+1)<<ix8);
         4867  +            }
         4868  +          }
         4869  +        }
         4870  +      }
         4871  +
         4872  +      if( unixCompareAndSwap(&pShmNode->lockmask, lockmask, newmask) ) break;
         4873  +    }
         4874  +
         4875  +    if( flags & SQLITE_SHM_UNLOCK ){
         4876  +      p->sharedMask &= ~mask;
         4877  +      p->exclMask &= ~mask;
         4878  +    }else if( flags & SQLITE_SHM_EXCLUSIVE ){
         4879  +      p->exclMask |= mask;
         4880  +    }else{
         4881  +      p->sharedMask |= mask;
         4882  +    }
         4883  +
         4884  +    return SQLITE_OK;
         4885  +  }
         4886  +#endif
         4887  +
  4803   4888     sqlite3_mutex_enter(pShmNode->pShmMutex);
  4804   4889     if( flags & SQLITE_SHM_UNLOCK ){
  4805   4890       u16 allMask = 0; /* Mask of locks held by siblings */
  4806   4891   
  4807   4892       /* See if any siblings hold this same lock */
  4808   4893       for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
  4809   4894         if( pX==p ) continue;

Changes to src/test_vfs.c.

  1558   1558   
  1559   1559     return TCL_OK;
  1560   1560   
  1561   1561    bad_args:
  1562   1562     Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-fullshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?");
  1563   1563     return TCL_ERROR;
  1564   1564   }
         1565  +
         1566  +extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
         1567  +extern const char *sqlite3ErrName(int);
         1568  +
         1569  +/*
         1570  +** tclcmd: vfs_shmlock DB DBNAME (shared|exclusive) (lock|unlock) OFFSET N
         1571  +*/
         1572  +static int SQLITE_TCLAPI test_vfs_shmlock(
         1573  +  void * clientData,
         1574  +  Tcl_Interp *interp,
         1575  +  int objc,
         1576  +  Tcl_Obj *CONST objv[]
         1577  +){
         1578  +  const char *azArg1[] = {"shared", "exclusive", 0};
         1579  +  const char *azArg2[] = {"lock", "unlock", 0};
         1580  +  sqlite3 *db = 0;
         1581  +  int rc = SQLITE_OK;
         1582  +  const char *zDbname = 0;
         1583  +  int iArg1 = 0;
         1584  +  int iArg2 = 0;
         1585  +  int iOffset = 0;
         1586  +  int n = 0;
         1587  +  sqlite3_file *pFd;
         1588  +
         1589  +  if( objc!=7 ){
         1590  +    Tcl_WrongNumArgs(interp, 1, objv, 
         1591  +        "DB DBNAME (shared|exclusive) (lock|unlock) OFFSET N"
         1592  +    );
         1593  +    return TCL_ERROR;
         1594  +  }
         1595  +
         1596  +  zDbname = Tcl_GetString(objv[2]);
         1597  +  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) 
         1598  +   || Tcl_GetIndexFromObj(interp, objv[3], azArg1, "ARG", 0, &iArg1) 
         1599  +   || Tcl_GetIndexFromObj(interp, objv[4], azArg2, "ARG", 0, &iArg2) 
         1600  +   || Tcl_GetIntFromObj(interp, objv[5], &iOffset)
         1601  +   || Tcl_GetIntFromObj(interp, objv[6], &n)
         1602  +  ){
         1603  +    return TCL_ERROR;
         1604  +  }
         1605  +
         1606  +  sqlite3_file_control(db, zDbname, SQLITE_FCNTL_FILE_POINTER, (void*)&pFd);
         1607  +  if( pFd==0 ){
         1608  +    return TCL_ERROR;
         1609  +  }
         1610  +  rc = pFd->pMethods->xShmLock(pFd, iOffset, n, 
         1611  +      (iArg1==0 ? SQLITE_SHM_SHARED : SQLITE_SHM_EXCLUSIVE)
         1612  +    | (iArg2==0 ? SQLITE_SHM_LOCK : SQLITE_SHM_UNLOCK)
         1613  +  );
         1614  +  Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
         1615  +  return TCL_OK;
         1616  +}
         1617  +
  1565   1618   
  1566   1619   int Sqlitetestvfs_Init(Tcl_Interp *interp){
  1567   1620     Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0);
         1621  +  Tcl_CreateObjCommand(interp, "vfs_shmlock", test_vfs_shmlock, 0, 0);
  1568   1622     return TCL_OK;
  1569   1623   }
  1570   1624   
  1571   1625   #endif

Changes to test/lock_common.tcl.

    11     11   # This file contains code used by several different test scripts. The
    12     12   # code in this file allows testfixture to control another process (or
    13     13   # processes) to test locking.
    14     14   #
    15     15   
    16     16   proc do_multiclient_test {varname script} {
    17     17   
    18         -  foreach code [list {
           18  +  foreach {tn code} [list 1 {
    19     19       if {[info exists ::G(valgrind)]} { db close ; continue }
    20     20       set ::code2_chan [launch_testfixture]
    21     21       set ::code3_chan [launch_testfixture]
    22     22       proc code2 {tcl} { testfixture $::code2_chan $tcl }
    23     23       proc code3 {tcl} { testfixture $::code3_chan $tcl }
    24         -    set tn 1
    25         -  } {
           24  +  } 2 {
    26     25       proc code2 {tcl} { uplevel #0 $tcl }
    27     26       proc code3 {tcl} { uplevel #0 $tcl }
    28         -    set tn 2
    29     27     }] {
           28  +    # Do not run multi-process tests with the unix-excl VFS.
           29  +    #
           30  +    if {$tn==1 && [permutation]=="unix-excl"} continue
           31  +
    30     32       faultsim_delete_and_reopen
    31     33   
    32     34       proc code1 {tcl} { uplevel #0 $tcl }
    33     35     
    34     36       # Open connections [db2] and [db3]. Depending on which iteration this
    35     37       # is, the connections may be created in this interpreter, or in 
    36     38       # interpreters running in other OS processes. As such, the [db2] and [db3]

Changes to test/permutations.test.

   602    602     Run some tests using the "test_onefile.c" demo
   603    603   } -initialize {
   604    604     set ::G(perm:sqlite3_args) [list -vfs fs]
   605    605   } -files {
   606    606     conflict.test  insert.test   insert2.test  insert3.test
   607    607     rollback.test  select1.test  select2.test  select3.test
   608    608   }
          609  +
          610  +# Run some tests using the "unix-excl" VFS.
          611  +#
          612  +test_suite "unix-excl" -description {
          613  +  Run some tests using the "unix-excl" VFS
          614  +} -initialize {
          615  +  set ::G(perm:sqlite3_args) [list -vfs unix-excl]
          616  +} -files {
          617  +  shmlock.test
          618  +}
   609    619   
   610    620   # Run some tests using UTF-16 databases.
   611    621   #
   612    622   test_suite "utf16" -description {
   613    623     Run tests using UTF-16 databases
   614    624   } -presql {
   615    625     pragma encoding = 'UTF-16'

Added test/shmlock.test.

            1  +# 2018 December 6
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +
           13  +set testdir [file dirname $argv0]
           14  +source $testdir/tester.tcl
           15  +
           16  +set testprefix shmlock
           17  +
           18  +ifcapable !wal {finish_test ; return }
           19  +
           20  +sqlite3 db2 test.db
           21  +sqlite3 db3 test.db
           22  +
           23  +do_execsql_test 1.0 {
           24  +  PRAGMA journal_mode = wal;
           25  +  CREATE TABLE t1(a, b);
           26  +  INSERT INTO t1 VALUES(1, 2);
           27  +} {wal}
           28  +do_test 1.1 { execsql { SELECT * FROM t1 } db2 } {1 2}
           29  +do_test 1.2 { execsql { SELECT * FROM t1 } db3 } {1 2}
           30  +
           31  +foreach {tn dbhandle cmd res} {
           32  +  1    db  {shared    lock   7 1}    OK
           33  +  2    db2 {exclusive lock   7 1}    BUSY
           34  +  3    db  {shared    unlock 7 1}    OK
           35  +  4    db2 {exclusive lock   7 1}    OK
           36  +  5    db  {shared    lock   7 1}    BUSY
           37  +  6    db  {exclusive lock   7 1}    BUSY
           38  +  7    db2 {exclusive unlock 7 1}    OK
           39  +
           40  +  8    db  {exclusive lock   0 8}    OK
           41  +  9    db  {exclusive unlock 0 8}    OK
           42  +  10   db2 {exclusive lock   0 8}    OK
           43  +  11   db2 {exclusive unlock 0 8}    OK
           44  +
           45  +  12   db  {shared    lock   0 1}    OK
           46  +  13   db2 {shared    lock   0 1}    OK
           47  +  14   db3 {shared    lock   0 1}    OK
           48  +  15   db3 {shared    unlock 0 1}    OK
           49  +  16   db3 {exclusive lock   0 1}    BUSY
           50  +  17   db2 {shared    unlock 0 1}    OK
           51  +  18   db3 {exclusive lock   0 1}    BUSY
           52  +  19   db  {shared    unlock 0 1}    OK
           53  +  20   db3 {exclusive lock   0 1}    OK
           54  +  21   db3 {exclusive unlock 0 1}    OK
           55  +
           56  +  22   db  {shared    lock   3 1}    OK
           57  +  23   db2 {exclusive lock   2 2}    BUSY
           58  +  24   db  {shared    lock   2 1}    OK
           59  +  25   db2 {exclusive lock   0 5}    BUSY
           60  +  26   db2 {exclusive lock   0 4}    BUSY
           61  +  27   db2 {exclusive lock   0 3}    BUSY
           62  +  28   db  {shared    unlock 3 1}    OK
           63  +  29   db2 {exclusive lock   2 2}    BUSY
           64  +  28   db  {shared    unlock 2 1}    OK
           65  +  29   db2 {exclusive lock   2 2}    OK
           66  +  29   db2 {exclusive unlock 2 2}    OK
           67  +} {
           68  +  do_test 1.3.$tn [list vfs_shmlock $dbhandle main {*}$cmd] "SQLITE_$res"
           69  +}
           70  +
           71  +db  close
           72  +db2 close
           73  +db3 close
           74  +
           75  +if {[permutation]=="unix-excl"} {
           76  +  do_test 2.0 {
           77  +    for {set i 0} {$i < 256} {incr i} { 
           78  +      sqlite3 db$i test.db 
           79  +      execsql { SELECT * FROM t1 } db$i
           80  +    }
           81  +    for {set i 0} {$i < 255} {incr i} { 
           82  +      set rc [vfs_shmlock db$i main shared lock 4 1]
           83  +      if {$rc != "SQLITE_OK"} { error $rc }
           84  +    }
           85  +
           86  +    vfs_shmlock db255 main shared lock 4 1
           87  +  } {SQLITE_BUSY}
           88  +
           89  +  do_test 2.1 { vfs_shmlock db255 main exclusive lock   4 1 } SQLITE_BUSY
           90  +  do_test 2.2 { vfs_shmlock db0   main shared    unlock 4 1 } SQLITE_OK
           91  +  do_test 2.3 { vfs_shmlock db255 main shared    lock   4 1 } SQLITE_OK
           92  +  do_test 2.4 { vfs_shmlock db255 main shared    unlock 4 1 } SQLITE_OK
           93  +  do_test 2.5 { vfs_shmlock db255 main exclusive lock   4 1 } SQLITE_BUSY
           94  +
           95  +  do_test 2.6 {
           96  +    for {set i 1} {$i < 255} {incr i} { 
           97  +      set rc [vfs_shmlock db255 main exclusive lock 4 1]
           98  +      if {$rc != "SQLITE_BUSY"} { error $rc }
           99  +      set rc [vfs_shmlock db$i main shared unlock 4 1]
          100  +      if {$rc != "SQLITE_OK"} { error $rc }
          101  +    }
          102  +
          103  +    vfs_shmlock db255 main exclusive lock 4 1
          104  +  } {SQLITE_OK}
          105  +
          106  +  vfs_shmlock db255 main exclusive unlock 4 1
          107  +}
          108  +
          109  +finish_test
          110  +
          111  +

Changes to test/wal.test.

  1293   1293   #
  1294   1294   #   3. Using connection 1, checkpoint the database. Make sure all
  1295   1295   #      the data is present and the database is not corrupt.
  1296   1296   #
  1297   1297   # At one point, SQLite was failing to grow the mapping of the wal-index
  1298   1298   # file in step 3 and the checkpoint was corrupting the database file.
  1299   1299   #
  1300         -do_test wal-20.1 {
  1301         -  catch {db close}
  1302         -  forcedelete test.db test.db-wal test.db-journal
  1303         -  sqlite3 db test.db
  1304         -  execsql {
  1305         -    PRAGMA journal_mode = WAL;
  1306         -    CREATE TABLE t1(x);
  1307         -    INSERT INTO t1 VALUES(randomblob(900));
  1308         -    SELECT count(*) FROM t1;
  1309         -  }
  1310         -} {wal 1}
  1311         -do_test wal-20.2 {
  1312         -  set ::buddy [launch_testfixture]
  1313         -  testfixture $::buddy {
         1300  +if {[permutation]!="unix-excl"} {
         1301  +  do_test wal-20.1 {
         1302  +    catch {db close}
         1303  +    forcedelete test.db test.db-wal test.db-journal
         1304  +    sqlite3 db test.db
         1305  +    execsql {
         1306  +      PRAGMA journal_mode = WAL;
         1307  +      CREATE TABLE t1(x);
         1308  +      INSERT INTO t1 VALUES(randomblob(900));
         1309  +      SELECT count(*) FROM t1;
         1310  +    }
         1311  +  } {wal 1}
         1312  +  do_test wal-20.2 {
         1313  +    set ::buddy [launch_testfixture]
         1314  +    testfixture $::buddy {
         1315  +      sqlite3 db test.db
         1316  +      db transaction { db eval {
         1317  +        PRAGMA wal_autocheckpoint = 0;
         1318  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 2 */
         1319  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 4 */
         1320  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 8 */
         1321  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 16 */
         1322  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 32 */
         1323  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 64 */
         1324  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 128 */
         1325  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 256 */
         1326  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 512 */
         1327  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 1024 */
         1328  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 2048 */
         1329  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 4096 */
         1330  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 8192 */
         1331  +        INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 16384 */
         1332  +      } }
         1333  +    }
         1334  +  } {0}
         1335  +  do_test wal-20.3 {
         1336  +    close $::buddy
         1337  +    execsql { PRAGMA wal_checkpoint }
         1338  +    execsql { SELECT count(*) FROM t1 }
         1339  +  } {16384}
         1340  +  do_test wal-20.4 {
         1341  +    db close
  1314   1342       sqlite3 db test.db
  1315         -    db transaction { db eval {
  1316         -      PRAGMA wal_autocheckpoint = 0;
  1317         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 2 */
  1318         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 4 */
  1319         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 8 */
  1320         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 16 */
  1321         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 32 */
  1322         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 64 */
  1323         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 128 */
  1324         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 256 */
  1325         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 512 */
  1326         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 1024 */
  1327         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 2048 */
  1328         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 4096 */
  1329         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 8192 */
  1330         -      INSERT INTO t1 SELECT randomblob(900) FROM t1;       /* 16384 */
  1331         -    } }
  1332         -  }
  1333         -} {0}
  1334         -do_test wal-20.3 {
  1335         -  close $::buddy
  1336         -  execsql { PRAGMA wal_checkpoint }
  1337         -  execsql { SELECT count(*) FROM t1 }
  1338         -} {16384}
  1339         -do_test wal-20.4 {
  1340         -  db close
  1341         -  sqlite3 db test.db
  1342         -  execsql { SELECT count(*) FROM t1 }
  1343         -} {16384}
  1344         -integrity_check wal-20.5
         1343  +    execsql { SELECT count(*) FROM t1 }
         1344  +  } {16384}
         1345  +  integrity_check wal-20.5
         1346  +}
  1345   1347   
  1346   1348   catch { db2 close }
  1347   1349   catch { db close }
  1348   1350   
  1349   1351   do_test wal-21.1 {
  1350   1352     faultsim_delete_and_reopen
  1351   1353     execsql {