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