/ Check-in [b78e58ae]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Do not create, open, or initialize the rollback journal until something actually needs to be written into the journal. That way, expensive filesystem operations are avoided if the transaction ends up being a no-op.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:b78e58ae1570ab4d66a69db445a752c6456038a0
User & Date: drh 2010-03-19 15:48:14
Original Comment: Do create, open, or initialize the rollback journal until something actually needs to be written into the journal. That way, expensive filesystem operations are avoided if the transaction ends up being a no-op.
References
2010-06-17
13:22 Ticket [fc62af45] Executing "PRAGMA journal_mode" may delete journal file while it is in use. status still Open with 1 other change artifact: 068d606e user: drh
10:45 Ticket [fc62af45]: 1 change artifact: deedf461 user: dan
09:52 Ticket [fc62af45]: 4 changes artifact: c98b4147 user: dan
Context
2010-03-19
16:52
Make sure the in-journal boolean vector is cleared and released when ending a transaction. This fixes an obscure problem with the previous check-in. check-in: 69d749d9 user: drh tags: trunk
15:48
Do not create, open, or initialize the rollback journal until something actually needs to be written into the journal. That way, expensive filesystem operations are avoided if the transaction ends up being a no-op. check-in: b78e58ae user: drh tags: trunk
13:59
Rewrite a couple of queries used internally by FTS3 to take advantage of the "SELECT max(x) FROM ..." optimization. check-in: b7e42ae7 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/pager.c.

  1311   1311         }
  1312   1312       }
  1313   1313   
  1314   1314   #ifdef SQLITE_CHECK_PAGES
  1315   1315       sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash);
  1316   1316   #endif
  1317   1317   
  1318         -    sqlite3PcacheCleanAll(pPager->pPCache);
  1319   1318       sqlite3BitvecDestroy(pPager->pInJournal);
  1320   1319       pPager->pInJournal = 0;
  1321   1320       pPager->nRec = 0;
  1322   1321     }
         1322  +  sqlite3PcacheCleanAll(pPager->pPCache);
  1323   1323   
  1324   1324     if( !pPager->exclusiveMode ){
  1325   1325       rc2 = osUnlock(pPager->fd, SHARED_LOCK);
  1326   1326       pPager->state = PAGER_SHARED;
  1327   1327       pPager->changeCountDone = 0;
  1328   1328     }else if( pPager->state==PAGER_SYNCED ){
  1329   1329       pPager->state = PAGER_EXCLUSIVE;
................................................................................
  4102   4102       if( rc==SQLITE_OK ){
  4103   4103         pPager->state = PAGER_RESERVED;
  4104   4104         if( exFlag ){
  4105   4105           rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
  4106   4106         }
  4107   4107       }
  4108   4108   
  4109         -    /* If the required locks were successfully obtained, open the journal
  4110         -    ** file and write the first journal-header to it.
         4109  +    /* No need to open the journal file at this time.  It will be
         4110  +    ** opened before it is written to.  If we defer opening the journal,
         4111  +    ** we might save the work of creating a file if the transaction
         4112  +    ** ends up being a no-op.
  4111   4113       */
  4112         -    if( rc==SQLITE_OK && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
  4113         -      rc = pager_open_journal(pPager);
  4114         -    }
  4115   4114     }else if( isOpen(pPager->jfd) && pPager->journalOff==0 ){
  4116   4115       /* This happens when the pager was in exclusive-access mode the last
  4117   4116       ** time a (read or write) transaction was successfully concluded
  4118   4117       ** by this connection. Instead of deleting the journal file it was 
  4119   4118       ** kept open and either was truncated to 0 bytes or its header was
  4120   4119       ** overwritten with zeros.
  4121   4120       */
................................................................................
  4122   4121       assert( pPager->nRec==0 );
  4123   4122       assert( pPager->dbOrigSize==0 );
  4124   4123       assert( pPager->pInJournal==0 );
  4125   4124       rc = pager_open_journal(pPager);
  4126   4125     }
  4127   4126   
  4128   4127     PAGERTRACE(("TRANSACTION %d\n", PAGERID(pPager)));
  4129         -  assert( !isOpen(pPager->jfd) || pPager->journalOff>0 || rc!=SQLITE_OK );
  4130   4128     if( rc!=SQLITE_OK ){
  4131   4129       assert( !pPager->dbModified );
  4132   4130       /* Ignore any IO error that occurs within pager_end_transaction(). The
  4133   4131       ** purpose of this call is to reset the internal state of the pager
  4134   4132       ** sub-system. It doesn't matter if the journal-file is not properly
  4135   4133       ** finalized at this point (since it is not a valid journal file anyway).
  4136   4134       */
................................................................................
  4178   4176     }else{
  4179   4177   
  4180   4178       /* If we get this far, it means that the page needs to be
  4181   4179       ** written to the transaction journal or the ckeckpoint journal
  4182   4180       ** or both.
  4183   4181       **
  4184   4182       ** Higher level routines should have already started a transaction,
  4185         -    ** which means they have acquired the necessary locks and opened
  4186         -    ** a rollback journal.  Double-check to makes sure this is the case.
         4183  +    ** which means they have acquired the necessary locks but the rollback
         4184  +    ** journal might not yet be open.
  4187   4185       */
  4188   4186       rc = sqlite3PagerBegin(pPager, 0, pPager->subjInMemory);
  4189         -    if( NEVER(rc!=SQLITE_OK) ){
         4187  +    if( rc!=SQLITE_OK ){
  4190   4188         return rc;
  4191   4189       }
  4192   4190       if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
  4193   4191         assert( pPager->useJournal );
  4194   4192         rc = pager_open_journal(pPager);
  4195   4193         if( rc!=SQLITE_OK ) return rc;
  4196   4194       }
................................................................................
  4917   4915     int rc = SQLITE_OK;                       /* Return code */
  4918   4916     int nCurrent = pPager->nSavepoint;        /* Current number of savepoints */
  4919   4917   
  4920   4918     if( nSavepoint>nCurrent && pPager->useJournal ){
  4921   4919       int ii;                                 /* Iterator variable */
  4922   4920       PagerSavepoint *aNew;                   /* New Pager.aSavepoint array */
  4923   4921   
  4924         -    /* Either there is no active journal or the sub-journal is open or 
  4925         -    ** the journal is always stored in memory */
  4926         -    assert( pPager->nSavepoint==0 || isOpen(pPager->sjfd) ||
  4927         -            pPager->journalMode==PAGER_JOURNALMODE_MEMORY );
  4928         -
  4929   4922       /* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM
  4930   4923       ** if the allocation fails. Otherwise, zero the new portion in case a 
  4931   4924       ** malloc failure occurs while populating it in the for(...) loop below.
  4932   4925       */
  4933   4926       aNew = (PagerSavepoint *)sqlite3Realloc(
  4934   4927           pPager->aSavepoint, sizeof(PagerSavepoint)*nSavepoint
  4935   4928       );
................................................................................
  4940   4933       pPager->aSavepoint = aNew;
  4941   4934       pPager->nSavepoint = nSavepoint;
  4942   4935   
  4943   4936       /* Populate the PagerSavepoint structures just allocated. */
  4944   4937       for(ii=nCurrent; ii<nSavepoint; ii++){
  4945   4938         assert( pPager->dbSizeValid );
  4946   4939         aNew[ii].nOrig = pPager->dbSize;
  4947         -      if( isOpen(pPager->jfd) && ALWAYS(pPager->journalOff>0) ){
         4940  +      if( isOpen(pPager->jfd) && pPager->journalOff>0 ){
  4948   4941           aNew[ii].iOffset = pPager->journalOff;
  4949   4942         }else{
  4950   4943           aNew[ii].iOffset = JOURNAL_HDR_SZ(pPager);
  4951   4944         }
  4952   4945         aNew[ii].iSubRec = pPager->nSubRec;
  4953   4946         aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
  4954   4947         if( !aNew[ii].pInSavepoint ){
................................................................................
  5333   5326                 || eMode==PAGER_JOURNALMODE_OFF)
  5334   5327      && !pPager->dbModified
  5335   5328      && (!isOpen(pPager->jfd) || 0==pPager->journalOff)
  5336   5329     ){
  5337   5330       if( isOpen(pPager->jfd) ){
  5338   5331         sqlite3OsClose(pPager->jfd);
  5339   5332       }
         5333  +    assert( (PAGER_JOURNALMODE_TRUNCATE & 1)==1 );
         5334  +    assert( (PAGER_JOURNALMODE_PERSIST & 1)==1 );
         5335  +    assert( (PAGER_JOURNALMODE_DELETE & 1)==0 );
         5336  +    assert( (PAGER_JOURNALMODE_MEMORY & 1)==0 );
         5337  +    assert( (PAGER_JOURNALMODE_OFF & 1)==0 );
         5338  +    if( (pPager->journalMode & 1)==1 && (eMode & 1)==0
         5339  +         && !pPager->exclusiveMode ){
         5340  +      sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
         5341  +    }
  5340   5342       pPager->journalMode = (u8)eMode;
  5341   5343     }
  5342   5344     return (int)pPager->journalMode;
  5343   5345   }
  5344   5346   
  5345   5347   /*
  5346   5348   ** Get/set the size-limit used for persistent journal files.

Changes to test/jrnlmode.test.

   480    480       do_test jrnlmode-6.5 {
   481    481         execsql {
   482    482           PRAGMA journal_mode = MEMORY;
   483    483           BEGIN;
   484    484             INSERT INTO t4 VALUES(3, 4);
   485    485         }
   486    486         file exists test.db-journal
   487         -    } {1}
          487  +    } {0}
   488    488       do_test jrnlmode-6.7 {
   489    489         execsql {
   490    490           COMMIT;
   491    491           SELECT * FROM t4;
   492    492         }
   493    493       } {1 2 3 4}
   494    494       do_test jrnlmode-6.8 {
   495    495         file exists test.db-journal
   496         -    } {1}
          496  +    } {0}
   497    497       do_test jrnlmode-6.9 {
   498    498         execsql {
   499    499           PRAGMA journal_mode = DELETE;
   500         -        BEGIN IMMEDIATE; COMMIT;
          500  +        BEGIN IMMEDIATE; INSERT INTO t4 VALUES(1,2); COMMIT;
   501    501         }
   502    502         file exists test.db-journal
   503    503       } {0}
   504    504     }
   505    505   }
   506    506   
   507    507   finish_test

Changes to test/misc1.test.

   477    477   #
   478    478   do_test misc1-14.1 {
   479    479     file mkdir tempdir
   480    480     cd tempdir
   481    481     execsql {BEGIN}
   482    482     file exists ./test.db-journal
   483    483   } {0}
   484         -do_test misc1-14.2 {
   485         -  execsql {UPDATE t1 SET a=0 WHERE 0}
          484  +do_test misc1-14.2a {
          485  +  execsql {UPDATE t1 SET a=a||'x' WHERE 0}
          486  +  file exists ../test.db-journal
          487  +} {0}
          488  +do_test misc1-14.2b {
          489  +  execsql {UPDATE t1 SET a=a||'y' WHERE 1}
   486    490     file exists ../test.db-journal
   487    491   } {1}
   488    492   do_test misc1-14.3 {
   489    493     cd ..
   490    494     file delete -force tempdir
   491    495     execsql {COMMIT}
   492    496     file exists ./test.db-journal