From: danielk1977 Date: Tue, 6 Jan 2009 13:40:08 +0000 (+0000) Subject: Add some savepoint related test cases and fix a few problems. (CVS 6116) X-Git-Tag: version-3.6.10~68 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f2c31ad8afa0f2f0493720acd6db5707b1b2bcd9;p=thirdparty%2Fsqlite.git Add some savepoint related test cases and fix a few problems. (CVS 6116) FossilOrigin-Name: 8c62ea4fded2251e9daf16f2a050f94359299d76 --- diff --git a/manifest b/manifest index 52ab79a224..44619fdb04 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sleftover\s"breakpoint"\sfrom\sthe\sfuzz.test\sscript.\s(CVS\s6115) -D 2009-01-06T00:11:26 +C Add\ssome\ssavepoint\srelated\stest\scases\sand\sfix\sa\sfew\sproblems.\s(CVS\s6116) +D 2009-01-06T13:40:08 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in 05461a9b5803d5ad10c79f989801e9fd2cc3e592 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -142,7 +142,7 @@ F src/os_common.h 24525d8b7bce66c374dfc1810a6c9043f3359b60 F src/os_os2.c bed77dc26e3a95ce4a204936b9a1ca6fe612fcc5 F src/os_unix.c e6eacc7ec735ded605fefcbaf250058baa8feb12 F src/os_win.c 496e3ceb499aedc63622a89ef76f7af2dd902709 -F src/pager.c b12dbe7e6c561d1675ddcc9c50b997c0692212e0 +F src/pager.c 9c9bc48765cb8d6c4445d3628bed52a0e0af762c F src/pager.h 75396879910768a0af03a4af8413e798d84c096f F src/parse.y 4d0e33a702dc3ea7b69d8ae1914b3fbd32e46057 F src/pcache.c 16dc8da6e6ba6250f8dfd9ee46036db1cbceedc6 @@ -477,7 +477,7 @@ F test/pageropt.test 3ee6578891baaca967f0bd349e4abfa736229e1a F test/pagesize.test 0d9ff3fedfce6e5ffe8fa7aca9b6d3433a2e843b F test/pcache.test 515b4c26e9f57660357dfff5b6b697acac1abc5f F test/pcache2.test 46efd980a89f737847b99327bda19e08fe11e402 -F test/permutations.test dccfc24254ab8d9cb9098e790c12fae52865f65f +F test/permutations.test 9e667c6b027856fc9b1d3d82cb51f0744885d010 F test/pragma.test 325aa0833d483b8e0c98e8196f1cc49fa5d8c336 F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47 F test/printf.test 262a5acd3158f788e9bdf7f18d718f3af32ff6ef @@ -493,12 +493,12 @@ F test/rollback.test 1f70ab4301d8d105d41438a436cad1fc8897f5e5 F test/rowid.test 1c8fc43c60d273e6ea44dfb992db587f3164312c F test/rtree.test b85fd4f0861a40ca366ac195e363be2528dcfadf F test/safety.test b69e2b2dd5d52a3f78e216967086884bbc1a09c6 -F test/savepoint.test 154001ac2863714eadd9c79865fa07faeda3d3a4 +F test/savepoint.test 7c743ac26268b042f8e16797c755644240c724e5 F test/savepoint2.test 18f6c75d5c133b93838019df8988b8cdf379d3de F test/savepoint3.test 1a0b1c0f59c6ae4402bfbca7cec29d4b1b272ff0 F test/savepoint4.test fd8850063e3c40565545f5c291e7f79a30591670 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd -F test/savepoint6.test 4808a41d2426d96d2fd742573c374f1d3ba90c61 +F test/savepoint6.test 7d584a665cb6e4f0c24d7a8ae7f8985461c683b1 F test/schema.test a8b000723375fd42c68d310091bdbd744fde647c F test/schema2.test 35e1c9696443d6694c8980c411497c2b5190d32e F test/select1.test d0a4cad954fd41c030ec16ffbd2d08a4c0548742 @@ -692,7 +692,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P a7015625610624be1645e918d0a62cf85bec86ce -R f82e1e4aa3ea5aea66445267a01cdb30 -U drh -Z b753d108e96492fb67c6923669f55766 +P c2482d8877a5f9e387b288377e410ae1b8267f3c +R 99d979f1a5afc6b0e70e7af446024426 +U danielk1977 +Z 76e17593f6a27ee09beef4dfa4478a92 diff --git a/manifest.uuid b/manifest.uuid index fb3293e5b4..00fa21adca 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c2482d8877a5f9e387b288377e410ae1b8267f3c \ No newline at end of file +8c62ea4fded2251e9daf16f2a050f94359299d76 \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index 9b669376df..c7904613e6 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.529 2009/01/03 12:55:18 drh Exp $ +** @(#) $Id: pager.c,v 1.530 2009/01/06 13:40:08 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -27,12 +27,13 @@ ** Macros for troubleshooting. Normally turned off */ #if 0 +int sqlite3PagerTrace=1; /* True to enable tracing */ #define sqlite3DebugPrintf printf -#define PAGERTRACE1(X) sqlite3DebugPrintf(X) -#define PAGERTRACE2(X,Y) sqlite3DebugPrintf(X,Y) -#define PAGERTRACE3(X,Y,Z) sqlite3DebugPrintf(X,Y,Z) -#define PAGERTRACE4(X,Y,Z,W) sqlite3DebugPrintf(X,Y,Z,W) -#define PAGERTRACE5(X,Y,Z,W,V) sqlite3DebugPrintf(X,Y,Z,W,V) +#define PAGERTRACE1(X) if( sqlite3PagerTrace ) sqlite3DebugPrintf(X) +#define PAGERTRACE2(X,Y) if( sqlite3PagerTrace ) sqlite3DebugPrintf(X,Y) +#define PAGERTRACE3(X,Y,Z) if( sqlite3PagerTrace ) sqlite3DebugPrintf(X,Y,Z) +#define PAGERTRACE4(X,Y,Z,W) if( sqlite3PagerTrace ) sqlite3DebugPrintf(X,Y,Z,W) +#define PAGERTRACE5(X,Y,Z,W,V) if( sqlite3PagerTrace ) sqlite3DebugPrintf(X,Y,Z,W,V) #else #define PAGERTRACE1(X) #define PAGERTRACE2(X,Y) @@ -1178,7 +1179,7 @@ static int pager_playback_one_page( if( rc!=SQLITE_OK ) return rc; rc = sqlite3OsRead(jfd, aData, pPager->pageSize, offset+4); if( rc!=SQLITE_OK ) return rc; - pPager->journalOff += pPager->pageSize + 4; + pPager->journalOff += pPager->pageSize + 4 + (isMainJrnl?4:0); /* Sanity checking on the page. This is more important that I originally ** thought. If a power failure occurs while the journal is being written, @@ -1194,7 +1195,6 @@ static int pager_playback_one_page( if( isMainJrnl ){ rc = read32bits(jfd, offset+pPager->pageSize+4, &cksum); if( rc ) return rc; - pPager->journalOff += 4; if( !isSavepnt && pager_cksum(pPager, aData)!=cksum ){ return SQLITE_DONE; } @@ -1251,6 +1251,29 @@ static int pager_playback_one_page( if( pgno>pPager->dbFileSize ){ pPager->dbFileSize = pgno; } + }else if( !isMainJrnl && pPg==0 ){ + /* If this is a rollback of a savepoint and data was not written to + ** the database and the page is not in-memory, there is a potential + ** problem. When the page is next fetched by the b-tree layer, it + ** will be read from the database file, which may or may not be + ** current. + ** + ** There are a couple of different ways this can happen. All are quite + ** obscure. When not running in synchronous mode, this can only happen + ** if the page is on the free-list at the start of the transaction, then + ** populated, then moved using sqlite3PagerMovepage(). + ** + ** The solution is to add an in-memory page to the cache containing + ** the data just read from the sub-journal. Mark the page as dirty + ** and if the pager requires a journal-sync, then mark the page as + ** requiring a journal-sync before it is written. + */ + assert( isSavepnt ); + if( (rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1)) ){ + return rc; + } + pPg->flags &= ~PGHDR_NEED_READ; + sqlite3PcacheMakeDirty(pPg); } if( pPg ){ /* No page should ever be explicitly rolled back that is in use, except @@ -1662,7 +1685,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){ i64 szJ; /* Size of the full journal */ i64 iHdrOff; /* End of first segment of main-journal records */ Pgno ii; /* Loop counter */ - int rc; /* Return code */ + int rc = SQLITE_OK; /* Return code */ Bitvec *pDone = 0; /* Bitvec to ensure pages played back only once */ /* Allocate a bitvec to use to store the set of pages rolled back */ @@ -1676,7 +1699,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){ /* Truncate the database back to the size it was before the ** savepoint being reverted was opened. */ - rc = pager_truncate(pPager, pSavepoint?pSavepoint->nOrig:pPager->dbOrigSize); + pPager->dbSize = pSavepoint?pSavepoint->nOrig:pPager->dbOrigSize; assert( pPager->state>=PAGER_SHARED ); /* Now roll back all main journal file records that occur after byte @@ -2350,6 +2373,13 @@ int sqlite3PagerClose(Pager *pPager){ pPager->exclusiveMode = 0; pager_reset(pPager); if( !MEMDB ){ + /* Set Pager.journalHdr to -1 for the benefit of the pager_playback() + ** call which may be made from within pagerUnlockAndRollback(). If it + ** is not -1, then the unsynced portion of an open journal file may + ** be played back into the database. If a power failure occurs while + ** this is happening, the database may become corrupt. + */ + pPager->journalHdr = -1; pagerUnlockAndRollback(pPager); } enable_simulated_io_errors(); @@ -2556,6 +2586,34 @@ static int pager_write_pagelist(PgHdr *pList){ return SQLITE_OK; } +/* +** Add the page to the sub-journal. It is the callers responsibility to +** use subjRequiresPage() to check that it is really required before +** calling this function. +*/ +static int subjournalPage(PgHdr *pPg){ + int rc; + void *pData = pPg->pData; + Pager *pPager = pPg->pPager; + i64 offset = pPager->stmtNRec*(4+pPager->pageSize); + char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7); + + PAGERTRACE3("STMT-JOURNAL %d page %d @ %d\n", PAGERID(pPager), pPg->pgno); + + assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize ); + rc = write32bits(pPager->sjfd, offset, pPg->pgno); + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4); + } + if( rc==SQLITE_OK ){ + pPager->stmtNRec++; + assert( pPager->nSavepoint>0 ); + rc = addToSavepointBitvecs(pPager, pPg->pgno); + } + return rc; +} + + /* ** This function is called by the pcache layer when it has reached some ** soft memory limit. The argument is a pointer to a purgeable Pager @@ -2585,7 +2643,12 @@ static int pagerStress(void *p, PgHdr *pPg){ } if( rc==SQLITE_OK ){ pPg->pDirty = 0; - rc = pager_write_pagelist(pPg); + if( pPg->pgno>pPager->dbSize && subjRequiresPage(pPg) ){ + rc = subjournalPage(pPg); + } + if( rc==SQLITE_OK ){ + rc = pager_write_pagelist(pPg); + } } if( rc!=SQLITE_OK ){ pager_error(pPager, rc); @@ -2593,6 +2656,7 @@ static int pagerStress(void *p, PgHdr *pPg){ } if( rc==SQLITE_OK ){ + PAGERTRACE3("STRESS %d page %d\n", PAGERID(pPager), pPg->pgno); sqlite3PcacheMakeClean(pPg); } return rc; @@ -3387,24 +3451,7 @@ static int pager_write(PgHdr *pPg){ ** in that it omits the checksums and the header. */ if( subjRequiresPage(pPg) ){ - i64 offset = pPager->stmtNRec*(4+pPager->pageSize); - char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7); - assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize ); - rc = write32bits(pPager->sjfd, offset, pPg->pgno); - if( rc==SQLITE_OK ){ - rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4); - } - PAGERTRACE3("STMT-JOURNAL %d page %d @ %d\n", PAGERID(pPager), pPg->pgno); - if( rc!=SQLITE_OK ){ - return rc; - } - pPager->stmtNRec++; - assert( pPager->nSavepoint>0 ); - rc = addToSavepointBitvecs(pPager, pPg->pgno); - if( rc!=SQLITE_OK ){ - assert( rc==SQLITE_NOMEM ); - return rc; - } + rc = subjournalPage(pPg); } } diff --git a/test/permutations.test b/test/permutations.test index 2599c2d586..bd92896d5a 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -9,7 +9,7 @@ # #*********************************************************************** # -# $Id: permutations.test,v 1.42 2009/01/03 15:06:38 danielk1977 Exp $ +# $Id: permutations.test,v 1.43 2009/01/06 13:40:08 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -712,7 +712,9 @@ run_tests "journaltest" -description { set ISQUICK 1 catch {db close} register_jt_vfs -default "" + #sqlite3_instvfs binarylog -default binarylog ostrace.bin } -shutdown { + #sqlite3_instvfs destroy binarylog unregister_jt_vfs } -include [concat $::ALLTESTS savepoint6.test ] -exclude { diff --git a/test/savepoint.test b/test/savepoint.test index b79c87f572..6ccb07762d 100644 --- a/test/savepoint.test +++ b/test/savepoint.test @@ -9,7 +9,7 @@ # #*********************************************************************** # -# $Id: savepoint.test,v 1.7 2009/01/03 15:06:38 danielk1977 Exp $ +# $Id: savepoint.test,v 1.8 2009/01/06 13:40:08 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -467,6 +467,35 @@ do_test savepoint-7.4.1 { execsql { PRAGMA integrity_check } } {ok} +do_test savepoint-7.5.1 { + execsql { + PRAGMA incremental_vacuum; + CREATE TABLE t5(x, y); + INSERT INTO t5 VALUES(1, randstr(1000,1000)); + INSERT INTO t5 VALUES(2, randstr(1000,1000)); + INSERT INTO t5 VALUES(3, randstr(1000,1000)); + + BEGIN; + INSERT INTO t5 VALUES(4, randstr(1000,1000)); + INSERT INTO t5 VALUES(5, randstr(1000,1000)); + DELETE FROM t5 WHERE x=1 OR x=2; + SAVEPOINT one; + PRAGMA incremental_vacuum; + SAVEPOINT two; + INSERT INTO t5 VALUES(1, randstr(1000,1000)); + INSERT INTO t5 VALUES(2, randstr(1000,1000)); + ROLLBACK TO two; + ROLLBACK TO one; + COMMIT; + PRAGMA integrity_check; + } +} {ok} +do_test savepoint-7.5.2 { + execsql { + DROP TABLE t5; + } +} {} + # Test oddly named and quoted savepoints. # do_test savepoint-8-1 { diff --git a/test/savepoint6.test b/test/savepoint6.test index 96d95fc2f0..474d1051fc 100644 --- a/test/savepoint6.test +++ b/test/savepoint6.test @@ -9,19 +9,22 @@ # #*********************************************************************** # -# $Id: savepoint6.test,v 1.1 2009/01/03 10:41:29 danielk1977 Exp $ +# $Id: savepoint6.test,v 1.2 2009/01/06 13:40:08 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl -do_test savepoint6-1.1 { - execsql { +proc sql {zSql} { + uplevel db eval [list $zSql] + #puts stderr "$zSql ;" +} + +set DATABASE_SCHEMA { PRAGMA auto_vacuum = incremental; CREATE TABLE t1(x, y); CREATE UNIQUE INDEX i1 ON t1(x); CREATE INDEX i2 ON t1(y); - } -} {} +} #-------------------------------------------------------------------------- # In memory database state. @@ -60,12 +63,12 @@ proc x_to_y {x} { # delete_rows XVALUES # proc savepoint {zName} { - catch { db eval "SAVEPOINT $zName" } + catch { sql "SAVEPOINT $zName" } lappend ::lSavepoint [list $zName [array get ::aEntry]] } proc rollback {zName} { - catch { db eval "ROLLBACK TO $zName" } + catch { sql "ROLLBACK TO $zName" } for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} { set zSavepoint [lindex $::lSavepoint $i 0] if {$zSavepoint eq $zName} { @@ -82,7 +85,7 @@ proc rollback {zName} { } proc release {zName} { - catch { db eval "RELEASE $zName" } + catch { sql "RELEASE $zName" } for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} { set zSavepoint [lindex $::lSavepoint $i 0] if {$zSavepoint eq $zName} { @@ -90,6 +93,10 @@ proc release {zName} { break } } + + if {[llength $::lSavepoint] == 0} { + #puts stderr "-- End of transaction!!!!!!!!!!!!!" + } } proc insert_rows {lX} { @@ -97,7 +104,7 @@ proc insert_rows {lX} { set y [x_to_y $x] # Update database [db] - db eval {INSERT OR REPLACE INTO t1 VALUES($x, $y)} + sql "INSERT OR REPLACE INTO t1 VALUES($x, '$y')" # Update the Tcl database. set ::aEntry($x) $y @@ -107,7 +114,7 @@ proc insert_rows {lX} { proc delete_rows {lX} { foreach x $lX { # Update database [db] - db eval {DELETE FROM t1 WHERE x = $x} + sql "DELETE FROM t1 WHERE x = $x" # Update the Tcl database. unset -nocomplain ::aEntry($x) @@ -153,9 +160,6 @@ proc random_integers {nRes nRange} { } #------------------------------------------------------------------------- -db eval { PRAGMA cache_size = 10 } -expr srand(0) - proc database_op {} { set i [expr int(rand()*2)] if {$i==0} { @@ -165,7 +169,7 @@ proc database_op {} { delete_rows [random_integers 100 1000] set i [expr int(rand()*3)] if {$i==0} { - db eval {PRAGMA incremental_vacuum} + sql {PRAGMA incremental_vacuum} } } } @@ -177,27 +181,82 @@ proc savepoint_op {} { set C [lindex $cmds [expr int(rand()*6)]] set N [lindex $names [expr int(rand()*5)]] + #puts stderr " $C $N ; " + #flush stderr + $C $N return ok } -do_test savepoint6-2.1 { +expr srand(0) + +############################################################################ +############################################################################ +# Start of test cases. + +do_test savepoint6-1.1 { + sql $DATABASE_SCHEMA +} {} +do_test savepoint6-1.2 { + insert_rows { + 497 166 230 355 779 588 394 317 290 475 362 193 805 851 564 + 763 44 930 389 819 765 760 966 280 538 414 500 18 25 287 320 + 30 382 751 87 283 981 429 630 974 421 270 810 405 + } + savepoint one - insert_rows [random_integers 100 1000] + insert_rows 858 + delete_rows 930 + savepoint two + execsql {PRAGMA incremental_vacuum} + savepoint three + insert_rows 144 + rollback three + rollback two release one - checkdb -} {ok} -for {set i 0} {$i < 1000} {incr i} { - do_test savepoint6-3.$i.1 { - savepoint_op - } {ok} + execsql {SELECT count(*) FROM t1} +} {44} + +foreach zSetup [list { + set testname normal + sqlite3 db test.db +} { + set testname tempdb + sqlite3 db "" +} { + set testname smallcache + sqlite3 db test.db + sql { PRAGMA cache_size = 10 } +}] { + + unset -nocomplain ::lSavepoint + unset -nocomplain ::aEntry - do_test savepoint6-3.$i.2 { - database_op - database_op + db close + file delete -force test.db + eval $zSetup + sql $DATABASE_SCHEMA + + do_test savepoint6-$testname.setup { + savepoint one + insert_rows [random_integers 100 1000] + release one checkdb } {ok} + + for {set i 0} {$i < 1000} {incr i} { + do_test savepoint6-$testname.$i.1 { + savepoint_op + checkdb + } {ok} + + do_test savepoint6-$testname.$i.2 { + database_op + database_op + checkdb + } {ok} + } } unset -nocomplain ::lSavepoint