]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Experimental fix for [a1fa75cbdd].
authordan <dan@noemail.net>
Fri, 16 Dec 2011 13:24:27 +0000 (13:24 +0000)
committerdan <dan@noemail.net>
Fri, 16 Dec 2011 13:24:27 +0000 (13:24 +0000)
FossilOrigin-Name: 6492af76ea6585a1b377d69751af930c0ccfe688

manifest
manifest.uuid
src/wal.c
test/walcrash3.test [new file with mode: 0644]

index ba72d04b26a0a590404322c0e0b934be09d5c45b..61d5f87ce3327616eb9dfee46ad2445da8e7852e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -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
index 07d7da1bd9e36f39f1abff09bce0dfff62ebbea0..3218c8eac2720c96532e1dd43192a9349858f52b 100644 (file)
@@ -1 +1 @@
-322bd15f97143d39b3a88d5f6cf7afb454e0666e
\ No newline at end of file
+6492af76ea6585a1b377d69751af930c0ccfe688
\ No newline at end of file
index 209c9097521c9c94071d605da0b92609a0006cf9..e3f9cd114960e3b64ae3ef53107a1008511f7d6b 100644 (file)
--- a/src/wal.c
+++ b/src/wal.c
@@ -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 (file)
index 0000000..156c2bd
--- /dev/null
@@ -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
+