From: dan Date: Wed, 21 Apr 2010 11:43:38 +0000 (+0000) Subject: If, after obtaining a SHARED lock, there exists a *-wal file in the file-system,... X-Git-Tag: version-3.7.2~455^2~66 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a470aeb4ac0de99fc8d34d1a4006fbc9ebb402c9;p=thirdparty%2Fsqlite.git If, after obtaining a SHARED lock, there exists a *-wal file in the file-system, use WAL mode. This is necessary to recover from a crash that damages the first page of the database file. FossilOrigin-Name: 33cabf271b8f4dda508a610bf59964273fe2cb84 --- diff --git a/manifest b/manifest index be9552df7d..324d0ff215 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\schanges\sto\stest\scases\sto\saccount\sfor\sthe\sfact\sthat\sdatabases\swith\sread/write\sversions\sof\s2\sare\snow\sunderstood. -D 2010-04-21T06:19:13 +C If,\safter\sobtaining\sa\sSHARED\slock,\sthere\sexists\sa\s*-wal\sfile\sin\sthe\sfile-system,\suse\sWAL\smode.\sThis\sis\snecessary\sto\srecover\sfrom\sa\scrash\sthat\sdamages\sthe\sfirst\spage\sof\sthe\sdatabase\sfile. +D 2010-04-21T11:43:38 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in 4f2f967b7e58a35bb74fb7ec8ae90e0f4ca7868b F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -109,7 +109,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c e86634da8c48357a759694c9c7c471125cd8d5a8 F src/bitvec.c 06ad2c36a9c3819c0b9cbffec7b15f58d5d834e0 F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff -F src/btree.c 013cf019484e309e909a667654612b38a02dc2b6 +F src/btree.c e6ef1020c35db638f9ebbc91b77bc6493d9be2a1 F src/btree.h dd83041eda10c17daf023257c1fc883b5f71f85a F src/btreeInt.h 22447d259639271774a931cbf66aa55112846681 F src/build.c 11100b66fb97638d2d874c1d34d8db90650bb1d7 @@ -154,7 +154,7 @@ F src/os_common.h 240c88b163b02c21a9f21f87d49678a0aa21ff30 F src/os_os2.c 75a8c7b9a00a2cf1a65f9fa4afbc27d46634bb2f F src/os_unix.c 5bf0015cebe2f21635da2af983c348eb88b3b4c1 F src/os_win.c 1c7453c2df4dab26d90ff6f91272aea18bcf7053 -F src/pager.c 1dcf76bead8f1b51809bd8189ef9b02f2c94dc7f +F src/pager.c 4ff50f4e72ca7fff6c1e40e67db78377a53879fe F src/pager.h cee4487ab4f0911dd9f22a40e3cd55afdb7ef444 F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf @@ -758,8 +758,8 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61 F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8 F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d -F test/wal.test 273c0006e75c99cb34d0659851e7103fd4748c20 -F test/walcrash.test 45cfbab30bb7cbe0b2e9d5cabe90dbcad10cb89b +F test/wal.test 9ee4025785972fa509250c1f20c5b9456472a789 +F test/walcrash.test f022cee7eb7baa5fb898726120a6a4073dd831d1 F test/walhook.test 76a559e262f0715c470bade4a8d8333035f8ee47 F test/walmode.test cd6ee20f08af2d81fddc049f8d7e387a807f067e F test/walslow.test 38076d5fad49e3678027be0f8110e6a32d531dc2 @@ -807,7 +807,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 96bef18c1411c3e0348295886f105e1646c46320 -R 9d271c34e1ffdb3d856b3b8726b0e8d7 +P 278ed41e1d4bbff9544cb2cf4cf52dbbcf0c17df +R aeea7589488764dd7471605e974b33ab U dan -Z 58b9eaab75f6eeb69a49f445ee7bfb3c +Z eeb703c307b6c73f6f34fd39a65a4afd diff --git a/manifest.uuid b/manifest.uuid index 3378df2d22..f51f56c3a0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -278ed41e1d4bbff9544cb2cf4cf52dbbcf0c17df \ No newline at end of file +33cabf271b8f4dda508a610bf59964273fe2cb84 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 069c2d0327..2c387ffabf 100644 --- a/src/btree.c +++ b/src/btree.c @@ -2268,7 +2268,14 @@ static int lockBtree(BtShared *pBt){ goto page1_init_failed; } - /* If the write version is set to 2, turn on write-ahead logging mode. */ + /* If the write version is set to 2, this database should be accessed + ** in WAL mode. If the log is not already open, open it now. Then + ** return SQLITE_OK and return without populating BtShared.pPage1. + ** The caller detects this and calls this function again. This is + ** required as the version of page 1 currently in the page1 buffer + ** may not be the latest version - there may be a newer one in the log + ** file. + */ if( page1[19]==2 ){ int isOpen = 0; rc = sqlite3PagerOpenLog(pBt->pPager, &isOpen); diff --git a/src/pager.c b/src/pager.c index 9d1fd0479c..48e67fdb03 100644 --- a/src/pager.c +++ b/src/pager.c @@ -491,6 +491,16 @@ static int assert_pager_state(Pager *pPager){ } #endif +#ifndef NDEBUG +static void assert_file_lock(Pager *pPager, int eLock){ + int locktype; + sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCKSTATE, &locktype); + assert( locktype==eLock ); +} +#else +# define assert_file_lock(x,y) +#endif + /* ** Return true if it is necessary to write page *pPg into the sub-journal. @@ -3726,6 +3736,59 @@ static int hasHotJournal(Pager *pPager, int *pExists){ return rc; } +/* +** Check if the *-wal file that corresponds to the database opened by pPager +** exists. Assuming no error occurs, set *pExists to 1 if the file exists, +** or 0 otherwise and return SQLITE_OK. If an IO or OOM error occurs, return +** an SQLite error code. +** +** The caller must hold a SHARED lock on the database file to call this +** function. +*/ +static int pagerHasWAL(Pager *pPager, int *pExists){ + int rc; /* Return code */ + + /* Check that a SHARED lock is held on the database file. Because an + ** EXCLUSIVE lock on the db file is required to delete a WAL, this + ** ensures there is no race condition between the xAccess() below and + ** an xDelete() being executed by some other connection. + */ + assert_file_lock(pPager, SQLITE_LOCK_SHARED); + + if( !pPager->tempFile ){ + char *zLog = sqlite3_mprintf("%s-wal", pPager->zFilename); + if( !zLog ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3OsAccess(pPager->pVfs, zLog, SQLITE_ACCESS_EXISTS, pExists); + sqlite3_free(zLog); + } + }else{ + rc = SQLITE_OK; + *pExists = 0; + } + return rc; +} + +static int pagerOpenSnapshot(Pager *pPager){ + int rc; + int changed; + + assert( pagerUseLog(pPager) ); + + rc = sqlite3LogOpenSnapshot(pPager->pLog, &changed); + if( rc==SQLITE_OK ){ + int dummy; + if( changed ){ + pager_reset(pPager); + assert( pPager->errCode || pPager->dbSizeValid==0 ); + } + rc = sqlite3PagerPagecount(pPager, &dummy); + } + pPager->state = PAGER_SHARED; + + return rc; +} /* ** This function is called to obtain a shared lock on the database file. @@ -3781,23 +3844,11 @@ int sqlite3PagerSharedLock(Pager *pPager){ } if( pagerUseLog(pPager) ){ - int changed = 0; /* True if the cache must be flushed */ - - /* Open a log snapshot to read from. */ - rc = sqlite3LogOpenSnapshot(pPager->pLog, &changed); - if( rc==SQLITE_OK ){ - int dummy; - if( changed ){ - pager_reset(pPager); - assert( pPager->errCode || pPager->dbSizeValid==0 ); - } - rc = sqlite3PagerPagecount(pPager, &dummy); - } - pPager->state = PAGER_SHARED; - + rc = pagerOpenSnapshot(pPager); }else if( pPager->state==PAGER_UNLOCK || isErrorReset ){ sqlite3_vfs * const pVfs = pPager->pVfs; int isHotJournal = 0; + int isWal = 0; assert( !MEMDB ); assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); if( pPager->noReadlock ){ @@ -3952,7 +4003,17 @@ int sqlite3PagerSharedLock(Pager *pPager){ } assert( pPager->exclusiveMode || pPager->state==PAGER_SHARED ); - if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){ + rc = pagerHasWAL(pPager, &isWal); + if( rc!=SQLITE_OK ){ + goto failed; + } + if( isWal ){ + pager_reset(pPager); + rc = sqlite3PagerOpenLog(pPager, 0); + if( rc==SQLITE_OK ){ + rc = pagerOpenSnapshot(pPager); + } + }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){ pPager->journalMode = PAGER_JOURNALMODE_DELETE; } } @@ -5675,13 +5736,7 @@ int sqlite3PagerLogCallback(Pager *pPager){ int sqlite3PagerOpenLog(Pager *pPager, int *pisOpen){ int rc = SQLITE_OK; /* Return code */ -#ifdef SQLITE_DEBUG - int locktype; - sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCKSTATE, &locktype); - assert( locktype==SQLITE_LOCK_SHARED ); - assert( pPager->state>=PAGER_SHARED ); -#endif - + assert_file_lock(pPager, SQLITE_LOCK_SHARED); if( !pPager->pLog ){ /* Open the connection to the log file. If this operation fails, @@ -5725,15 +5780,7 @@ int sqlite3PagerCloseLog(Pager *pPager){ pPager->pLog = 0; } - /* Make sure the EXCLUSIVE lock has not been lost somehow */ -#ifdef SQLITE_DEBUG - { - int locktype; - sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCKSTATE, &locktype); - assert( locktype==SQLITE_LOCK_EXCLUSIVE ); - } -#endif - + assert_file_lock(pPager, SQLITE_LOCK_EXCLUSIVE); } return rc; } diff --git a/test/wal.test b/test/wal.test index bb538b120f..2c73904634 100644 --- a/test/wal.test +++ b/test/wal.test @@ -685,7 +685,6 @@ do_test wal-12.4 { } {B 1} db2 close -file copy -force test.db-wal A do_test wal-12.5 { execsql { PRAGMA checkpoint; @@ -697,7 +696,6 @@ do_test wal-12.5 { SELECT * FROM t2; } } {B 2} -file copy -force test.db-wal B do_test wal-12.4 { file copy -force test.db test2.db diff --git a/test/walcrash.test b/test/walcrash.test index dd4c572941..ed2b292861 100644 --- a/test/walcrash.test +++ b/test/walcrash.test @@ -32,11 +32,6 @@ db close set seed 0 set REPEATS 100 -proc sqlite3_wal {args} { - eval sqlite3 $args - [lindex $args 0] eval { PRAGMA journal_mode = wal } -} - # walcrash-1.* # for {set i 1} {$i < $REPEATS} {incr i} { @@ -51,7 +46,7 @@ for {set i 1} {$i < $REPEATS} {incr i} { } } {1 {child process exited abnormally}} do_test walcrash-1.$i.2 { - sqlite3_wal db test.db + sqlite3 db test.db execsql { SELECT sum(a)==max(b) FROM t1 } } {1} integrity_check walcrash-1.$i.3 @@ -59,17 +54,18 @@ for {set i 1} {$i < $REPEATS} {incr i} { do_test walcrash-1.$i.4 { crashsql -delay 2 -file test.db-wal -seed [incr seed] { - PRAGMA journal_mode = WAL; - PRAGMA journal_mode = WAL; INSERT INTO t1 VALUES(4, (SELECT sum(a) FROM t1) + 4); INSERT INTO t1 VALUES(5, (SELECT sum(a) FROM t1) + 5); } } {1 {child process exited abnormally}} do_test walcrash-1.$i.5 { - sqlite3_wal db test.db + sqlite3 db test.db execsql { SELECT sum(a)==max(b) FROM t1 } } {1} integrity_check walcrash-1.$i.6 + do_test walcrash-1.$i.5 { + execsql { PRAGMA main.journal_mode } + } {wal} db close } @@ -87,7 +83,7 @@ for {set i 1} {$i < $REPEATS} {incr i} { } } {1 {child process exited abnormally}} do_test walcrash-2.$i.2 { - sqlite3_wal db test.db + sqlite3 db test.db execsql { SELECT sum(a)==max(b) FROM t1 } } {1} integrity_check walcrash-2.$i.3 @@ -95,16 +91,18 @@ for {set i 1} {$i < $REPEATS} {incr i} { do_test walcrash-2.$i.4 { crashsql -delay 2 -file test.db-wal -seed [incr seed] { - PRAGMA journal_mode = WAL; INSERT INTO t1 VALUES(6, (SELECT sum(a) FROM t1) + 6); INSERT INTO t1 VALUES(7, (SELECT sum(a) FROM t1) + 7); } } {1 {child process exited abnormally}} do_test walcrash-2.$i.5 { - sqlite3_wal db test.db + sqlite3 db test.db execsql { SELECT sum(a)==max(b) FROM t1 } } {1} integrity_check walcrash-2.$i.6 + do_test walcrash-2.$i.6 { + execsql { PRAGMA main.journal_mode } + } {wal} db close } @@ -157,12 +155,13 @@ for {set i 1} {$i < $REPEATS} {incr i} { } {1 {child process exited abnormally}} do_test walcrash-4.$i.2 { - sqlite3_wal db test.db + sqlite3 db test.db execsql { SELECT * FROM t1 WHERE a = 1; } } {1 2} do_test walcrash-4.$i.3 { execsql { PRAGMA main.integrity_check } } {ok} + do_test walcrash-4.$i.4 { execsql { PRAGMA main.journal_mode } } {wal} db close } @@ -199,10 +198,11 @@ for {set i 1} {$i < $REPEATS} {incr i} { } {1 {child process exited abnormally}} do_test walcrash-5.$i.2 { - sqlite3_wal db test.db + sqlite3 db test.db execsql { SELECT count(*)==33 OR count(*)==34 FROM t1 WHERE x != 1 } } {1} do_test walcrash-5.$i.3 { execsql { PRAGMA main.integrity_check } } {ok} + do_test walcrash-5.$i.4 { execsql { PRAGMA main.journal_mode } } {wal} db close } @@ -239,10 +239,37 @@ for {set i 1} {$i < $REPEATS} {incr i} { } {1 {child process exited abnormally}} do_test walcrash-6.$i.2 { - sqlite3_wal db test.db + sqlite3 db test.db execsql { SELECT count(*)==34 OR count(*)==35 FROM t1 WHERE x != 1 } } {1} do_test walcrash-6.$i.3 { execsql { PRAGMA main.integrity_check } } {ok} + do_test walcrash-6.$i.4 { execsql { PRAGMA main.journal_mode } } {wal} + + db close +} + +for {set i 1} {$i < $REPEATS} {incr i} { + file delete -force test.db test.db-wal + + do_test walcrash-7.$i.1 { + crashsql -delay 3 -file test.db -seed [incr seed] -blocksize 512 { + PRAGMA journal_mode = wal; + BEGIN; + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 2); + COMMIT; + PRAGMA checkpoint; + CREATE INDEX i1 ON t1(a); + PRAGMA checkpoint; + } + } {1 {child process exited abnormally}} + + do_test walcrash-7.$i.2 { + sqlite3 db test.db + execsql { SELECT b FROM t1 WHERE a = 1 } + } {2} + do_test walcrash-7.$i.3 { execsql { PRAGMA main.integrity_check } } {ok} + do_test walcrash-7.$i.4 { execsql { PRAGMA main.journal_mode } } {wal} db close }