mirror of
https://github.com/sqlite/sqlite.git
synced 2024-12-01 17:23:42 +01:00
Fixes and tests for backup of a WAL database.
FossilOrigin-Name: 480d12db4c0ebcc37598f7620d39193875eab15b
This commit is contained in:
parent
d5c99c3939
commit
3306c4a945
20
manifest
20
manifest
@ -1,5 +1,5 @@
|
||||
C Add\svery\ssimple\stest\scases\sfor\sbackup\sand\sVACUUM\sof\sWAL\sdatabases.\sMore\sto\scome.
|
||||
D 2010-04-23T11:44:41
|
||||
C Fixes\sand\stests\sfor\sbackup\sof\sa\sWAL\sdatabase.
|
||||
D 2010-04-23T19:15:00
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in 4f2f967b7e58a35bb74fb7ec8ae90e0f4ca7868b
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@ -131,8 +131,8 @@ F src/journal.c b0ea6b70b532961118ab70301c00a33089f9315c
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
||||
F src/loadext.c 1c7a61ce1281041f437333f366a96aa0d29bb581
|
||||
F src/log.c da486aab7abfab8edbc20eb49e2f68e9d3a902b6
|
||||
F src/log.h b8c45a6348d9ef57c5205a08c611d57d07ee9feb
|
||||
F src/log.c d9fdaad6b0b5ace54153b85f5bfcf1b9d1abac67
|
||||
F src/log.h bc44b0eec723648c8aa0a05ab78e1b76a4032e02
|
||||
F src/main.c 867de6aa444abd97771b2b70472f448d65c1c77e
|
||||
F src/malloc.c a08f16d134f0bfab6b20c3cd142ebf3e58235a6a
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
@ -154,7 +154,7 @@ F src/os_common.h 240c88b163b02c21a9f21f87d49678a0aa21ff30
|
||||
F src/os_os2.c 75a8c7b9a00a2cf1a65f9fa4afbc27d46634bb2f
|
||||
F src/os_unix.c 5bf0015cebe2f21635da2af983c348eb88b3b4c1
|
||||
F src/os_win.c 1c7453c2df4dab26d90ff6f91272aea18bcf7053
|
||||
F src/pager.c d83d2ea6d2025554e079f891854b133924305e19
|
||||
F src/pager.c 485a34834a96863fd709f4d01f886ae70a9689ea
|
||||
F src/pager.h cee4487ab4f0911dd9f22a40e3cd55afdb7ef444
|
||||
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
|
||||
F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf
|
||||
@ -253,7 +253,7 @@ F test/autoindex1.test ffb06a246e2c1f89cfbe3d93eca513c9e78d4063
|
||||
F test/autovacuum.test 25f891bc343a8bf5d9229e2e9ddab9f31a9ab5ec
|
||||
F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6
|
||||
F test/avtrans.test 1e901d8102706b63534dbd2bdd4d8f16c4082650
|
||||
F test/backup.test 3549ea8f541a08205c0eb813b21e81ea8301f6ed
|
||||
F test/backup.test b1e874fa9b01de9dd5137a8371d060b76a435162
|
||||
F test/backup2.test 159419073d9769fdb1780ed7e5b391a046f898d5
|
||||
F test/backup_ioerr.test 1f012e692f42c0442ae652443258f70e9f20fa38
|
||||
F test/backup_malloc.test 1e063c6d75143d0d6e0ae77971dd690070369387
|
||||
@ -759,7 +759,7 @@ F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
|
||||
F test/wal.test fcb5ec1fbec08c1165b6974f126056f2b4cead49
|
||||
F test/walbak.test 3aecf824ee6433bd34673336623c4990aa1346ba
|
||||
F test/walbak.test f6fde9a5f59d0c697cb1f4af7876178c2f69a7ba
|
||||
F test/walcrash.test f022cee7eb7baa5fb898726120a6a4073dd831d1
|
||||
F test/walhook.test 76a559e262f0715c470bade4a8d8333035f8ee47
|
||||
F test/walmode.test c2f4e30ad64910b2d8faf6cf4e940b3f201b41df
|
||||
@ -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 5d6d4423d1def39bd2424703120aa985085c3f8e
|
||||
R 7813072bd3855cfe2a094b15eff01c69
|
||||
P 1077d8130b8ed5716ad73f78382270909d347963
|
||||
R 0d1581e70f8ee05579afbc11de72b135
|
||||
U dan
|
||||
Z f898bd1b5727c5103088c594c0575550
|
||||
Z c6fc40f98d5658443e299ebf167b2a61
|
||||
|
@ -1 +1 @@
|
||||
1077d8130b8ed5716ad73f78382270909d347963
|
||||
480d12db4c0ebcc37598f7620d39193875eab15b
|
@ -1568,6 +1568,14 @@ int sqlite3LogWriteLock(Log *pLog, int op){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if data has been written but not committed to the log file.
|
||||
*/
|
||||
int sqlite3LogDirty(Log *pLog){
|
||||
assert( pLog->isWriteLocked );
|
||||
return( pLog->hdr.iLastPg!=((LogSummaryHdr*)pLog->pSummary->aData)->iLastPg );
|
||||
}
|
||||
|
||||
/*
|
||||
** Write a set of frames to the log. The caller must hold at least a
|
||||
** RESERVED lock on the database file.
|
||||
|
@ -37,6 +37,9 @@ void sqlite3LogDbsize(Log *pLog, Pgno *pPgno);
|
||||
/* Obtain or release the WRITER lock. */
|
||||
int sqlite3LogWriteLock(Log *pLog, int op);
|
||||
|
||||
/* Return true if data has been written but not committed to the log file. */
|
||||
int sqlite3LogDirty(Log *pLog);
|
||||
|
||||
/* Write a frame or frames to the log. */
|
||||
int sqlite3LogFrames(Log *pLog, int, PgHdr *, Pgno, int, int);
|
||||
|
||||
|
55
src/pager.c
55
src/pager.c
@ -2234,9 +2234,30 @@ static int readDbPage(PgHdr *pPg){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called when a transaction on a WAL database is rolled
|
||||
** back. For each dirty page in the cache, do one of the following:
|
||||
**
|
||||
** * If the page has no outstanding references, simply discard it.
|
||||
** * Otherwise, if the page has one or more outstanding references,
|
||||
** reload the original content from the database (or log file).
|
||||
*/
|
||||
static int pagerRollbackLog(Pager *pPager){
|
||||
int rc = SQLITE_OK;
|
||||
PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
|
||||
|
||||
/* Normally, if a transaction is rolled back, any backup processes are
|
||||
** updated as data is copied out of the rollback journal and into the
|
||||
** database. This is not generally possible with a WAL database, as
|
||||
** rollback involves simply truncating the log file. Therefore, if one
|
||||
** or more frames have already been written to the log (and therefore
|
||||
** also copied into the backup databases) as part of this transaction,
|
||||
** the backups must be restarted.
|
||||
*/
|
||||
if( sqlite3LogDirty(pPager->pLog) ){
|
||||
sqlite3BackupRestart(pPager->pBackup);
|
||||
}
|
||||
|
||||
pPager->dbSize = pPager->dbOrigSize;
|
||||
while( pList && rc==SQLITE_OK ){
|
||||
PgHdr *pNext = pList->pDirty;
|
||||
@ -3218,6 +3239,33 @@ static int subjournalPage(PgHdr *pPg){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is a wrapper around sqlite3LogFrames(). As well as logging
|
||||
** the contents of the list of pages headed by pList (connected by pDirty),
|
||||
** this function notifies any active backup processes that the pages have
|
||||
** changed.
|
||||
*/
|
||||
static int pagerLogFrames(
|
||||
Pager *pPager, /* Pager object */
|
||||
PgHdr *pList, /* List of frames to log */
|
||||
Pgno nTruncate, /* Database size after this commit */
|
||||
int isCommit, /* True if this is a commit */
|
||||
int sync_flags /* Flags to pass to OsSync() (or 0) */
|
||||
){
|
||||
int rc; /* Return code */
|
||||
|
||||
assert( pPager->pLog );
|
||||
rc = sqlite3LogFrames(pPager->pLog,
|
||||
pPager->pageSize, pList, nTruncate, isCommit, sync_flags
|
||||
);
|
||||
if( rc==SQLITE_OK && pPager->pBackup ){
|
||||
PgHdr *p;
|
||||
for(p=pList; p; p=p->pDirty){
|
||||
sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called by the pcache layer when it has reached some
|
||||
@ -3248,7 +3296,7 @@ static int pagerStress(void *p, PgHdr *pPg){
|
||||
pPg->pDirty = 0;
|
||||
if( pagerUseLog(pPager) ){
|
||||
/* Write a single frame for this page to the log. */
|
||||
rc = sqlite3LogFrames(pPager->pLog, pPager->pageSize, pPg, 0, 0, 0);
|
||||
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
|
||||
@ -4881,8 +4929,8 @@ int sqlite3PagerCommitPhaseOne(
|
||||
if( pagerUseLog(pPager) ){
|
||||
PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
|
||||
if( pList ){
|
||||
rc = sqlite3LogFrames(pPager->pLog, pPager->pageSize, pList,
|
||||
pPager->dbSize, 1, (pPager->fullSync ? pPager->sync_flags : 0)
|
||||
rc = pagerLogFrames(pPager, pList, pPager->dbSize, 1,
|
||||
(pPager->fullSync ? pPager->sync_flags : 0)
|
||||
);
|
||||
}
|
||||
sqlite3PcacheCleanAll(pPager->pPCache);
|
||||
@ -5119,6 +5167,7 @@ int sqlite3PagerRollback(Pager *pPager){
|
||||
PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager)));
|
||||
if( pagerUseLog(pPager) ){
|
||||
int rc2;
|
||||
|
||||
rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
|
||||
rc2 = pager_end_transaction(pPager, pPager->setMaster);
|
||||
if( rc==SQLITE_OK ) rc = rc2;
|
||||
|
@ -38,6 +38,8 @@ source $testdir/tester.tcl
|
||||
#
|
||||
# backup-9.*: Test that passing a negative argument to backup_step() is
|
||||
# interpreted as "copy the whole file".
|
||||
#
|
||||
# backup-10.*: Test writing the source database mid backup.
|
||||
#
|
||||
|
||||
proc data_checksum {db file} { $db one "SELECT md5sum(a, b) FROM ${file}.t1" }
|
||||
@ -905,6 +907,7 @@ ifcapable memorymanage {
|
||||
}
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Test that if the database is written to via the same database handle being
|
||||
# used as the source by a backup operation:
|
||||
#
|
||||
|
110
test/walbak.test
110
test/walbak.test
@ -20,6 +20,12 @@ proc log_file_size {nFrame pgsz} {
|
||||
expr {12 + ($pgsz+16)*$nFrame}
|
||||
}
|
||||
|
||||
# Test organization:
|
||||
#
|
||||
# walback-1.*: Simple tests.
|
||||
# walback-2.*: Test backups when the source db is modified mid-backup.
|
||||
#
|
||||
|
||||
# Make sure a simple backup from a WAL database works.
|
||||
#
|
||||
do_test walbak-1.0 {
|
||||
@ -53,20 +59,20 @@ db2 close
|
||||
|
||||
# Try a VACUUM on a WAL database.
|
||||
#
|
||||
do_test walbak-2.1 {
|
||||
do_test walbak-1.4 {
|
||||
execsql {
|
||||
VACUUM;
|
||||
PRAGMA main.journal_mode;
|
||||
}
|
||||
} {wal}
|
||||
do_test walbak-2.2 {
|
||||
do_test walbak-1.5 {
|
||||
list [file size test.db] [file size test.db-wal]
|
||||
} [list 1024 [log_file_size 6 1024]]
|
||||
do_test walbak-2.3 {
|
||||
do_test walbak-1.6 {
|
||||
execsql { PRAGMA checkpoint }
|
||||
list [file size test.db] [file size test.db-wal]
|
||||
} [list [expr 3*1024] [log_file_size 6 1024]]
|
||||
do_test walbak-2.4 {
|
||||
do_test walbak-1.7 {
|
||||
execsql {
|
||||
CREATE TABLE t2(a, b);
|
||||
INSERT INTO t2 SELECT * FROM t1;
|
||||
@ -74,13 +80,105 @@ do_test walbak-2.4 {
|
||||
}
|
||||
list [file size test.db] [file size test.db-wal]
|
||||
} [list [expr 3*1024] [log_file_size 6 1024]]
|
||||
do_test walbak-2.5 {
|
||||
do_test walbak-1.8 {
|
||||
execsql { VACUUM }
|
||||
list [file size test.db] [file size test.db-wal]
|
||||
} [list [expr 3*1024] [log_file_size 8 1024]]
|
||||
do_test walbak-2.6 {
|
||||
do_test walbak-1.9 {
|
||||
execsql { PRAGMA checkpoint }
|
||||
list [file size test.db] [file size test.db-wal]
|
||||
} [list [expr 2*1024] [log_file_size 8 1024]]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Backups when the source db is modified mid-backup.
|
||||
#
|
||||
proc sig {{db db}} {
|
||||
$db eval {
|
||||
PRAGMA integrity_check;
|
||||
SELECT md5sum(a, b) FROM t1;
|
||||
}
|
||||
}
|
||||
db close
|
||||
file delete test.db
|
||||
sqlite3 db test.db
|
||||
do_test walbak-2.1 {
|
||||
execsql { PRAGMA journal_mode = WAL }
|
||||
execsql {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(randomblob(500), randomblob(500));
|
||||
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1; /* 2 */
|
||||
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1; /* 4 */
|
||||
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1; /* 8 */
|
||||
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1; /* 16 */
|
||||
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1; /* 32 */
|
||||
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM t1; /* 64 */
|
||||
COMMIT;
|
||||
}
|
||||
} {}
|
||||
do_test walbak-2.2 {
|
||||
db backup abc.db
|
||||
sqlite3 db2 abc.db
|
||||
string compare [sig db] [sig db2]
|
||||
} {0}
|
||||
|
||||
do_test walbak-2.3 {
|
||||
sqlite3_backup B db2 main db main
|
||||
B step 50
|
||||
execsql { UPDATE t1 SET b = randomblob(500) }
|
||||
list [B step 1000] [B finish]
|
||||
} {SQLITE_DONE SQLITE_OK}
|
||||
do_test walbak-2.4 {
|
||||
string compare [sig db] [sig db2]
|
||||
} {0}
|
||||
|
||||
do_test walbak-2.5 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { PRAGMA cache_size = 10 }
|
||||
sqlite3_backup B db2 main db main
|
||||
B step 50
|
||||
execsql {
|
||||
BEGIN;
|
||||
UPDATE t1 SET b = randomblob(500);
|
||||
}
|
||||
expr [file size test.db-wal] > 10*1024
|
||||
} {1}
|
||||
do_test walbak-2.6 {
|
||||
B step 1000
|
||||
} {SQLITE_BUSY}
|
||||
do_test walbak-2.7 {
|
||||
execsql COMMIT
|
||||
list [B step 1000] [B finish]
|
||||
} {SQLITE_DONE SQLITE_OK}
|
||||
do_test walbak-2.8 {
|
||||
string compare [sig db] [sig db2]
|
||||
} {0}
|
||||
|
||||
do_test walbak-2.9 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { PRAGMA cache_size = 10 }
|
||||
sqlite3_backup B db2 main db main
|
||||
B step 50
|
||||
execsql {
|
||||
BEGIN;
|
||||
UPDATE t1 SET b = randomblob(500);
|
||||
}
|
||||
expr [file size test.db-wal] > 10*1024
|
||||
} {1}
|
||||
do_test walbak-2.10 {
|
||||
B step 1000
|
||||
} {SQLITE_BUSY}
|
||||
do_test walbak-2.11 {
|
||||
execsql ROLLBACK
|
||||
set sigB [sig db]
|
||||
list [B step 1000] [B finish]
|
||||
} {SQLITE_DONE SQLITE_OK}
|
||||
do_test walbak-2.12 {
|
||||
string compare [sig db] [sig db2]
|
||||
} {0}
|
||||
db2 close
|
||||
|
||||
finish_test
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user