mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-27 20:41:58 +03:00
Enhancements to test_vfs.c and walfault.test.
FossilOrigin-Name: ac0de2f39e948f3b00e96eebf56ebee70472020d
This commit is contained in:
18
manifest
18
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.
|
C Enhancements\sto\stest_vfs.c\sand\swalfault.test.
|
||||||
D 2010-06-03T09:17:38
|
D 2010-06-03T09:25:10
|
||||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||||
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
|
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@ -207,7 +207,7 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
|||||||
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
||||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||||
F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726
|
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/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||||
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
|
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
|
||||||
F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d
|
F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d
|
||||||
@ -506,7 +506,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
|
|||||||
F test/mallocI.test e3ea401904d010cb7c1e4b2ee8803f4a9f5b999d
|
F test/mallocI.test e3ea401904d010cb7c1e4b2ee8803f4a9f5b999d
|
||||||
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
||||||
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
||||||
F test/malloc_common.tcl 7d2478b7f084afd8cb14b1121097ea3d989216b3
|
F test/malloc_common.tcl 9b58ffd50d073dccf0493e3ca4aa39bc64ce3047
|
||||||
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
|
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
|
||||||
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
|
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
|
||||||
F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
|
F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
|
||||||
@ -762,12 +762,12 @@ F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
|||||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||||
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
|
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
|
||||||
F test/wal.test bfec61450b47cdf09f7d2269f9e9967683b8b0fc
|
F test/wal.test bfec61450b47cdf09f7d2269f9e9967683b8b0fc
|
||||||
F test/wal2.test a2146846c4dd940252f18ec1e00431346286bcb3
|
F test/wal2.test 1dcbbe59ab662bebb859bb1ede83143f8a39814e
|
||||||
F test/walbak.test e7650a26eb4b8abeca9b145b1af1e63026dde432
|
F test/walbak.test e7650a26eb4b8abeca9b145b1af1e63026dde432
|
||||||
F test/walcksum.test 4efa8fb88c32bed8288ea4385a9cc113a5c8f0bf
|
F test/walcksum.test 4efa8fb88c32bed8288ea4385a9cc113a5c8f0bf
|
||||||
F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
|
F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
|
||||||
F test/walcrash2.test 14585ad1a2c85da2de721caa3b4deeea55213008
|
F test/walcrash2.test 14585ad1a2c85da2de721caa3b4deeea55213008
|
||||||
F test/walfault.test 9015004b56bc2cb8cf5c96183853f1157e61ff70
|
F test/walfault.test 058c9e2829fc5e3e01ae4984980a6da9af15368a
|
||||||
F test/walhook.test 67e675127f4acb72f061a12667ce6e5460b06b78
|
F test/walhook.test 67e675127f4acb72f061a12667ce6e5460b06b78
|
||||||
F test/walmode.test 6ca9d710cc9f6545b913abcded6d6b0b15641048
|
F test/walmode.test 6ca9d710cc9f6545b913abcded6d6b0b15641048
|
||||||
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
|
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
|
||||||
@ -815,7 +815,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
|||||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||||
P 91cb08ffb6332a142542c012b58aa49206ee5704
|
P eb80ddc665132c607c258b59131025a296269dad
|
||||||
R efb6b25ebd6ed72f29b742d935423851
|
R b8571e46e77ae4334ee4b99c40b16506
|
||||||
U dan
|
U dan
|
||||||
Z 0bec386ab07ce5c674d40d75eae0944a
|
Z a97b394e32c2defcb9f264e6738c31ca
|
||||||
|
@ -1 +1 @@
|
|||||||
eb80ddc665132c607c258b59131025a296269dad
|
ac0de2f39e948f3b00e96eebf56ebee70472020d
|
219
src/test_vfs.c
219
src/test_vfs.c
@ -44,16 +44,36 @@ struct Testvfs {
|
|||||||
sqlite3_vfs *pParent; /* The VFS to use for file IO */
|
sqlite3_vfs *pParent; /* The VFS to use for file IO */
|
||||||
sqlite3_vfs *pVfs; /* The testvfs registered with SQLite */
|
sqlite3_vfs *pVfs; /* The testvfs registered with SQLite */
|
||||||
Tcl_Interp *interp; /* Interpreter to run script in */
|
Tcl_Interp *interp; /* Interpreter to run script in */
|
||||||
|
Tcl_Obj *pScript; /* Script to execute */
|
||||||
int nScript; /* Number of elements in array apScript */
|
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 */
|
TestvfsBuffer *pBuffer; /* List of shared buffers */
|
||||||
int isNoshm;
|
int isNoshm;
|
||||||
|
|
||||||
int mask;
|
int mask;
|
||||||
int iIoerrCnt;
|
int iIoerrCnt;
|
||||||
int ioerr;
|
int ioerr;
|
||||||
|
int nIoerrFail;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 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.
|
||||||
|
*/
|
||||||
|
#define TESTVFS_SHMOPEN_MASK 0x00000001
|
||||||
|
#define TESTVFS_SHMSIZE_MASK 0x00000002
|
||||||
|
#define TESTVFS_SHMGET_MASK 0x00000004
|
||||||
|
#define TESTVFS_SHMRELEASE_MASK 0x00000008
|
||||||
|
#define TESTVFS_SHMLOCK_MASK 0x00000010
|
||||||
|
#define TESTVFS_SHMBARRIER_MASK 0x00000020
|
||||||
|
#define TESTVFS_SHMCLOSE_MASK 0x00000040
|
||||||
|
|
||||||
|
#define TESTVFS_ALL_MASK 0x0000007F
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A shared-memory buffer.
|
** A shared-memory buffer.
|
||||||
*/
|
*/
|
||||||
@ -65,19 +85,11 @@ struct TestvfsBuffer {
|
|||||||
TestvfsBuffer *pNext; /* Next in linked list of all buffers */
|
TestvfsBuffer *pNext; /* Next in linked list of all buffers */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TESTVFS_SHMOPEN_MASK 0x00000001
|
|
||||||
#define TESTVFS_SHMSIZE_MASK 0x00000002
|
|
||||||
#define TESTVFS_SHMGET_MASK 0x00000004
|
|
||||||
#define TESTVFS_SHMRELEASE_MASK 0x00000008
|
|
||||||
#define TESTVFS_SHMLOCK_MASK 0x00000010
|
|
||||||
#define TESTVFS_SHMBARRIER_MASK 0x00000020
|
|
||||||
#define TESTVFS_SHMCLOSE_MASK 0x00000040
|
|
||||||
|
|
||||||
#define TESTVFS_ALL_MASK 0x0000007F
|
|
||||||
|
|
||||||
|
|
||||||
#define PARENTVFS(x) (((Testvfs *)((x)->pAppData))->pParent)
|
#define PARENTVFS(x) (((Testvfs *)((x)->pAppData))->pParent)
|
||||||
|
|
||||||
|
#define TESTVFS_MAX_ARGS 12
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Method declarations for TestvfsFile.
|
** Method declarations for TestvfsFile.
|
||||||
@ -403,6 +415,27 @@ static void tvfsExecTcl(
|
|||||||
){
|
){
|
||||||
int rc; /* Return code from Tcl_EvalObj() */
|
int rc; /* Return code from Tcl_EvalObj() */
|
||||||
int nArg; /* Elements in eval'd list */
|
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] = Tcl_NewStringObj(zMethod, -1);
|
||||||
p->apScript[p->nScript+1] = arg1;
|
p->apScript[p->nScript+1] = arg1;
|
||||||
@ -451,6 +484,18 @@ static int tvfsResultCode(Testvfs *p, int *pRc){
|
|||||||
return 0;
|
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(
|
static int tvfsShmOpen(
|
||||||
sqlite3_file *pFileDes
|
sqlite3_file *pFileDes
|
||||||
){
|
){
|
||||||
@ -474,16 +519,25 @@ static int tvfsShmOpen(
|
|||||||
** script is used as the connection name.
|
** script is used as the connection name.
|
||||||
*/
|
*/
|
||||||
Tcl_ResetResult(p->interp);
|
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);
|
tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0);
|
||||||
}
|
|
||||||
if( tvfsResultCode(p, &rc) ){
|
if( tvfsResultCode(p, &rc) ){
|
||||||
if( rc!=SQLITE_OK ) return rc;
|
if( rc!=SQLITE_OK ) return rc;
|
||||||
pId = Tcl_NewStringObj("anon", -1);
|
|
||||||
}else{
|
}else{
|
||||||
pId = Tcl_GetObjResult(p->interp);
|
pId = Tcl_GetObjResult(p->interp);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if( !pId ){
|
||||||
|
pId = Tcl_NewStringObj("anon", -1);
|
||||||
|
}
|
||||||
Tcl_IncrRefCount(pId);
|
Tcl_IncrRefCount(pId);
|
||||||
|
|
||||||
|
assert( rc==SQLITE_OK );
|
||||||
|
if( p->mask&TESTVFS_SHMOPEN_MASK && tvfsInjectIoerr(p) ){
|
||||||
|
Tcl_DecrRefCount(pId);
|
||||||
|
return SQLITE_IOERR;
|
||||||
|
}
|
||||||
|
|
||||||
pFd->pShmId = pId;
|
pFd->pShmId = pId;
|
||||||
|
|
||||||
/* Search for a TestvfsBuffer. Create a new one if required. */
|
/* Search for a TestvfsBuffer. Create a new one if required. */
|
||||||
@ -515,12 +569,15 @@ static int tvfsShmSize(
|
|||||||
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||||
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
|
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
|
||||||
|
|
||||||
if( p->mask&TESTVFS_SHMSIZE_MASK ){
|
if( p->pScript && p->mask&TESTVFS_SHMSIZE_MASK ){
|
||||||
tvfsExecTcl(p, "xShmSize",
|
tvfsExecTcl(p, "xShmSize",
|
||||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
||||||
);
|
);
|
||||||
tvfsResultCode(p, &rc);
|
tvfsResultCode(p, &rc);
|
||||||
}
|
}
|
||||||
|
if( rc==SQLITE_OK && p->mask&TESTVFS_SHMSIZE_MASK && tvfsInjectIoerr(p) ){
|
||||||
|
rc = SQLITE_IOERR;
|
||||||
|
}
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
tvfsGrowBuffer(pFd, reqSize, pNewSize);
|
tvfsGrowBuffer(pFd, reqSize, pNewSize);
|
||||||
}
|
}
|
||||||
@ -537,12 +594,15 @@ static int tvfsShmGet(
|
|||||||
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||||
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
|
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
|
||||||
|
|
||||||
if( p->mask&TESTVFS_SHMGET_MASK ){
|
if( p->pScript && p->mask&TESTVFS_SHMGET_MASK ){
|
||||||
tvfsExecTcl(p, "xShmGet",
|
tvfsExecTcl(p, "xShmGet",
|
||||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
||||||
);
|
);
|
||||||
tvfsResultCode(p, &rc);
|
tvfsResultCode(p, &rc);
|
||||||
}
|
}
|
||||||
|
if( rc==SQLITE_OK && p->mask&TESTVFS_SHMGET_MASK && tvfsInjectIoerr(p) ){
|
||||||
|
rc = SQLITE_IOERR;
|
||||||
|
}
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
tvfsGrowBuffer(pFd, reqMapSize, pMapSize);
|
tvfsGrowBuffer(pFd, reqMapSize, pMapSize);
|
||||||
*pp = pFd->pShm->a;
|
*pp = pFd->pShm->a;
|
||||||
@ -555,7 +615,7 @@ static int tvfsShmRelease(sqlite3_file *pFile){
|
|||||||
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||||
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
|
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
|
||||||
|
|
||||||
if( p->mask&TESTVFS_SHMRELEASE_MASK ){
|
if( p->pScript && p->mask&TESTVFS_SHMRELEASE_MASK ){
|
||||||
tvfsExecTcl(p, "xShmRelease",
|
tvfsExecTcl(p, "xShmRelease",
|
||||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
||||||
);
|
);
|
||||||
@ -577,7 +637,7 @@ static int tvfsShmLock(
|
|||||||
int nLock;
|
int nLock;
|
||||||
char zLock[80];
|
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);
|
sqlite3_snprintf(sizeof(zLock), zLock, "%d %d", ofst, n);
|
||||||
nLock = strlen(zLock);
|
nLock = strlen(zLock);
|
||||||
if( flags & SQLITE_SHM_LOCK ){
|
if( flags & SQLITE_SHM_LOCK ){
|
||||||
@ -604,7 +664,7 @@ static void tvfsShmBarrier(sqlite3_file *pFile){
|
|||||||
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
TestvfsFile *pFd = (TestvfsFile *)pFile;
|
||||||
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
|
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
|
||||||
|
|
||||||
if( p->mask&TESTVFS_SHMBARRIER_MASK ){
|
if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){
|
||||||
tvfsExecTcl(p, "xShmBarrier",
|
tvfsExecTcl(p, "xShmBarrier",
|
||||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
||||||
);
|
);
|
||||||
@ -625,7 +685,7 @@ static int tvfsShmClose(
|
|||||||
assert( (deleteFlag!=0)==(pBuffer->nRef==1) );
|
assert( (deleteFlag!=0)==(pBuffer->nRef==1) );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( p->mask&TESTVFS_SHMCLOSE_MASK ){
|
if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){
|
||||||
tvfsExecTcl(p, "xShmClose",
|
tvfsExecTcl(p, "xShmClose",
|
||||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
||||||
);
|
);
|
||||||
@ -655,8 +715,13 @@ static int testvfs_obj_cmd(
|
|||||||
){
|
){
|
||||||
Testvfs *p = (Testvfs *)cd;
|
Testvfs *p = (Testvfs *)cd;
|
||||||
|
|
||||||
static const char *CMD_strs[] = { "shm", "delete", "filter", "ioerr", 0 };
|
static const char *CMD_strs[] = {
|
||||||
enum DB_enum { CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR };
|
"shm", "delete", "filter", "ioerr", "script", 0
|
||||||
|
};
|
||||||
|
enum DB_enum {
|
||||||
|
CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT
|
||||||
|
};
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( objc<2 ){
|
if( objc<2 ){
|
||||||
@ -738,22 +803,55 @@ static int testvfs_obj_cmd(
|
|||||||
break;
|
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: {
|
case CMD_IOERR: {
|
||||||
int iRet = ((p->iIoerrCnt<0) ? (1+(p->iIoerrCnt*-1)) : 0);
|
int iRet = p->nIoerrFail;
|
||||||
if( objc==2 ){
|
|
||||||
|
p->nIoerrFail = 0;
|
||||||
p->ioerr = 0;
|
p->ioerr = 0;
|
||||||
p->iIoerrCnt = 0;
|
p->iIoerrCnt = 0;
|
||||||
}else if( objc==4 ){
|
|
||||||
|
if( objc==4 ){
|
||||||
int iCnt, iPersist;
|
int iCnt, iPersist;
|
||||||
if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iCnt)
|
if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iCnt)
|
||||||
|| TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &iPersist)
|
|| TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &iPersist)
|
||||||
){
|
){
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
p->ioerr = (iPersist!=0) + 1;
|
p->ioerr = (iCnt>0) + iPersist;
|
||||||
p->iIoerrCnt = iCnt;
|
p->iIoerrCnt = iCnt;
|
||||||
}else{
|
}else if( objc!=2 ){
|
||||||
Tcl_AppendResult(interp, "Bad args", 0);
|
Tcl_AppendResult(interp, "Bad args", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet));
|
Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet));
|
||||||
break;
|
break;
|
||||||
@ -769,20 +867,21 @@ static int testvfs_obj_cmd(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void testvfs_obj_del(ClientData cd){
|
static void testvfs_obj_del(ClientData cd){
|
||||||
int i;
|
|
||||||
Testvfs *p = (Testvfs *)cd;
|
Testvfs *p = (Testvfs *)cd;
|
||||||
for(i=0; i<p->nScript; i++){
|
if( p->pScript ) Tcl_DecrRefCount(p->pScript);
|
||||||
Tcl_DecrRefCount(p->apScript[i]);
|
|
||||||
}
|
|
||||||
sqlite3_vfs_unregister(p->pVfs);
|
sqlite3_vfs_unregister(p->pVfs);
|
||||||
|
ckfree((char *)p->apScript);
|
||||||
ckfree((char *)p->pVfs);
|
ckfree((char *)p->pVfs);
|
||||||
ckfree((char *)p);
|
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
|
** 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
|
** 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 */
|
Testvfs *p; /* New object */
|
||||||
sqlite3_vfs *pVfs; /* New VFS */
|
sqlite3_vfs *pVfs; /* New VFS */
|
||||||
char *zVfs;
|
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 nByte; /* Bytes of space to allocate at p */
|
||||||
int i; /* Counter variable */
|
|
||||||
|
int i;
|
||||||
int isNoshm = 0; /* True if -noshm is passed */
|
int isNoshm = 0; /* True if -noshm is passed */
|
||||||
|
int isDefault = 0; /* True if -default is passed */
|
||||||
|
|
||||||
if( objc<3 ) goto bad_args;
|
if( objc<2 || 0!=(objc%2) ) goto bad_args;
|
||||||
if( strcmp(Tcl_GetString(objv[1]), "-noshm")==0 ){
|
for(i=2; i<objc; i += 2){
|
||||||
isNoshm = 1;
|
int nSwitch;
|
||||||
}
|
char *zSwitch;
|
||||||
if( objc!=3+isNoshm ) goto bad_args;
|
|
||||||
zVfs = Tcl_GetString(objv[isNoshm+1]);
|
|
||||||
pScript = objv[isNoshm+2];
|
|
||||||
|
|
||||||
if( TCL_OK!=Tcl_ListObjGetElements(interp, pScript, &nScript, &apScript) ){
|
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;
|
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)
|
zVfs = Tcl_GetString(objv[1]);
|
||||||
+ (nScript+TESTVFS_MAX_ARGS)*sizeof(Tcl_Obj *)
|
nByte = sizeof(Testvfs) + strlen(zVfs)+1;
|
||||||
+ strlen(zVfs)+1;
|
|
||||||
p = (Testvfs *)ckalloc(nByte);
|
p = (Testvfs *)ckalloc(nByte);
|
||||||
memset(p, 0, nByte);
|
memset(p, 0, nByte);
|
||||||
|
|
||||||
p->pParent = sqlite3_vfs_find(0);
|
p->pParent = sqlite3_vfs_find(0);
|
||||||
p->interp = interp;
|
p->interp = interp;
|
||||||
p->nScript = nScript;
|
|
||||||
p->apScript = (Tcl_Obj **)&p[1];
|
p->zName = (char *)&p[1];
|
||||||
for(i=0; i<nScript; i++){
|
memcpy(p->zName, zVfs, strlen(zVfs)+1);
|
||||||
p->apScript[i] = apScript[i];
|
|
||||||
Tcl_IncrRefCount(p->apScript[i]);
|
|
||||||
}
|
|
||||||
p->zName = (char *)&p->apScript[nScript+TESTVFS_MAX_ARGS];
|
|
||||||
strcpy(p->zName, zVfs);
|
|
||||||
|
|
||||||
pVfs = (sqlite3_vfs *)ckalloc(sizeof(sqlite3_vfs));
|
pVfs = (sqlite3_vfs *)ckalloc(sizeof(sqlite3_vfs));
|
||||||
memcpy(pVfs, &tvfs_vfs, sizeof(sqlite3_vfs));
|
memcpy(pVfs, &tvfs_vfs, sizeof(sqlite3_vfs));
|
||||||
@ -899,12 +1000,12 @@ static int testvfs_cmd(
|
|||||||
p->mask = TESTVFS_ALL_MASK;
|
p->mask = TESTVFS_ALL_MASK;
|
||||||
|
|
||||||
Tcl_CreateObjCommand(interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del);
|
Tcl_CreateObjCommand(interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del);
|
||||||
sqlite3_vfs_register(pVfs, 0);
|
sqlite3_vfs_register(pVfs, isDefault);
|
||||||
|
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
|
|
||||||
bad_args:
|
bad_args:
|
||||||
Tcl_WrongNumArgs(interp, 1, objv, "?-noshm? VFSNAME SCRIPT");
|
Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-default BOOL?");
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,50 @@ ifcapable builtin_test {
|
|||||||
return 0
|
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...?
|
# Usage do_faultsim_test NAME ?OPTIONS...?
|
||||||
@ -36,10 +80,9 @@ ifcapable builtin_test {
|
|||||||
# -test Script to execute after -body.
|
# -test Script to execute after -body.
|
||||||
#
|
#
|
||||||
proc do_faultsim_test {name args} {
|
proc do_faultsim_test {name args} {
|
||||||
set DEFAULT(-faults) [list \
|
global FAULTSIM
|
||||||
oom-transient oom-persistent \
|
|
||||||
ioerr-transient ioerr-persistent \
|
set DEFAULT(-faults) [array names FAULTSIM]
|
||||||
]
|
|
||||||
set DEFAULT(-prep) ""
|
set DEFAULT(-prep) ""
|
||||||
set DEFAULT(-body) ""
|
set DEFAULT(-body) ""
|
||||||
set DEFAULT(-test) ""
|
set DEFAULT(-test) ""
|
||||||
@ -50,35 +93,16 @@ proc do_faultsim_test {name args} {
|
|||||||
if {[info exists DEFAULT($o)]==0} { error "unknown option: $o" }
|
if {[info exists DEFAULT($o)]==0} { error "unknown option: $o" }
|
||||||
}
|
}
|
||||||
|
|
||||||
set A(oom-transient) [list \
|
set faultlist [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}}} \
|
|
||||||
]
|
|
||||||
|
|
||||||
foreach f $O(-faults) {
|
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)]
|
set testspec [list -prep $O(-prep) -body $O(-body) -test $O(-test)]
|
||||||
foreach f $O(-faults) {
|
foreach f [lsort -unique $faultlist] {
|
||||||
eval do_one_faultsim_test "$name-$f" $A($f) $testspec
|
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
|
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" }
|
||||||
|
}
|
||||||
|
|
||||||
# The following procs are used as [do_faultsim_test] when injecting OOM
|
proc faultsim_delete_and_reopen {{file test.db}} {
|
||||||
# faults into test cases.
|
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_one_faultsim_test] callbacks when
|
||||||
|
# injecting OOM faults into test cases.
|
||||||
#
|
#
|
||||||
proc oom_injectstart {nRepeat iFail} {
|
proc oom_injectstart {nRepeat iFail} {
|
||||||
sqlite3_memdebug_fail $iFail -repeat $nRepeat
|
sqlite3_memdebug_fail $iFail -repeat $nRepeat
|
||||||
@ -132,6 +167,9 @@ proc oom_injectstop {} {
|
|||||||
sqlite3_memdebug_fail -1
|
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} {
|
proc ioerr_injectstart {persist iFail} {
|
||||||
set ::sqlite_io_error_persist $persist
|
set ::sqlite_io_error_persist $persist
|
||||||
set ::sqlite_io_error_pending $iFail
|
set ::sqlite_io_error_pending $iFail
|
||||||
@ -146,6 +184,24 @@ proc ioerr_injectstop {} {
|
|||||||
return $sv
|
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
|
# This command is not called directly. It is used by the
|
||||||
# [faultsim_test_result] command created by [do_faultsim_test] and used
|
# [faultsim_test_result] command created by [do_faultsim_test] and used
|
||||||
# by -test scripts.
|
# by -test scripts.
|
||||||
@ -173,6 +229,10 @@ proc faultsim_test_result_int {args} {
|
|||||||
# -injecterrlist List of generally acceptable test results (i.e. error
|
# -injecterrlist List of generally acceptable test results (i.e. error
|
||||||
# messages). Example: [list {1 {out of memory}}]
|
# messages). Example: [list {1 {out of memory}}]
|
||||||
#
|
#
|
||||||
|
# -injectinstall
|
||||||
|
#
|
||||||
|
# -injectuninstall
|
||||||
|
#
|
||||||
# -prep Script to execute before -body.
|
# -prep Script to execute before -body.
|
||||||
#
|
#
|
||||||
# -body Script to execute (with fault injection).
|
# -body Script to execute (with fault injection).
|
||||||
@ -181,9 +241,11 @@ proc faultsim_test_result_int {args} {
|
|||||||
#
|
#
|
||||||
proc do_one_faultsim_test {testname args} {
|
proc do_one_faultsim_test {testname args} {
|
||||||
|
|
||||||
set DEFAULT(-injectstart) {oom_injectstart 0}
|
set DEFAULT(-injectstart) "expr"
|
||||||
set DEFAULT(-injectstop) {oom_injectstop}
|
set DEFAULT(-injectstop) "expr 0"
|
||||||
set DEFAULT(-injecterrlist) [list {1 {out of memory}}]
|
set DEFAULT(-injecterrlist) [list]
|
||||||
|
set DEFAULT(-injectinstall) ""
|
||||||
|
set DEFAULT(-injectuninstall) ""
|
||||||
set DEFAULT(-prep) ""
|
set DEFAULT(-prep) ""
|
||||||
set DEFAULT(-body) ""
|
set DEFAULT(-body) ""
|
||||||
set DEFAULT(-test) ""
|
set DEFAULT(-test) ""
|
||||||
@ -199,6 +261,8 @@ proc do_one_faultsim_test {testname args} {
|
|||||||
uplevel faultsim_test_result_int \$args [list $O(-injecterrlist)]
|
uplevel faultsim_test_result_int \$args [list $O(-injecterrlist)]
|
||||||
"
|
"
|
||||||
|
|
||||||
|
eval $O(-injectinstall)
|
||||||
|
|
||||||
set stop 0
|
set stop 0
|
||||||
for {set iFail 1} {!$stop} {incr iFail} {
|
for {set iFail 1} {!$stop} {incr iFail} {
|
||||||
|
|
||||||
@ -228,6 +292,8 @@ proc do_one_faultsim_test {testname args} {
|
|||||||
#
|
#
|
||||||
if {$nfail==0} { set stop 1 }
|
if {$nfail==0} { set stop 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eval $O(-injectuninstall)
|
||||||
}
|
}
|
||||||
|
|
||||||
# Usage: do_malloc_test <test number> <options...>
|
# Usage: do_malloc_test <test number> <options...>
|
||||||
|
@ -72,7 +72,8 @@ proc incr_tvfs_hdr {file idx incrval} {
|
|||||||
#
|
#
|
||||||
do_test wal2-1.0 {
|
do_test wal2-1.0 {
|
||||||
proc tvfs_cb {method args} { return SQLITE_OK }
|
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 db test.db -vfs tvfs
|
||||||
sqlite3 db2 test.db -vfs tvfs
|
sqlite3 db2 test.db -vfs tvfs
|
||||||
@ -166,7 +167,8 @@ set LOCKS [list \
|
|||||||
]
|
]
|
||||||
do_test wal2-2.0 {
|
do_test wal2-2.0 {
|
||||||
|
|
||||||
testvfs tvfs tvfs_cb
|
testvfs tvfs
|
||||||
|
tvfs script tvfs_cb
|
||||||
proc tvfs_cb {method args} {
|
proc tvfs_cb {method args} {
|
||||||
if {$method == "xShmOpen"} { set ::shm_file [lindex $args 0] }
|
if {$method == "xShmOpen"} { set ::shm_file [lindex $args 0] }
|
||||||
return SQLITE_OK
|
return SQLITE_OK
|
||||||
@ -281,7 +283,8 @@ do_test wal2-3.0 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
testvfs tvfs tvfs_cb
|
testvfs tvfs
|
||||||
|
tvfs script tvfs_cb
|
||||||
sqlite3 db test.db -vfs tvfs
|
sqlite3 db test.db -vfs tvfs
|
||||||
db busy busyhandler
|
db busy busyhandler
|
||||||
|
|
||||||
@ -348,15 +351,13 @@ do_test wal2-4.1 {
|
|||||||
} {wal}
|
} {wal}
|
||||||
do_test wal2-4.2 {
|
do_test wal2-4.2 {
|
||||||
db close
|
db close
|
||||||
proc ok {args} {return SQLITE_OK}
|
testvfs tvfs -noshm 1
|
||||||
testvfs -noshm tvfs ok
|
|
||||||
sqlite3 db test.db -vfs tvfs
|
sqlite3 db test.db -vfs tvfs
|
||||||
catchsql { SELECT * FROM data }
|
catchsql { SELECT * FROM data }
|
||||||
} {1 {unable to open database file}}
|
} {1 {unable to open database file}}
|
||||||
do_test wal2-4.3 {
|
do_test wal2-4.3 {
|
||||||
db close
|
db close
|
||||||
proc ok {args} {return SQLITE_OK}
|
testvfs tvfs
|
||||||
testvfs tvfs ok
|
|
||||||
sqlite3 db test.db -vfs tvfs
|
sqlite3 db test.db -vfs tvfs
|
||||||
catchsql { SELECT * FROM data }
|
catchsql { SELECT * FROM data }
|
||||||
} {0 {{need xShmOpen to see this}}}
|
} {0 {{need xShmOpen to see this}}}
|
||||||
@ -388,7 +389,8 @@ do_test wal2-5.1 {
|
|||||||
}
|
}
|
||||||
set tvfs_cb_return SQLITE_OK
|
set tvfs_cb_return SQLITE_OK
|
||||||
|
|
||||||
testvfs tvfs tvfs_cb
|
testvfs tvfs
|
||||||
|
tvfs script tvfs_cb
|
||||||
|
|
||||||
sqlite3 db test.db -vfs tvfs
|
sqlite3 db test.db -vfs tvfs
|
||||||
execsql {
|
execsql {
|
||||||
@ -578,7 +580,8 @@ do_test wal2-6.4.1 {
|
|||||||
if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] }
|
if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] }
|
||||||
return "SQLITE_OK"
|
return "SQLITE_OK"
|
||||||
}
|
}
|
||||||
testvfs tvfs tvfs_cb
|
testvfs tvfs
|
||||||
|
tvfs script tvfs_cb
|
||||||
sqlite3 db test.db -vfs tvfs
|
sqlite3 db test.db -vfs tvfs
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
|
@ -91,13 +91,8 @@ do_faultsim_test walfault-2 -prep {
|
|||||||
} -body {
|
} -body {
|
||||||
execsql { SELECT count(*) FROM x }
|
execsql { SELECT count(*) FROM x }
|
||||||
} -test {
|
} -test {
|
||||||
|
|
||||||
faultsim_test_result {0 8}
|
faultsim_test_result {0 8}
|
||||||
|
faultsim_integrity_check
|
||||||
# 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" }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
@ -126,92 +121,39 @@ do_faultsim_test walfault-3 -prep {
|
|||||||
faultsim_test_result {0 {}}
|
faultsim_test_result {0 {}}
|
||||||
}
|
}
|
||||||
|
|
||||||
# A [testvfs] callback for the VFS created by [do_shmfault_test]. This
|
file delete -force test.db test.db-wal test.db-journal
|
||||||
# callback injects SQLITE_IOERR faults into methods for which an entry
|
faultsim_save_and_close
|
||||||
# in array ::shmfault_ioerr_methods is defined. For example, to enable
|
do_faultsim_test walfault-4 -prep {
|
||||||
# errors in xShmOpen:
|
faultsim_restore_and_reopen
|
||||||
#
|
} -body {
|
||||||
# set ::shmfault_ioerr_methods(xShmOpen) 1
|
execsql {
|
||||||
#
|
|
||||||
# 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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shmfault delete
|
|
||||||
}
|
|
||||||
|
|
||||||
do_shmfault_test walfault-shm-1 -sqlbody {
|
|
||||||
PRAGMA journal_mode = WAL;
|
PRAGMA journal_mode = WAL;
|
||||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||||
INSERT INTO t1 VALUES('a', 'b');
|
INSERT INTO t1 VALUES('a', 'b');
|
||||||
PRAGMA wal_checkpoint;
|
PRAGMA wal_checkpoint;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
}
|
||||||
|
} -test {
|
||||||
|
faultsim_test_result {0 {wal a b}}
|
||||||
|
faultsim_integrity_check
|
||||||
}
|
}
|
||||||
|
|
||||||
do_shmfault_test walfault-shm-2 -methods xShmSize -sqlprep {
|
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 page_size = 512;
|
||||||
PRAGMA journal_mode = WAL;
|
PRAGMA journal_mode = WAL;
|
||||||
PRAGMA wal_autocheckpoint = 0;
|
}
|
||||||
} -sqlbody {
|
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);
|
CREATE TABLE t1(x);
|
||||||
BEGIN;
|
BEGIN;
|
||||||
INSERT INTO t1 VALUES(randomblob(400)); /* 1 */
|
INSERT INTO t1 VALUES(randomblob(400)); /* 1 */
|
||||||
@ -230,12 +172,19 @@ do_shmfault_test walfault-shm-2 -methods xShmSize -sqlprep {
|
|||||||
INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */
|
INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 8192 */
|
||||||
INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */
|
INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
SELECT count(*) FROM t1;
|
||||||
|
}
|
||||||
|
} -test {
|
||||||
|
faultsim_test_result {0 16384}
|
||||||
|
faultsim_integrity_check
|
||||||
}
|
}
|
||||||
|
|
||||||
do_shmfault_test walfault-shm-3 -methods xShmSize -tclprep {
|
|
||||||
sqlite3 db test.db -vfs shmfault
|
do_test walfault-6-pre-1 {
|
||||||
shmfault filter {}
|
catch { db close }
|
||||||
db eval {
|
file delete -force test.db test.db-wal test.db-journal
|
||||||
|
sqlite3 db test.db
|
||||||
|
execsql {
|
||||||
PRAGMA page_size = 512;
|
PRAGMA page_size = 512;
|
||||||
PRAGMA journal_mode = WAL;
|
PRAGMA journal_mode = WAL;
|
||||||
PRAGMA wal_autocheckpoint = 0;
|
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 */
|
INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 16384 */
|
||||||
COMMIT;
|
COMMIT;
|
||||||
}
|
}
|
||||||
|
faultsim_save_and_close
|
||||||
set ::shmfault_ioerr_countdown 1
|
} {}
|
||||||
shmfault filter xShmGet
|
do_faultsim_test walfault-6 -faults shmerr* -prep {
|
||||||
db close
|
faultsim_restore_and_reopen
|
||||||
shmfault filter {}
|
shmfault filter xShmSize
|
||||||
if {[file exists test.db-wal]==0} {error "Failed to create WAL file!"}
|
} -body {
|
||||||
|
execsql { SELECT count(*) FROM t1 }
|
||||||
sqlite3 db test.db -vfs shmfault
|
} -test {
|
||||||
} -sqlbody {
|
faultsim_test_result {0 16384}
|
||||||
SELECT count(*) FROM t1;
|
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 {
|
do_test walfault-7-pre-1 {
|
||||||
sqlite3 db test.db -vfs shmfault
|
faultsim_delete_and_reopen
|
||||||
unset -nocomplain ::shmfault_ioerr_countdown
|
execsql {
|
||||||
db eval {
|
|
||||||
PRAGMA page_size = 512;
|
PRAGMA page_size = 512;
|
||||||
PRAGMA journal_mode = WAL;
|
PRAGMA journal_mode = WAL;
|
||||||
PRAGMA wal_autocheckpoint = 0;
|
PRAGMA wal_autocheckpoint = 0;
|
||||||
@ -284,37 +234,68 @@ do_shmfault_test walfault-shm-4 -tclprep {
|
|||||||
INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */
|
INSERT INTO t1 SELECT randomblob(400) FROM t1; /* 4 */
|
||||||
COMMIT;
|
COMMIT;
|
||||||
}
|
}
|
||||||
|
faultsim_save_and_close
|
||||||
set ::shmfault_ioerr_countdown 1
|
} {}
|
||||||
shmfault filter xShmGet
|
do_faultsim_test walfault-7 -prep {
|
||||||
db close
|
faultsim_restore_and_reopen
|
||||||
shmfault filter {}
|
} -body {
|
||||||
if {[file exists test.db-wal]==0} {error "Failed to create WAL file!"}
|
execsql { SELECT count(*) FROM t1 }
|
||||||
sqlite3 db test.db -vfs shmfault
|
} -test {
|
||||||
} -sqlbody {
|
faultsim_test_result {0 4}
|
||||||
SELECT count(*) FROM t1;
|
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 {
|
do_test walfault-8-pre-1 {
|
||||||
PRAGMA cache_size = 10;
|
faultsim_delete_and_reopen
|
||||||
|
execsql {
|
||||||
PRAGMA journal_mode = WAL;
|
PRAGMA journal_mode = WAL;
|
||||||
CREATE TABLE abc(a PRIMARY KEY);
|
CREATE TABLE abc(a PRIMARY KEY);
|
||||||
INSERT INTO abc VALUES(randomblob(900));
|
INSERT INTO abc VALUES(randomblob(900));
|
||||||
} -sqlbody {
|
}
|
||||||
|
faultsim_save_and_close
|
||||||
|
} {}
|
||||||
|
do_faultsim_test walfault-8 -prep {
|
||||||
|
faultsim_restore_and_reopen
|
||||||
|
execsql { PRAGMA cache_size = 10 }
|
||||||
|
} -body {
|
||||||
|
execsql {
|
||||||
BEGIN;
|
BEGIN;
|
||||||
INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */
|
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; /* 2 */
|
||||||
INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */
|
--INSERT INTO abc SELECT randomblob(900) FROM abc; /* 4 */
|
||||||
INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */
|
--INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */
|
||||||
ROLLBACK;
|
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 {
|
do_test walfault-9-pre-1 {
|
||||||
PRAGMA cache_size = 10;
|
faultsim_delete_and_reopen
|
||||||
|
execsql {
|
||||||
PRAGMA journal_mode = WAL;
|
PRAGMA journal_mode = WAL;
|
||||||
CREATE TABLE abc(a PRIMARY KEY);
|
CREATE TABLE abc(a PRIMARY KEY);
|
||||||
INSERT INTO abc VALUES(randomblob(900));
|
INSERT INTO abc VALUES(randomblob(900));
|
||||||
} -sqlbody {
|
}
|
||||||
|
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;
|
BEGIN;
|
||||||
INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */
|
INSERT INTO abc SELECT randomblob(900) FROM abc; /* 1 */
|
||||||
SAVEPOINT spoint;
|
SAVEPOINT spoint;
|
||||||
@ -323,6 +304,16 @@ do_shmfault_test walfault-shm-5.2 -coverageonly 1 -sqlprep {
|
|||||||
INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */
|
INSERT INTO abc SELECT randomblob(900) FROM abc; /* 8 */
|
||||||
ROLLBACK TO spoint;
|
ROLLBACK TO spoint;
|
||||||
COMMIT;
|
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 {
|
do_test walfault-shm-6.1 {
|
||||||
set ::shm_state 0
|
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 db test.db -vfs tvfs
|
||||||
sqlite3 db2 test.db -vfs tvfs
|
sqlite3 db2 test.db -vfs tvfs
|
||||||
|
Reference in New Issue
Block a user