]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
When saving the state of an RBU update in the incremental-checkpoint phase,
authordan <dan@noemail.net>
Thu, 2 Mar 2017 14:51:47 +0000 (14:51 +0000)
committerdan <dan@noemail.net>
Thu, 2 Mar 2017 14:51:47 +0000 (14:51 +0000)
sync the database file. Otherwise, if a power failure occurs and the RBU
update resumed following system recovery, the database may become corrupt.

FossilOrigin-Name: edee6a80e1cc7e6a2b8c3c7f76dd794fc8ab9a72

ext/rbu/rbucrash2.test [new file with mode: 0644]
ext/rbu/sqlite3rbu.c
manifest
manifest.uuid
src/test6.c
test/tester.tcl

diff --git a/ext/rbu/rbucrash2.test b/ext/rbu/rbucrash2.test
new file mode 100644 (file)
index 0000000..89c2535
--- /dev/null
@@ -0,0 +1,101 @@
+# 2017 March 02
+#
+# 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
+set ::testprefix rbucrash2
+
+db close
+forcedelete test.db-oal rbu.db
+sqlite3_shutdown
+sqlite3_config_uri 1
+reset_db
+
+# Set up a target database and an rbu update database. The target
+# db is the usual "test.db", the rbu db is "test.db2".
+#
+forcedelete test.db2
+do_execsql_test 1.0 {
+  CREATE TABLE t1(a, b, c, PRIMARY KEY(a), UNIQUE(b));
+  INSERT INTO t1 VALUES(1, 2, 3);
+  INSERT INTO t1 VALUES(4, 5, 6);
+  INSERT INTO t1 VALUES(7, 8, 9);
+
+  ATTACH 'test.db2' AS rbu;
+  CREATE TABLE rbu.data_t1(a, b, c, rbu_control);
+  INSERT INTO data_t1 VALUES('one', randomblob(3500), NULL, 0);
+  INSERT INTO data_t1 VALUES('two', randomblob(3500), NULL, 0);
+  INSERT INTO data_t1 VALUES('three', randomblob(3500), NULL, 0);
+  INSERT INTO data_t1 VALUES('four', randomblob(3500), NULL, 0);
+  INSERT INTO data_t1 VALUES('five', randomblob(3500), NULL, 0);
+  INSERT INTO data_t1 VALUES('six', randomblob(3500), NULL, 0);
+}
+db_save_and_close
+
+proc do_rbu_crash_test2 {tn script} {
+
+  foreach f {test.db test.db2} {
+    set bDone 0
+    for {set iDelay 1} {$bDone==0} {incr iDelay} {
+      forcedelete test.db2 test.db2-journal test.db test.db-oal test.db-wal
+      db_restore
+  
+      set res [
+        crashsql -file $f -delay $iDelay -tclbody $script -dflt 1 -opendb {} \
+            -blocksize 512 {}
+      ]
+  
+      set bDone 1
+      if {$res == "1 {child process exited abnormally}"} {
+        set bDone 0
+      } elseif {$res != "0 {}"} {
+        error "unexected catchsql result: $res"
+      }
+  
+      sqlite3rbu rbu test.db test.db2
+      while {[rbu step]=="SQLITE_OK"} {}
+      rbu close
+  
+      sqlite3 db test.db
+      do_execsql_test $tn.delay=$iDelay.f=$f {
+        PRAGMA integrity_check;
+      } {ok}
+      db close
+    }
+  }
+}
+
+for {set x 1} {$x < 10} {incr x} {
+  do_rbu_crash_test2 1.$x {
+    sqlite3rbu rbu test.db test.db2
+    while {[rbu step]=="SQLITE_OK"} {
+      rbu savestate
+    }
+    rbu close
+  }
+}
+
+for {set x 1} {$x < 2} {incr x} {
+  do_rbu_crash_test2 2.$x {
+    sqlite3rbu rbu test.db test.db2
+    while {[rbu step]=="SQLITE_OK"} {
+      rbu close
+      sqlite3rbu rbu test.db test.db2
+    }
+    rbu close
+  }
+}
+
+finish_test
+
index 48c69115ee5a5dd8858acadc65b04e0594ccf90b..262f96ea3c62c2acb613080ddb4b0753416660ad 100644 (file)
@@ -3718,6 +3718,12 @@ int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
       p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
     }
 
+    /* Sync the db file if currently doing an incremental checkpoint */
+    if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
+      sqlite3_file *pDb = p->pTargetFd->pReal;
+      p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
+    }
+
     rbuSaveState(p, p->eStage);
 
     if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
@@ -3842,6 +3848,12 @@ int sqlite3rbu_savestate(sqlite3rbu *p){
     if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0);
   }
 
+  /* Sync the db file */
+  if( rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
+    sqlite3_file *pDb = p->pTargetFd->pReal;
+    rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
+  }
+
   p->rc = rc;
   rbuSaveState(p, p->eStage);
   rc = p->rc;
index 646adca563d24a5dd4f6c130d0a98f2e104b03e5..4ab87a35ed737e854e2736bd380864d114890306 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Make\ssure\sthe\sVdbe.expmask\svalue\sis\sset\scorrectly\sin\ssqlite3VdbeSwap().\nThis\sfixes\sa\sproblem\sintroduced\sby\s[a8fd7052].
-D 2017-03-02T13:13:30.327
+C When\ssaving\sthe\sstate\sof\san\sRBU\supdate\sin\sthe\sincremental-checkpoint\sphase,\nsync\sthe\sdatabase\sfile.\sOtherwise,\sif\sa\spower\sfailure\soccurs\sand\sthe\sRBU\nupdate\sresumed\sfollowing\ssystem\srecovery,\sthe\sdatabase\smay\sbecome\scorrupt.
+D 2017-03-02T14:51:47.379
 F Makefile.in edb6bcdd37748d2b1c3422ff727c748df7ffe918
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc a89ea37ab5928026001569f056973b9059492fe2
@@ -250,6 +250,7 @@ F ext/rbu/rbuB.test c25bc325b8072a766e56bb76c001866b405925c2
 F ext/rbu/rbuC.test efe47db508a0269b683cb2a1913a425ffd39a831
 F ext/rbu/rbu_common.tcl a38e8e2d4a50fd6aaf151633714c1b1d2fae3ead
 F ext/rbu/rbucrash.test 8d2ed5d4b05fef6c00c2a6b5f7ead71fa172a695
+F ext/rbu/rbucrash2.test 7f3fe5d6d930be0965f27b49bdcdc8d4a078b73c
 F ext/rbu/rbudiff.test 3e605cf624d00d04d0fb1316a3acec4fbe3b3ac5
 F ext/rbu/rbudor.test 99b05cc0df613e962c2c8085cfb05686a09cf315
 F ext/rbu/rbufault.test cc0be8d5d392d98b0c2d6a51be377ea989250a89
@@ -262,7 +263,7 @@ F ext/rbu/rburesume.test 8acb77f4a422ff55acfcfc9cc15a5cb210b1de83
 F ext/rbu/rbusave.test 0f43b6686084f426ddd040b878426452fd2c2f48
 F ext/rbu/rbuvacuum.test 4a977447c15c2581ab668781d9ef4294382530e0
 F ext/rbu/rbuvacuum2.test 2074ab14fe66e1c7e7210c62562650dcd215bbaa
-F ext/rbu/sqlite3rbu.c bb0de6cdbdb14a7d55a097238a434b7e99caf318
+F ext/rbu/sqlite3rbu.c 3c2dfd3f27a3ecc5f017ecf82d563b522bbc341a
 F ext/rbu/sqlite3rbu.h 6fb6294c34a9ca93b5894a33bca530c6f08decba
 F ext/rbu/test_rbu.c 5aa22616afac6f71ebd3d9bc9bf1006cfabcca88
 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
@@ -411,7 +412,7 @@ F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
 F src/test3.c d03f5b5da9a2410b7a91c64b0d3306ed28ab6fee
 F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
 F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
-F src/test6.c 121060d2e79a4f5047eb12b5135b23a6a7a5af01
+F src/test6.c 004ad42f121f693b8cbe060d1a330678abc61620
 F src/test7.c 5612e9aecf934d6df7bba6ce861fdf5ba5456010
 F src/test8.c 4f4904721167b32f7a4fa8c7b32a07a673d6cc86
 F src/test9.c 12e5ba554d2d1cbe0158f6ab3f7ffcd7a86ee4e5
@@ -1173,7 +1174,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
 F test/temptable2.test cd396beb41117a5302fff61767c35fa4270a0d5e
 F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
 F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
-F test/tester.tcl 67835ac17e90055f24a9cf52e5c5bce0dd511c74
+F test/tester.tcl 581f0185434daf7026ccede4c07e8d1479186ec5
 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -1559,7 +1560,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 ac760db0727209db0a816e112ea5f47e54d54dac
-R be25bb329cc9311f7d92b42176424b6a
-U drh
-Z eb983447910676b385a2c6496a637326
+P 29f54b899e5cf22ece98ab41c39c41d75a4b228d
+R fd6b0917cff6359266006d6c00dd0a12
+U dan
+Z 1a59570e49a3b7cf84dd8025330375c8
index 9f406e4ffa3627cc2446ef244be0402762af8efc..f24ae9a62ab992d106c74106aac594d88c72b976 100644 (file)
@@ -1 +1 @@
-29f54b899e5cf22ece98ab41c39c41d75a4b228d
\ No newline at end of file
+edee6a80e1cc7e6a2b8c3c7f76dd794fc8ab9a72
\ No newline at end of file
index a103b9619e0e2d52154ccdaf2c40f079d59eac32..849cdeb3b9bca13fadec0532476bae20f13a0c8c 100644 (file)
@@ -315,8 +315,9 @@ static int writeListSync(CrashFile *pFile, int isCrash){
         assert(pWrite->zBuf);
 
 #ifdef TRACE_CRASHTEST
-        printf("Trashing %d sectors @ %lld (sector %d) (%s)\n", 
-            1+iLast-iFirst, pWrite->iOffset, iFirst, pWrite->pFile->zName
+        printf("Trashing %d sectors (%d bytes) @ %lld (sector %d) (%s)\n", 
+            1+iLast-iFirst, (1+iLast-iFirst)*g.iSectorSize,
+            pWrite->iOffset, iFirst, pWrite->pFile->zName
         );
 #endif
 
@@ -827,7 +828,7 @@ static int SQLITE_TCLAPI crashNowCmd(
 }
 
 /*
-** tclcmd:   sqlite_crash_enable ENABLE
+** tclcmd:   sqlite_crash_enable ENABLE ?DEFAULT?
 **
 ** Parameter ENABLE must be a boolean value. If true, then the "crash"
 ** vfs is added to the system. If false, it is removed.
@@ -839,6 +840,7 @@ static int SQLITE_TCLAPI crashEnableCmd(
   Tcl_Obj *CONST objv[]
 ){
   int isEnable;
+  int isDefault = 0;
   static sqlite3_vfs crashVfs = {
     2,                  /* iVersion */
     0,                  /* szOsFile */
@@ -862,14 +864,17 @@ static int SQLITE_TCLAPI crashEnableCmd(
     0,                    /* xCurrentTimeInt64 */
   };
 
-  if( objc!=2 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "ENABLE");
+  if( objc!=2 && objc!=3 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "ENABLE ?DEFAULT?");
     return TCL_ERROR;
   }
 
   if( Tcl_GetBooleanFromObj(interp, objv[1], &isEnable) ){
     return TCL_ERROR;
   }
+  if( objc==3 && Tcl_GetBooleanFromObj(interp, objv[2], &isDefault) ){
+    return TCL_ERROR;
+  }
 
   if( (isEnable && crashVfs.pAppData) || (!isEnable && !crashVfs.pAppData) ){
     return TCL_OK;
@@ -880,7 +885,7 @@ static int SQLITE_TCLAPI crashEnableCmd(
     crashVfs.mxPathname = pOriginalVfs->mxPathname;
     crashVfs.pAppData = (void *)pOriginalVfs;
     crashVfs.szOsFile = sizeof(CrashFile) + pOriginalVfs->szOsFile;
-    sqlite3_vfs_register(&crashVfs, 0);
+    sqlite3_vfs_register(&crashVfs, isDefault);
   }else{
     crashVfs.pAppData = 0;
     sqlite3_vfs_unregister(&crashVfs);
index 1da89fec2692423e2651c7f8f5bb48ac12350fb9..dc6547d033a3c9cc890e2fb3fd9af796e826edf6 100644 (file)
@@ -1533,6 +1533,7 @@ proc crashsql {args} {
   set tclbody {}
   set crashfile ""
   set dc ""
+  set dfltvfs 0
   set sql [lindex $args end]
 
   for {set ii 0} {$ii < [llength $args]-1} {incr ii 2} {
@@ -1546,7 +1547,8 @@ proc crashsql {args} {
     elseif {$n>1 && [string first $z -file]==0}      {set crashfile $z2}  \
     elseif {$n>1 && [string first $z -tclbody]==0}   {set tclbody $z2}  \
     elseif {$n>1 && [string first $z -blocksize]==0} {set blocksize "-s $z2" } \
-    elseif {$n>1 && [string first $z -characteristics]==0} {set dc "-c {$z2}" } \
+    elseif {$n>1 && [string first $z -characteristics]==0} {set dc "-c {$z2}" }\
+    elseif {$n>1 && [string first $z -dfltvfs]==0} {set dfltvfs $z2 }\
     else   { error "Unrecognized option: $z" }
   }
 
@@ -1560,7 +1562,7 @@ proc crashsql {args} {
   set cfile [string map {\\ \\\\} [file nativename [file join [get_pwd] $crashfile]]]
 
   set f [open crash.tcl w]
-  puts $f "sqlite3_crash_enable 1"
+  puts $f "sqlite3_crash_enable 1 $dfltvfs"
   puts $f "sqlite3_crashparams $blocksize $dc $crashdelay $cfile"
   puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte"