mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
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
This commit is contained in:
18
manifest
18
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
|
||||
|
@ -1 +1 @@
|
||||
278ed41e1d4bbff9544cb2cf4cf52dbbcf0c17df
|
||||
33cabf271b8f4dda508a610bf59964273fe2cb84
|
@ -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);
|
||||
|
109
src/pager.c
109
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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user