Index: src/os_test.c ================================================================== --- src/os_test.c +++ src/os_test.c @@ -188,11 +188,11 @@ } return SQLITE_OK; } -/* #define TRACE_WRITECACHE */ +/* #define TRACE_WRITECACHE */ /* ** Write the cache of pFile to disk. If crash is non-zero, randomly ** skip blocks when writing. The cache is deleted before returning. */ @@ -210,11 +210,11 @@ int trash = 0; if( crash ){ char random; sqlite3Randomness(1, &random); if( random & 0x01 ){ - if( 0 && random & 0x02 ){ + if( random & 0x02 ){ trash = 1; #ifdef TRACE_WRITECACHE printf("Trashing block %d of %s\n", i, pFile->zName); #endif }else{ @@ -263,11 +263,11 @@ if( pFile->apBlk ){ int c = crashRequired(pFile->zName); if( c ){ OsTestFile *p; #ifdef TRACE_WRITECACHE - printf("Crash during sync of %s\n", pFile->zName); + printf("\nCrash during sync of %s\n", pFile->zName); #endif for(p=pAllFiles; p; p=p->pNext){ writeCache2(p, 1); } exit(-1); Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -16,11 +16,11 @@ ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.138 2004/06/25 02:38:55 danielk1977 Exp $ +** @(#) $Id: pager.c,v 1.139 2004/06/25 06:23:23 danielk1977 Exp $ */ #include "os.h" /* Must be first to enable large file support */ #include "sqliteInt.h" #include "pager.h" #include @@ -2044,10 +2044,11 @@ ** header that is involved in the rollback of pages that have ** already been written to the database (in case the header is ** trashed when the nRec field is updated). */ pPager->nRec = 0; + assert( pPager->journalOff > 0 ); rc = writeJournalHdr(pPager); if( rc!=0 ){ sqlite3pager_rollback(pPager); return SQLITE_IOERR; } Index: test/crash.test ================================================================== --- test/crash.test +++ test/crash.test @@ -8,17 +8,17 @@ # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # -# $Id: crash.test,v 1.3 2004/06/23 10:43:15 danielk1977 Exp $ +# $Id: crash.test,v 1.4 2004/06/25 06:23:23 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set repeats 100 -# set repeats 5 +# set repeats 10 # This proc execs a seperate process that crashes midway through executing # the SQL script $sql on database test.db. # # The crash occurs during a sync() of file $crashfile. When the crash @@ -35,18 +35,19 @@ set cfile [file join [pwd] $crashfile] set f [open crash.tcl w] puts $f "sqlite3_crashparams $crashdelay $cfile" puts $f "sqlite3 db test.db" - puts $f "db eval {pragma full_synchronous = 1}" + puts $f "db eval {pragma synchronous = full}" + puts $f "db eval {pragma cache_size = 10}" puts $f "db eval {" puts $f "$sql" puts $f "}" close $f set r [catch { - exec [file join . crashtest] crash.tcl + exec [file join . crashtest] crash.tcl >@stdout } msg] lappend r $msg } # The following procedure computes a "signature" for table "abc". If @@ -56,15 +57,10 @@ } proc signature2 {} { return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc2}] } -# Use a small pager-cache for these tests. -do_test crash-0.1 { - execsql { pragma default_cache_size = 10 } -} {} - #-------------------------------------------------------------------------- # Simple crash test: # # crash-1.1: Create a database with a table with two rows. # crash-1.2: Run a 'DELETE FROM abc WHERE a = 1' that crashes during @@ -71,15 +67,18 @@ # the first journal-sync. # crash-1.3: Ensure the database is in the same state as after crash-1.1. # crash-1.4: Run a 'DELETE FROM abc WHERE a = 1' that crashes during # the first database-sync. # crash-1.5: Ensure the database is in the same state as after crash-1.1. +# crash-1.6: Run a 'DELETE FROM abc WHERE a = 1' that crashes during +# the second journal-sync. +# crash-1.7: Ensure the database is in the same state as after crash-1.1. # -# Tests 1.6 through 1.9 are the same as 1.2 through 1.5, except the crash -# is requested on the second sync of each file. This doesn't happen in -# such a small test case, so these tests are just to verify that the -# test infrastructure operates as expected. +# Tests 1.8 through 1.11 test for crashes on the third journal sync and +# second database sync. Neither of these is required in such a small test +# case, so these tests are just to verify that the test infrastructure +# operates as expected. # do_test crash-1.1 { execsql { CREATE TABLE abc(a, b, c); INSERT INTO abc VALUES(1, 2, 3); @@ -91,13 +90,10 @@ do_test crash-1.2 { crashsql 1 test.db-journal { DELETE FROM abc WHERE a = 1; } } {1 {child process exited abnormally}} - -# exit - do_test crash-1.3 { signature } $::sig do_test crash-1.4 { crashsql 1 test.db { @@ -109,22 +105,33 @@ } $::sig do_test crash-1.6 { crashsql 2 test.db-journal { DELETE FROM abc WHERE a = 1; } -} {0 {}} +} {1 {child process exited abnormally}} do_test crash-1.7 { catchsql { SELECT * FROM abc; } -} {0 {4 5 6}} +} {0 {1 2 3 4 5 6}} + do_test crash-1.8 { + crashsql 3 test.db-journal { + DELETE FROM abc WHERE a = 1; + } +} {0 {}} +do_test crash-1.9 { + catchsql { + SELECT * FROM abc; + } +} {0 {4 5 6}} +do_test crash-1.10 { crashsql 2 test.db { DELETE FROM abc WHERE a = 4; } } {0 {}} -do_test crash-1.9 { +do_test crash-1.11 { catchsql { SELECT * FROM abc; } } {0 {}} @@ -224,11 +231,14 @@ # do_test crash-4.0 { file delete -force test2.db file delete -force test2.db-journal sqlite3 db2 test2.db - execsql {pragma default_cache_size = 10} db2 + execsql { + pragma default_cache_size = 10; + pragma default_synchronous = full; + } db2 db2 close execsql { ATTACH 'test2.db' AS aux; CREATE TABLE aux.abc2 AS SELECT 2*a as a, 2*b as b, 2*c as c FROM abc; } @@ -300,7 +310,6 @@ do_test crash-4.3.$i.3 { signature2 } $sig2 } -finish_test