From: dan Date: Thu, 3 Jun 2010 09:25:10 +0000 (+0000) Subject: Enhancements to test_vfs.c and walfault.test. X-Git-Tag: version-3.7.2~310 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1f55e28d2a523bfb43d28a3baf553fec00dac77d;p=thirdparty%2Fsqlite.git Enhancements to test_vfs.c and walfault.test. FossilOrigin-Name: ac0de2f39e948f3b00e96eebf56ebee70472020d --- diff --git a/manifest b/manifest index 028568ac8c..5acb674857 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 213df0ba77..a192ea4b1e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -eb80ddc665132c607c258b59131025a296269dad \ No newline at end of file +ac0de2f39e948f3b00e96eebf56ebee70472020d \ No newline at end of file diff --git a/src/test_vfs.c b/src/test_vfs.c index fda44a725c..8e7f0ce028 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -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; iapScript[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; inScript; 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; i2 && 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; iapScript[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; } diff --git a/test/malloc_common.tcl b/test/malloc_common.tcl index 057cf7c412..902f683104 100644 --- a/test/malloc_common.tcl +++ b/test/malloc_common.tcl @@ -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 diff --git a/test/wal2.test b/test/wal2.test index 91ae546ee0..d8e556080e 100644 --- a/test/wal2.test +++ b/test/wal2.test @@ -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 } {} diff --git a/test/walfault.test b/test/walfault.test index 499f794bbe..edb78358e7 100644 --- a/test/walfault.test +++ b/test/walfault.test @@ -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