1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Fixes for problems with small caches and SAVEPOINT rollback in WAL mode.

FossilOrigin-Name: 6a944f028d4a070bef29e1fbc6fbef481ebcd34c
This commit is contained in:
dan
2010-04-26 16:57:10 +00:00
parent 71cb518fca
commit 4cd78b4d89
8 changed files with 141 additions and 28 deletions

View File

@@ -1,5 +1,5 @@
C Add\sthe\s"wal"\spermutation\sto\srun\sexisting\stest\sfiles\ssavepoint.test\sand\ssavepoint2.test\sin\sWAL\smode.
D 2010-04-26T12:39:04
C Fixes\sfor\sproblems\swith\ssmall\scaches\sand\sSAVEPOINT\srollback\sin\sWAL\smode.
D 2010-04-26T16:57:10
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in d83a0ffef3dcbfb08b410a6c6dd6c009ec9167fb
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -152,7 +152,7 @@ F src/os_common.h 240c88b163b02c21a9f21f87d49678a0aa21ff30
F src/os_os2.c 082884dc2a20a2f1fddc404f3606ec2abe907b56
F src/os_unix.c 1acc854259b045cf029c6f95828a5f4b84f361c7
F src/os_win.c 607b40e40662c6c74ff2400ff03e7f42521d5c75
F src/pager.c 5924538fb99f62774419bfae882debb0d65bc3c8
F src/pager.c b4a41030860229e80295fa1f37addab24d21799c
F src/pager.h cee4487ab4f0911dd9f22a40e3cd55afdb7ef444
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf
@@ -221,8 +221,8 @@ F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
F src/wal.c f93ce8968d6e86378aa2d465f592027e02929a7a
F src/wal.h 1a34bb71642b46af5e6d51c2f69ae0f55268df81
F src/wal.c ce03bdd759c7b949188c0b75c46777fe0f7f105e
F src/wal.h 812101dd76610401fbcd44114e7e8b7ce0224645
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c faadd9c2bf08868e5135192b44e0d753e363a885
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -532,7 +532,7 @@ F test/pageropt.test 3ee6578891baaca967f0bd349e4abfa736229e1a
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
F test/pcache.test eebc4420b37cb07733ae9b6e99c9da7c40dd6d58
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
F test/permutations.test e9a9070862e3c675f0844815054cfd2ed4ed9c66
F test/permutations.test 0730dc6c028b620a15c38a0a7d07238da088ecd3
F test/pragma.test 6960f9efbce476f70ba9ee2171daf5042f9e3d8a
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
@@ -553,7 +553,7 @@ F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7
F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
F test/savepoint6.test 2df1d093e59e78d688c64eb20e0457aaea7d08f9
F test/savepoint6.test 8e871226bcd20241c0ee7da28166f5c525d7cba9
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
F test/securedel.test 328d2921c0ca49bdd3352e516b0377fc07143254
@@ -758,7 +758,7 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
F test/wal.test 7d44c2ee327e86a7c26052795789dd2d472bd1d4
F test/wal.test b5d5fe1b3171eefb25355758e0dc689096bc1f87
F test/walbak.test f6fde9a5f59d0c697cb1f4af7876178c2f69a7ba
F test/walcrash.test f022cee7eb7baa5fb898726120a6a4073dd831d1
F test/walhook.test 76a559e262f0715c470bade4a8d8333035f8ee47
@@ -808,7 +808,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 3d159939cc2beb18c4ca0c8e9a99a75d4107e6e4
R 9cdc568754b75f48338d755d9a93a206
P 205e5d8ac08f7d7853427b4cd235fca125155d2d
R f3447c8eaaa2559454ba677c09b3ac47
U dan
Z e32fb56774989323e02682dddebb9008
Z 1f4eebc47ae413fc016108c1a59ad1db

View File

@@ -1 +1 @@
205e5d8ac08f7d7853427b4cd235fca125155d2d
6a944f028d4a070bef29e1fbc6fbef481ebcd34c

View File

@@ -221,6 +221,7 @@ struct PagerSavepoint {
Bitvec *pInSavepoint; /* Set of pages in this savepoint */
Pgno nOrig; /* Original number of pages in file */
Pgno iSubRec; /* Index of first record in sub-journal */
u32 iFrame; /* Last frame in WAL when savepoint opened */
};
/*
@@ -1539,6 +1540,7 @@ static int pager_playback_one_page(
aData = pPager->pTmpSpace;
assert( aData ); /* Temp storage must have already been allocated */
assert( pagerUseLog(pPager)==0 || (!isMainJrnl && isSavepnt) );
/* Read the page number and page data from the journal or sub-journal
** file. Return an error code to the caller if an IO error occurs.
@@ -1608,7 +1610,11 @@ static int pager_playback_one_page(
** is possible to fail a statement on a database that does not yet exist.
** Do not attempt to write if database file has never been opened.
*/
if( pagerUseLog(pPager) ){
pPg = 0;
}else{
pPg = pager_lookup(pPager, pgno);
}
assert( pPg || !MEMDB );
PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData),
@@ -1625,6 +1631,7 @@ static int pager_playback_one_page(
){
i64 ofst = (pgno-1)*(i64)pPager->pageSize;
testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
assert( !pagerUseLog(pPager) );
rc = sqlite3OsWrite(pPager->fd, (u8*)aData, pPager->pageSize, ofst);
if( pgno>pPager->dbFileSize ){
pPager->dbFileSize = pgno;
@@ -1689,6 +1696,7 @@ static int pager_playback_one_page(
** segment is synced. If a crash occurs during or following this,
** database corruption may ensue.
*/
assert( !pagerUseLog(pPager) );
sqlite3PcacheMakeClean(pPg);
}
#ifdef SQLITE_CHECK_PAGES
@@ -2428,6 +2436,10 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
if( pSavepoint ){
u32 ii; /* Loop counter */
i64 offset = pSavepoint->iSubRec*(4+pPager->pageSize);
if( pagerUseLog(pPager) ){
rc = sqlite3WalSavepointUndo(pPager->pLog, pSavepoint->iFrame);
}
for(ii=pSavepoint->iSubRec; rc==SQLITE_OK && ii<pPager->nSubRec; ii++){
assert( offset==ii*(4+pPager->pageSize) );
rc = pager_playback_one_page(pPager, &offset, pDone, 0, 1);
@@ -2439,6 +2451,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
if( rc==SQLITE_OK ){
pPager->journalOff = szJ;
}
return rc;
}
@@ -3326,7 +3339,12 @@ static int pagerStress(void *p, PgHdr *pPg){
pPg->pDirty = 0;
if( pagerUseLog(pPager) ){
/* Write a single frame for this page to the log. */
if( subjRequiresPage(pPg) ){
rc = subjournalPage(pPg);
}
if( rc==SQLITE_OK ){
rc = pagerLogFrames(pPager, pPg, 0, 0, 0);
}
}else{
/* The doNotSync flag is set by the sqlite3PagerWrite() function while it
** is journalling a set of two or more database pages that are stored
@@ -5342,6 +5360,9 @@ int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
if( !aNew[ii].pInSavepoint ){
return SQLITE_NOMEM;
}
if( pagerUseLog(pPager) ){
aNew[ii].iFrame = sqlite3WalSavepoint(pPager->pLog);
}
}
/* Open the sub-journal, if it is not already opened. */

View File

@@ -1669,6 +1669,27 @@ int sqlite3WalUndo(Log *pLog, int (*xUndo)(void *, Pgno), void *pUndoCtx){
return rc;
}
u32 sqlite3WalSavepoint(Log *pLog){
assert( pLog->isWriteLocked );
return pLog->hdr.iLastPg;
}
int sqlite3WalSavepointUndo(Log *pLog, u32 iFrame){
int rc = SQLITE_OK;
u8 aCksum[8];
assert( pLog->isWriteLocked );
pLog->hdr.iLastPg = iFrame;
if( iFrame>0 ){
i64 iOffset = logFrameOffset(iFrame, pLog->hdr.pgsz) + sizeof(u32)*2;
rc = sqlite3OsRead(pLog->pFd, aCksum, sizeof(aCksum), iOffset);
pLog->hdr.iCheck1 = sqlite3Get4byte(&aCksum[0]);
pLog->hdr.iCheck2 = sqlite3Get4byte(&aCksum[4]);
}
return rc;
}
/*
** Return true if data has been written but not committed to the log file.
*/
@@ -1678,8 +1699,8 @@ int sqlite3WalDirty(Log *pLog){
}
/*
** Write a set of frames to the log. The caller must hold at least a
** RESERVED lock on the database file.
** Write a set of frames to the log. The caller must hold the write-lock
** on the log file (obtained using sqlite3WalWriteLock()).
*/
int sqlite3WalFrames(
Log *pLog, /* Log handle to write to */

View File

@@ -40,6 +40,9 @@ int sqlite3WalWriteLock(Log *pLog, int op);
/* Undo any frames written (but not committed) to the log */
int sqlite3WalUndo(Log *pLog, int (*xUndo)(void *, Pgno), void *pUndoCtx);
u32 sqlite3WalSavepoint(Log *pLog);
int sqlite3WalSavepointUndo(Log *pLog, u32 iFrame);
/* Return true if data has been written but not committed to the log file. */
int sqlite3WalDirty(Log *pLog);

View File

@@ -761,6 +761,7 @@ run_tests "wal" -description {
} -include {
savepoint.test
savepoint2.test
savepoint6.test
}
# End of tests

View File

@@ -222,6 +222,7 @@ foreach zSetup [list {
set testname normal
sqlite3 db test.db
} {
if {[wal_is_wal_mode]} continue
set testname tempdb
sqlite3 db ""
} {
@@ -241,10 +242,12 @@ foreach zSetup [list {
unset -nocomplain ::aEntry
catch { db close }
file delete -force test.db
file delete -force test.db test.db-wal test.db-journal
eval $zSetup
sql $DATABASE_SCHEMA
wal_set_journal_mode
do_test savepoint6-$testname.setup {
savepoint one
insert_rows [random_integers 100 1000]
@@ -252,7 +255,7 @@ foreach zSetup [list {
checkdb
} {ok}
for {set i 0} {$i < 1000} {incr i} {
for {set i 0} {$i < 50} {incr i} {
do_test savepoint6-$testname.$i.1 {
savepoint_op
checkdb
@@ -264,6 +267,8 @@ foreach zSetup [list {
checkdb
} {ok}
}
wal_check_journal_mode savepoint6-$testname.walok
}
unset -nocomplain ::lSavepoint

View File

@@ -166,13 +166,13 @@ do_test wal-4.3 {
}
} {a b}
do_test wal-4.4 {
do_test wal-4.4.1 {
db close
sqlite3 db test.db
db func blob blob
list [execsql { SELECT * FROM t1 }] [file size test.db-wal]
} {{a b} 0}
do_test wal-4.5 {
do_test wal-4.4.2 {
execsql { PRAGMA cache_size = 10 }
execsql {
CREATE TABLE t2(a, b);
@@ -191,10 +191,10 @@ do_test wal-4.5 {
SELECT count(*) FROM t2;
}
} {32}
do_test wal-4.6 {
do_test wal-4.4.3 {
execsql { ROLLBACK TO tr }
} {}
do_test wal-4.7 {
do_test wal-4.4.4 {
set logsize [file size test.db-wal]
execsql {
INSERT INTO t1 VALUES('x', 'y');
@@ -202,20 +202,82 @@ do_test wal-4.7 {
}
expr { $logsize == [file size test.db-wal] }
} {1}
do_test wal-4.8 {
do_test wal-4.4.5 {
execsql { SELECT count(*) FROM t2 }
} {1}
do_test wal-4.9 {
do_test wal-4.4.6 {
file copy -force test.db test2.db
file copy -force test.db-wal test2.db-wal
sqlite3 db2 test2.db
execsql { SELECT count(*) FROM t2 ; SELECT count(*) FROM t1 } db2
} {1 2}
do_test wal-4.10 {
do_test wal-4.4.7 {
execsql { PRAGMA integrity_check } db2
} {ok}
db2 close
do_test wal-4.5.1 {
reopen_db
db func blob blob
execsql {
PRAGMA journal_mode = WAL;
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES('a', 'b');
}
sqlite3 db test.db
db func blob blob
list [execsql { SELECT * FROM t1 }] [file size test.db-wal]
} {{a b} 0}
do_test wal-4.5.2 {
execsql { PRAGMA cache_size = 10 }
execsql {
CREATE TABLE t2(a, b);
BEGIN;
INSERT INTO t2 VALUES(blob(400), blob(400));
SAVEPOINT tr;
INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 2 */
INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 4 */
INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 8 */
INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 16 */
INSERT INTO t2 SELECT blob(400), blob(400) FROM t2; /* 32 */
INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 2 */
INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 4 */
INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 8 */
INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 16 */
INSERT INTO t1 SELECT blob(400), blob(400) FROM t1; /* 32 */
SELECT count(*) FROM t2;
}
} {32}
do_test wal-4.5.3 {
breakpoint
execsql { ROLLBACK TO tr }
} {}
do_test wal-4.5.4 {
set logsize [file size test.db-wal]
breakpoint
execsql {
INSERT INTO t1 VALUES('x', 'y');
RELEASE tr;
COMMIT;
}
expr { $logsize == [file size test.db-wal] }
} {1}
do_test wal-4.5.5 {
execsql { SELECT count(*) FROM t2 ; SELECT count(*) FROM t1 }
} {1 2}
do_test wal-4.5.6 {
file copy -force test.db test2.db
file copy -force test.db-wal test2.db-wal
sqlite3 db2 test2.db
breakpoint
execsql { SELECT count(*) FROM t2 ; SELECT count(*) FROM t1 } db2
} {1 2}
do_test wal-4.5.7 {
execsql { PRAGMA integrity_check } db2
} {ok}
db2 close
reopen_db
do_test wal-5.1 {
execsql {
@@ -680,7 +742,7 @@ do_test wal-11.10 {
SELECT count(*) FROM t1;
}
list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [log_file_size 35 1024]]
} [list 37 [log_file_size 37 1024]]
do_test wal-11.11 {
execsql {
SELECT count(*) FROM t1;
@@ -690,7 +752,7 @@ do_test wal-11.11 {
} {32 16}
do_test wal-11.12 {
list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [log_file_size 35 1024]]
} [list 37 [log_file_size 37 1024]]
do_test wal-11.13 {
execsql {
INSERT INTO t1 VALUES( blob(900) );
@@ -700,7 +762,7 @@ do_test wal-11.13 {
} {17 ok}
do_test wal-11.14 {
list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [log_file_size 35 1024]]
} [list 37 [log_file_size 37 1024]]
#-------------------------------------------------------------------------