]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix some problems with multi-file transactions in persistent journal mode. (CVS 5102)
authordanielk1977 <danielk1977@noemail.net>
Wed, 7 May 2008 19:11:03 +0000 (19:11 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Wed, 7 May 2008 19:11:03 +0000 (19:11 +0000)
FossilOrigin-Name: e98a7f87f91c62676f94ad5a0c4980ab929ca79d

manifest
manifest.uuid
src/btree.c
src/pager.c
test/jrnlmode.test

index 56338c1f1fcf2ed83f244cfd0b995ef401d4cdb0..33ffeb72088695849eded152441a23b57d590fc2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Added\stest\scases\sfor\scorrupt\sSerialTypeLen\sheader\svalues,\sand\sadditional\scheck\sto\simprove\sdetection\sof\scorrupt\svalues.\s(CVS\s5101)
-D 2008-05-07T18:59:29
+C Fix\ssome\sproblems\swith\smulti-file\stransactions\sin\spersistent\sjournal\smode.\s(CVS\s5102)
+D 2008-05-07T19:11:03
 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
 F Makefile.in 8b9b8263852f0217157f9042b8e3dae7427ec739
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -85,7 +85,7 @@ F src/attach.c 496cc628b2e8c4d8db99d7c136761fcbebd8420b
 F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
 F src/bitvec.c 8ec2212cfb702bc4f402c0b7ae7623d85320c714
 F src/btmutex.c 483ced3c52205b04b97df69161fadbf87f4f1ea2
-F src/btree.c 556adb8f6905303d6ea00d35a0d1e1fe8a07efe2
+F src/btree.c 7401bcbdabd87360351953e5009530c47e4fb305
 F src/btree.h 8826591bf54dd35fcf2e67473d5f1bae253861c7
 F src/btreeInt.h dc04ee33d8eb84714b2acdf81336fbbf6e764530
 F src/build.c a52d9d51341444a2131e3431608f245db80d9591
@@ -121,7 +121,7 @@ F src/os_common.h e8b748b2f2ecc8a498e50bfe5d8721f189c19d2a
 F src/os_os2.c 30c378b093d9c17387ebb0ebbf21b7d55a98202b
 F src/os_unix.c a810e2aefdaddacf479407f76f8f4ca381d231b2
 F src/os_win.c 3a60bddd07ea6f8adb2314dd5996ac97b988f403
-F src/pager.c 547079d36fb3ca227e77e669268ea910c90774ef
+F src/pager.c fc173b7ee0b9ee630688466adacd506225417eb7
 F src/pager.h 4f051fd856de6fd3c19aef5f82eace54122b9173
 F src/parse.y fc4bd35c6088901f7c8daead26c6fb11c87d22e7
 F src/pragma.c 2e4bb2e76e48a32750529fdc4bfe86ac5f54e01b
@@ -351,7 +351,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
 F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe
 F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
-F test/jrnlmode.test 89acaa81503e349a49da73570b1a104f8fd93de7
+F test/jrnlmode.test 5b650ba0630fc1089688e18bb7f0c9b8a33417ed
 F test/jrnlmode2.test e48ec49320a3f849a5036e3551bf2394112a4aae
 F test/jrnlmode3.test c77f9d4095945f234dddd60ca0f73c24802ed0c1
 F test/jrnlmode4.test 8ee031603fef8ed5deba0de8b012a82be6d5a6a0
@@ -634,7 +634,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P ed728104c8e77a5526a2fcb62fea577940731d90
-R 662f2572cbb8e504e1cbbe6b8cab0ff5
-U shane
-Z d87bdc7540c0da4b026b69711c54995d
+P 530c6360610f737e85608b23ede2646d69d1bc9a
+R b3765e5e9b24b682270f8e36c5449957
+U danielk1977
+Z 58d2f3d9b823776050be08ba53db12b8
index 7fbb5f90d2e8a0c41709b86289e1829d5e98a6d6..f1bb64c6c7c20294f52ce2d9a6b0737865cc7484 100644 (file)
@@ -1 +1 @@
-530c6360610f737e85608b23ede2646d69d1bc9a
\ No newline at end of file
+e98a7f87f91c62676f94ad5a0c4980ab929ca79d
\ No newline at end of file
index f61be962663d37e83476dfa97225e39157dc9057..d87eb040f21fac7c7d781be9297080d5593f5aef 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.456 2008/05/07 07:13:16 danielk1977 Exp $
+** $Id: btree.c,v 1.457 2008/05/07 19:11:03 danielk1977 Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** See the header comment on "btreeInt.h" for additional information.
@@ -6839,20 +6839,20 @@ static int btreeCopyFile(Btree *pTo, Btree *pFrom){
       rc = sqlite3PagerGet(pBtTo->pPager, i, &pDbPage);
       if( rc==SQLITE_OK ){
         rc = sqlite3PagerWrite(pDbPage);
+        if( rc==SQLITE_OK && i>nFromPage ){
+          /* Yeah.  It seems wierd to call DontWrite() right after Write(). But
+          ** that is because the names of those procedures do not exactly 
+          ** represent what they do.  Write() really means "put this page in the
+          ** rollback journal and mark it as dirty so that it will be written
+          ** to the database file later."  DontWrite() undoes the second part of
+          ** that and prevents the page from being written to the database. The
+          ** page is still on the rollback journal, though.  And that is the 
+          ** whole point of this block: to put pages on the rollback journal. 
+          */
+          sqlite3PagerDontWrite(pDbPage);
+        }
+        sqlite3PagerUnref(pDbPage);
       }
-      if( rc==SQLITE_OK && i>nFromPage ){
-        /* Yeah.  It seems wierd to call DontWrite() right after Write(). But
-        ** that is because the names of those procedures do not exactly 
-        ** represent what they do.  Write() really means "put this page in the
-        ** rollback journal and mark it as dirty so that it will be written
-        ** to the database file later."  DontWrite() undoes the second part of
-        ** that and prevents the page from being written to the database. The
-        ** page is still on the rollback journal, though.  And that is the 
-        ** whole point of this block: to put pages on the rollback journal. 
-        */
-        sqlite3PagerDontWrite(pDbPage);
-      }
-      sqlite3PagerUnref(pDbPage);
     }
 
     /* Overwrite the data in page i of the target database */
index 5a7c2667fb1ed98e067150b6a2ced293aa47b6d8..e99e60a53bfb815754a4196e6a22c336eb261998 100644 (file)
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.442 2008/05/07 12:45:41 drh Exp $
+** @(#) $Id: pager.c,v 1.443 2008/05/07 19:11:03 danielk1977 Exp $
 */
 #ifndef SQLITE_OMIT_DISKIO
 #include "sqliteInt.h"
@@ -968,14 +968,20 @@ static void seekJournalHdr(Pager *pPager){
 ** effect of invalidating the journal file and committing the
 ** transaction.
 */
-static int zeroJournalHdr(Pager *pPager){
-  int rc;
+static int zeroJournalHdr(Pager *pPager, int doTruncate){
+  int rc = SQLITE_OK;
   static const char zeroHdr[28];
 
-  IOTRACE(("JZEROHDR %p\n", pPager))
-  rc = sqlite3OsWrite(pPager->jfd, zeroHdr, sizeof(zeroHdr), 0);
-  if( rc==SQLITE_OK ){
-    rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_DATAONLY | pPager->sync_flags);
+  if( pPager->journalOff ){
+    IOTRACE(("JZEROHDR %p\n", pPager))
+    if( doTruncate ){
+      rc = sqlite3OsTruncate(pPager->jfd, 0);
+    }else{
+      rc = sqlite3OsWrite(pPager->jfd, zeroHdr, sizeof(zeroHdr), 0);
+    }
+    if( rc==SQLITE_OK ){
+      rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_DATAONLY|pPager->sync_flags);
+    }
   }
   return rc;
 }
@@ -1163,6 +1169,7 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
   int len; 
   int i; 
   i64 jrnlOff;
+  i64 jrnlSize;
   u32 cksum = 0;
   char zBuf[sizeof(aJournalMagic)+2*4];
 
@@ -1196,7 +1203,25 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
   put32bits(&zBuf[4], cksum);
   memcpy(&zBuf[8], aJournalMagic, sizeof(aJournalMagic));
   rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic), jrnlOff);
+  jrnlOff += 8+sizeof(aJournalMagic);
   pPager->needSync = !pPager->noSync;
+
+  /* If the pager is in peristent-journal mode, then the physical 
+  ** journal-file may extend past the end of the master-journal name
+  ** and 8 bytes of magic data just written to the file. This is 
+  ** dangerous because the code to rollback a hot-journal file
+  ** will not be able to find the master-journal name to determine 
+  ** whether or not the journal is hot. 
+  **
+  ** Easiest thing to do in this scenario is to truncate the journal 
+  ** file to the required size.
+  */ 
+  if( (rc==SQLITE_OK)
+   && (rc = sqlite3OsFileSize(pPager->jfd, &jrnlSize))==SQLITE_OK
+   && jrnlSize>jrnlOff
+  ){
+    rc = sqlite3OsTruncate(pPager->jfd, jrnlOff);
+  }
   return rc;
 }
 
@@ -1358,7 +1383,7 @@ static void pagerUnlockAndRollback(Pager *p){
 ** This might give a performance improvement on windows where opening
 ** a file is an expensive operation.
 */
-static int pager_end_transaction(Pager *pPager){
+static int pager_end_transaction(Pager *pPager, int hasMaster){
   PgHdr *pPg;
   int rc = SQLITE_OK;
   int rc2 = SQLITE_OK;
@@ -1374,7 +1399,7 @@ static int pager_end_transaction(Pager *pPager){
   if( pPager->journalOpen ){
     if( (pPager->exclusiveMode ||
          pPager->journalMode==PAGER_JOURNALMODE_PERSIST) 
-       && (rc = zeroJournalHdr(pPager))==SQLITE_OK ){
+       && (rc = zeroJournalHdr(pPager, hasMaster))==SQLITE_OK ){
       pPager->journalOff = 0;
       pPager->journalStarted = 0;
     }else{
@@ -1908,7 +1933,7 @@ end_playback:
     rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
   }
   if( rc==SQLITE_OK ){
-    rc = pager_end_transaction(pPager);
+    rc = pager_end_transaction(pPager, zMaster[0]!='\0');
   }
   if( rc==SQLITE_OK && zMaster[0] ){
     /* If there was a master journal and this routine will return success,
@@ -3960,7 +3985,7 @@ static int pager_open_journal(Pager *pPager){
     rc = sqlite3PagerStmtBegin(pPager);
   }
   if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && rc!=SQLITE_IOERR_NOMEM ){
-    rc = pager_end_transaction(pPager);
+    rc = pager_end_transaction(pPager, 0);
     if( rc==SQLITE_OK ){
       rc = SQLITE_FULL;
     }
@@ -4759,7 +4784,7 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
     return SQLITE_OK;
   }
   assert( pPager->state==PAGER_SYNCED || !pPager->dirtyCache );
-  rc = pager_end_transaction(pPager);
+  rc = pager_end_transaction(pPager, pPager->setMaster);
   rc = pager_error(pPager, rc);
   pagerLeave(pPager);
   return rc;
@@ -4818,7 +4843,7 @@ int sqlite3PagerRollback(Pager *pPager){
 
   pagerEnter(pPager);
   if( !pPager->dirtyCache || !pPager->journalOpen ){
-    rc = pager_end_transaction(pPager);
+    rc = pager_end_transaction(pPager, pPager->setMaster);
     pagerLeave(pPager);
     return rc;
   }
@@ -4833,7 +4858,7 @@ int sqlite3PagerRollback(Pager *pPager){
   if( pPager->state==PAGER_RESERVED ){
     int rc2;
     rc = pager_playback(pPager, 0);
-    rc2 = pager_end_transaction(pPager);
+    rc2 = pager_end_transaction(pPager, pPager->setMaster);
     if( rc==SQLITE_OK ){
       rc = rc2;
     }
index 78fd8a569884469482826e5da9ef6316c9a17bcb..a5e60adabb730accfc5bf0e943e8e69dce5deea3 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library. The focus
 # of these tests is the journal mode pragma.
 #
-# $Id: jrnlmode.test,v 1.1 2008/04/19 20:34:19 drh Exp $
+# $Id: jrnlmode.test,v 1.2 2008/05/07 19:11:03 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -152,5 +152,48 @@ ifcapable attach {
   } {}
 }
 
+ifcapable attach {
+  file delete -force test2.db
+  do_test jrnlmode-2.1 {
+    execsql {
+      ATTACH 'test2.db' AS aux;
+      PRAGMA main.journal_mode = persist;
+      PRAGMA aux.journal_mode = persist;
+      CREATE TABLE abc(a, b, c);
+      CREATE TABLE aux.def(d, e, f);
+    }
+    execsql {
+      BEGIN;
+      INSERT INTO abc VALUES(1, 2, 3);
+      INSERT INTO def VALUES(4, 5, 6);
+      COMMIT;
+    }
+    list [file exists test.db-journal] [file exists test2.db-journal]
+  } {1 1}
+
+  do_test jrnlmode-2.2 {
+    file size test.db-journal
+  } {0}
+
+  do_test jrnlmode-2.3 {
+    execsql {
+      SELECT * FROM abc;
+    }
+  } {1 2 3}
+
+  do_test jrnlmode-2.4 {
+    file size test.db-journal
+  } {0}
+
+  do_test jrnlmode-2.5 {
+    execsql {
+      SELECT * FROM def;
+    }
+  } {4 5 6}
+
+}
+
+
+
 
 finish_test