]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add extra coverage test cases for wal.c. No changes to production code.
authordan <dan@noemail.net>
Sat, 5 Jun 2010 11:53:34 +0000 (11:53 +0000)
committerdan <dan@noemail.net>
Sat, 5 Jun 2010 11:53:34 +0000 (11:53 +0000)
FossilOrigin-Name: f9d4ae0e8cc5d32c52eb78799f7959dd236ea9de

manifest
manifest.uuid
src/test_vfs.c
test/wal3.test
test/walfault.test

index 89cefd2d55595fd66af090720d7d1249c571563b..172043c4ec31c0d62ea1c13871eb9bd8e844d468 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Clarify\san\sassert\sin\ssqlite3WalExclusiveMode().
-D 2010-06-04T18:38:00
+C Add\sextra\scoverage\stest\scases\sfor\swal.c.\sNo\schanges\sto\sproduction\scode.
+D 2010-06-05T11:53:34
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -207,7 +207,7 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
 F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
 F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
 F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726
-F src/test_vfs.c d3338794b50d1c777d583fbfa71b41a273684ced
+F src/test_vfs.c d329e3ea93624f65d7b6a46209861ddecea4e21d
 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
 F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
 F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d
@@ -763,13 +763,13 @@ F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
 F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
 F test/wal.test bfec61450b47cdf09f7d2269f9e9967683b8b0fc
 F test/wal2.test 743d9b86041e57ba986dd7e3891c67725f9e2b2b
-F test/wal3.test 08626ca06bc87f34179258515c2d674b56b7e150
+F test/wal3.test 91243bd815e35cfda977df071f95ee2be3cfe236
 F test/wal_common.tcl 3e953ae60919281688ea73e4d0aa0e1bc94becd9
 F test/walbak.test e7650a26eb4b8abeca9b145b1af1e63026dde432
 F test/walcksum.test 4efa8fb88c32bed8288ea4385a9cc113a5c8f0bf
 F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
 F test/walcrash2.test 14585ad1a2c85da2de721caa3b4deeea55213008
-F test/walfault.test 4c412eae947aea5f58d5c616a4d8740f034e49d1
+F test/walfault.test 0f9524cedbba0e5d48b58cabdc2dd7ae2c375476
 F test/walhook.test 67e675127f4acb72f061a12667ce6e5460b06b78
 F test/walmode.test 6ca9d710cc9f6545b913abcded6d6b0b15641048
 F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
@@ -817,7 +817,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 8e54786c9a0c5c399f228f56c73271f84d75694b
-R 723b0db73791affd894a1e0706a506aa
+P 255850699ddbf4aad8cc3223aefbada35daa0703
+R 7ac85a4afc11bde0cbb8862c4d4688fc
 U dan
-Z 1b6d1f85256b6057d423f1cf677d1ba1
+Z 575989e6baec836caf7d32e1a4d39d95
index cdec3e7710f19c7f753fb41d58203ef9e6802ae9..8218c59feda2847f6886c3b4b23386e799695f75 100644 (file)
@@ -1 +1 @@
-255850699ddbf4aad8cc3223aefbada35daa0703
\ No newline at end of file
+f9d4ae0e8cc5d32c52eb78799f7959dd236ea9de
\ No newline at end of file
index b538d049a872b6f5c1d6e0b63f00cc843f01f6ae..1083080eb9e6453a1e20270722e38836d400d160 100644 (file)
@@ -30,7 +30,11 @@ struct TestvfsFile {
   const char *zFilename;          /* Filename as passed to xOpen() */
   sqlite3_file *pReal;            /* The real, underlying file descriptor */
   Tcl_Obj *pShmId;                /* Shared memory id for Tcl callbacks */
+
   TestvfsBuffer *pShm;            /* Shared memory buffer */
+  u32 excllock;                   /* Mask of exclusive locks */
+  u32 sharedlock;                 /* Mask of shared locks */
+  TestvfsFile *pNext;             /* Next handle opened on the same file */
 };
 
 
@@ -77,13 +81,15 @@ struct Testvfs {
 #define TESTVFS_ALL_MASK        0x000001FF
 
 /*
-** A shared-memory buffer.
+** A shared-memory buffer. There is one of these objects for each shared
+** memory region opened by clients. If two clients open the same file,
+** there are two TestvfsFile structures but only one TestvfsBuffer structure.
 */
 struct TestvfsBuffer {
   char *zFile;                    /* Associated file name */
   int n;                          /* Size of allocated buffer in bytes */
   u8 *a;                          /* Buffer allocated using ckalloc() */
-  int nRef;                       /* Number of references to this object */
+  TestvfsFile *pFile;             /* List of open handles */
   TestvfsBuffer *pNext;           /* Next in linked list of all buffers */
 };
 
@@ -573,7 +579,7 @@ static int tvfsShmOpen(
 
   pFd = (TestvfsFile*)pFileDes;
   p = (Testvfs *)pFd->pVfs->pAppData;
-  assert( pFd->pShmId && pFd->pShm==0 );
+  assert( pFd->pShmId && pFd->pShm==0 && pFd->pNext==0 );
 
   /* Evaluate the Tcl script: 
   **
@@ -607,7 +613,8 @@ static int tvfsShmOpen(
   }
 
   /* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */
-  pBuffer->nRef++;
+  pFd->pNext = pBuffer->pFile;
+  pBuffer->pFile = pFd;
   pFd->pShm = pBuffer;
   return SQLITE_OK;
 }
@@ -713,6 +720,30 @@ static int tvfsShmLock(
   if( rc==SQLITE_OK && p->mask&TESTVFS_SHMLOCK_MASK && tvfsInjectIoerr(p) ){
     rc = SQLITE_IOERR;
   }
+
+  if( rc==SQLITE_OK ){
+    int isLock = (flags & SQLITE_SHM_LOCK);
+    int isExcl = (flags & SQLITE_SHM_EXCLUSIVE);
+    u32 mask = (((1<<n)-1) << ofst);
+    if( isLock ){
+      TestvfsFile *p2;
+      for(p2=pFd->pShm->pFile; p2; p2=p2->pNext){
+        if( p2==pFd ) continue;
+        if( (p2->excllock&mask) || (isExcl && p2->sharedlock&mask) ){
+          rc = SQLITE_BUSY;
+          break;
+        }
+      }
+      if( rc==SQLITE_OK ){
+        if( isExcl )  pFd->excllock |= mask;
+        if( !isExcl ) pFd->sharedlock |= mask;
+      }
+    }else{
+      if( isExcl )  pFd->excllock &= (~mask);
+      if( !isExcl ) pFd->sharedlock &= (~mask);
+    }
+  }
+
   return rc;
 }
 
@@ -735,11 +766,9 @@ static int tvfsShmClose(
   TestvfsFile *pFd = (TestvfsFile *)pFile;
   Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
   TestvfsBuffer *pBuffer = pFd->pShm;
+  TestvfsFile **ppFd;
 
   assert( pFd->pShmId && pFd->pShm );
-#if 0
-  assert( (deleteFlag!=0)==(pBuffer->nRef==1) );
-#endif
 
   if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){
     tvfsExecTcl(p, "xShmClose", 
@@ -748,8 +777,11 @@ static int tvfsShmClose(
     tvfsResultCode(p, &rc);
   }
 
-  pBuffer->nRef--;
-  if( pBuffer->nRef==0 ){
+  for(ppFd=&pBuffer->pFile; *ppFd!=pFd; ppFd=&((*ppFd)->pNext));
+  assert( (*ppFd)==pFd );
+  *ppFd = pFd->pNext;
+
+  if( pBuffer->pFile==0 ){
     TestvfsBuffer **pp;
     for(pp=&p->pBuffer; *pp!=pBuffer; pp=&((*pp)->pNext));
     *pp = (*pp)->pNext;
index 5b9fcd5cbfd43ab4c656cf5dcde0bfac25f61cf9..56eae516ccbdcf8cd6aa6fc67116e272bfe89947 100644 (file)
@@ -316,10 +316,110 @@ do_test wal3-4.4 {
   sqlite3 db test.db -vfs T
   catchsql { SELECT * FROM x }
 } {1 {locking protocol}}
+db close
+T delete
+
+
+#-------------------------------------------------------------------------
+# Only one client may run recovery at a time. Test this mechanism.
+#
+# When client-2 tries to open a read transaction while client-1 is 
+# running recovery, it fails to obtain a lock on an aReadMark[] slot
+# (because they are all locked by recovery). It then tries to obtain
+# a shared lock on the RECOVER lock to see if there really is a
+# recovery running or not.
+#
+# This block of tests checks the effect of an SQLITE_BUSY or SQLITE_IOERR
+# being returned when client-2 attempts a shared lock on the RECOVER byte.
+#
+# An SQLITE_BUSY should be converted to an SQLITE_BUSY_RECOVERY. An
+# SQLITE_IOERR should be returned to the caller.
+#
+do_test wal3-5.1 {
+  faultsim_delete_and_reopen
+  execsql {
+    PRAGMA journal_mode = WAL;
+    CREATE TABLE t1(a, b);
+    INSERT INTO t1 VALUES(1, 2);
+    INSERT INTO t1 VALUES(3, 4);
+  }
+  faultsim_save_and_close
+} {}
+
+testvfs T -default 1
+T script method_callback
+
+proc method_callback {method args} {
+  if {$method == "xShmBarrier"} {
+    incr ::barrier_count
+    if {$::barrier_count == 1} {
+      # This code is executed within the xShmBarrier() callback invoked
+      # by the client running recovery as part of writing the recovered
+      # wal-index header. If a second client attempts to access the 
+      # database now, it reads a corrupt (partially written) wal-index
+      # header. But it cannot even get that far, as the first client
+      # is still holding all the locks (recovery takes an exclusive lock
+      # on *all* db locks, preventing access by any other client).
+      #
+      # If global variable ::wal3_do_lockfailure is non-zero, then set
+      # things up so that an IO error occurs within an xShmLock() callback
+      # made by the second client (aka [db2]).
+      #
+      sqlite3 db2 test.db
+      if { $::wal3_do_lockfailure } { T filter xShmLock }
+      set ::testrc [ catch { db2 eval "SELECT * FROM t1" } ::testmsg ]
+      T filter {}
+      db2 close
+    }
+  }
+
+  if {$method == "xShmLock"} {
+    foreach {file handle spec} $args break
+    if { $spec == "2 1 lock shared" } {
+      return SQLITE_IOERR
+    }
+  }
+
+  return SQLITE_OK
+}
+
+# Test a normal SQLITE_BUSY return.
+#
+T filter xShmBarrier
+set testrc ""
+set testmsg ""
+set barrier_count 0
+set wal3_do_lockfailure 0
+do_test wal3-5.2 {
+  faultsim_restore_and_reopen
+  execsql { SELECT * FROM t1 }
+} {1 2 3 4}
+do_test wal3-5.3 {
+  list $::testrc $::testmsg
+} {1 {database is locked}}
+db close
+
+# Test an SQLITE_IOERR return.
+#
+T filter xShmBarrier
+set barrier_count 0
+set wal3_do_lockfailure 1
+set testrc ""
+set testmsg ""
+do_test wal3-5.4 {
+  faultsim_restore_and_reopen
+  execsql { SELECT * FROM t1 }
+} {1 2 3 4}
+do_test wal3-5.5 {
+  list $::testrc $::testmsg
+} {1 {disk I/O error}}
 
 db close
 T delete
 
-finish_test
+#-------------------------------------------------------------------------
+# When opening a read-transaction on a database 
+#
 
+finish_test
 
index a0552021e18db85c7a6cfcfb715e3c77930f79b3..ad7bf97cb2f3389b3d409283b5a5accd242b2572 100644 (file)
@@ -322,5 +322,46 @@ do_faultsim_test walfault-9 -prep {
   if {$n != 1 && $n != 2} { error "Incorrect number of rows: $n" }
 }
 
+do_test walfault-10-pre1 {
+  faultsim_delete_and_reopen
+  execsql {
+    PRAGMA journal_mode = WAL;
+    PRAGMA wal_checkpoint = 0;
+    CREATE TABLE z(zz INTEGER PRIMARY KEY, zzz BLOB);
+    CREATE INDEX zzzz ON z(zzz);
+    INSERT INTO z VALUES(NULL, randomblob(800));
+    INSERT INTO z VALUES(NULL, randomblob(800));
+    INSERT INTO z SELECT NULL, randomblob(800) FROM z;
+    INSERT INTO z SELECT NULL, randomblob(800) FROM z;
+    INSERT INTO z SELECT NULL, randomblob(800) FROM z;
+    INSERT INTO z SELECT NULL, randomblob(800) FROM z;
+    INSERT INTO z SELECT NULL, randomblob(800) FROM z;
+  }
+  faultsim_save_and_close
+} {}
+do_faultsim_test walfault-10 -prep {
+  faultsim_restore_and_reopen
+  execsql {
+    PRAGMA cache_size = 10;
+    BEGIN;
+      UPDATE z SET zzz = randomblob(799);
+  }
+
+  set ::stmt [sqlite3_prepare db "SELECT zzz FROM z WHERE zz IN (1, 2, 3)" -1]
+  sqlite3_step $::stmt
+} -body {
+  execsql { INSERT INTO z VALUES(NULL, NULL) }
+} -test {
+  sqlite3_finalize $::stmt
+  faultsim_integrity_check
+
+  faultsim_test_result {0 {}}
+  catch { db eval { ROLLBACK } }
+  faultsim_integrity_check
+
+  set n [db eval {SELECT count(*), sum(length(zzz)) FROM z}]
+  if {$n != "64 51200"} { error "Incorrect data: $n" }
+}
+
 finish_test