mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Add some fault-injection tests to improve coverage.
FossilOrigin-Name: 37b26d125f4b1d8e75bb38800fefd145611f94aa
This commit is contained in:
16
manifest
16
manifest
@@ -1,5 +1,5 @@
|
||||
C Fix\ssome\sproblems\swith\shandling\sIO\serrors\son\sthe\sexperimental\sbranch.
|
||||
D 2010-06-12T12:02:36
|
||||
C Add\ssome\sfault-injection\stests\sto\simprove\scoverage.
|
||||
D 2010-06-14T07:53:26
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@@ -209,7 +209,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 c3643e985b000e1f7555bd843a508512a33ab60e
|
||||
F src/test_vfs.c 15bddcddf6b1bf6360130e09aee950f5f563d5f3
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
|
||||
F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d
|
||||
@@ -226,7 +226,7 @@ F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
|
||||
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
|
||||
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
|
||||
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
|
||||
F src/wal.c ca3e0bf68c78005dee4e0d44d112e26975476d10
|
||||
F src/wal.c 75c55049c0923418f10bbef842b846374637b595
|
||||
F src/wal.h 4ace25262452d17e7d3ec970c89ee17794004008
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 1c895bef33d0dfc7ed90fb1f74120435d210ea56
|
||||
@@ -772,7 +772,7 @@ F test/walbak.test e7650a26eb4b8abeca9b145b1af1e63026dde432
|
||||
F test/walcksum.test 4efa8fb88c32bed8288ea4385a9cc113a5c8f0bf
|
||||
F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
|
||||
F test/walcrash2.test 14585ad1a2c85da2de721caa3b4deeea55213008
|
||||
F test/walfault.test 0f9524cedbba0e5d48b58cabdc2dd7ae2c375476
|
||||
F test/walfault.test f6c1d0eade34fd0102e083726092d9bebd48bf7b
|
||||
F test/walhook.test 67e675127f4acb72f061a12667ce6e5460b06b78
|
||||
F test/walmode.test 6ca9d710cc9f6545b913abcded6d6b0b15641048
|
||||
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
|
||||
@@ -820,7 +820,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P ca68472db01c14a899892007d1cbaff5e86ae193
|
||||
R 8c9eec4fce430c14365187b617d56771
|
||||
P eade8bc238df580412f5cf1b91a91532ae671e46
|
||||
R d24014573c5813c3e5f096c2f4031503
|
||||
U dan
|
||||
Z 808594079cf8cc56f07144318e40eca2
|
||||
Z e43653a42fa5b8fa5bb9c7db25e1bbd8
|
||||
|
@@ -1 +1 @@
|
||||
eade8bc238df580412f5cf1b91a91532ae671e46
|
||||
37b26d125f4b1d8e75bb38800fefd145611f94aa
|
@@ -659,6 +659,7 @@ static int tvfsShmPage(
|
||||
|
||||
if( p->pScript && p->mask&TESTVFS_SHMPAGE_MASK ){
|
||||
Tcl_Obj *pArg = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(pArg);
|
||||
Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(iPage));
|
||||
Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(pgsz));
|
||||
Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(isWrite));
|
||||
@@ -666,6 +667,7 @@ static int tvfsShmPage(
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, pArg
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
Tcl_DecrRefCount(pArg);
|
||||
}
|
||||
if( rc==SQLITE_OK && p->mask&TESTVFS_SHMPAGE_MASK && tvfsInjectIoerr(p) ){
|
||||
rc = SQLITE_IOERR;
|
||||
@@ -828,12 +830,17 @@ static int testvfs_obj_cmd(
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "FILE ?VALUE?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zName = Tcl_GetString(objv[2]);
|
||||
zName = ckalloc(p->pParent->mxPathname);
|
||||
p->pParent->xFullPathname(
|
||||
p->pParent, Tcl_GetString(objv[2]),
|
||||
p->pParent->mxPathname, zName
|
||||
);
|
||||
for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){
|
||||
if( 0==strcmp(pBuffer->zFile, zName) ) break;
|
||||
}
|
||||
ckfree(zName);
|
||||
if( !pBuffer ){
|
||||
Tcl_AppendResult(interp, "no such file: ", zName, 0);
|
||||
Tcl_AppendResult(interp, "no such file: ", Tcl_GetString(objv[2]), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( objc==4 ){
|
||||
@@ -870,6 +877,7 @@ static int testvfs_obj_cmd(
|
||||
{ "xShmLock", TESTVFS_SHMLOCK_MASK },
|
||||
{ "xShmBarrier", TESTVFS_SHMBARRIER_MASK },
|
||||
{ "xShmClose", TESTVFS_SHMCLOSE_MASK },
|
||||
{ "xShmPage", TESTVFS_SHMPAGE_MASK },
|
||||
{ "xSync", TESTVFS_SYNC_MASK },
|
||||
{ "xOpen", TESTVFS_OPEN_MASK },
|
||||
};
|
||||
@@ -911,6 +919,7 @@ static int testvfs_obj_cmd(
|
||||
ckfree((char *)p->apScript);
|
||||
p->apScript = 0;
|
||||
p->nScript = 0;
|
||||
p->pScript = 0;
|
||||
}
|
||||
Tcl_GetStringFromObj(objv[2], &nByte);
|
||||
if( nByte>0 ){
|
||||
@@ -1083,6 +1092,13 @@ static int testvfs_cmd(
|
||||
p = (Testvfs *)ckalloc(nByte);
|
||||
memset(p, 0, nByte);
|
||||
|
||||
/* Create the new object command before querying SQLite for a default VFS
|
||||
** to use for 'real' IO operations. This is because creating the new VFS
|
||||
** may delete an existing [testvfs] VFS of the same name. If such a VFS
|
||||
** is currently the default, the new [testvfs] may end up calling the
|
||||
** methods of a deleted object.
|
||||
*/
|
||||
Tcl_CreateObjCommand(interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del);
|
||||
p->pParent = sqlite3_vfs_find(0);
|
||||
p->interp = interp;
|
||||
|
||||
@@ -1099,7 +1115,6 @@ static int testvfs_cmd(
|
||||
p->isNoshm = isNoshm;
|
||||
p->mask = TESTVFS_ALL_MASK;
|
||||
|
||||
Tcl_CreateObjCommand(interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del);
|
||||
sqlite3_vfs_register(pVfs, isDefault);
|
||||
|
||||
return TCL_OK;
|
||||
|
66
src/wal.c
66
src/wal.c
@@ -1281,6 +1281,13 @@ static void walMergesort(
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Free an iterator allocated by walIteratorInit().
|
||||
*/
|
||||
static void walIteratorFree(WalIterator *p){
|
||||
sqlite3_free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Map the wal-index into memory owned by this thread, if it is not
|
||||
** mapped already. Then construct a WalInterator object that can be
|
||||
@@ -1337,6 +1344,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
|
||||
|
||||
rc = walHashGet(pWal, i, &aHash, &aPgno, &iZero);
|
||||
if( rc!=SQLITE_OK ){
|
||||
walIteratorFree(p);
|
||||
return rc;
|
||||
}
|
||||
nEntry = ((i+1)==nSegment)?iLast-iZero:(u32 *)aHash-(u32 *)&aPgno[iZero+1];
|
||||
@@ -1361,13 +1369,6 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
|
||||
return SQLITE_OK ;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free an iterator allocated by walIteratorInit().
|
||||
*/
|
||||
static void walIteratorFree(WalIterator *p){
|
||||
sqlite3_free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Copy as much content as we can from the WAL back into the database file
|
||||
** in response to an sqlite3_wal_checkpoint() request or the equivalent.
|
||||
@@ -2076,30 +2077,33 @@ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
|
||||
Pgno iMax = pWal->hdr.mxFrame;
|
||||
Pgno iFrame;
|
||||
|
||||
rc = walIndexReadHdr(pWal, &unused);
|
||||
if( rc==SQLITE_OK ){
|
||||
for(iFrame=pWal->hdr.mxFrame+1;
|
||||
ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
|
||||
iFrame++
|
||||
){
|
||||
/* This call cannot fail. Unless the page for which the page number
|
||||
** is passed as the second argument is (a) in the cache and
|
||||
** (b) has an outstanding reference, then xUndo is either a no-op
|
||||
** (if (a) is false) or simply expels the page from the cache (if (b)
|
||||
** is false).
|
||||
**
|
||||
** If the upper layer is doing a rollback, it is guaranteed that there
|
||||
** are no outstanding references to any page other than page 1. And
|
||||
** page 1 is never written to the log until the transaction is
|
||||
** committed. As a result, the call to xUndo may not fail.
|
||||
*/
|
||||
assert( pWal->writeLock );
|
||||
assert( walFramePgno(pWal, iFrame)!=1 );
|
||||
rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
|
||||
}
|
||||
walCleanupHash(pWal);
|
||||
/* Restore the clients cache of the wal-index header to the state it
|
||||
** was in before the client began writing to the database.
|
||||
*/
|
||||
memcpy(&pWal->hdr, walIndexHdr(pWal), sizeof(WalIndexHdr));
|
||||
|
||||
for(iFrame=pWal->hdr.mxFrame+1;
|
||||
ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
|
||||
iFrame++
|
||||
){
|
||||
/* This call cannot fail. Unless the page for which the page number
|
||||
** is passed as the second argument is (a) in the cache and
|
||||
** (b) has an outstanding reference, then xUndo is either a no-op
|
||||
** (if (a) is false) or simply expels the page from the cache (if (b)
|
||||
** is false).
|
||||
**
|
||||
** If the upper layer is doing a rollback, it is guaranteed that there
|
||||
** are no outstanding references to any page other than page 1. And
|
||||
** page 1 is never written to the log until the transaction is
|
||||
** committed. As a result, the call to xUndo may not fail.
|
||||
*/
|
||||
assert( pWal->writeLock );
|
||||
assert( walFramePgno(pWal, iFrame)!=1 );
|
||||
rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
|
||||
}
|
||||
walCleanupHash(pWal);
|
||||
}
|
||||
assert( rc==SQLITE_OK );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2142,9 +2146,7 @@ int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
|
||||
pWal->hdr.mxFrame = aWalData[0];
|
||||
pWal->hdr.aFrameCksum[0] = aWalData[1];
|
||||
pWal->hdr.aFrameCksum[1] = aWalData[2];
|
||||
if( rc==SQLITE_OK ){
|
||||
walCleanupHash(pWal);
|
||||
}
|
||||
walCleanupHash(pWal);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@@ -120,6 +120,7 @@ do_faultsim_test walfault-3 -prep {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
#
|
||||
faultsim_delete_and_reopen
|
||||
@@ -152,7 +153,7 @@ do_test walfault-5-pre-1 {
|
||||
do_faultsim_test walfault-5 -faults shmerr* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql { PRAGMA wal_autocheckpoint = 0 }
|
||||
shmfault filter xShmSize
|
||||
shmfault filter xShmPage
|
||||
} -body {
|
||||
execsql {
|
||||
CREATE TABLE t1(x);
|
||||
@@ -211,7 +212,7 @@ do_test walfault-6-pre-1 {
|
||||
} {}
|
||||
do_faultsim_test walfault-6 -faults shmerr* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
shmfault filter xShmSize
|
||||
shmfault filter xShmPage
|
||||
} -body {
|
||||
execsql { SELECT count(*) FROM t1 }
|
||||
} -test {
|
||||
@@ -326,7 +327,7 @@ do_test walfault-10-pre1 {
|
||||
faultsim_delete_and_reopen
|
||||
execsql {
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA wal_checkpoint = 0;
|
||||
PRAGMA wal_autocheckpoint = 0;
|
||||
CREATE TABLE z(zz INTEGER PRIMARY KEY, zzz BLOB);
|
||||
CREATE INDEX zzzz ON z(zzz);
|
||||
INSERT INTO z VALUES(NULL, randomblob(800));
|
||||
@@ -363,5 +364,84 @@ do_faultsim_test walfault-10 -prep {
|
||||
if {$n != "64 51200"} { error "Incorrect data: $n" }
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Test fault injection while checkpointing a large WAL file, if the
|
||||
# checkpoint is the first operation run after opening the database.
|
||||
# This means that some of the required wal-index pages are mapped as part of
|
||||
# the checkpoint process, which means there are a few more opportunities
|
||||
# for IO errors.
|
||||
#
|
||||
# To speed this up, IO errors are only simulated within xShmPage() calls.
|
||||
#
|
||||
do_test walfault-11-pre-1 {
|
||||
sqlite3 db test.db
|
||||
execsql {
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA wal_autocheckpoint = 0;
|
||||
BEGIN;
|
||||
CREATE TABLE abc(a PRIMARY KEY);
|
||||
INSERT INTO abc VALUES(randomblob(1500));
|
||||
INSERT INTO abc VALUES(randomblob(1500));
|
||||
INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 4
|
||||
INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 8
|
||||
INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 16
|
||||
INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 32
|
||||
INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 64
|
||||
INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 128
|
||||
INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 256
|
||||
INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 512
|
||||
INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 1024
|
||||
INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 2048
|
||||
INSERT INTO abc SELECT randomblob(1500) FROM abc; -- 4096
|
||||
COMMIT;
|
||||
}
|
||||
faultsim_save_and_close
|
||||
} {}
|
||||
do_faultsim_test walfault-11 -faults shmerr* -prep {
|
||||
catch { db2 close }
|
||||
faultsim_restore_and_reopen
|
||||
shmfault filter xShmPage
|
||||
} -body {
|
||||
db eval { SELECT count(*) FROM abc }
|
||||
sqlite3 db2 test.db -vfs shmfault
|
||||
db2 eval { PRAGMA wal_checkpoint }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the handling of the various IO/OOM/SHM errors that may occur during
|
||||
# a log recovery operation undertaken as part of a call to
|
||||
# sqlite3_wal_checkpoint().
|
||||
#
|
||||
do_test walfault-12-pre-1 {
|
||||
faultsim_delete_and_reopen
|
||||
execsql {
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA wal_autocheckpoint = 0;
|
||||
BEGIN;
|
||||
CREATE TABLE abc(a PRIMARY KEY);
|
||||
INSERT INTO abc VALUES(randomblob(1500));
|
||||
INSERT INTO abc VALUES(randomblob(1500));
|
||||
COMMIT;
|
||||
}
|
||||
faultsim_save_and_close
|
||||
} {}
|
||||
do_faultsim_test walfault-12 -prep {
|
||||
if {[info commands shmfault] == ""} {
|
||||
testvfs shmfault -default true
|
||||
}
|
||||
faultsim_restore_and_reopen
|
||||
db eval { SELECT * FROM sqlite_master }
|
||||
shmfault shm test.db [string repeat "\000" 40]
|
||||
} -body {
|
||||
set rc [sqlite3_wal_checkpoint db]
|
||||
if {$rc != "SQLITE_OK"} { error [sqlite3_errmsg db] }
|
||||
} -test {
|
||||
db close
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
Reference in New Issue
Block a user