Fix bugs in WAL mode rollback.
FossilOrigin-Name: 31215969f59be536fe87431bb9fbfa7d13027e35
This commit is contained in:
parent
9de7943783
commit
74d6cd887f
18
manifest
18
manifest
@ -1,5 +1,5 @@
|
|||||||
C Merge\swith\s[0291ed974d].\nMerge\swith\s[0291ed974d].\nMerge\swith\s[0291ed974d].
|
C Fix\sbugs\sin\sWAL\smode\srollback.
|
||||||
D 2010-04-24T14:33:08
|
D 2010-04-24T18:44:05
|
||||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||||
F Makefile.in 4f2f967b7e58a35bb74fb7ec8ae90e0f4ca7868b
|
F Makefile.in 4f2f967b7e58a35bb74fb7ec8ae90e0f4ca7868b
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@ -131,8 +131,8 @@ F src/journal.c b0ea6b70b532961118ab70301c00a33089f9315c
|
|||||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||||
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
||||||
F src/loadext.c 1c7a61ce1281041f437333f366a96aa0d29bb581
|
F src/loadext.c 1c7a61ce1281041f437333f366a96aa0d29bb581
|
||||||
F src/log.c 7569a2f6541c86127914d50e9fd6e65c17111bc6
|
F src/log.c 6097555f746e9992b3bb7a257d2e60ced69e3a84
|
||||||
F src/log.h bc44b0eec723648c8aa0a05ab78e1b76a4032e02
|
F src/log.h 06eacedac8b5a720cb88aa3c9e5d886ba7b394fe
|
||||||
F src/main.c 867de6aa444abd97771b2b70472f448d65c1c77e
|
F src/main.c 867de6aa444abd97771b2b70472f448d65c1c77e
|
||||||
F src/malloc.c a08f16d134f0bfab6b20c3cd142ebf3e58235a6a
|
F src/malloc.c a08f16d134f0bfab6b20c3cd142ebf3e58235a6a
|
||||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||||
@ -154,7 +154,7 @@ F src/os_common.h 240c88b163b02c21a9f21f87d49678a0aa21ff30
|
|||||||
F src/os_os2.c 75a8c7b9a00a2cf1a65f9fa4afbc27d46634bb2f
|
F src/os_os2.c 75a8c7b9a00a2cf1a65f9fa4afbc27d46634bb2f
|
||||||
F src/os_unix.c 5bf0015cebe2f21635da2af983c348eb88b3b4c1
|
F src/os_unix.c 5bf0015cebe2f21635da2af983c348eb88b3b4c1
|
||||||
F src/os_win.c 1c7453c2df4dab26d90ff6f91272aea18bcf7053
|
F src/os_win.c 1c7453c2df4dab26d90ff6f91272aea18bcf7053
|
||||||
F src/pager.c 485a34834a96863fd709f4d01f886ae70a9689ea
|
F src/pager.c 9da40bb50d2baa8f7cbb18579f147b7623856211
|
||||||
F src/pager.h cee4487ab4f0911dd9f22a40e3cd55afdb7ef444
|
F src/pager.h cee4487ab4f0911dd9f22a40e3cd55afdb7ef444
|
||||||
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
|
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
|
||||||
F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf
|
F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf
|
||||||
@ -758,7 +758,7 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
|
|||||||
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
||||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||||
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
|
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
|
||||||
F test/wal.test fcb5ec1fbec08c1165b6974f126056f2b4cead49
|
F test/wal.test 8dcfd1ce874aead6199fa715ba8e35cfbb3ef766
|
||||||
F test/walbak.test f6fde9a5f59d0c697cb1f4af7876178c2f69a7ba
|
F test/walbak.test f6fde9a5f59d0c697cb1f4af7876178c2f69a7ba
|
||||||
F test/walcrash.test f022cee7eb7baa5fb898726120a6a4073dd831d1
|
F test/walcrash.test f022cee7eb7baa5fb898726120a6a4073dd831d1
|
||||||
F test/walhook.test 76a559e262f0715c470bade4a8d8333035f8ee47
|
F test/walhook.test 76a559e262f0715c470bade4a8d8333035f8ee47
|
||||||
@ -808,7 +808,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
|||||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||||
P 1e793d3a6d46ec5d744e077b10362e7cfa118eef 0291ed974d5bf1e344e2c38422530cc961b897da
|
P a352f6285e33a806fbe4475e720e763fdc5bb47d
|
||||||
R 2a96ead5dd8a150336ca23e8e3a9aa5f
|
R a372a014eac56d1df8e79bcff4ecc6e7
|
||||||
U dan
|
U dan
|
||||||
Z 95ff3026ac52c375d39478f793178d69
|
Z 3d8f3676c5fc9fd427fe6aa0aa15e428
|
||||||
|
@ -1 +1 @@
|
|||||||
a352f6285e33a806fbe4475e720e763fdc5bb47d
|
31215969f59be536fe87431bb9fbfa7d13027e35
|
27
src/log.c
27
src/log.c
@ -1611,6 +1611,33 @@ int sqlite3LogWriteLock(Log *pLog, int op){
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The log handle passed to this function must be holding the write-lock.
|
||||||
|
**
|
||||||
|
** If any data has been written (but not committed) to the log file, this
|
||||||
|
** function moves the write-pointer back to the start of the transaction.
|
||||||
|
**
|
||||||
|
** Additionally, the callback function is invoked for each frame written
|
||||||
|
** to the log since the start of the transaction. If the callback returns
|
||||||
|
** other than SQLITE_OK, it is not invoked again and the error code is
|
||||||
|
** returned to the caller.
|
||||||
|
**
|
||||||
|
** Otherwise, if the callback function does not return an error, this
|
||||||
|
** function returns SQLITE_OK.
|
||||||
|
*/
|
||||||
|
int sqlite3LogUndo(Log *pLog, int (*xUndo)(void *, Pgno), void *pUndoCtx){
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
Pgno iMax = pLog->hdr.iLastPg;
|
||||||
|
Pgno iFrame;
|
||||||
|
|
||||||
|
assert( pLog->isWriteLocked );
|
||||||
|
logSummaryReadHdr(pLog, 0);
|
||||||
|
for(iFrame=pLog->hdr.iLastPg+1; iFrame<=iMax && rc==SQLITE_OK; iFrame++){
|
||||||
|
rc = xUndo(pUndoCtx, pLog->pSummary->aData[logSummaryEntry(iFrame)]);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return true if data has been written but not committed to the log file.
|
** Return true if data has been written but not committed to the log file.
|
||||||
*/
|
*/
|
||||||
|
@ -37,6 +37,9 @@ void sqlite3LogDbsize(Log *pLog, Pgno *pPgno);
|
|||||||
/* Obtain or release the WRITER lock. */
|
/* Obtain or release the WRITER lock. */
|
||||||
int sqlite3LogWriteLock(Log *pLog, int op);
|
int sqlite3LogWriteLock(Log *pLog, int op);
|
||||||
|
|
||||||
|
/* Undo any frames written (but not committed) to the log */
|
||||||
|
int sqlite3LogUndo(Log *pLog, int (*xUndo)(void *, Pgno), void *pUndoCtx);
|
||||||
|
|
||||||
/* Return true if data has been written but not committed to the log file. */
|
/* Return true if data has been written but not committed to the log file. */
|
||||||
int sqlite3LogDirty(Log *pLog);
|
int sqlite3LogDirty(Log *pLog);
|
||||||
|
|
||||||
|
62
src/pager.c
62
src/pager.c
@ -2235,16 +2235,44 @@ static int readDbPage(PgHdr *pPg){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This function is called when a transaction on a WAL database is rolled
|
** This function is invoked once for each page that has already been
|
||||||
** back. For each dirty page in the cache, do one of the following:
|
** written into the log file when a WAL transaction is rolled back.
|
||||||
|
** Parameter iPg is the page number of said page. The pCtx argument
|
||||||
|
** is actually a pointer to the Pager structure.
|
||||||
**
|
**
|
||||||
** * If the page has no outstanding references, simply discard it.
|
** If page iPg is present in the cache, and has no outstanding references,
|
||||||
** * Otherwise, if the page has one or more outstanding references,
|
** it is discarded. Otherwise, if there are one or more outstanding
|
||||||
** reload the original content from the database (or log file).
|
** references, the page content is reloaded from the database. If the
|
||||||
|
** attempt to reload content from the database is required and fails,
|
||||||
|
** return an SQLite error code. Otherwise, SQLITE_OK.
|
||||||
|
*/
|
||||||
|
static int pagerUndoCallback(void *pCtx, Pgno iPg){
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
Pager *pPager = (Pager *)pCtx;
|
||||||
|
PgHdr *pPg;
|
||||||
|
|
||||||
|
pPg = sqlite3PagerLookup(pPager, iPg);
|
||||||
|
if( pPg ){
|
||||||
|
if( sqlite3PcachePageRefcount(pPg)==1 ){
|
||||||
|
sqlite3PcacheDrop(pPg);
|
||||||
|
}else{
|
||||||
|
rc = readDbPage(pPg);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
pPager->xReiniter(pPg);
|
||||||
|
}
|
||||||
|
sqlite3PagerUnref(pPg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This function is called to rollback a transaction on a WAL database.
|
||||||
*/
|
*/
|
||||||
static int pagerRollbackLog(Pager *pPager){
|
static int pagerRollbackLog(Pager *pPager){
|
||||||
int rc = SQLITE_OK;
|
int rc; /* Return Code */
|
||||||
PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
|
PgHdr *pList; /* List of dirty pages to revert */
|
||||||
|
|
||||||
/* Normally, if a transaction is rolled back, any backup processes are
|
/* Normally, if a transaction is rolled back, any backup processes are
|
||||||
** updated as data is copied out of the rollback journal and into the
|
** updated as data is copied out of the rollback journal and into the
|
||||||
@ -2258,20 +2286,22 @@ static int pagerRollbackLog(Pager *pPager){
|
|||||||
sqlite3BackupRestart(pPager->pBackup);
|
sqlite3BackupRestart(pPager->pBackup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For all pages in the cache that are currently dirty or have already
|
||||||
|
** been written (but not committed) to the log file, do one of the
|
||||||
|
** following:
|
||||||
|
**
|
||||||
|
** + Discard the cached page (if refcount==0), or
|
||||||
|
** + Reload page content from the database (if refcount>0).
|
||||||
|
*/
|
||||||
pPager->dbSize = pPager->dbOrigSize;
|
pPager->dbSize = pPager->dbOrigSize;
|
||||||
|
rc = sqlite3LogUndo(pPager->pLog, pagerUndoCallback, (void *)pPager);
|
||||||
|
pList = sqlite3PcacheDirtyList(pPager->pPCache);
|
||||||
while( pList && rc==SQLITE_OK ){
|
while( pList && rc==SQLITE_OK ){
|
||||||
PgHdr *pNext = pList->pDirty;
|
PgHdr *pNext = pList->pDirty;
|
||||||
if( sqlite3PcachePageRefcount(pList)==0 ){
|
rc = pagerUndoCallback((void *)pPager, pList->pgno);
|
||||||
sqlite3PagerLookup(pPager, pList->pgno);
|
|
||||||
sqlite3PcacheDrop(pList);
|
|
||||||
}else{
|
|
||||||
rc = readDbPage(pList);
|
|
||||||
if( rc==SQLITE_OK ){
|
|
||||||
pPager->xReiniter(pList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pList = pNext;
|
pList = pNext;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +139,10 @@ do_test wal-3.3 {
|
|||||||
} {1 2 3 4 5 6 7 8 9 10 11 12 13 14}
|
} {1 2 3 4 5 6 7 8 9 10 11 12 13 14}
|
||||||
db2 close
|
db2 close
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# The following tests, wal-4.*, test that savepoints work with WAL
|
||||||
|
# databases.
|
||||||
|
#
|
||||||
do_test wal-4.1 {
|
do_test wal-4.1 {
|
||||||
execsql {
|
execsql {
|
||||||
DELETE FROM t1;
|
DELETE FROM t1;
|
||||||
@ -162,6 +166,57 @@ do_test wal-4.3 {
|
|||||||
}
|
}
|
||||||
} {a b}
|
} {a b}
|
||||||
|
|
||||||
|
do_test wal-4.4 {
|
||||||
|
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 {
|
||||||
|
execsql { PRAGMA cache_size = 10 }
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t2(a, b);
|
||||||
|
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.6 {
|
||||||
|
execsql { ROLLBACK TO tr }
|
||||||
|
} {}
|
||||||
|
do_test wal-4.7 {
|
||||||
|
set logsize [file size test.db-wal]
|
||||||
|
execsql {
|
||||||
|
INSERT INTO t1 VALUES('x', 'y');
|
||||||
|
RELEASE tr;
|
||||||
|
}
|
||||||
|
expr { $logsize == [file size test.db-wal] }
|
||||||
|
} {1}
|
||||||
|
do_test wal-4.8 {
|
||||||
|
execsql { SELECT count(*) FROM t2 }
|
||||||
|
} {1}
|
||||||
|
do_test wal-4.9 {
|
||||||
|
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 {
|
||||||
|
execsql { PRAGMA integrity_check } db2
|
||||||
|
} {ok}
|
||||||
|
db2 close
|
||||||
|
|
||||||
|
reopen_db
|
||||||
do_test wal-5.1 {
|
do_test wal-5.1 {
|
||||||
execsql {
|
execsql {
|
||||||
CREATE TEMP TABLE t2(a, b);
|
CREATE TEMP TABLE t2(a, b);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user