Fix some problems with multi-file transactions in persistent journal mode. (CVS 5102)

FossilOrigin-Name: e98a7f87f91c62676f94ad5a0c4980ab929ca79d
This commit is contained in:
danielk1977 2008-05-07 19:11:03 +00:00
parent 2ca8bc08dd
commit df2566a33d
5 changed files with 107 additions and 39 deletions

View File

@ -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

View File

@ -1 +1 @@
530c6360610f737e85608b23ede2646d69d1bc9a
e98a7f87f91c62676f94ad5a0c4980ab929ca79d

View 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 */

View 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;
}

View 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