]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Enhancements to test_vfs.c and walfault.test.
authordan <dan@noemail.net>
Thu, 3 Jun 2010 09:25:10 +0000 (09:25 +0000)
committerdan <dan@noemail.net>
Thu, 3 Jun 2010 09:25:10 +0000 (09:25 +0000)
FossilOrigin-Name: ac0de2f39e948f3b00e96eebf56ebee70472020d

manifest
manifest.uuid
src/test_vfs.c
test/malloc_common.tcl
test/wal2.test
test/walfault.test

index 028568ac8cc16d8be74a6f2955ff3847c795da69..5acb674857f2229b31572f77c3e033513e29bb7d 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C If\san\serror\s(OOM\sor\sSQLITE_FULL\serror)\soccurs\swhile\sexecuting\san\sSQL\sstatement\sand\sa\sstatement-transaction\sis\sautomatically\srolled\sback\sas\sa\sresult,\sif\sa\ssecond\serror\soccurs\sduring\sthe\sstatement\srollback\sdo\sa\sfull\stransaction\srollback\sinstead.\sOtherwise\sthe\sclient\scan\sbe\sleft\swith\san\sinconsistent\scache.
-D 2010-06-03T09:17:38
+C Enhancements\sto\stest_vfs.c\sand\swalfault.test.
+D 2010-06-03T09:25:10
 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 fe1eda8d3910823d9edc26113f91bb292369850a
+F src/test_vfs.c bae03f62556a11cf5c7c3ea1211a604a3834263a
 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
 F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
 F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d
@@ -506,7 +506,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
 F test/mallocI.test e3ea401904d010cb7c1e4b2ee8803f4a9f5b999d
 F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
 F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
-F test/malloc_common.tcl 7d2478b7f084afd8cb14b1121097ea3d989216b3
+F test/malloc_common.tcl 9b58ffd50d073dccf0493e3ca4aa39bc64ce3047
 F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
 F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
 F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
@@ -762,12 +762,12 @@ F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
 F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
 F test/wal.test bfec61450b47cdf09f7d2269f9e9967683b8b0fc
-F test/wal2.test a2146846c4dd940252f18ec1e00431346286bcb3
+F test/wal2.test 1dcbbe59ab662bebb859bb1ede83143f8a39814e
 F test/walbak.test e7650a26eb4b8abeca9b145b1af1e63026dde432
 F test/walcksum.test 4efa8fb88c32bed8288ea4385a9cc113a5c8f0bf
 F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
 F test/walcrash2.test 14585ad1a2c85da2de721caa3b4deeea55213008
-F test/walfault.test 9015004b56bc2cb8cf5c96183853f1157e61ff70
+F test/walfault.test 058c9e2829fc5e3e01ae4984980a6da9af15368a
 F test/walhook.test 67e675127f4acb72f061a12667ce6e5460b06b78
 F test/walmode.test 6ca9d710cc9f6545b913abcded6d6b0b15641048
 F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
@@ -815,7 +815,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 91cb08ffb6332a142542c012b58aa49206ee5704
-R efb6b25ebd6ed72f29b742d935423851
+P eb80ddc665132c607c258b59131025a296269dad
+R b8571e46e77ae4334ee4b99c40b16506
 U dan
-Z 0bec386ab07ce5c674d40d75eae0944a
+Z a97b394e32c2defcb9f264e6738c31ca
index 213df0ba775bdc26503ff5617c7845ad6e9b3f45..a192ea4b1e9e563b8531b60096e299ce250658e7 100644 (file)
@@ -1 +1 @@
-eb80ddc665132c607c258b59131025a296269dad
\ No newline at end of file
+ac0de2f39e948f3b00e96eebf56ebee70472020d
\ No newline at end of file
index fda44a725ccc6d5ed6067c1d96db85f69c1eebee..8e7f0ce02880658731cc21c54fe022ca2563d158 100644 (file)
@@ -44,27 +44,26 @@ struct Testvfs {
   sqlite3_vfs *pParent;           /* The VFS to use for file IO */
   sqlite3_vfs *pVfs;              /* The testvfs registered with SQLite */
   Tcl_Interp *interp;             /* Interpreter to run script in */
+  Tcl_Obj *pScript;               /* Script to execute */
   int nScript;                    /* Number of elements in array apScript */
-  Tcl_Obj **apScript;             /* Script to execute */
+  Tcl_Obj **apScript;             /* Array version of pScript */
   TestvfsBuffer *pBuffer;         /* List of shared buffers */
   int isNoshm;
 
   int mask;
   int iIoerrCnt;
   int ioerr;
+  int nIoerrFail;
 };
 
 /*
-** A shared-memory buffer.
+** The Testvfs.mask variable is set to a combination of the following.
+** If a bit is clear in Testvfs.mask, then calls made by SQLite to the 
+** corresponding VFS method is ignored for purposes of:
+**
+**   + Simulating IO errors, and
+**   + Invoking the Tcl callback script.
 */
-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 */
-  TestvfsBuffer *pNext;           /* Next in linked list of all buffers */
-};
-
 #define TESTVFS_SHMOPEN_MASK    0x00000001
 #define TESTVFS_SHMSIZE_MASK    0x00000002
 #define TESTVFS_SHMGET_MASK     0x00000004
@@ -75,9 +74,22 @@ struct TestvfsBuffer {
 
 #define TESTVFS_ALL_MASK        0x0000007F
 
+/*
+** A shared-memory buffer.
+*/
+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 */
+  TestvfsBuffer *pNext;           /* Next in linked list of all buffers */
+};
+
 
 #define PARENTVFS(x) (((Testvfs *)((x)->pAppData))->pParent)
 
+#define TESTVFS_MAX_ARGS 12
+
 
 /*
 ** Method declarations for TestvfsFile.
@@ -403,6 +415,27 @@ static void tvfsExecTcl(
 ){
   int rc;                         /* Return code from Tcl_EvalObj() */
   int nArg;                       /* Elements in eval'd list */
+  int nScript;
+  Tcl_Obj ** ap;
+
+  assert( p->pScript );
+
+  if( !p->apScript ){
+    int nByte;
+    int i;
+    if( TCL_OK!=Tcl_ListObjGetElements(p->interp, p->pScript, &nScript, &ap) ){
+      Tcl_BackgroundError(p->interp);
+      Tcl_ResetResult(p->interp);
+      return;
+    }
+    p->nScript = nScript;
+    nByte = (nScript+TESTVFS_MAX_ARGS)*sizeof(Tcl_Obj *);
+    p->apScript = (Tcl_Obj **)ckalloc(nByte);
+    memset(p->apScript, 0, nByte);
+    for(i=0; i<nScript; i++){
+      p->apScript[i] = ap[i];
+    }
+  }
 
   p->apScript[p->nScript] = Tcl_NewStringObj(zMethod, -1);
   p->apScript[p->nScript+1] = arg1;
@@ -451,6 +484,18 @@ static int tvfsResultCode(Testvfs *p, int *pRc){
   return 0;
 }
 
+static int tvfsInjectIoerr(Testvfs *p){
+  int ret = 0;
+  if( p->ioerr ){
+    p->iIoerrCnt--;
+    if( p->iIoerrCnt==0 || (p->iIoerrCnt<0 && p->ioerr==2) ){
+      ret = 1;
+      p->nIoerrFail++;
+    }
+  }
+  return ret;
+}
+
 static int tvfsShmOpen(
   sqlite3_file *pFileDes
 ){
@@ -474,16 +519,25 @@ static int tvfsShmOpen(
   ** script is used as the connection name.
   */
   Tcl_ResetResult(p->interp);
-  if( p->mask&TESTVFS_SHMOPEN_MASK ){
+  if( p->pScript && p->mask&TESTVFS_SHMOPEN_MASK ){
     tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0);
+    if( tvfsResultCode(p, &rc) ){
+      if( rc!=SQLITE_OK ) return rc;
+    }else{
+      pId = Tcl_GetObjResult(p->interp);
+    }
   }
-  if( tvfsResultCode(p, &rc) ){
-    if( rc!=SQLITE_OK ) return rc;
+  if( !pId ){
     pId = Tcl_NewStringObj("anon", -1);
-  }else{
-    pId = Tcl_GetObjResult(p->interp);
   }
   Tcl_IncrRefCount(pId);
+
+  assert( rc==SQLITE_OK );
+  if( p->mask&TESTVFS_SHMOPEN_MASK && tvfsInjectIoerr(p) ){
+    Tcl_DecrRefCount(pId);
+    return SQLITE_IOERR;
+  }
+
   pFd->pShmId = pId;
 
   /* Search for a TestvfsBuffer. Create a new one if required. */
@@ -515,12 +569,15 @@ static int tvfsShmSize(
   TestvfsFile *pFd = (TestvfsFile *)pFile;
   Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
 
-  if( p->mask&TESTVFS_SHMSIZE_MASK ){
+  if( p->pScript && p->mask&TESTVFS_SHMSIZE_MASK ){
     tvfsExecTcl(p, "xShmSize", 
         Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
     );
     tvfsResultCode(p, &rc);
   }
+  if( rc==SQLITE_OK && p->mask&TESTVFS_SHMSIZE_MASK && tvfsInjectIoerr(p) ){
+    rc = SQLITE_IOERR;
+  }
   if( rc==SQLITE_OK ){
     tvfsGrowBuffer(pFd, reqSize, pNewSize);
   }
@@ -537,12 +594,15 @@ static int tvfsShmGet(
   TestvfsFile *pFd = (TestvfsFile *)pFile;
   Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
 
-  if( p->mask&TESTVFS_SHMGET_MASK ){
+  if( p->pScript && p->mask&TESTVFS_SHMGET_MASK ){
     tvfsExecTcl(p, "xShmGet", 
         Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
     );
     tvfsResultCode(p, &rc);
   }
+  if( rc==SQLITE_OK && p->mask&TESTVFS_SHMGET_MASK && tvfsInjectIoerr(p) ){
+    rc = SQLITE_IOERR;
+  }
   if( rc==SQLITE_OK ){
     tvfsGrowBuffer(pFd, reqMapSize, pMapSize);
     *pp = pFd->pShm->a;
@@ -555,7 +615,7 @@ static int tvfsShmRelease(sqlite3_file *pFile){
   TestvfsFile *pFd = (TestvfsFile *)pFile;
   Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
 
-  if( p->mask&TESTVFS_SHMRELEASE_MASK ){
+  if( p->pScript && p->mask&TESTVFS_SHMRELEASE_MASK ){
     tvfsExecTcl(p, "xShmRelease", 
         Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
     );
@@ -577,7 +637,7 @@ static int tvfsShmLock(
   int nLock;
   char zLock[80];
 
-  if( p->mask&TESTVFS_SHMLOCK_MASK ){
+  if( p->pScript && p->mask&TESTVFS_SHMLOCK_MASK ){
     sqlite3_snprintf(sizeof(zLock), zLock, "%d %d", ofst, n);
     nLock = strlen(zLock);
     if( flags & SQLITE_SHM_LOCK ){
@@ -604,7 +664,7 @@ static void tvfsShmBarrier(sqlite3_file *pFile){
   TestvfsFile *pFd = (TestvfsFile *)pFile;
   Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
 
-  if( p->mask&TESTVFS_SHMBARRIER_MASK ){
+  if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){
     tvfsExecTcl(p, "xShmBarrier", 
         Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
     );
@@ -625,7 +685,7 @@ static int tvfsShmClose(
   assert( (deleteFlag!=0)==(pBuffer->nRef==1) );
 #endif
 
-  if( p->mask&TESTVFS_SHMCLOSE_MASK ){
+  if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){
     tvfsExecTcl(p, "xShmClose", 
         Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
     );
@@ -655,8 +715,13 @@ static int testvfs_obj_cmd(
 ){
   Testvfs *p = (Testvfs *)cd;
 
-  static const char *CMD_strs[] = { "shm", "delete", "filter", "ioerr", 0 };
-  enum DB_enum { CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR };
+  static const char *CMD_strs[] = { 
+    "shm",   "delete",   "filter",   "ioerr",   "script", 0 
+  };
+  enum DB_enum { 
+    CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT
+  };
+
   int i;
   
   if( objc<2 ){
@@ -738,22 +803,55 @@ static int testvfs_obj_cmd(
       break;
     }
 
+    case CMD_SCRIPT: {
+      if( objc==3 ){
+        int nByte;
+        if( p->pScript ){
+          Tcl_DecrRefCount(p->pScript);
+          ckfree((char *)p->apScript);
+          p->apScript = 0;
+          p->nScript = 0;
+        }
+        Tcl_GetStringFromObj(objv[2], &nByte);
+        if( nByte>0 ){
+          p->pScript = Tcl_DuplicateObj(objv[2]);
+          Tcl_IncrRefCount(p->pScript);
+        }
+      }else if( objc!=2 ){
+        Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?");
+        return TCL_ERROR;
+      }
+
+      Tcl_ResetResult(interp);
+      if( p->pScript ) Tcl_SetObjResult(interp, p->pScript);
+
+      break;
+    }
+
+    /*
+    ** TESTVFS ioerr ?IFAIL PERSIST?
+    **
+    **   Where IFAIL is an integer and PERSIST is boolean.
+    */
     case CMD_IOERR: {
-      int iRet = ((p->iIoerrCnt<0) ? (1+(p->iIoerrCnt*-1)) : 0);
-      if( objc==2 ){
-        p->ioerr = 0;
-        p->iIoerrCnt = 0;
-      }else if( objc==4 ){
+      int iRet = p->nIoerrFail;
+
+      p->nIoerrFail = 0;
+      p->ioerr = 0;
+      p->iIoerrCnt = 0;
+
+      if( objc==4 ){
         int iCnt, iPersist;
         if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iCnt)
          || TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &iPersist)
         ){
           return TCL_ERROR;
         }
-        p->ioerr = (iPersist!=0) + 1;
+        p->ioerr = (iCnt>0) + iPersist;
         p->iIoerrCnt = iCnt;
-      }else{
+      }else if( objc!=2 ){
         Tcl_AppendResult(interp, "Bad args", 0);
+        return TCL_ERROR;
       }
       Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet));
       break;
@@ -769,20 +867,21 @@ static int testvfs_obj_cmd(
 }
 
 static void testvfs_obj_del(ClientData cd){
-  int i;
   Testvfs *p = (Testvfs *)cd;
-  for(i=0; i<p->nScript; i++){
-    Tcl_DecrRefCount(p->apScript[i]);
-  }
+  if( p->pScript ) Tcl_DecrRefCount(p->pScript);
   sqlite3_vfs_unregister(p->pVfs);
+  ckfree((char *)p->apScript);
   ckfree((char *)p->pVfs);
   ckfree((char *)p);
 }
 
-#define TESTVFS_MAX_ARGS 12
-
 /*
-** Usage:  testvfs ?-noshm? VFSNAME SCRIPT
+** Usage:  testvfs VFSNAME ?SWITCHES?
+**
+** Switches are:
+**
+**   -noshm   BOOLEAN             (True to omit shm methods. Default false)
+**   -default BOOLEAN             (True to make the vfs default. Default false)
 **
 ** This command creates two things when it is invoked: an SQLite VFS, and
 ** a Tcl command. Both are named VFSNAME. The VFS is installed. It is not
@@ -852,41 +951,43 @@ static int testvfs_cmd(
   Testvfs *p;                     /* New object */
   sqlite3_vfs *pVfs;              /* New VFS */
   char *zVfs;
-  Tcl_Obj *pScript;
-  int nScript;                    /* Number of elements in list pScript */
-  Tcl_Obj **apScript;             /* Array of pScript elements */
   int nByte;                      /* Bytes of space to allocate at p */
-  int i;                          /* Counter variable */
+
+  int i;
   int isNoshm = 0;                /* True if -noshm is passed */
+  int isDefault = 0;              /* True if -default is passed */
 
-  if( objc<3 ) goto bad_args;
-  if( strcmp(Tcl_GetString(objv[1]), "-noshm")==0 ){
-    isNoshm = 1;
-  }
-  if( objc!=3+isNoshm ) goto bad_args;
-  zVfs = Tcl_GetString(objv[isNoshm+1]);
-  pScript = objv[isNoshm+2];
+  if( objc<2 || 0!=(objc%2) ) goto bad_args;
+  for(i=2; i<objc; i += 2){
+    int nSwitch;
+    char *zSwitch;
 
-  if( TCL_OK!=Tcl_ListObjGetElements(interp, pScript, &nScript, &apScript) ){
-    return TCL_ERROR;
+    zSwitch = Tcl_GetStringFromObj(objv[i], &nSwitch); 
+    if( nSwitch>2 && 0==strncmp("-noshm", zSwitch, nSwitch) ){
+      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &isNoshm) ){
+        return TCL_ERROR;
+      }
+    }
+    else if( nSwitch>2 && 0==strncmp("-default", zSwitch, nSwitch) ){
+      if( Tcl_GetBooleanFromObj(interp, objv[i+1], &isDefault) ){
+        return TCL_ERROR;
+      }
+    }
+    else{
+      goto bad_args;
+    }
   }
 
-  nByte = sizeof(Testvfs)
-        + (nScript+TESTVFS_MAX_ARGS)*sizeof(Tcl_Obj *) 
-        + strlen(zVfs)+1;
+  zVfs = Tcl_GetString(objv[1]);
+  nByte = sizeof(Testvfs) + strlen(zVfs)+1;
   p = (Testvfs *)ckalloc(nByte);
   memset(p, 0, nByte);
 
   p->pParent = sqlite3_vfs_find(0);
   p->interp = interp;
-  p->nScript = nScript;
-  p->apScript = (Tcl_Obj **)&p[1];
-  for(i=0; i<nScript; i++){
-    p->apScript[i] = apScript[i];
-    Tcl_IncrRefCount(p->apScript[i]);
-  }
-  p->zName = (char *)&p->apScript[nScript+TESTVFS_MAX_ARGS];
-  strcpy(p->zName, zVfs);
+
+  p->zName = (char *)&p[1];
+  memcpy(p->zName, zVfs, strlen(zVfs)+1);
 
   pVfs = (sqlite3_vfs *)ckalloc(sizeof(sqlite3_vfs));
   memcpy(pVfs, &tvfs_vfs, sizeof(sqlite3_vfs));
@@ -899,12 +1000,12 @@ static int testvfs_cmd(
   p->mask = TESTVFS_ALL_MASK;
 
   Tcl_CreateObjCommand(interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del);
-  sqlite3_vfs_register(pVfs, 0);
+  sqlite3_vfs_register(pVfs, isDefault);
 
   return TCL_OK;
 
  bad_args:
-  Tcl_WrongNumArgs(interp, 1, objv, "?-noshm? VFSNAME SCRIPT");
+  Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-default BOOL?");
   return TCL_ERROR;
 }
 
index 057cf7c4128a6cd6b0843c50e644329c52265da7..902f683104db1532013db09b579636b718f7f8f2 100644 (file)
@@ -23,6 +23,50 @@ ifcapable builtin_test {
   return 0
 }
 
+# Transient and persistent OOM errors:
+#
+set FAULTSIM(oom-transient) [list          \
+  -injectstart   {oom_injectstart 0}       \
+  -injectstop    oom_injectstop            \
+  -injecterrlist {{1 {out of memory}}}     \
+]
+set FAULTSIM(oom-persistent) [list         \
+  -injectstart {oom_injectstart 1000000}   \
+  -injectstop oom_injectstop               \
+  -injecterrlist {{1 {out of memory}}}     \
+]
+  
+# Transient and persistent IO errors:
+#
+set FAULTSIM(ioerr-transient) [list        \
+  -injectstart   {ioerr_injectstart 0}     \
+  -injectstop    ioerr_injectstop          \
+  -injecterrlist {{1 {disk I/O error}}}    \
+]
+set FAULTSIM(ioerr-persistent) [list       \
+  -injectstart   {ioerr_injectstart 1}     \
+  -injectstop    ioerr_injectstop          \
+  -injecterrlist {{1 {disk I/O error}}}    \
+]
+
+# Transient and persistent SHM errors:
+#
+set FAULTSIM(shmerr-transient) [list       \
+  -injectinstall   shmerr_injectinstall    \
+  -injectstart     {shmerr_injectstart 0}  \
+  -injectstop      shmerr_injectstop       \
+  -injecterrlist   {{1 {disk I/O error}}}  \
+  -injectuninstall shmerr_injectuninstall  \
+]
+set FAULTSIM(shmerr-persistent) [list      \
+  -injectinstall   shmerr_injectinstall    \
+  -injectstart     {shmerr_injectstart 1}  \
+  -injectstop      shmerr_injectstop       \
+  -injecterrlist   {{1 {disk I/O error}}}  \
+  -injectuninstall shmerr_injectuninstall  \
+]
+
+
 
 #--------------------------------------------------------------------------
 # Usage do_faultsim_test NAME ?OPTIONS...? 
@@ -36,10 +80,9 @@ ifcapable builtin_test {
 #     -test             Script to execute after -body.
 #
 proc do_faultsim_test {name args} {
-  set DEFAULT(-faults)        [list       \
-    oom-transient     oom-persistent      \
-    ioerr-transient   ioerr-persistent    \
-  ]
+  global FAULTSIM
+  
+  set DEFAULT(-faults)        [array names FAULTSIM]
   set DEFAULT(-prep)          ""
   set DEFAULT(-body)          ""
   set DEFAULT(-test)          ""
@@ -50,35 +93,16 @@ proc do_faultsim_test {name args} {
     if {[info exists DEFAULT($o)]==0} { error "unknown option: $o" }
   }
 
-  set A(oom-transient) [list                 \
-    -injectstart   {oom_injectstart 0}       \
-    -injectstop    oom_injectstop            \
-    -injecterrlist {{1 {out of memory}}}     \
-  ]
-  set A(oom-persistent) [list                \
-    -injectstart {oom_injectstart 1000000}   \
-    -injectstop oom_injectstop               \
-    -injecterrlist {{1 {out of memory}}}     \
-  ]
-  
-  set A(ioerr-transient) [list               \
-    -injectstart   {ioerr_injectstart 0}     \
-    -injectstop    ioerr_injectstop          \
-    -injecterrlist {{1 {disk I/O error}}}    \
-  ]
-
-  set A(ioerr-persistent) [list              \
-    -injectstart   {ioerr_injectstart 1}     \
-    -injectstop    ioerr_injectstop          \
-    -injecterrlist {{1 {disk I/O error}}}    \
-  ]
-
+  set faultlist [list]
   foreach f $O(-faults) {
-    if {[info exists A($f)]==0} { error "unknown fault: $f" }
+    set flist [array names FAULTSIM $f]
+    if {[llength $flist]==0} { error "unknown fault: $f" }
+    set faultlist [concat $faultlist $flist]
   }
+
   set testspec [list -prep $O(-prep) -body $O(-body) -test $O(-test)]
-  foreach f $O(-faults) {
-    eval do_one_faultsim_test "$name-$f" $A($f) $testspec
+  foreach f [lsort -unique $faultlist] {
+    eval do_one_faultsim_test "$name-$f" $FAULTSIM($f) $testspec
   }
 }
 
@@ -121,9 +145,20 @@ proc faultsim_restore_and_reopen {} {
   sqlite3_db_config_lookaside db 0 0 0
 }
 
+proc faultsim_integrity_check {{db db}} {
+  set ic [$db eval { PRAGMA integrity_check }]
+  if {$ic != "ok"} { error "Integrity check: $ic" }
+}
+
+proc faultsim_delete_and_reopen {{file test.db}} {
+  catch { db close }
+  file delete -force test.db test.db-wal test.db-journal
+  sqlite3 db test.db
+}
+
 
-# The following procs are used as [do_faultsim_test] when injecting OOM
-# faults into test cases.
+# The following procs are used as [do_one_faultsim_test] callbacks when 
+# injecting OOM faults into test cases.
 #
 proc oom_injectstart {nRepeat iFail} {
   sqlite3_memdebug_fail $iFail -repeat $nRepeat
@@ -132,6 +167,9 @@ proc oom_injectstop {} {
   sqlite3_memdebug_fail -1
 }
 
+# The following procs are used as [do_one_faultsim_test] callbacks when 
+# injecting IO error faults into test cases.
+#
 proc ioerr_injectstart {persist iFail} {
   set ::sqlite_io_error_persist $persist
   set ::sqlite_io_error_pending $iFail
@@ -146,6 +184,24 @@ proc ioerr_injectstop {} {
   return $sv
 }
 
+# The following procs are used as [do_one_faultsim_test] callbacks when 
+# injecting shared-memory related error faults into test cases.
+#
+proc shmerr_injectinstall {} {
+  testvfs shmfault -default true
+}
+proc shmerr_injectuninstall {} {
+  catch {db  close}
+  catch {db2 close}
+  shmfault delete
+}
+proc shmerr_injectstart {persist iFail} {
+  shmfault ioerr $iFail $persist
+}
+proc shmerr_injectstop {} {
+  shmfault ioerr 0 0
+}
+
 # This command is not called directly. It is used by the 
 # [faultsim_test_result] command created by [do_faultsim_test] and used
 # by -test scripts.
@@ -173,6 +229,10 @@ proc faultsim_test_result_int {args} {
 #     -injecterrlist    List of generally acceptable test results (i.e. error
 #                       messages). Example: [list {1 {out of memory}}]
 #
+#     -injectinstall
+#
+#     -injectuninstall
+#
 #     -prep             Script to execute before -body.
 #
 #     -body             Script to execute (with fault injection).
@@ -181,12 +241,14 @@ proc faultsim_test_result_int {args} {
 #
 proc do_one_faultsim_test {testname args} {
 
-  set DEFAULT(-injectstart)   {oom_injectstart 0}
-  set DEFAULT(-injectstop)    {oom_injectstop}
-  set DEFAULT(-injecterrlist) [list {1 {out of memory}}]
-  set DEFAULT(-prep)          ""
-  set DEFAULT(-body)          ""
-  set DEFAULT(-test)          ""
+  set DEFAULT(-injectstart)     "expr"
+  set DEFAULT(-injectstop)      "expr 0"
+  set DEFAULT(-injecterrlist)   [list]
+  set DEFAULT(-injectinstall)   ""
+  set DEFAULT(-injectuninstall) ""
+  set DEFAULT(-prep)            ""
+  set DEFAULT(-body)            ""
+  set DEFAULT(-test)            ""
 
   array set O [array get DEFAULT]
   array set O $args
@@ -199,6 +261,8 @@ proc do_one_faultsim_test {testname args} {
     uplevel faultsim_test_result_int \$args [list $O(-injecterrlist)]
   "
 
+  eval $O(-injectinstall)
+
   set stop 0
   for {set iFail 1} {!$stop} {incr iFail} {
 
@@ -228,6 +292,8 @@ proc do_one_faultsim_test {testname args} {
     #
     if {$nfail==0} { set stop 1 }
   }
+
+  eval $O(-injectuninstall)
 }
 
 # Usage: do_malloc_test <test number> <options...>
index 91ae546ee02226c60a5ce83458f36bf022413689..d8e556080e6785e0c08117400c75c0cc338da1d9 100644 (file)
@@ -72,7 +72,8 @@ proc incr_tvfs_hdr {file idx incrval} {
 #
 do_test wal2-1.0 {
   proc tvfs_cb {method args} { return SQLITE_OK }
-  testvfs tvfs tvfs_cb
+  testvfs tvfs
+  tvfs script tvfs_cb
 
   sqlite3 db  test.db -vfs tvfs
   sqlite3 db2 test.db -vfs tvfs
@@ -166,7 +167,8 @@ set LOCKS  [list \
 ]
 do_test wal2-2.0 {
 
-  testvfs tvfs tvfs_cb
+  testvfs tvfs
+  tvfs script tvfs_cb
   proc tvfs_cb {method args} {
     if {$method == "xShmOpen"} { set ::shm_file [lindex $args 0] }
     return SQLITE_OK
@@ -281,7 +283,8 @@ do_test wal2-3.0 {
     return 0
   }
 
-  testvfs tvfs tvfs_cb
+  testvfs tvfs
+  tvfs script tvfs_cb
   sqlite3 db test.db -vfs tvfs
   db busy busyhandler
 
@@ -348,15 +351,13 @@ do_test wal2-4.1 {
 } {wal}
 do_test wal2-4.2 {
   db close
-  proc ok {args} {return SQLITE_OK}
-  testvfs -noshm tvfs ok
+  testvfs tvfs -noshm 1
   sqlite3 db test.db -vfs tvfs
   catchsql { SELECT * FROM data }
 } {1 {unable to open database file}}
 do_test wal2-4.3 {
   db close
-  proc ok {args} {return SQLITE_OK}
-  testvfs tvfs ok
+  testvfs tvfs
   sqlite3 db test.db -vfs tvfs
   catchsql { SELECT * FROM data }
 } {0 {{need xShmOpen to see this}}}
@@ -388,7 +389,8 @@ do_test wal2-5.1 {
   }
   set tvfs_cb_return SQLITE_OK
 
-  testvfs tvfs tvfs_cb
+  testvfs tvfs
+  tvfs script tvfs_cb
 
   sqlite3 db test.db -vfs tvfs
   execsql {
@@ -578,7 +580,8 @@ do_test wal2-6.4.1 {
     if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] }
     return "SQLITE_OK"
   }
-  testvfs tvfs tvfs_cb
+  testvfs tvfs
+  tvfs script tvfs_cb
   sqlite3 db test.db -vfs tvfs
 } {}
 
index 499f794bbe67882477077476d25f8ee5187b8901..edb78358e7975723f83bd9b3aa6fd482f622775f 100644 (file)
@@ -91,13 +91,8 @@ do_faultsim_test walfault-2 -prep {
 } -body {
   execsql { SELECT count(*) FROM x }
 } -test {
-
   faultsim_test_result {0 8}
-
-  # Run the integrity_check to make sure nothing strange has occurred.
-  #
-  set ic [db eval { PRAGMA integrity_check }]
-  if {$ic != "ok"} { error "Integrity check: $ic" }
+  faultsim_integrity_check
 }
 
 #--------------------------------------------------------------------------
@@ -126,116 +121,70 @@ do_faultsim_test walfault-3 -prep {
   faultsim_test_result {0 {}}
 }
 
-# A [testvfs] callback for the VFS created by [do_shmfault_test]. This
-# callback injects SQLITE_IOERR faults into methods for which an entry
-# in array ::shmfault_ioerr_methods is defined. For example, to enable
-# errors in xShmOpen:
-#
-#   set ::shmfault_ioerr_methods(xShmOpen) 1
-# 
-# Faults are not injected into xShmRelease, xShmClose or xShmLock method 
-# calls. The global tcl variables used are:
-#
-#   $::shmfault_ioerr_countdown
-#   $::shmfault_ioerr_persist
-#
-proc shmfault_vfs_cb {method args} {
-
-  # If ::shmfault_ioerr_countdown is not set, always return SQLITE_OK.
-  #
-  if {[info exists ::shmfault_ioerr_countdown]==0} { return SQLITE_OK }
-
-  incr ::shmfault_ioerr_countdown -1
-  if { ($::shmfault_ioerr_countdown==0)
-    || ($::shmfault_ioerr_countdown<=0 && $::shmfault_ioerr_persist)
-  } {
-    return SQLITE_IOERR
+file delete -force test.db test.db-wal test.db-journal
+faultsim_save_and_close
+do_faultsim_test walfault-4 -prep {
+  faultsim_restore_and_reopen
+} -body {
+  execsql {
+    PRAGMA journal_mode = WAL;
+    CREATE TABLE t1(a PRIMARY KEY, b);
+    INSERT INTO t1 VALUES('a', 'b');
+    PRAGMA wal_checkpoint;
+    SELECT * FROM t1;
   }
-  return SQLITE_OK
-}
-
-# Options are:
-#
-#   -tclprep TCL
-#   -sqlprep SQL
-#   -sqlbody SQL
-#
-proc do_shmfault_test {name args} {
-
-  set A(-tclprep) "sqlite3 db test.db -vfs shmfault"
-  set A(-sqlprep) ""
-  set A(-sqlbody) ""
-  set A(-methods) [list xShmGet xShmOpen xShmSize]
-  set A(-coverageonly) 0
-  array set A $args
-
-  # Create a VFS to use:
-  testvfs shmfault shmfault_vfs_cb
-  shmfault filter $A(-methods)
-  
-  foreach mode {transient persistent} {
-    set ::shmfault_ioerr_persist [expr {$mode == "persistent"}]
-
-    for {set nDelay 1} {$nDelay < 10000} {incr nDelay} {
-  
-      file delete -force test.db test.db-wal test.db-journal
-
-      eval $A(-tclprep)
-      db eval $A(-sqlprep)
-
-      set ::shmfault_ioerr_countdown $nDelay
-      set rc [catch { db eval $A(-sqlbody) } msg]
-      set hit_error [expr {$::shmfault_ioerr_countdown<=0}]
-      unset ::shmfault_ioerr_countdown
+} -test {
+  faultsim_test_result {0 {wal a b}}
+  faultsim_integrity_check
+} 
 
-      catch { db close }
-      
-      if {$A(-coverageonly)} { set rc $hit_error }
-      do_test $name-$mode.$nDelay.1 [list set {} $hit_error] $rc
-  
-      if {$hit_error==0} break
-    }
+do_test walfault-5-pre-1 {
+  catch { db close }
+  file delete -force test.db test.db-wal test.db-journal
+  sqlite3 db test.db
+  execsql {
+    PRAGMA page_size = 512;
+    PRAGMA journal_mode = WAL;
   }
-
-  shmfault delete
-}
-
-do_shmfault_test walfault-shm-1 -sqlbody {
-  PRAGMA journal_mode = WAL;
-  CREATE TABLE t1(a PRIMARY KEY, b);
-  INSERT INTO t1 VALUES('a', 'b');
-  PRAGMA wal_checkpoint;
+  faultsim_save_and_close
+} {}
+do_faultsim_test walfault-5 -faults shmerr* -prep {
+  faultsim_restore_and_reopen
+  execsql { PRAGMA wal_autocheckpoint = 0 }
+  shmfault filter xShmSize
+} -body {
+  execsql {
+    CREATE TABLE t1(x);
+    BEGIN;
+      INSERT INTO t1 VALUES(randomblob(400));           /* 1 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 2 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 4 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 8 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 16 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 32 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 64 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 128 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 256 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 512 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 1024 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 2048 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 4096 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 8192 */
+      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 16384 */
+    COMMIT;
+    SELECT count(*) FROM t1;
+  }
+} -test {
+  faultsim_test_result {0 16384}
+  faultsim_integrity_check
 }
 
-do_shmfault_test walfault-shm-2 -methods xShmSize -sqlprep {
-  PRAGMA page_size = 512;
-  PRAGMA journal_mode = WAL;
-  PRAGMA wal_autocheckpoint = 0;
-} -sqlbody {
-  CREATE TABLE t1(x);
-  BEGIN;
-    INSERT INTO t1 VALUES(randomblob(400));           /* 1 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 2 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 4 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 8 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 16 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 32 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 64 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 128 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 256 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 512 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 1024 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 2048 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 4096 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 8192 */
-    INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 16384 */
-  COMMIT;
-}
 
-do_shmfault_test walfault-shm-3 -methods xShmSize -tclprep {
-  sqlite3 db test.db -vfs shmfault
-  shmfault filter {}
-  db eval {
+do_test walfault-6-pre-1 {
+  catch { db close }
+  file delete -force test.db test.db-wal test.db-journal
+  sqlite3 db test.db
+  execsql {
     PRAGMA page_size = 512;
     PRAGMA journal_mode = WAL;
     PRAGMA wal_autocheckpoint = 0;
@@ -258,22 +207,23 @@ do_shmfault_test walfault-shm-3 -methods xShmSize -tclprep {
       INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 16384 */
     COMMIT;
   }
-
-  set ::shmfault_ioerr_countdown 1
-  shmfault filter xShmGet
-  db close
-  shmfault filter {}
-  if {[file exists test.db-wal]==0} {error "Failed to create WAL file!"}
-
-  sqlite3 db test.db -vfs shmfault
-} -sqlbody {
-  SELECT count(*) FROM t1;
+  faultsim_save_and_close
+} {}
+do_faultsim_test walfault-6 -faults shmerr* -prep {
+  faultsim_restore_and_reopen
+  shmfault filter xShmSize
+} -body {
+  execsql { SELECT count(*) FROM t1 }
+} -test {
+  faultsim_test_result {0 16384}
+  faultsim_integrity_check
+  set n [db one {SELECT count(*) FROM t1}]
+  if {$n != 16384 && $n != 0} { error "Incorrect number of rows: $n" }
 }
 
-do_shmfault_test walfault-shm-4 -tclprep {
-  sqlite3 db test.db -vfs shmfault
-  unset -nocomplain ::shmfault_ioerr_countdown
-  db eval {
+do_test walfault-7-pre-1 {
+  faultsim_delete_and_reopen
+  execsql {
     PRAGMA page_size = 512;
     PRAGMA journal_mode = WAL;
     PRAGMA wal_autocheckpoint = 0;
@@ -284,45 +234,86 @@ do_shmfault_test walfault-shm-4 -tclprep {
       INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 4 */
     COMMIT;
   }
-
-  set ::shmfault_ioerr_countdown 1
-  shmfault filter xShmGet
-  db close
-  shmfault filter {}
-  if {[file exists test.db-wal]==0} {error "Failed to create WAL file!"}
-  sqlite3 db test.db -vfs shmfault
-} -sqlbody {
-  SELECT count(*) FROM t1;
+  faultsim_save_and_close
+} {}
+do_faultsim_test walfault-7 -prep {
+  faultsim_restore_and_reopen
+} -body {
+  execsql { SELECT count(*) FROM t1 }
+} -test {
+  faultsim_test_result {0 4}
+  set n [db one {SELECT count(*) FROM t1}]
+  if {$n != 4 && $n != 0} { error "Incorrect number of rows: $n" }
 }
 
-do_shmfault_test walfault-shm-5.1 -coverageonly 1 -sqlprep {
-  PRAGMA cache_size = 10;
-  PRAGMA journal_mode = WAL;
-  CREATE TABLE abc(a PRIMARY KEY);
-  INSERT INTO abc VALUES(randomblob(900));
-} -sqlbody {
-  BEGIN;
-    INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 1 */
-    INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 2 */
-    INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 4 */
-    INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 8 */
-  ROLLBACK;
+do_test walfault-8-pre-1 {
+  faultsim_delete_and_reopen
+  execsql {
+    PRAGMA journal_mode = WAL;
+    CREATE TABLE abc(a PRIMARY KEY);
+    INSERT INTO abc VALUES(randomblob(900));
+  }
+  faultsim_save_and_close
+} {}
+do_faultsim_test walfault-8 -prep {
+  faultsim_restore_and_reopen
+  execsql { PRAGMA cache_size = 10 }
+} -body {
+  execsql {
+    BEGIN;
+      INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 1 */
+      --INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 2 */
+      --INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 4 */
+      --INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 8 */
+    ROLLBACK;
+    SELECT count(*) FROM abc;
+  }
+} -test {
+  faultsim_test_result {0 1}
+
+  faultsim_integrity_check
+  catch { db eval ROLLBACK }
+  faultsim_integrity_check
+
+  set n [db one {SELECT count(*) FROM abc}]
+  if {$n != 1} { error "Incorrect number of rows: $n" }
 }
 
-do_shmfault_test walfault-shm-5.2 -coverageonly 1 -sqlprep {
-  PRAGMA cache_size = 10;
-  PRAGMA journal_mode = WAL;
-  CREATE TABLE abc(a PRIMARY KEY);
-  INSERT INTO abc VALUES(randomblob(900));
-} -sqlbody {
-  BEGIN;
-    INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 1 */
-    SAVEPOINT spoint;
-      INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 2 */
-      INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 4 */
-      INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 8 */
-    ROLLBACK TO spoint;
-  COMMIT;
+do_test walfault-9-pre-1 {
+  faultsim_delete_and_reopen
+  execsql {
+    PRAGMA journal_mode = WAL;
+    CREATE TABLE abc(a PRIMARY KEY);
+    INSERT INTO abc VALUES(randomblob(900));
+  }
+  faultsim_save_and_close
+} {}
+do_faultsim_test walfault-9 -prep {
+  #if {$iFail<73} { set iFail 73 }
+  #if {$iFail>73} { exit }
+  
+  faultsim_restore_and_reopen
+  execsql { PRAGMA cache_size = 10 }
+} -body {
+  execsql {
+    BEGIN;
+      INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 1 */
+      SAVEPOINT spoint;
+        INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 2 */
+        INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 4 */
+        INSERT INTO abc SELECT randomblob(900) FROM abc;    /* 8 */
+      ROLLBACK TO spoint;
+    COMMIT;
+    SELECT count(*) FROM abc;
+  }
+} -test {
+  faultsim_test_result {0 2}
+  faultsim_integrity_check
+
+  catch { db eval { ROLLBACK TO spoint } }
+  catch { db eval { COMMIT } }
+  set n [db one {SELECT count(*) FROM abc}]
+  if {$n != 1 && $n != 2} { error "Incorrect number of rows: $n" }
 }
 
 #-------------------------------------------------------------------------
@@ -358,7 +349,8 @@ proc shmfault_vfs_cb_6 {method args} {
 }
 do_test walfault-shm-6.1 {
   set ::shm_state 0
-  testvfs tvfs shmfault_vfs_cb_6
+  testvfs tvfs 
+  tvfs script shmfault_vfs_cb_6
 
   sqlite3 db  test.db -vfs tvfs
   sqlite3 db2 test.db -vfs tvfs