]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix a problem whereby following an IO error in CommitPhaseTwo() of a multi-file trans...
authordan <dan@noemail.net>
Tue, 29 Mar 2011 15:40:55 +0000 (15:40 +0000)
committerdan <dan@noemail.net>
Tue, 29 Mar 2011 15:40:55 +0000 (15:40 +0000)
FossilOrigin-Name: dbe569a099c2855480e35c0cc4d9332821ad80da

12 files changed:
install-sh [changed mode: 0644->0755]
manifest
manifest.uuid
src/backup.c
src/btree.c
src/btree.h
src/test_syscall.c
src/vdbeaux.c
test/fts3fault2.test
test/progress.test [changed mode: 0755->0644]
test/syscall.test
test/sysfault.test

old mode 100644 (file)
new mode 100755 (executable)
index 5041a0d7f084602602d94ea226ae9de7f2cf6fd2..e1497c5c61024c72a7d031b29e8d84783de70264 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\sproblem\sin\sthe\sunix\sVFS\simplementation\sof\sxNextSystemCall().\sAlso\ssome\stypos\sthat\sprevent\scompilation\swhen\sHAVE_POSIX_FALLOCATE\sis\sdefined.
-D 2011-03-29T10:04:23
+C Fix\sa\sproblem\swhereby\sfollowing\san\sIO\serror\sin\sCommitPhaseTwo()\sof\sa\smulti-file\stransaction\sthe\sb-tree\slayer\scould\sbe\sleft\sin\sTRANS_WRITE\sstate,\scausing\sproblems\slater\son.
+D 2011-03-29T15:40:55.407
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -99,7 +99,7 @@ F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
 F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
 F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
 F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
-F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
+F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
 F main.mk 7e4d4d0433c9cbfd906c6451a7cc50310a8f4555
 F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
@@ -118,11 +118,11 @@ F src/alter.c 6a0c176e64a34929a4436048066a84ef4f1445b3
 F src/analyze.c a038162344265ac21dfb24b3fcc06c666ebb9c07
 F src/attach.c 438ea6f6b5d5961c1f49b737f2ce0f14ce7c6877
 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
-F src/backup.c 6728d6d48d55b449af76a3e51c0808849cb32a2e
+F src/backup.c 537f89c7ef5021cb580f31f782e556ffffcb2ed1
 F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
 F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
-F src/btree.c 43302cc4f3de6479b90fa6bb271b65d86333d00e
-F src/btree.h e2f2cd9933bf30724f53ffa12c4c5a3a864bbd6e
+F src/btree.c 2b9c81ff64da339a67dda4f94c0d763627be0b67
+F src/btree.h 8d36f774ec4b1d0027b8966f8c03d9a72a518c14
 F src/btreeInt.h 20f73dc93b1eeb83afd7259fbc6bd7dcf2df7fe4
 F src/build.c 6c490fe14dedb094a202f559e3b29a276abffcf8
 F src/callback.c 5069f224882cbdccd559f591271d28d7f37745bc
@@ -220,7 +220,7 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
 F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
 F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c
 F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
-F src/test_syscall.c b2b3aef993253395da25d564a920014cc3673f09
+F src/test_syscall.c bbdc88d0a5e42d0c35eaff8ae7ec86e8867f5543
 F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
 F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0
 F src/test_vfs.c 2ed8853c1e51ac6f9ea091f7ce4e0d618bba8b86
@@ -236,7 +236,7 @@ F src/vdbe.c e3f37ca0afdd72e883475e2a32a06167df2810d0
 F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
 F src/vdbeInt.h e1c6254641168507d25b46affb6dfb53c782f553
 F src/vdbeapi.c a09ad9164cafc505250d5dd6b69660c960f1308c
-F src/vdbeaux.c cfd3f3ac674691ba1166ceb9a2698b0d00b2ef91
+F src/vdbeaux.c 9211dfa7d79d94d4e50714bfd0497ff3588a739d
 F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562
 F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
 F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5
@@ -459,7 +459,7 @@ F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
 F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
 F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
 F test/fts3fault.test f83e556465bb69dc8bc676339eca408dce4ca246
-F test/fts3fault2.test f275554f4a4fc7abf71e2975a9d6f4693f390526
+F test/fts3fault2.test dc96203af6ba31ce20163fc35460e1556e8edf4d
 F test/fts3malloc.test 9c8cc3f885bb4dfc66d0460c52f68f45e4710d1b
 F test/fts3matchinfo.test cc0b009edbbf575283d5fdb53271179e0d8019ba
 F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844
@@ -604,7 +604,7 @@ F test/permutations.test 5b2a4cb756ffb2407cb4743163668d1d769febb6
 F test/pragma.test fdfc09067ea104a0c247a1a79d8093b56656f850
 F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
 F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
-F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x
+F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
 F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
 F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
 F test/quota.test ddafe133653093eb9a99ccd6264884ae43f9c9b8
@@ -672,8 +672,8 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
 F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
 F test/superlock.test 5d7a4954b0059c903f82c7b67867bc5451a7c082
 F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3
-F test/syscall.test 2f3e4e2cf91c3b870c4eac37f62c61208a199403
-F test/sysfault.test 63144f0000167f12676adccee2a0db45eb5c2314
+F test/syscall.test 5ae4b3d4f2aca2ef3c3a777f619e0c6b0cf592aa
+F test/sysfault.test 359ea90a58788c867ac0f9cb52431f56ed975672
 F test/table.test 04ba066432430657712d167ebf28080fe878d305
 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
 F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3
@@ -919,7 +919,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 7270f80ac5dd17b979f1f790b2dfcf811866c1dc
-R 667989871349daf241bf6e2f9ef88c3d
+P bc6cce81565b17f886478bd51500bba2ed11ec1d
+R 4ba5c752b69008d11d64e0bac5b06138
 U dan
-Z e094d9a9a392624fe79d654e33f9ed32
+Z d0374b5c64afa57baa2ab5bac0bd8f73
index 96763a4275498d681167697d102c47750b783e92..e5596a7f20aadc1be90d4c7c405488948c5c7952 100644 (file)
@@ -1 +1 @@
-bc6cce81565b17f886478bd51500bba2ed11ec1d
\ No newline at end of file
+dbe569a099c2855480e35c0cc4d9332821ad80da
\ No newline at end of file
index 5d8ea7f3fe67f958d4d7c8215965355fb44e0307..82be9635b1295929f09926a6296edb9ad1467247 100644 (file)
@@ -488,7 +488,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
   
       /* Finish committing the transaction to the destination database. */
       if( SQLITE_OK==rc
-       && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest))
+       && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0))
       ){
         rc = SQLITE_DONE;
       }
@@ -502,7 +502,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
     if( bCloseTrans ){
       TESTONLY( int rc2 );
       TESTONLY( rc2  = ) sqlite3BtreeCommitPhaseOne(p->pSrc, 0);
-      TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc);
+      TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc, 0);
       assert( rc2==SQLITE_OK );
     }
   
index 33d74606758f3a894ec033c365cc1d9c6c58f0d9..088c555fc62ea585156a46d8b723808ea55b95b8 100644 (file)
@@ -3160,10 +3160,21 @@ static void btreeEndTransaction(Btree *p){
 ** the rollback journal (which causes the transaction to commit) and
 ** drop locks.
 **
+** Normally, if an error occurs while the pager layer is attempting to 
+** finalize the underlying journal file, this function returns an error and
+** the upper layer will attempt a rollback. However, if the second argument
+** is non-zero then this b-tree transaction is part of a multi-file 
+** transaction. In this case, the transaction has already been committed 
+** (by deleting a master journal file) and the caller will ignore this 
+** functions return code. So, even if an error occurs in the pager layer,
+** reset the b-tree objects internal state to indicate that the write
+** transaction has been closed. This is quite safe, as the pager will have
+** transitioned to the error state.
+**
 ** This will release the write lock on the database file.  If there
 ** are no active cursors, it also releases the read lock.
 */
-int sqlite3BtreeCommitPhaseTwo(Btree *p){
+int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){
 
   if( p->inTrans==TRANS_NONE ) return SQLITE_OK;
   sqlite3BtreeEnter(p);
@@ -3178,7 +3189,7 @@ int sqlite3BtreeCommitPhaseTwo(Btree *p){
     assert( pBt->inTransaction==TRANS_WRITE );
     assert( pBt->nTransaction>0 );
     rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
-    if( rc!=SQLITE_OK ){
+    if( rc!=SQLITE_OK && bCleanup==0 ){
       sqlite3BtreeLeave(p);
       return rc;
     }
@@ -3198,7 +3209,7 @@ int sqlite3BtreeCommit(Btree *p){
   sqlite3BtreeEnter(p);
   rc = sqlite3BtreeCommitPhaseOne(p, 0);
   if( rc==SQLITE_OK ){
-    rc = sqlite3BtreeCommitPhaseTwo(p);
+    rc = sqlite3BtreeCommitPhaseTwo(p, 0);
   }
   sqlite3BtreeLeave(p);
   return rc;
index 6886dd9444cfbe9eb857410a6adc5d1adb6fc89a..468723b33e96764dfff7da1248b1088c8b2b04ff 100644 (file)
@@ -87,7 +87,7 @@ int sqlite3BtreeSetAutoVacuum(Btree *, int);
 int sqlite3BtreeGetAutoVacuum(Btree *);
 int sqlite3BtreeBeginTrans(Btree*,int);
 int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
-int sqlite3BtreeCommitPhaseTwo(Btree*);
+int sqlite3BtreeCommitPhaseTwo(Btree*, int);
 int sqlite3BtreeCommit(Btree*);
 int sqlite3BtreeRollback(Btree*);
 int sqlite3BtreeBeginStmt(Btree*,int);
index 88e1943a66dabf27d46c0ce5a205a4ffa1f0cf28..0ecf6c40012c75345b32bd883121747bfc0c6cd4 100644 (file)
@@ -120,7 +120,7 @@ struct TestSyscallArray {
   /*  3 */ { "getcwd",    (sqlite3_syscall_ptr)ts_getcwd,    0, 0, 0 },
   /*  4 */ { "stat",      (sqlite3_syscall_ptr)ts_stat,      0, 0, 0 },
   /*  5 */ { "fstat",     (sqlite3_syscall_ptr)ts_fstat,     0, 0, 0 },
-  /*  6 */ { "ftruncate", (sqlite3_syscall_ptr)ts_ftruncate, 0, 0, 0 },
+  /*  6 */ { "ftruncate", (sqlite3_syscall_ptr)ts_ftruncate, 0, EIO, 0 },
   /*  7 */ { "fcntl",     (sqlite3_syscall_ptr)ts_fcntl,     0, 0, 0 },
   /*  8 */ { "read",      (sqlite3_syscall_ptr)ts_read,      0, 0, 0 },
   /*  9 */ { "pread",     (sqlite3_syscall_ptr)ts_pread,     0, 0, 0 },
@@ -152,7 +152,6 @@ struct TestSyscallArray {
 #define orig_fchmod    ((int(*)(int,mode_t))aSyscall[14].xOrig)
 #define orig_fallocate ((int(*)(int,off_t,off_t))aSyscall[15].xOrig)
 
-
 /*
 ** This function is called exactly once from within each invocation of a
 ** system call wrapper in this file. It returns 1 if the function should
@@ -264,7 +263,7 @@ static int ts_fstat(int fd, struct stat *p){
 ** A wrapper around ftruncate().
 */
 static int ts_ftruncate(int fd, off_t n){
-  if( tsIsFail() ){
+  if( tsIsFailErrno("ftruncate") ){
     return -1;
   }
   return orig_ftruncate(fd, n);
@@ -533,6 +532,8 @@ static int test_syscall_errno(
     int i;
   } aErrno[] = {
     { "EACCES", EACCES },
+    { "EINTR", EINTR },
+    { "EIO", EIO },
     { 0, 0 }
   };
 
index 36e0d260b3b6c1a61dfc763a9a59c08dc31fcbc3..5887cab047c6a94d68d125cfce49c06b24e60992 100644 (file)
@@ -1703,7 +1703,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
     for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
       Btree *pBt = db->aDb[i].pBt;
       if( pBt ){
-        rc = sqlite3BtreeCommitPhaseTwo(pBt);
+        rc = sqlite3BtreeCommitPhaseTwo(pBt, 0);
       }
     }
     if( rc==SQLITE_OK ){
@@ -1835,7 +1835,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
     for(i=0; i<db->nDb; i++){ 
       Btree *pBt = db->aDb[i].pBt;
       if( pBt ){
-        sqlite3BtreeCommitPhaseTwo(pBt);
+        sqlite3BtreeCommitPhaseTwo(pBt, 1);
       }
     }
     sqlite3EndBenignMalloc();
index 6d41aee1c606b08d95cb4a32acf249acf270c23a..fb877737f4ef88b20fb995c0c5a9d74d410fee29 100644 (file)
@@ -14,6 +14,9 @@ set testdir [file dirname $argv0]
 source $testdir/tester.tcl
 set ::testprefix fts3fault2
 
+# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
+ifcapable !fts3 { finish_test ; return }
+
 do_test 1.0 {
   execsql {
     CREATE VIRTUAL TABLE t1 USING fts4(x);
old mode 100755 (executable)
new mode 100644 (file)
index a860e40ad37411615b4b3bfe7b49c09b50270fc5..836e00dd860ab974038f4599b639b9a91a5bc20f 100644 (file)
@@ -59,4 +59,53 @@ set syscall_list [list                                \
 if {[test_syscall exists fallocate]} {lappend syscall_list fallocate}
 do_test 3.1 { test_syscall list } $syscall_list
 
+#-------------------------------------------------------------------------
+# This test verifies that if a call to open() fails and errno is set to
+# EINTR, the call is retried. If it succeeds, execution continues as if
+# nothing happened. 
+#
+test_syscall reset
+forcedelete test.db2
+do_execsql_test 4.1 {
+  CREATE TABLE t1(x, y);
+  INSERT INTO t1 VALUES(1, 2);
+  ATTACH 'test.db2' AS aux;
+  CREATE TABLE aux.t2(x, y);
+  INSERT INTO t2 VALUES(3, 4);
+}
+
+db_save_and_close
+test_syscall install open
+foreach jrnl [list wal delete] {
+  for {set i 1} {$i < 20} {incr i} {
+    db_restore_and_reopen
+    test_syscall fault $i 0
+    test_syscall errno open EINTR
+  
+    do_test 4.2.$jrnl.$i {
+      sqlite3 db test.db
+      execsql { ATTACH 'test.db2' AS aux }
+      execsql "PRAGMA main.journal_mode = $jrnl"
+      execsql "PRAGMA aux.journal_mode = $jrnl"
+      execsql {
+        BEGIN;
+          INSERT INTO t1 VALUES(5, 6);
+          INSERT INTO t2 VALUES(7, 8);
+        COMMIT;
+      }
+
+      db close
+      sqlite3 db test.db
+      execsql { ATTACH 'test.db2' AS aux }
+      execsql {
+        SELECT * FROM t1;
+        SELECT * FROM t2;
+      }
+    } {1 2 5 6 3 4 7 8}
+  }
+
+}
+
+
+
 finish_test
index 2d0d8b3828f655fee2425b11ea6a8536e6e00cdc..2e958642df1b998f953884f468e2f9b2736c5ab7 100644 (file)
@@ -66,5 +66,79 @@ do_faultsim_test 1 -faults vfsfault-* -prep {
     {1 {attempt to write a readonly database}}
 }
 
+#-------------------------------------------------------------------------
+# Check that a single EINTR error does not affect processing.
+#
+proc vfsfault_install {} { 
+  test_syscall reset
+  test_syscall install {open ftruncate close}
+}
+
+forcedelete test.db test.db2
+sqlite3 db test.db
+do_test 2.setup {
+  execsql {
+    CREATE TABLE t1(a, b, c, PRIMARY KEY(a));
+    INSERT INTO t1 VALUES('abc', 'def', 'ghi');
+    ATTACH 'test.db2' AS 'aux';
+    CREATE TABLE aux.t2(x);
+    INSERT INTO t2 VALUES(1);
+  }
+  faultsim_save_and_close
+} {}
+
+do_faultsim_test 2.1 -faults vfsfault-transient -prep {
+  catch { db close }
+  faultsim_restore
+} -body {
+  test_syscall errno open      EINTR
+  test_syscall errno ftruncate EINTR
+  test_syscall errno close     EINTR
+
+  sqlite3 db test.db
+  set res [db eval {
+    ATTACH 'test.db2' AS 'aux';
+    SELECT * FROM t1;
+    PRAGMA journal_mode = truncate;
+    BEGIN;
+      INSERT INTO t1 VALUES('jkl', 'mno', 'pqr');
+      UPDATE t2 SET x = 2;
+    COMMIT;
+    SELECT * FROM t1;
+    SELECT * FROM t2;
+  }]
+  db close
+  set res
+} -test {
+  faultsim_test_result {0 {abc def ghi truncate abc def ghi jkl mno pqr 2}}
+}
+
+do_faultsim_test 2.2 -faults vfsfault-* -prep {
+  catch { db close }
+  faultsim_restore
+} -body {
+  sqlite3 db test.db
+  set res [db eval {
+    ATTACH 'test.db2' AS 'aux';
+    SELECT * FROM t1;
+    PRAGMA journal_mode = truncate;
+    BEGIN;
+      INSERT INTO t1 VALUES('jkl', 'mno', 'pqr');
+      UPDATE t2 SET x = 2;
+    COMMIT;
+    SELECT * FROM t1;
+    SELECT * FROM t2;
+  }]
+  db close
+  set res
+} -test {
+  faultsim_test_result {0 {abc def ghi truncate abc def ghi jkl mno pqr 2}} \
+    {1 {unable to open database file}}                                      \
+    {1 {unable to open database: test.db2}}                                 \
+    {1 {attempt to write a readonly database}}                              \
+    {1 {disk I/O error}}                                                  
+}
+
+
 finish_test