]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Defer opening the file used for the temp database (where CREATE TEMP TABLE tables...
authordan <dan@noemail.net>
Tue, 5 Apr 2016 21:07:58 +0000 (21:07 +0000)
committerdan <dan@noemail.net>
Tue, 5 Apr 2016 21:07:58 +0000 (21:07 +0000)
FossilOrigin-Name: be5a549eba6cf8e29cb6b9824fd6d0db9d03ca7f

manifest
manifest.uuid
src/pager.c
src/pcache.c
test/temptable2.test [new file with mode: 0644]

index 04532b4880678aa37daafc34e55dfc7cda206e50..261df5d6bf482c9acc2ae3449136ec6f160aecca 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Carry\stable\scolumn\stypes\sthrough\sinto\sVIEW\sdefinitions,\swhere\spossible.
-D 2016-04-05T20:59:12.069
+C Defer\sopening\sthe\sfile\sused\sfor\sthe\stemp\sdatabase\s(where\sCREATE\sTEMP\sTABLE\stables\sare\sstored)\suntil\sthe\sdatabase\sis\stoo\slarge\sto\sreside\sentirely\swithin\sthe\scache.\sThere\sare\slikely\sstill\sproblems\son\sthis\sbranch.
+D 2016-04-05T21:07:58.179
 F Makefile.in eba680121821b8a60940a81454316f47a341487a
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc 1f123a0757f6f04f0341accb46457e116817159a
@@ -362,10 +362,10 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
 F src/os_unix.c b1ccb273771f41dbdbe0ba7c1ad63c38ad5972ec
 F src/os_win.c b3ba9573d8d893e70a6a8015bbee572ecf7ffbef
 F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
-F src/pager.c 38718a019ca762ba4f6795425d5a54db70d1790d
+F src/pager.c 123dbae47bf27915a4b567915ff8dcc27cfcd369
 F src/pager.h e1d38a2f14849e219df0f91f8323504d134c8a56
 F src/parse.y 5ea8c81c5c41b27887f41b4a7e1c58470d7d3821
-F src/pcache.c 647bb53a86b7bbcf55ad88089b3ea5a9170b90df
+F src/pcache.c e9c00846d3dcdaa75b288c6f16238c2fe2177823
 F src/pcache.h 4d0ccaad264d360981ec5e6a2b596d6e85242545
 F src/pcache1.c c40cdb93586e21b5dd826b5e671240bd91c26b05
 F src/pragma.c faf42922bb7ab2f6672cb550356c1967abae3c84
@@ -1110,6 +1110,7 @@ F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
 F test/tclsqlite.test e1306001a0ca92250b691ea6d3cecaca5b6342aa
 F test/tempdb.test bd92eba8f20e16a9136e434e20b280794de3cdb6
 F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
+F test/temptable2.test f3b198e386f6494082c87accc8780cdf84b36e6d
 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
 F test/tester.tcl 7b740ee852c55e1e72b6ebe5044acee7aa4e5553
 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
@@ -1482,7 +1483,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 0bf9926c7a7865694edd48535777248e73d86bbf
-R c7f5a7683cc4a0d14362e20e6891847a
-U drh
-Z ec8e2cff7764d808576889c190bbf60c
+P fb555c3c2af7f5e62ff839658f4fba7b645d3a68
+R f511e5baaeaad693345498b91b98e90f
+T *branch * tempfiles-lazy-open
+T *sym-tempfiles-lazy-open *
+T -sym-trunk *
+U dan
+Z 505ba6148fb8f2c79237e86b07655c1c
index d21138d9ad8f04b5f6a35eb0ea46d036e588ac64..0e8a9ef13012ba144422b0eee822e95c47424aa3 100644 (file)
@@ -1 +1 @@
-fb555c3c2af7f5e62ff839658f4fba7b645d3a68
\ No newline at end of file
+be5a549eba6cf8e29cb6b9824fd6d0db9d03ca7f
\ No newline at end of file
index c18b3a32f7b1fb98b3f0a2ecfe689af4e16e6927..45f54ef30d04088f5a2b9126b1f6c93fcb09d9ff 100644 (file)
@@ -2006,7 +2006,11 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
   sqlite3BitvecDestroy(pPager->pInJournal);
   pPager->pInJournal = 0;
   pPager->nRec = 0;
-  sqlite3PcacheCleanAll(pPager->pPCache);
+  if( pPager->tempFile==0 || MEMDB ){
+    sqlite3PcacheCleanAll(pPager->pPCache);
+  }else{
+    sqlite3PcacheClearWritable(pPager->pPCache);
+  }
   sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
 
   if( pagerUseWal(pPager) ){
@@ -2374,9 +2378,13 @@ static int pager_playback_one_page(
       ** be written out into the database file before its journal file
       ** segment is synced. If a crash occurs during or following this,
       ** database corruption may ensue.
+      **
+      ** Update: Another exception is for temp files that are not 
+      ** in-memory databases. In this case the page may have been dirty
+      ** at the start of the transaction.
       */
       assert( !pagerUseWal(pPager) );
-      sqlite3PcacheMakeClean(pPg);
+      if( pPager->tempFile==0 ) sqlite3PcacheMakeClean(pPg);
     }
     pager_set_pagehash(pPg);
 
@@ -4258,8 +4266,9 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
 
   /* This function is only called for rollback pagers in WRITER_DBMOD state. */
   assert( !pagerUseWal(pPager) );
-  assert( pPager->eState==PAGER_WRITER_DBMOD );
+  assert( pPager->tempFile || pPager->eState==PAGER_WRITER_DBMOD );
   assert( pPager->eLock==EXCLUSIVE_LOCK );
+  assert( pPager->tempFile==0 || pList->pDirty==0 );
 
   /* If the file is a temp-file has not yet been opened, open it now. It
   ** is not possible for rc to be other than SQLITE_OK if this branch
@@ -5941,6 +5950,7 @@ int sqlite3PagerWrite(PgHdr *pPg){
     if( pPager->nSavepoint ) return subjournalPageIfRequired(pPg);
     return SQLITE_OK;
   }else if( pPager->sectorSize > (u32)pPager->pageSize ){
+    assert( pPager->tempFile==0 );
     return pagerWriteLargeSector(pPg);
   }else{
     return pager_write(pPg);
@@ -6179,11 +6189,11 @@ int sqlite3PagerCommitPhaseOne(
   /* If no database changes have been made, return early. */
   if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
 
-  if( MEMDB ){
+  assert( MEMDB==0 || pPager->tempFile );
+  if( pPager->tempFile ){
     /* If this is an in-memory db, or no pages have been written to, or this
     ** function has already been called, it is mostly a no-op.  However, any
-    ** backup in progress needs to be restarted.
-    */
+    ** backup in progress needs to be restarted.  */
     sqlite3BackupRestart(pPager->pBackup);
   }else{
     if( pagerUseWal(pPager) ){
@@ -6845,7 +6855,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
   ** the journal needs to be sync()ed before database page pPg->pgno 
   ** can be written to. The caller has already promised not to write to it.
   */
-  if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
+  if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit && pPager->tempFile==0 ){
     needSyncPgno = pPg->pgno;
     assert( pPager->journalMode==PAGER_JOURNALMODE_OFF ||
             pageInJournal(pPager, pPg) || pPg->pgno>pPager->dbOrigSize );
index 61e7587422a0dc3ad2c771b44bcdae52f638b412..52661c28a92a137b43e27d15c77736efcae53c7f 100644 (file)
@@ -254,7 +254,7 @@ sqlite3_pcache_page *sqlite3PcacheFetch(
 
 /*
 ** If the sqlite3PcacheFetch() routine is unable to allocate a new
-** page because new clean pages are available for reuse and the cache
+** page because no clean pages are available for reuse and the cache
 ** size limit has been reached, then this routine can be invoked to 
 ** try harder to allocate a page.  This routine might invoke the stress
 ** callback to spill dirty pages to the journal.  It will then try to
@@ -439,6 +439,17 @@ void sqlite3PcacheCleanAll(PCache *pCache){
   }
 }
 
+/*
+** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages.
+*/
+void sqlite3PcacheClearWritable(PCache *pCache){
+  PgHdr *p;
+  for(p=pCache->pDirty; p; p=p->pDirtyNext){
+    p->flags &= ~(PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
+  }
+  pCache->pSynced = pCache->pDirtyTail;
+}
+
 /*
 ** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
 */
@@ -484,7 +495,7 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
       ** it must be that pgno==0.
       */
       assert( p->pgno>0 );
-      if( ALWAYS(p->pgno>pgno) ){
+      if( p->pgno>pgno ){
         assert( p->flags&PGHDR_DIRTY );
         sqlite3PcacheMakeClean(p);
       }
diff --git a/test/temptable2.test b/test/temptable2.test
new file mode 100644 (file)
index 0000000..daeb206
--- /dev/null
@@ -0,0 +1,157 @@
+# 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 temptable2
+
+do_execsql_test 1.1 {
+  CREATE TEMP TABLE t1(a, b);
+  CREATE INDEX i1 ON t1(a, b);
+}
+
+do_execsql_test 1.2 {
+  WITH x(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<100000 )
+  INSERT INTO t1 SELECT randomblob(100), randomblob(100) FROM X;
+} {}
+
+do_execsql_test 1.3 {
+  PRAGMA temp.integrity_check;
+} {ok}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 2.1 {
+  CREATE TEMP TABLE t2(a, b);
+  INSERT INTO t2 VALUES(1, 2);
+} {}
+
+do_execsql_test 2.2 {
+  BEGIN;
+    INSERT INTO t2 VALUES(3, 4);
+    SELECT * FROM t2;
+} {1 2 3 4}
+
+do_execsql_test 2.3 {
+  ROLLBACK;
+  SELECT * FROM t2;
+} {1 2}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 3.1.1 {
+  PRAGMA main.cache_size = 10;
+  PRAGMA temp.cache_size = 10;
+
+  CREATE TEMP TABLE t1(a, b);
+  CREATE INDEX i1 ON t1(a, b);
+
+  WITH x(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<1000 )
+  INSERT INTO t1 SELECT randomblob(100), randomblob(100) FROM x;
+
+  SELECT count(*) FROM t1;
+} {1000}
+do_execsql_test 3.1.2 {
+  BEGIN;
+    UPDATE t1 SET b=randomblob(100) WHERE (rowid%10)==0;
+  ROLLBACK;
+}
+do_execsql_test 3.1.3 {
+  SELECT count(*) FROM t1;
+} {1000}
+do_execsql_test 3.1.4 { PRAGMA temp.integrity_check } {ok}
+
+do_execsql_test 3.2.1 {
+  BEGIN;
+    UPDATE t1 SET b=randomblob(100) WHERE (rowid%10)==0;
+    SAVEPOINT abc;
+      UPDATE t1 SET b=randomblob(100) WHERE (rowid%10)==1;
+    ROLLBACK TO abc;
+    UPDATE t1 SET b=randomblob(100) WHERE (rowid%10)==2;
+  COMMIT;
+}
+do_execsql_test 3.2.2 { PRAGMA temp.integrity_check } {ok}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 4.1.1 {
+  PRAGMA main.cache_size = 10;
+  PRAGMA temp.cache_size = 10;
+
+  CREATE TEMP TABLE t1(a, b);
+  CREATE INDEX i1 ON t1(a, b);
+
+  WITH x(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<10 )
+  INSERT INTO t1 SELECT randomblob(100), randomblob(100) FROM x;
+
+  SELECT count(*) FROM t1;
+  PRAGMA temp.page_count;
+} {10 9}
+
+do_execsql_test 4.1.2 {
+  BEGIN;
+    UPDATE t1 SET b=randomblob(100);
+  ROLLBACK;
+}
+
+do_execsql_test 4.1.3 {
+  CREATE TEMP TABLE t2(a, b);
+  CREATE INDEX i2 ON t2(a, b);
+  WITH x(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<500 )
+  INSERT INTO t2 SELECT randomblob(100), randomblob(100) FROM x;
+
+  SELECT count(*) FROM t2;
+  SELECT count(*) FROM t1;
+  PRAGMA temp.page_count;
+} {500 10 292}
+
+do_execsql_test 4.1.4 { PRAGMA temp.integrity_check } {ok}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 5.1.1 {
+  PRAGMA main.cache_size = 10;
+  PRAGMA temp.cache_size = 10;
+
+  CREATE TEMP TABLE t2(a, b);
+  CREATE INDEX i2 ON t2(a, b);
+  WITH x(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<500 )
+  INSERT INTO t2 SELECT randomblob(100), randomblob(100) FROM x;
+
+  CREATE TEMP TABLE t1(a, b);
+  CREATE INDEX i1 ON t1(a, b);
+  INSERT INTO t1 VALUES(1, 2);
+
+  PRAGMA temp.page_count;
+} {286}
+
+do_execsql_test 5.1.2 {
+  BEGIN;
+    UPDATE t1 SET a=2;
+    UPDATE t2 SET a=randomblob(100);
+    SELECT count(*) FROM t1;
+  ROLLBACK;
+} {1}
+
+do_execsql_test 5.1.3 {
+  UPDATE t2 SET a=randomblob(100);
+
+  SELECT * FROM t1;
+} {1 2}
+
+do_execsql_test 5.1.4 { PRAGMA temp.integrity_check } {ok}
+
+finish_test
+