diff options
author | dan <dan@noemail.net> | 2011-12-16 13:24:27 +0000 |
---|---|---|
committer | dan <dan@noemail.net> | 2011-12-16 13:24:27 +0000 |
commit | f60b7f36c1c83e9154aa8985162fb35bf9dcc984 (patch) | |
tree | e147aeffce567dab04ad00105d4d5b6922f894cc | |
parent | 14ec1ffecfe7b2bac08d064ecaccf45ccbc4b61f (diff) | |
download | sqlite-f60b7f36c1c83e9154aa8985162fb35bf9dcc984.tar.gz sqlite-f60b7f36c1c83e9154aa8985162fb35bf9dcc984.zip |
Experimental fix for [a1fa75cbdd].
FossilOrigin-Name: 6492af76ea6585a1b377d69751af930c0ccfe688
-rw-r--r-- | manifest | 18 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/wal.c | 47 | ||||
-rw-r--r-- | test/walcrash3.test | 75 |
4 files changed, 115 insertions, 27 deletions
@@ -1,5 +1,5 @@ -C Add\sstdio\ssupport\sto\sthe\squota\sVFS. -D 2011-12-15T17:44:33.259 +C Experimental\sfix\sfor\s[a1fa75cbdd]. +D 2011-12-16T13:24:27.257 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -250,7 +250,7 @@ F src/vdbemem.c 2fc78b3e0fabcc1eaa23cd79dd2e30e6dcfe1e56 F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790 F src/vdbetrace.c d6e50e04e1ec498150e519058f617d91b8f5c843 F src/vtab.c e9318d88feac85be8e27ee783ac8f5397933fc8a -F src/wal.c 7e6e7fe68ee649505dca38c8ab83eda0d0d96ae5 +F src/wal.c dc5c0606db24a1c6b982de212bfbf6e56ac1c01c F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/where.c af623942514571895818b9b7ae11db95ae3b3d88 @@ -914,6 +914,7 @@ F test/walbig.test 0ab8a430ef420a3114f7092e0f30fc9585ffa155 F test/walcksum.test f5447800a157c9e2234fbb8e80243f0813941bde F test/walcrash.test 4fcb661faf71db91214156d52d43ee327f52bde1 F test/walcrash2.test 019d60b89d96c1937adb2b30b850ac7e86e5a142 +F test/walcrash3.test 26d251a6dfaa1daae983268ccc6da0521d61e2e7 F test/walfault.test efb0d5724893133e71b8d9d90abdb781845a6bb0 F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483 F test/walmode.test 4022fe03ae6e830583672caa101f046438a0473c @@ -983,7 +984,10 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P da118e02c0576ce16f7a26663f59413316223d55 e85cfe9a17a2943ee0cf7915451ff6cc05908030 -R 4fb854e64d34a9b880548a23455e8f4d -U drh -Z 1f8384d1da732a66b49bdc6038214de7 +P 322bd15f97143d39b3a88d5f6cf7afb454e0666e +R c026e9599d51ae1a18c03cd1d5a83b3e +T *branch * experimental +T *sym-experimental * +T -sym-trunk * +U dan +Z 172fee4764ec1b8014a478816f19a037 diff --git a/manifest.uuid b/manifest.uuid index 07d7da1bd..3218c8eac 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -322bd15f97143d39b3a88d5f6cf7afb454e0666e
\ No newline at end of file +6492af76ea6585a1b377d69751af930c0ccfe688
\ No newline at end of file @@ -421,6 +421,7 @@ struct Wal { u8 writeLock; /* True if in a write transaction */ u8 ckptLock; /* True if holding a checkpoint lock */ u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */ + u8 truncateOnCommit; /* True to truncate WAL file on commit */ WalIndexHdr hdr; /* Wal-index header for current transaction */ const char *zWalName; /* Name of WAL file */ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */ @@ -1782,22 +1783,20 @@ static int walCheckpoint( } /* -** Attempt to limit the WAL size to the size limit defined by -** PRAGMA journal_size_limit. -*/ -static void walLimitSize(Wal *pWal){ - if( pWal->mxWalSize>=0 ){ - i64 sz; - int rx; - sqlite3BeginBenignMalloc(); - rx = sqlite3OsFileSize(pWal->pWalFd, &sz); - if( rx==SQLITE_OK && (sz > pWal->mxWalSize) ){ - rx = sqlite3OsTruncate(pWal->pWalFd, pWal->mxWalSize); - } - sqlite3EndBenignMalloc(); - if( rx ){ - sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName); - } +** If the WAL file is currently larger than nMax bytes in size, truncate +** it to exactly nMax bytes. If an error occurs while doing so, ignore it. +*/ +static void walLimitSize(Wal *pWal, i64 nMax){ + i64 sz; + int rx; + sqlite3BeginBenignMalloc(); + rx = sqlite3OsFileSize(pWal->pWalFd, &sz); + if( rx==SQLITE_OK && (sz > nMax ) ){ + rx = sqlite3OsTruncate(pWal->pWalFd, nMax); + } + sqlite3EndBenignMalloc(); + if( rx ){ + sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName); } } @@ -1834,8 +1833,8 @@ int sqlite3WalClose( sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersistWal); if( rc==SQLITE_OK && bPersistWal!=1 ){ isDelete = 1; - }else{ - walLimitSize(pWal); + }else if( pWal->mxWalSize>=0 ){ + walLimitSize(pWal, pWal->mxWalSize); } } @@ -2444,6 +2443,7 @@ int sqlite3WalEndWriteTransaction(Wal *pWal){ if( pWal->writeLock ){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); pWal->writeLock = 0; + pWal->truncateOnCommit = 0; } return SQLITE_OK; } @@ -2578,7 +2578,6 @@ static int walRestartLog(Wal *pWal){ int i; /* Loop counter */ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ - walLimitSize(pWal); pWal->nCkpt++; pWal->hdr.mxFrame = 0; sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); @@ -2666,6 +2665,7 @@ int sqlite3WalFrames( pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN; pWal->hdr.aFrameCksum[0] = aCksum[0]; pWal->hdr.aFrameCksum[1] = aCksum[1]; + pWal->truncateOnCommit = 1; rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0); WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok")); @@ -2739,6 +2739,15 @@ int sqlite3WalFrames( rc = sqlite3OsSync(pWal->pWalFd, sync_flags); } + if( isCommit && pWal->truncateOnCommit && pWal->mxWalSize>=0 ){ + i64 sz = pWal->mxWalSize; + if( walFrameOffset(iFrame+nLast+1, szPage)>pWal->mxWalSize ){ + sz = walFrameOffset(iFrame+nLast+1, szPage); + } + walLimitSize(pWal, sz); + pWal->truncateOnCommit = 0; + } + /* Append data to the wal-index. It is not necessary to lock the ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index ** guarantees that there are no other writers, and no data that may diff --git a/test/walcrash3.test b/test/walcrash3.test new file mode 100644 index 000000000..156c2bd1c --- /dev/null +++ b/test/walcrash3.test @@ -0,0 +1,75 @@ +# 2011 December 16 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This test simulates an application crash immediately following a +# system call to truncate a file. Specifically, the system call that +# truncates the WAL file if "PRAGMA journal_size_limit" is configured. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !wal {finish_test ; return } +set testprefix walcrash3 + +db close +testvfs tvfs +tvfs filter {xTruncate xWrite} +tvfs script tvfs_callback +proc tvfs_callback {args} {} + +sqlite3 db test.db -vfs tvfs +do_execsql_test 1.1 { + PRAGMA page_size = 1024; + PRAGMA journal_mode = WAL; + PRAGMA wal_autocheckpoint = 128; + PRAGMA journal_size_limit = 16384; + + CREATE TABLE t1(a BLOB, b BLOB, UNIQUE(a, b)); + INSERT INTO t1 VALUES(randomblob(10), randomblob(1000)); +} {wal 128 16384} + +proc tvfs_callback {method file arglist} { + if {$::state==1} { + foreach f [glob -nocomplain xx_test.*] { forcedelete $f } + foreach f [glob -nocomplain test.*] { forcecopy $f "xx_$f" } + set ::state 2 + } + if {$::state==0 && $method=="xTruncate" && [file tail $file]=="test.db-wal"} { + set ::state 1 + } +} + +for {set i 2} {$i<1000} {incr i} { + + # If the WAL file is truncated within the following, within the following + # xWrite call the [tvfs_callback] makes a copy of the database and WAL + # files set sets $::state to 2. So that the copied files are in the same + # state as the real database and WAL files would be if an application crash + # occurred immediately following the xTruncate(). + # + set ::state 0 + do_execsql_test 1.$i.1 { + INSERT INTO t1 VALUES(randomblob(10), randomblob(1000)); + } + + # If a copy was made, open it and run the integrity-check. + # + if {$::state==2} { + sqlite3 db2 xx_test.db + do_test 1.$i.2 { execsql { PRAGMA integrity_check } db2 } "ok" + do_test 1.$i.3 { execsql { SELECT count(*) FROM t1 } db2 } [expr $i-1] + db2 close + } +} + +finish_test + |