]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add a test for the outcome of a process crash within an xWrite VFS method
authordan <dan@noemail.net>
Sat, 22 Jul 2017 20:12:31 +0000 (20:12 +0000)
committerdan <dan@noemail.net>
Sat, 22 Jul 2017 20:12:31 +0000 (20:12 +0000)
call.

FossilOrigin-Name: eb8718006cb23ba9304da5c30d19863d688495f0eaae3794c5ad870e481866f8

manifest
manifest.uuid
src/test6.c
src/test_devsym.c
test/tester.tcl
test/writecrash.test [new file with mode: 0644]

index e915c71f603b95712bf6b6ca0653cbe82ed2b482..03946f8c1a3576845c0dce88554b5e28ac95b323 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\s"atomic-batch-write"\spermutation\sto\spermutations.test.\sThis\npermutation\sfails\sif\snot\srun\son\sa\sfile-system\sthat\ssupports\natomic-batch-writes.
-D 2017-07-22T16:58:47.336
+C Add\sa\stest\sfor\sthe\soutcome\sof\sa\sprocess\scrash\swithin\san\sxWrite\sVFS\smethod\ncall.
+D 2017-07-22T20:12:31.931
 F Makefile.in d9873c9925917cca9990ee24be17eb9613a668012c85a343aef7e5536ae266e8
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc 02b469e9dcd5b7ee63fc1fb05babc174260ee4cfa4e0ef2e48c3c6801567a016
@@ -468,7 +468,7 @@ F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
 F src/test3.c b8434949dfb8aff8dfa082c8b592109e77844c2135ed3c492113839b6956255b
 F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
 F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
-F src/test6.c 004ad42f121f693b8cbe060d1a330678abc61620
+F src/test6.c e8d839fbc552ce044bec8234561a2d5b8819b48e29548ad0ba400471697946a8
 F src/test7.c 5612e9aecf934d6df7bba6ce861fdf5ba5456010
 F src/test8.c 4f4904721167b32f7a4fa8c7b32a07a673d6cc86
 F src/test9.c 12e5ba554d2d1cbe0158f6ab3f7ffcd7a86ee4e5
@@ -481,7 +481,7 @@ F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
 F src/test_config.c abf6fc1fe9d041b699578c42e3db81f8831c4f5b804f1927958102ee8f2b773e
 F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
 F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
-F src/test_devsym.c 4e58dec2602d8e139ca08659f62a62450587cb58
+F src/test_devsym.c 1960abbb234b97e9b920f07e99503fc04b443f62bbc3c6ff2c2cea2133e3b8a2
 F src/test_fs.c 35a2f7dd8a915900873386331386d9ba1ae1b5026d74fd20c2807bc76221f291
 F src/test_func.c a4fdab3363b436c1b12660e9362ce3f3782b7b5e
 F src/test_hexio.c 1d4469ca61ab202a1fcec6543f584d2407205e8d
@@ -1246,7 +1246,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 581f0185434daf7026ccede4c07e8d1479186ec5
+F test/tester.tcl eb7ec55fe074a909423c1de701f7c545417b8aa96787b8c3e7a79203f2cebec8
 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -1542,6 +1542,7 @@ F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
 F test/without_rowid5.test 89b1c587bd92a0590e440da33e7666bf4891572a
 F test/without_rowid6.test 1f99644e6508447fb050f73697350c7ceca3392e
 F test/wordcount.c 06efb84b7c48a4973c2c24ea06c93d00bce24389
+F test/writecrash.test e6dc9d470d43710c3f780a50d29cce1c3884ca34ff50e737bc9ab8724c7c2398
 F test/zeroblob.test 3857870fe681b8185654414a9bccfde80b62a0fa
 F test/zerodamage.test e59a56443d6298ecf7435f618f0b27654f0c849e
 F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
@@ -1637,7 +1638,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 2e80e19e4faac30947ed56aa3601c45c758cafb27f84780df255fdbcdc9a6999
-R f3cc9474e40dfdafd1378160ccb50876
+P 9f1b83fae9c973eee80eefefe7bd3a1eb7bba8af4cd919d7a2ce911900dd9087
+R f23da5f714bc905d7cb0056ef392fdf9
 U dan
-Z e9e3d5840c0aa48b88a9ce806cb1e69e
+Z 063d069885d7a39f9c6cf058832bceb7
index 0361e53d3b3a9a40d5f8152282bcf20e724051af..f6a017d89b06bf954b08aec612758cb12d949e6c 100644 (file)
@@ -1 +1 @@
-9f1b83fae9c973eee80eefefe7bd3a1eb7bba8af4cd919d7a2ce911900dd9087
\ No newline at end of file
+eb8718006cb23ba9304da5c30d19863d688495f0eaae3794c5ad870e481866f8
\ No newline at end of file
index 849cdeb3b9bca13fadec0532476bae20f13a0c8c..9a3aa093f06e632154f49b87d57da16bc2c63c1a 100644 (file)
@@ -736,6 +736,7 @@ static int processDevSymArgs(
     { "sequential",          SQLITE_IOCAP_SEQUENTIAL            },
     { "safe_append",         SQLITE_IOCAP_SAFE_APPEND           },
     { "powersafe_overwrite", SQLITE_IOCAP_POWERSAFE_OVERWRITE   },
+    { "batch-atomic",        SQLITE_IOCAP_BATCH_ATOMIC          },
     { 0, 0 }
   };
 
@@ -976,7 +977,30 @@ static int SQLITE_TCLAPI devSymObjCmd(
   devsym_register(iDc, iSectorSize);
 
   return TCL_OK;
+}
 
+/*
+** tclcmd: sqlite3_crash_on_write N
+*/
+static int SQLITE_TCLAPI writeCrashObjCmd(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  void devsym_crash_on_write(int);
+  int nWrite = 0;
+
+  if( objc!=2 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "NWRITE");
+    return TCL_ERROR;
+  }
+  if( Tcl_GetIntFromObj(interp, objv[1], &nWrite) ){
+    return TCL_ERROR;
+  }
+
+  devsym_crash_on_write(nWrite);
+  return TCL_OK;
 }
 
 /*
@@ -1068,6 +1092,7 @@ int Sqlitetest6_Init(Tcl_Interp *interp){
   Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0);
   Tcl_CreateObjCommand(interp, "sqlite3_crash_now", crashNowCmd, 0, 0);
   Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0);
+  Tcl_CreateObjCommand(interp, "sqlite3_crash_on_write", writeCrashObjCmd,0,0);
   Tcl_CreateObjCommand(interp, "unregister_devsim", dsUnregisterObjCmd, 0, 0);
   Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0);
   Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0);
index 9a1ba09d69bc0fc61e0e898c616157bf1bcc473c..0da6671cf4c48832dc35bcee80f802291f9a7313 100644 (file)
@@ -28,6 +28,7 @@
 ** Name used to identify this VFS.
 */
 #define DEVSYM_VFS_NAME "devsym"
+#define WRITECRASH_NAME "writecrash"
 
 typedef struct devsym_file devsym_file;
 struct devsym_file {
@@ -72,61 +73,13 @@ static int devsymRandomness(sqlite3_vfs*, int nByte, char *zOut);
 static int devsymSleep(sqlite3_vfs*, int microseconds);
 static int devsymCurrentTime(sqlite3_vfs*, double*);
 
-static sqlite3_vfs devsym_vfs = {
-  2,                     /* iVersion */
-  sizeof(devsym_file),      /* szOsFile */
-  DEVSYM_MAX_PATHNAME,      /* mxPathname */
-  0,                     /* pNext */
-  DEVSYM_VFS_NAME,          /* zName */
-  0,                     /* pAppData */
-  devsymOpen,               /* xOpen */
-  devsymDelete,             /* xDelete */
-  devsymAccess,             /* xAccess */
-  devsymFullPathname,       /* xFullPathname */
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
-  devsymDlOpen,             /* xDlOpen */
-  devsymDlError,            /* xDlError */
-  devsymDlSym,              /* xDlSym */
-  devsymDlClose,            /* xDlClose */
-#else
-  0,                        /* xDlOpen */
-  0,                        /* xDlError */
-  0,                        /* xDlSym */
-  0,                        /* xDlClose */
-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
-  devsymRandomness,         /* xRandomness */
-  devsymSleep,              /* xSleep */
-  devsymCurrentTime,        /* xCurrentTime */
-  0,                        /* xGetLastError */
-  0                         /* xCurrentTimeInt64 */
-};
-
-static sqlite3_io_methods devsym_io_methods = {
-  2,                                /* iVersion */
-  devsymClose,                      /* xClose */
-  devsymRead,                       /* xRead */
-  devsymWrite,                      /* xWrite */
-  devsymTruncate,                   /* xTruncate */
-  devsymSync,                       /* xSync */
-  devsymFileSize,                   /* xFileSize */
-  devsymLock,                       /* xLock */
-  devsymUnlock,                     /* xUnlock */
-  devsymCheckReservedLock,          /* xCheckReservedLock */
-  devsymFileControl,                /* xFileControl */
-  devsymSectorSize,                 /* xSectorSize */
-  devsymDeviceCharacteristics,      /* xDeviceCharacteristics */
-  devsymShmMap,                     /* xShmMap */
-  devsymShmLock,                    /* xShmLock */
-  devsymShmBarrier,                 /* xShmBarrier */
-  devsymShmUnmap                    /* xShmUnmap */
-};
-
 struct DevsymGlobal {
   sqlite3_vfs *pVfs;
   int iDeviceChar;
   int iSectorSize;
+  int nWriteCrash;
 };
-struct DevsymGlobal g = {0, 0, 512};
+struct DevsymGlobal g = {0, 0, 512, 0};
 
 /*
 ** Close an devsym-file.
@@ -271,6 +224,26 @@ static int devsymOpen(
   int flags,
   int *pOutFlags
 ){
+static sqlite3_io_methods devsym_io_methods = {
+  2,                                /* iVersion */
+  devsymClose,                      /* xClose */
+  devsymRead,                       /* xRead */
+  devsymWrite,                      /* xWrite */
+  devsymTruncate,                   /* xTruncate */
+  devsymSync,                       /* xSync */
+  devsymFileSize,                   /* xFileSize */
+  devsymLock,                       /* xLock */
+  devsymUnlock,                     /* xUnlock */
+  devsymCheckReservedLock,          /* xCheckReservedLock */
+  devsymFileControl,                /* xFileControl */
+  devsymSectorSize,                 /* xSectorSize */
+  devsymDeviceCharacteristics,      /* xDeviceCharacteristics */
+  devsymShmMap,                     /* xShmMap */
+  devsymShmLock,                    /* xShmLock */
+  devsymShmBarrier,                 /* xShmBarrier */
+  devsymShmUnmap                    /* xShmUnmap */
+};
+
   int rc;
   devsym_file *p = (devsym_file *)pFile;
   p->pReal = (sqlite3_file *)&p[1];
@@ -372,6 +345,137 @@ static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
   return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
 }
 
+/*
+** Return the sector-size in bytes for an writecrash-file.
+*/
+static int writecrashSectorSize(sqlite3_file *pFile){
+  devsym_file *p = (devsym_file *)pFile;
+  return sqlite3OsSectorSize(p->pReal);
+}
+
+/*
+** Return the device characteristic flags supported by an writecrash-file.
+*/
+static int writecrashDeviceCharacteristics(sqlite3_file *pFile){
+  devsym_file *p = (devsym_file *)pFile;
+  return sqlite3OsDeviceCharacteristics(p->pReal);
+}
+
+/*
+** Write data to an writecrash-file.
+*/
+static int writecrashWrite(
+  sqlite3_file *pFile, 
+  const void *zBuf, 
+  int iAmt, 
+  sqlite_int64 iOfst
+){
+  devsym_file *p = (devsym_file *)pFile;
+  if( g.nWriteCrash>0 ){
+    g.nWriteCrash--;
+    if( g.nWriteCrash==0 ) abort();
+  }
+  return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
+}
+
+/*
+** Open an writecrash file handle.
+*/
+static int writecrashOpen(
+  sqlite3_vfs *pVfs,
+  const char *zName,
+  sqlite3_file *pFile,
+  int flags,
+  int *pOutFlags
+){
+static sqlite3_io_methods writecrash_io_methods = {
+  2,                                /* iVersion */
+  devsymClose,                      /* xClose */
+  devsymRead,                       /* xRead */
+  writecrashWrite,                  /* xWrite */
+  devsymTruncate,                   /* xTruncate */
+  devsymSync,                       /* xSync */
+  devsymFileSize,                   /* xFileSize */
+  devsymLock,                       /* xLock */
+  devsymUnlock,                     /* xUnlock */
+  devsymCheckReservedLock,          /* xCheckReservedLock */
+  devsymFileControl,                /* xFileControl */
+  writecrashSectorSize,             /* xSectorSize */
+  writecrashDeviceCharacteristics,  /* xDeviceCharacteristics */
+  devsymShmMap,                     /* xShmMap */
+  devsymShmLock,                    /* xShmLock */
+  devsymShmBarrier,                 /* xShmBarrier */
+  devsymShmUnmap                    /* xShmUnmap */
+};
+
+  int rc;
+  devsym_file *p = (devsym_file *)pFile;
+  p->pReal = (sqlite3_file *)&p[1];
+  rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
+  if( p->pReal->pMethods ){
+    pFile->pMethods = &writecrash_io_methods;
+  }
+  return rc;
+}
+
+static sqlite3_vfs devsym_vfs = {
+  2,                     /* iVersion */
+  sizeof(devsym_file),      /* szOsFile */
+  DEVSYM_MAX_PATHNAME,      /* mxPathname */
+  0,                     /* pNext */
+  DEVSYM_VFS_NAME,          /* zName */
+  0,                     /* pAppData */
+  devsymOpen,               /* xOpen */
+  devsymDelete,             /* xDelete */
+  devsymAccess,             /* xAccess */
+  devsymFullPathname,       /* xFullPathname */
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+  devsymDlOpen,             /* xDlOpen */
+  devsymDlError,            /* xDlError */
+  devsymDlSym,              /* xDlSym */
+  devsymDlClose,            /* xDlClose */
+#else
+  0,                        /* xDlOpen */
+  0,                        /* xDlError */
+  0,                        /* xDlSym */
+  0,                        /* xDlClose */
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */
+  devsymRandomness,         /* xRandomness */
+  devsymSleep,              /* xSleep */
+  devsymCurrentTime,        /* xCurrentTime */
+  0,                        /* xGetLastError */
+  0                         /* xCurrentTimeInt64 */
+};
+
+static sqlite3_vfs writecrash_vfs = {
+  2,                     /* iVersion */
+  sizeof(devsym_file),      /* szOsFile */
+  DEVSYM_MAX_PATHNAME,      /* mxPathname */
+  0,                     /* pNext */
+  WRITECRASH_NAME,          /* zName */
+  0,                     /* pAppData */
+  writecrashOpen,           /* xOpen */
+  devsymDelete,             /* xDelete */
+  devsymAccess,             /* xAccess */
+  devsymFullPathname,       /* xFullPathname */
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+  devsymDlOpen,             /* xDlOpen */
+  devsymDlError,            /* xDlError */
+  devsymDlSym,              /* xDlSym */
+  devsymDlClose,            /* xDlClose */
+#else
+  0,                        /* xDlOpen */
+  0,                        /* xDlError */
+  0,                        /* xDlSym */
+  0,                        /* xDlClose */
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */
+  devsymRandomness,         /* xRandomness */
+  devsymSleep,              /* xSleep */
+  devsymCurrentTime,        /* xCurrentTime */
+  0,                        /* xGetLastError */
+  0                         /* xCurrentTimeInt64 */
+};
+
 
 /*
 ** This procedure registers the devsym vfs with SQLite. If the argument is
@@ -379,10 +483,13 @@ static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
 ** available function in this file.
 */
 void devsym_register(int iDeviceChar, int iSectorSize){
+
   if( g.pVfs==0 ){
     g.pVfs = sqlite3_vfs_find(0);
     devsym_vfs.szOsFile += g.pVfs->szOsFile;
+    writecrash_vfs.szOsFile += g.pVfs->szOsFile;
     sqlite3_vfs_register(&devsym_vfs, 0);
+    sqlite3_vfs_register(&writecrash_vfs, 0);
   }
   if( iDeviceChar>=0 ){
     g.iDeviceChar = iDeviceChar;
@@ -403,4 +510,15 @@ void devsym_unregister(){
   g.iSectorSize = 0;
 }
 
+void devsym_crash_on_write(int nWrite){
+  if( g.pVfs==0 ){
+    g.pVfs = sqlite3_vfs_find(0);
+    devsym_vfs.szOsFile += g.pVfs->szOsFile;
+    writecrash_vfs.szOsFile += g.pVfs->szOsFile;
+    sqlite3_vfs_register(&devsym_vfs, 0);
+    sqlite3_vfs_register(&writecrash_vfs, 0);
+  }
+  g.nWriteCrash = nWrite;
+}
+
 #endif
index dc6547d033a3c9cc890e2fb3fd9af796e826edf6..38c19701c6aecce3942bd14ad31dda7ac1e33b6c 100644 (file)
@@ -1608,6 +1608,54 @@ proc crashsql {args} {
   lappend r $msg
 }
 
+#   crash_on_write ?-devchar DEVCHAR? CRASHDELAY SQL
+#
+proc crash_on_write {args} {
+
+  set nArg [llength $args]
+  if {$nArg<2 || $nArg%2} {
+    error "bad args: $args"
+  }
+  set zSql [lindex $args end]
+  set nDelay [lindex $args end-1]
+
+  set devchar {}
+  for {set ii 0} {$ii < $nArg-2} {incr ii 2} {
+    set opt [lindex $args $ii]
+    switch -- [lindex $args $ii] {
+      -devchar {
+        set devchar [lindex $args [expr $ii+1]]
+      }
+
+      default { error "unrecognized option: $opt" }
+    }
+  }
+
+  set f [open crash.tcl w]
+  puts $f "sqlite3_crash_on_write $nDelay"
+  puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte"
+  puts $f "sqlite3 db test.db -vfs writecrash"
+  puts $f "db eval {$zSql}"
+  puts $f "set {} {}"
+
+  close $f
+  set r [catch {
+    exec [info nameofexec] crash.tcl >@stdout
+  } msg]
+
+  # Windows/ActiveState TCL returns a slightly different
+  # error message.  We map that to the expected message
+  # so that we don't have to change all of the test
+  # cases.
+  if {$::tcl_platform(platform)=="windows"} {
+    if {$msg=="child killed: unknown signal"} {
+      set msg "child process exited abnormally"
+    }
+  }
+
+  lappend r $msg
+}
+
 proc run_ioerr_prep {} {
   set ::sqlite_io_error_pending 0
   catch {db close}
diff --git a/test/writecrash.test b/test/writecrash.test
new file mode 100644 (file)
index 0000000..25fe6b4
--- /dev/null
@@ -0,0 +1,62 @@
+# 2009 January 8
+#
+# 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.
+#
+#***********************************************************************
+#
+# Test the outcome of a writer crashing within a call to the VFS
+# xWrite function.
+#
+
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix writecrash
+
+do_not_use_codec
+
+do_execsql_test 1.0 {
+  CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB UNIQUE);
+  WITH s(i) AS (
+    VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100
+  )
+  INSERT INTO t1 SELECT NULL, randomblob(900) FROM s;
+} {}
+
+set bGo 1
+for {set tn 1} {$bGo} {incr tn} {
+
+db close
+sqlite3 db test.db
+
+  do_test 1.$tn.1 {
+    set res [crash_on_write $tn {
+      UPDATE t1 SET b = randomblob(899) WHERE (a%3)==0
+    }]
+    set bGo 0
+    if {[string match {1 {child killed:*}} $res]} {
+      set res {0 {}}
+      set bGo 1
+    }
+    set res
+  } {0 {}}
+
+#db close
+#sqlite3 db test.db
+
+  do_execsql_test 1.$tn.2 { PRAGMA integrity_check } {ok}
+
+db close
+sqlite3 db test.db
+
+  do_execsql_test 1.$tn.3 { PRAGMA integrity_check } {ok}
+}
+
+
+
+finish_test