aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordanielk1977 <danielk1977@noemail.net>2008-05-07 19:11:03 +0000
committerdanielk1977 <danielk1977@noemail.net>2008-05-07 19:11:03 +0000
commitdf2566a33d3808521f53302960709b421e23474a (patch)
treeef32a2a94c4cdf60787c60395344fa670cfe3018 /src
parent2ca8bc08dd5f18bdfc209a131370675f7e2893e2 (diff)
downloadsqlite-df2566a33d3808521f53302960709b421e23474a.tar.gz
sqlite-df2566a33d3808521f53302960709b421e23474a.zip
Fix some problems with multi-file transactions in persistent journal mode. (CVS 5102)
FossilOrigin-Name: e98a7f87f91c62676f94ad5a0c4980ab929ca79d
Diffstat (limited to 'src')
-rw-r--r--src/btree.c28
-rw-r--r--src/pager.c53
2 files changed, 53 insertions, 28 deletions
diff --git a/src/btree.c b/src/btree.c
index f61be9626..d87eb040f 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -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 */
diff --git a/src/pager.c b/src/pager.c
index 5a7c2667f..e99e60a53 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -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;
}