]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix a problem that could cause a spurious SQLITE_NOMEM error when attempting
authordan <dan@noemail.net>
Tue, 17 Jan 2017 10:41:42 +0000 (10:41 +0000)
committerdan <dan@noemail.net>
Tue, 17 Jan 2017 10:41:42 +0000 (10:41 +0000)
to resume an RBU operation if the previous client failed right after
completing the incremental checkpoint. Also a "cannot vacuum wal db" error
that could occur when resuming an RBU vacuum if an error (OOM or IO error)
occurs during the incremental checkpoint.

FossilOrigin-Name: 681d96eb822e606da53700867191d4738bda20c8

ext/rbu/rbufault4.test [new file with mode: 0644]
ext/rbu/rbuvacuum2.test
ext/rbu/sqlite3rbu.c
manifest
manifest.uuid

diff --git a/ext/rbu/rbufault4.test b/ext/rbu/rbufault4.test
new file mode 100644 (file)
index 0000000..fe6cc90
--- /dev/null
@@ -0,0 +1,66 @@
+# 2014 October 22
+#
+# 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.
+#
+#***********************************************************************
+#
+
+if {![info exists testdir]} {
+  set testdir [file join [file dirname [info script]] .. .. test]
+}
+source $testdir/tester.tcl
+source $testdir/malloc_common.tcl
+set ::testprefix rbufault4
+
+for {set tn 1} {1} {incr tn} {
+  reset_db
+  do_execsql_test 1.0 {
+    CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
+    CREATE INDEX i1b ON t1(b);
+    CREATE INDEX i1c ON t1(c);
+    INSERT INTO t1 VALUES(1, 2, 3);
+    INSERT INTO t1 VALUES(4, 5, 6);
+  }
+
+  forcedelete test.db2
+  sqlite3rbu_vacuum rbu test.db test.db2
+  for {set i 0} {$i < $tn} {incr i} { rbu step }
+  set rc [rbu close]
+  if {$rc!="SQLITE_OK"} { 
+    if {$rc!="SQLITE_DONE"} {error $rc}
+    break
+  }
+  faultsim_save
+
+  do_faultsim_test $tn -faults oom-t* -prep {
+    faultsim_restore
+  } -body {
+    sqlite3rbu_vacuum rbu test.db test.db2
+    while 1 {
+      set rc [rbu step]
+      if {$rc=="SQLITE_DONE"} break
+      if {$rc!="SQLITE_OK"} { error $rc }
+    }
+  } -test {
+    catch {rbu close}
+    faultsim_test_result {0 {}} {1 SQLITE_NOMEM} {1 SQLITE_IOERR_NOMEM}
+
+    sqlite3rbu_vacuum rbu test.db test.db2
+    while {[rbu step]=="SQLITE_OK"} {}
+    set trc [rbu close]
+    if {$trc!="SQLITE_DONE"} { error "Got $trc instead of SQLITE_DONE!" }
+
+    set rc [db one {PRAGMA integrity_check}]
+    if {$rc!="ok"} { error "Got $rc instead of ok!" }
+  }
+}
+
+
+
+finish_test
+
index bd386603206e020e4b44900f2c3dbb1394c30fbe..0a1fe3da94a5674bd5adb973e39549968cff07b7 100644 (file)
@@ -199,6 +199,37 @@ if {$::tcl_platform(platform)=="unix"} {
   }
 }
 
+#-------------------------------------------------------------------------
+# Test the outcome of some other connection running a checkpoint while
+# the incremental checkpoint is suspended.
+#
+reset_db
+do_execsql_test 6.0 {
+  CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
+  CREATE INDEX i1b ON t1(b);
+  CREATE INDEX i1c ON t1(c);
+  INSERT INTO t1 VALUES(1, 2, 3);
+  INSERT INTO t1 VALUES(4, 5, 6);
+}
+forcedelete test.db2
+
+do_test 6.1 {
+  sqlite3rbu_vacuum rbu test.db test.db2
+  while {[rbu state]!="checkpoint"} { rbu step }
+  rbu close
+} {SQLITE_OK}
+
+do_execsql_test 6.2 {
+  SELECT 1 FROM sqlite_master LIMIT 1;
+  PRAGMA wal_checkpoint;
+} {1 0 4 4}
+
+do_test 6.3 {
+  sqlite3rbu_vacuum rbu test.db test.db2
+  while {[rbu step]!="SQLITE_DONE"} { rbu step }
+  rbu close
+  execsql { PRAGMA integrity_check }
+} {ok}
 
 finish_test
 
index 235ba3fe2a6ab4b0a4b3c6234ad4d2c6124cf92e..48c69115ee5a5dd8858acadc65b04e0594ccf90b 100644 (file)
@@ -2333,7 +2333,7 @@ static RbuState *rbuLoadState(sqlite3rbu *p){
 ** Open the database handle and attach the RBU database as "rbu". If an
 ** error occurs, leave an error code and message in the RBU handle.
 */
-static void rbuOpenDatabase(sqlite3rbu *p){
+static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
   assert( p->rc || (p->dbMain==0 && p->dbRbu==0) );
   assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 );
 
@@ -2420,6 +2420,15 @@ static void rbuOpenDatabase(sqlite3rbu *p){
     if( !rbuIsVacuum(p) ){
       p->dbMain = rbuOpenDbhandle(p, p->zTarget, 1);
     }else if( p->pRbuFd->pWalFd ){
+      if( pbRetry ){
+        p->pRbuFd->bNolock = 0;
+        sqlite3_close(p->dbRbu);
+        sqlite3_close(p->dbMain);
+        p->dbMain = 0;
+        p->dbRbu = 0;
+        *pbRetry = 1;
+        return;
+      }
       p->rc = SQLITE_ERROR;
       p->zErrmsg = sqlite3_mprintf("cannot vacuum wal mode database");
     }else{
@@ -2600,16 +2609,18 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
     if( rc2!=SQLITE_INTERNAL ) p->rc = rc2;
   }
 
-  if( p->rc==SQLITE_OK ){
+  if( p->rc==SQLITE_OK && p->nFrame>0 ){
     p->eStage = RBU_STAGE_CKPT;
     p->nStep = (pState ? pState->nRow : 0);
     p->aBuf = rbuMalloc(p, p->pgsz);
     p->iWalCksum = rbuShmChecksum(p);
   }
 
-  if( p->rc==SQLITE_OK && pState && pState->iWalCksum!=p->iWalCksum ){
-    p->rc = SQLITE_DONE;
-    p->eStage = RBU_STAGE_DONE;
+  if( p->rc==SQLITE_OK ){
+    if( p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum) ){
+      p->rc = SQLITE_DONE;
+      p->eStage = RBU_STAGE_DONE;
+    }
   }
 }
 
@@ -2782,7 +2793,7 @@ static void rbuMoveOalFile(sqlite3rbu *p){
 #endif
 
       if( p->rc==SQLITE_OK ){
-        rbuOpenDatabase(p);
+        rbuOpenDatabase(p, 0);
         rbuSetupCheckpoint(p, 0);
       }
     }
@@ -3493,6 +3504,7 @@ static sqlite3rbu *openRbuHandle(
     /* Open the target, RBU and state databases */
     if( p->rc==SQLITE_OK ){
       char *pCsr = (char*)&p[1];
+      int bRetry = 0;
       if( zTarget ){
         p->zTarget = pCsr;
         memcpy(p->zTarget, zTarget, nTarget+1);
@@ -3504,7 +3516,18 @@ static sqlite3rbu *openRbuHandle(
       if( zState ){
         p->zState = rbuMPrintf(p, "%s", zState);
       }
-      rbuOpenDatabase(p);
+
+      /* If the first attempt to open the database file fails and the bRetry
+      ** flag it set, this means that the db was not opened because it seemed
+      ** to be a wal-mode db. But, this may have happened due to an earlier
+      ** RBU vacuum operation leaving an old wal file in the directory.
+      ** If this is the case, it will have been checkpointed and deleted
+      ** when the handle was closed and a second attempt to open the 
+      ** database may succeed.  */
+      rbuOpenDatabase(p, &bRetry);
+      if( bRetry ){
+        rbuOpenDatabase(p, 0);
+      }
     }
 
     if( p->rc==SQLITE_OK ){
index 2715f1f973dbfd380568acd5a642f4a6485c9bf4..e888f901e2096c677e4a602607fc96ed619edc72 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Disable\sintrinsic\sfunctions\sfor\sWindows\susing\sClang,\sdue\sto\sreports\sof\nlinkage\serrors.\s\sThis\scauses\sa\s0.6%\sperformance\sreduction.\s\sWe\swill\swant\sto\nrevisit\sthis\schange\sin\sthe\sfuture.
-D 2017-01-17T00:10:58.166
+C Fix\sa\sproblem\sthat\scould\scause\sa\sspurious\sSQLITE_NOMEM\serror\swhen\sattempting\nto\sresume\san\sRBU\soperation\sif\sthe\sprevious\sclient\sfailed\sright\safter\ncompleting\sthe\sincremental\scheckpoint.\sAlso\sa\s"cannot\svacuum\swal\sdb"\serror\nthat\scould\soccur\swhen\sresuming\san\sRBU\svacuum\sif\san\serror\s(OOM\sor\sIO\serror)\noccurs\sduring\sthe\sincremental\scheckpoint.
+D 2017-01-17T10:41:42.780
 F Makefile.in 41bd4cad981487345c4a84081074bcdb876e4b2e
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc b8ca53350ae545e3562403d5da2a69cec79308da
@@ -252,13 +252,14 @@ F ext/rbu/rbudor.test 99b05cc0df613e962c2c8085cfb05686a09cf315
 F ext/rbu/rbufault.test cc0be8d5d392d98b0c2d6a51be377ea989250a89
 F ext/rbu/rbufault2.test 9a7f19edd6ea35c4c9f807d8a3db0a03a5670c06
 F ext/rbu/rbufault3.test 54a399888ac4af44c68f9f58afbed23149428bca
+F ext/rbu/rbufault4.test 34e70701cbec51571ffbd9fbf9d4e0f2ec495ca7
 F ext/rbu/rbufts.test 828cd689da825f0a7b7c53ffc1f6f7fdb6fa5bda
 F ext/rbu/rbuprogress.test e3e25fb7622641b8f2df7c6b7a7eb6fddfc46a4b
 F ext/rbu/rburesume.test 8acb77f4a422ff55acfcfc9cc15a5cb210b1de83
 F ext/rbu/rbusave.test 0f43b6686084f426ddd040b878426452fd2c2f48
 F ext/rbu/rbuvacuum.test 4a977447c15c2581ab668781d9ef4294382530e0
-F ext/rbu/rbuvacuum2.test 2569205b74ff40fbf3bda2fce33a58eb40eebdcc
-F ext/rbu/sqlite3rbu.c 4ca89fbe9ca501da17f338d580d3f19d59fc6053
+F ext/rbu/rbuvacuum2.test 2074ab14fe66e1c7e7210c62562650dcd215bbaa
+F ext/rbu/sqlite3rbu.c bb0de6cdbdb14a7d55a097238a434b7e99caf318
 F ext/rbu/sqlite3rbu.h 6fb6294c34a9ca93b5894a33bca530c6f08decba
 F ext/rbu/test_rbu.c 5aa22616afac6f71ebd3d9bc9bf1006cfabcca88
 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
@@ -1546,7 +1547,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 9b64af7b5201a8700ae9e384b04714ca18df7449
-R 2a65551e28553413c063bc022e23faf5
-U drh
-Z 6f331e0f247acb77a734fb284e31d3c4
+P 7fd560c6d2ff470b755ad118287a0a8825b3009e
+R 3b5f909693e02732236a5ff9d24ebb43
+U dan
+Z 623656530433c4c90deab7fe9f3d0d79
index 30780fc11a0b8eaab490aa3abf9962c998554728..4ce408071418f151928823276ee23fc17c67953c 100644 (file)
@@ -1 +1 @@
-7fd560c6d2ff470b755ad118287a0a8825b3009e
\ No newline at end of file
+681d96eb822e606da53700867191d4738bda20c8
\ No newline at end of file