From 8e6cf0a7c50ad9e1e8eb09b56d12e22f1a6b380c Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 22 Feb 2016 14:57:38 +0000 Subject: [PATCH] Avoid creating a master journal unless two or more databases in the transaction can actually benefit from that master journal. FossilOrigin-Name: 3ed1890612bd45bd9c72f670d2cbb0b8fbd35d92 --- manifest | 14 ++++---- manifest.uuid | 2 +- src/vdbeaux.c | 26 ++++++++++++-- test/pager1.test | 92 ++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 105 insertions(+), 29 deletions(-) diff --git a/manifest b/manifest index 737d2b6c22..82a5265498 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\smagic\snumbers\sassociated\swith\ssynchronous\ssettings\sto\snamed\sconstants. -D 2016-02-22T13:23:16.525 +C Avoid\screating\sa\smaster\sjournal\sunless\stwo\sor\smore\sdatabases\sin\sthe\ntransaction\scan\sactually\sbenefit\sfrom\sthat\smaster\sjournal. +D 2016-02-22T14:57:38.065 F Makefile.in 4e90dc1521879022aa9479268a4cd141d1771142 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc 28fc4ee02333996d31b3602b39eeb8e609a89ce4 @@ -418,7 +418,7 @@ F src/vdbe.c 822e44c1dd859794f8c414e8bae4d96ac1fa774d F src/vdbe.h c743791f723049db94f009e3e30958952bc2d512 F src/vdbeInt.h 581e5bff9a401fabdb917b816503cda7356ec3e1 F src/vdbeapi.c 95b1f8e527240a18a9aea41a655b013bf07a7009 -F src/vdbeaux.c ec9a4d939a7430b76f53c5ef5cdbca3c8704848a +F src/vdbeaux.c 51aaf15e5c29512423429cc0e0477e08f7181514 F src/vdbeblob.c 3b570b730109e8f653d9d2081649f6e7015113db F src/vdbemem.c be8381ed6de54eb9cb9dfa802823cdeb5166d855 F src/vdbesort.c 307460bfa4de4d1c3901fcd42089159131e34062 @@ -932,7 +932,7 @@ F test/orderby8.test 23ef1a5d72bd3adcc2f65561c654295d1b8047bd F test/orderby9.test 87fb9548debcc2cd141c5299002dd94672fa76a3 F test/oserror.test b32dc34f2363ef18532e3a0a7358e3e7e321974f F test/ovfl.test 199c482696defceacee8c8e0e0ef36da62726b2f -F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa +F test/pager1.test f49df1a8b0e38b9ee3a7dd2ab4d427507b7314ce F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71 F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f F test/pager4.test a122e9e6925d5b23b31e3dfef8c6a44bbf19590e @@ -1429,7 +1429,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh a98af506df552f3b3c0d904f94e4cdc4e1a6d598 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P a48ac4c347813bd2b416b1cb06c3cbf1f4b3781a -R 5ba950defec5ebb5c806c723cbc4f5b9 +P 9230ba6c01f4a550d92a0cbbf36dbe81af14fbfc +R 28c7602ad1de5114aacb14204e4f7226 U drh -Z 3422238b7807aea6814e5b393b012e9d +Z aad5fe626dac38bb4fd331764966d6a1 diff --git a/manifest.uuid b/manifest.uuid index b896d3d101..4ab1f4a5a5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9230ba6c01f4a550d92a0cbbf36dbe81af14fbfc \ No newline at end of file +3ed1890612bd45bd9c72f670d2cbb0b8fbd35d92 \ No newline at end of file diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 9aa05fc868..4f539f0a29 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2155,7 +2155,9 @@ int sqlite3VdbeSetColName( */ static int vdbeCommit(sqlite3 *db, Vdbe *p){ int i; - int nTrans = 0; /* Number of databases with an active write-transaction */ + int nTrans = 0; /* Number of databases with an active write-transaction + ** that are candidates for a two-phase commit using a + ** master-journal */ int rc = SQLITE_OK; int needXcommit = 0; @@ -2183,10 +2185,28 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; if( sqlite3BtreeIsInTrans(pBt) ){ + /* Whether or not a database might need a master journal depends upon + ** its journal mode (among other things). This matrix determines which + ** journal modes use a master journal and which do not */ + static const u8 aMJNeeded[] = { + /* DELETE */ 1, + /* PERSIST */ 1, + /* OFF */ 0, + /* TRUNCATE */ 1, + /* MEMORY */ 0, + /* WAL */ 0 + }; + Pager *pPager; /* Pager associated with pBt */ needXcommit = 1; - if( i!=1 ) nTrans++; sqlite3BtreeEnter(pBt); - rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt)); + pPager = sqlite3BtreePager(pBt); + if( db->aDb[i].safety_level!=PAGER_SYNCHRONOUS_OFF + && aMJNeeded[sqlite3PagerGetJournalMode(pPager)] + ){ + assert( i!=1 ); + nTrans++; + } + rc = sqlite3PagerExclusiveLock(pPager); sqlite3BtreeLeave(pBt); } } diff --git a/test/pager1.test b/test/pager1.test index 005b356080..bc9ad83fd4 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -529,6 +529,7 @@ set pwd [get_pwd] testvfs tv -default 1 tv script copy_on_mj_delete set ::mj_filename_length 0 +set ::mj_delete_cnt 0 proc copy_on_mj_delete {method filename args} { if {[string match *mj* [file tail $filename]]} { # @@ -542,6 +543,7 @@ proc copy_on_mj_delete {method filename args} { set ::mj_filename_length [string length $filename] } faultsim_save + incr ::mj_delete_cnt } return SQLITE_OK } @@ -579,29 +581,68 @@ foreach {tn1 tcl} { } } { eval $tcl - foreach {tn2 sql} { + foreach {tn2 sql usesMJ} { o { PRAGMA main.synchronous=OFF; PRAGMA aux.synchronous=OFF; PRAGMA journal_mode = DELETE; - } + } 0 o512 { PRAGMA main.synchronous=OFF; PRAGMA aux.synchronous=OFF; PRAGMA main.page_size = 512; PRAGMA aux.page_size = 512; PRAGMA journal_mode = DELETE; - } + } 0 n { PRAGMA main.synchronous=NORMAL; PRAGMA aux.synchronous=NORMAL; PRAGMA journal_mode = DELETE; - } + } 1 f { PRAGMA main.synchronous=FULL; PRAGMA aux.synchronous=FULL; PRAGMA journal_mode = DELETE; - } + } 1 + w1 { + PRAGMA main.synchronous=NORMAL; + PRAGMA aux.synchronous=NORMAL; + PRAGMA journal_mode = WAL; + } 0 + w2 { + PRAGMA main.synchronous=NORMAL; + PRAGMA aux.synchronous=NORMAL; + PRAGMA main.journal_mode=DELETE; + PRAGMA aux.journal_mode=WAL; + } 0 + o1a { + PRAGMA main.synchronous=FULL; + PRAGMA aux.synchronous=OFF; + PRAGMA journal_mode=DELETE; + } 0 + o1b { + PRAGMA main.synchronous=OFF; + PRAGMA aux.synchronous=NORMAL; + PRAGMA journal_mode=DELETE; + } 0 + m1 { + PRAGMA main.synchronous=NORMAL; + PRAGMA aux.synchronous=NORMAL; + PRAGMA main.journal_mode=DELETE; + PRAGMA aux.journal_mode = MEMORY; + } 0 + t1 { + PRAGMA main.synchronous=NORMAL; + PRAGMA aux.synchronous=NORMAL; + PRAGMA main.journal_mode=DELETE; + PRAGMA aux.journal_mode = TRUNCATE; + } 1 + p1 { + PRAGMA main.synchronous=NORMAL; + PRAGMA aux.synchronous=NORMAL; + PRAGMA main.journal_mode=DELETE; + PRAGMA aux.journal_mode = PERSIST; + } 1 } { set tn "${tn1}.${tn2}" @@ -613,6 +654,7 @@ foreach {tn1 tcl} { # tv filter xDelete do_test pager1-4.4.$tn.1 { + set ::mj_delete_cnt 0 faultsim_delete_and_reopen $prefix execsql " ATTACH '${prefix}2' AS aux; @@ -634,6 +676,13 @@ foreach {tn1 tcl} { } } {} tv filter {} + + # Verify that a master journal was deleted only for those cases where + # master journals really ought to be used + # + do_test pager1-4.4.$tn.1b { + set ::mj_delete_cnt + } $usesMJ # Check that the transaction was committed successfully. # @@ -644,25 +693,33 @@ foreach {tn1 tcl} { SELECT * FROM b } {won too free double-you why zed} - # Restore the file-system and reopen the databases. Check that it now - # appears that the transaction was not committed (because the file-system - # was restored to the state where it had not been). - # - do_test pager1-4.4.$tn.4 { - faultsim_restore_and_reopen $prefix - execsql "ATTACH '${prefix}2' AS aux" - } {} - do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed} - do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free} + if {$usesMJ} { + # Restore the file-system and reopen the databases. Check that it now + # appears that the transaction was not committed (because the file-system + # was restored to the state where it had not been). + # + do_test pager1-4.4.$tn.4 { + faultsim_restore_and_reopen $prefix + execsql "ATTACH '${prefix}2' AS aux" + } {} + do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed} + do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free} + } # Restore the file-system again. This time, before reopening the databases, # delete the master-journal file from the file-system. It now appears that # the transaction was committed (no master-journal file == no rollback). # do_test pager1-4.4.$tn.7 { - faultsim_restore_and_reopen $prefix - foreach f [glob ${prefix}-mj*] { forcedelete $f } + if {$::mj_delete_cnt>0} { + faultsim_restore_and_reopen $prefix + foreach f [glob ${prefix}-mj*] { forcedelete $f } + } else { + db close + sqlite3 db $prefix + } execsql "ATTACH '${prefix}2' AS aux" + glob -nocomplain ${prefix}-mj* } {} do_execsql_test pager1-4.4.$tn.8 { SELECT * FROM a @@ -678,7 +735,6 @@ db close tv delete forcedelete $dirname - # Set up a VFS to make a copy of the file-system just before deleting a # journal file to commit a transaction. The transaction modifies exactly # two database pages (and page 1 - the change counter). -- 2.47.2