1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-05 15:55:57 +03:00

Disable the PagerDontWrite() optimization for temp tables. It can cause database corruption if a page passed to PagerDontWrite() is dirty at the start of a transaction that is subsequently rolled back.

FossilOrigin-Name: 6341ab2ffef298ca16b323358afbea4a4c1fb0e1
This commit is contained in:
dan
2016-05-04 11:28:03 +00:00
parent 12b35ea980
commit c88ae52d86
4 changed files with 93 additions and 9 deletions

View File

@@ -1,5 +1,5 @@
C Minor\sstyle\stweaks\sin\sthe\sMSVC\smakefile.
D 2016-05-03T19:40:54.328
C Disable\sthe\sPagerDontWrite()\soptimization\sfor\stemp\stables.\sIt\scan\scause\sdatabase\scorruption\sif\sa\spage\spassed\sto\sPagerDontWrite()\sis\sdirty\sat\sthe\sstart\sof\sa\stransaction\sthat\sis\ssubsequently\srolled\sback.
D 2016-05-04T11:28:03.301
F Makefile.in 9eda6e1c90d05c199c3ec8a7069b0682ad307657
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc db82b35aef27f412fef14d8534afc022138bcdfd
@@ -364,7 +364,7 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
F src/os_unix.c a9443cdab41d7f3cdf0df3a5aab62fd6e1c9b234
F src/os_win.c 852fc2ff6084296348ed3739c548b2cf32df394e
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
F src/pager.c a8d30c49c231e9a20d05257613db922532588963
F src/pager.c c512873311087cd22372f2b076fc869e090e8e16
F src/pager.h 329bdf078a4e0a3b35084534d58625d21fd03681
F src/parse.y 10eb2f3fb62341291528c7984498054731f9d31e
F src/pcache.c b3230ecfc7f797063fbe167f2845da363e8f07f8
@@ -1111,6 +1111,7 @@ F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
F test/tclsqlite.test e1306001a0ca92250b691ea6d3cecaca5b6342aa
F test/tempdb.test bd92eba8f20e16a9136e434e20b280794de3cdb6
F test/tempdb2.test 4fc92055f2a3f7626c0f2eabbb637dc021b311d5
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptable2.test cd396beb41117a5302fff61767c35fa4270a0d5e
@@ -1486,7 +1487,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P bcaa650e8796984b275eceba0ed477f360295d01
R 962b079d2f6aa84ad32617180232ff75
U mistachkin
Z 45ce4bc83f501da24480cd14c4b0de07
P 1b43358f8979c4f18519e824e0d5f6ef2250107c
R ddb8134dc049c780758987466a2a1e86
U dan
Z 527ddc60688e8fba4830106202c052a2

View File

@@ -1 +1 @@
1b43358f8979c4f18519e824e0d5f6ef2250107c
6341ab2ffef298ca16b323358afbea4a4c1fb0e1

View File

@@ -6008,10 +6008,16 @@ int sqlite3PagerIswriteable(DbPage *pPg){
**
** Tests show that this optimization can quadruple the speed of large
** DELETE operations.
**
** This optimization cannot be used with a temp-file, as the page may
** have been dirty at the start of the transaction. In that case, if
** memory pressure forces page pPg out of the cache, the data does need
** to be written out to disk so that it may be read back in if the
** current transaction is rolled back.
*/
void sqlite3PagerDontWrite(PgHdr *pPg){
Pager *pPager = pPg->pPager;
if( (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
if( !pPager->tempFile && (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
PAGERTRACE(("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager)));
IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno))
pPg->flags |= PGHDR_DONT_WRITE;

77
test/tempdb2.test Normal file
View File

@@ -0,0 +1,77 @@
# 2016 March 3
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix tempdb2
db close
sqlite3 db ""
proc int2str {i} { string range [string repeat "$i." 450] 0 899 }
db func int2str int2str
#-------------------------------------------------------------------------
#
# 1.1: Write a big transaction to the db. One so large that it forces
# the file to be created and the cache flushed to disk on COMMIT.
#
# 1.2: Write a small transaction - one small enough that it remains in
# memory on COMMIT. All the pages of table [t1] are now dirty.
#
# 1.3: Delete the contents of [t1]. This moves all of its leaves to the
# free-list and causes the btree layer to call PagerDontWrite() on
# each of them.
#
# Then do a big update on table [t2]. So big that the former leaves
# of [t1] are forced out of the cache. Then roll back the transaction.
# If the PagerDontWrite() calls are honoured and the data is not written
# to disk, the update made in test 1.2 will be lost at this point. Or, if
# they are ignored (as they should be for temp databases), the update
# will be safely written out to disk before the cache entries are
# discarded.
#
do_execsql_test 1.1 {
PRAGMA page_size=1024;
PRAGMA cache_size=50;
BEGIN;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, int2str(1));
INSERT INTO t1 VALUES(2, int2str(1));
INSERT INTO t1 VALUES(3, int2str(1));
CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
WITH c(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100 )
INSERT INTO t2 SELECT x, int2str(x) FROM c;
COMMIT;
PRAGMA lock_status;
} {main unlocked temp closed}
do_execsql_test 1.2 {
UPDATE t1 SET b=int2str(2);
SELECT b=int2str(2) FROM t1
} {1 1 1}
do_execsql_test 1.3 {
BEGIN;
DELETE FROM t1;
UPDATE t2 SET b=int2str(a+1);
ROLLBACK;
}
do_execsql_test 1.4 {
SELECT b=int2str(2) FROM t1
} {1 1 1}
finish_test