1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Import experimental write-ahead-logging code.

FossilOrigin-Name: 409d61baeb0a19d1700c973f16c8acef7b8506cd
This commit is contained in:
dan
2010-04-12 19:00:29 +00:00
parent eada58aa49
commit 7c24610e64
14 changed files with 2772 additions and 231 deletions

View File

@@ -20,6 +20,7 @@
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include "log.h"
/*
******************** NOTES ON THE DESIGN OF THE PAGER ************************
@@ -397,6 +398,7 @@ struct Pager {
char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
PCache *pPCache; /* Pointer to page cache object */
sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */
Log *pLog; /* Log used by "journal_mode=wal" */
};
/*
@@ -1185,6 +1187,27 @@ static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){
return rc;
}
/*
** Open a connection to the write-ahead log file for pager pPager.
*/
static int pagerOpenLog(Pager *pPager){
if( !pPager->pLog ){
int rc; /* Return code from LogOpen() */
rc = sqlite3LogOpen(pPager->pVfs, pPager->zFilename, &pPager->pLog);
if( rc!=SQLITE_OK ) return rc;
}
return SQLITE_OK;
}
/*
** Return true if this pager uses a write-ahead log instead of the usual
** rollback journal. Otherwise false.
*/
static int pagerUseLog(Pager *pPager){
return (pPager->pLog!=0);
}
/*
** Unlock the database file. This function is a no-op if the pager
** is in exclusive mode.
@@ -1197,7 +1220,7 @@ static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){
*/
static void pager_unlock(Pager *pPager){
if( !pPager->exclusiveMode ){
int rc; /* Return code */
int rc = SQLITE_OK; /* Return code */
/* Always close the journal file when dropping the database lock.
** Otherwise, another connection with journal_mode=delete might
@@ -1216,6 +1239,9 @@ static void pager_unlock(Pager *pPager){
*/
pPager->dbSizeValid = 0;
if( pagerUseLog(pPager) ){
sqlite3LogCloseSnapshot(pPager->pLog);
}
rc = osUnlock(pPager->fd, NO_LOCK);
if( rc ){
pPager->errCode = rc;
@@ -1365,6 +1391,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );
if( isOpen(pPager->jfd) ){
assert( !pagerUseLog(pPager) );
/* Finalize the journal file. */
if( sqlite3IsMemJournal(pPager->jfd) ){
@@ -1408,7 +1435,10 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
pPager->nRec = 0;
sqlite3PcacheCleanAll(pPager->pPCache);
if( !pPager->exclusiveMode ){
if( pagerUseLog(pPager) ){
rc2 = sqlite3LogWriteLock(pPager->pLog, 0);
pPager->state = PAGER_SHARED;
}else if( !pPager->exclusiveMode ){
rc2 = osUnlock(pPager->fd, SHARED_LOCK);
pPager->state = PAGER_SHARED;
pPager->changeCountDone = 0;
@@ -2120,6 +2150,9 @@ end_playback:
if( rc==SQLITE_OK && pPager->noSync==0 && pPager->state>=PAGER_EXCLUSIVE ){
rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
}
if( rc==SQLITE_OK && pPager->noSync==0 && pPager->state>=PAGER_EXCLUSIVE ){
rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
}
if( rc==SQLITE_OK ){
rc = pager_end_transaction(pPager, zMaster[0]!='\0');
testcase( rc!=SQLITE_OK );
@@ -2140,6 +2173,97 @@ end_playback:
return rc;
}
/*
** Read the content for page pPg out of the database file and into
** pPg->pData. A shared lock or greater must be held on the database
** file before this function is called.
**
** If page 1 is read, then the value of Pager.dbFileVers[] is set to
** the value read from the database file.
**
** If an IO error occurs, then the IO error is returned to the caller.
** Otherwise, SQLITE_OK is returned.
*/
static int readDbPage(PgHdr *pPg){
Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
Pgno pgno = pPg->pgno; /* Page number to read */
int rc; /* Return code */
i64 iOffset; /* Byte offset of file to read from */
int isInLog = 0; /* True if page is in log file */
assert( pPager->state>=PAGER_SHARED && !MEMDB );
assert( isOpen(pPager->fd) );
if( NEVER(!isOpen(pPager->fd)) ){
assert( pPager->tempFile );
memset(pPg->pData, 0, pPager->pageSize);
return SQLITE_OK;
}
if( pagerUseLog(pPager) ){
/* Try to pull the page from the write-ahead log. */
rc = sqlite3LogRead(pPager->pLog, pgno, &isInLog, pPg->pData);
}
if( rc==SQLITE_OK && !isInLog ){
iOffset = (pgno-1)*(i64)pPager->pageSize;
rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
}
if( pgno==1 ){
if( rc ){
/* If the read is unsuccessful, set the dbFileVers[] to something
** that will never be a valid file version. dbFileVers[] is a copy
** of bytes 24..39 of the database. Bytes 28..31 should always be
** zero. Bytes 32..35 and 35..39 should be page numbers which are
** never 0xffffffff. So filling pPager->dbFileVers[] with all 0xff
** bytes should suffice.
**
** For an encrypted database, the situation is more complex: bytes
** 24..39 of the database are white noise. But the probability of
** white noising equaling 16 bytes of 0xff is vanishingly small so
** we should still be ok.
*/
memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers));
}else{
u8 *dbFileVers = &((u8*)pPg->pData)[24];
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
}
}
CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
PAGER_INCR(sqlite3_pager_readdb_count);
PAGER_INCR(pPager->nRead);
IOTRACE(("PGIN %p %d\n", pPager, pgno));
PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
PAGERID(pPager), pgno, pager_pagehash(pPg)));
return rc;
}
static int pagerRollbackLog(Pager *pPager){
int rc = SQLITE_OK;
PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
pPager->dbSize = pPager->dbOrigSize;
while( pList && rc==SQLITE_OK ){
PgHdr *pNext = pList->pDirty;
if( sqlite3PcachePageRefcount(pList)==0 ){
sqlite3PagerLookup(pPager, pList->pgno);
sqlite3PcacheDrop(pList);
}else{
rc = readDbPage(pList);
if( rc==SQLITE_OK ){
pPager->xReiniter(pList);
}
}
pList = pNext;
}
return rc;
}
/*
** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback
** the entire master journal file. The case pSavepoint==NULL occurs when
@@ -2197,12 +2321,17 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
*/
pPager->dbSize = pSavepoint ? pSavepoint->nOrig : pPager->dbOrigSize;
if( !pSavepoint && pagerUseLog(pPager) ){
return pagerRollbackLog(pPager);
}
/* Use pPager->journalOff as the effective size of the main rollback
** journal. The actual file might be larger than this in
** PAGER_JOURNALMODE_TRUNCATE or PAGER_JOURNALMODE_PERSIST. But anything
** past pPager->journalOff is off-limits to us.
*/
szJ = pPager->journalOff;
assert( pagerUseLog(pPager)==0 || szJ==0 );
/* Begin by rolling back records from the main journal starting at
** PagerSavepoint.iOffset and continuing to the next journal header.
@@ -2211,7 +2340,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
** will be skipped automatically. Pages are added to pDone as they
** are played back.
*/
if( pSavepoint ){
if( pSavepoint && !pagerUseLog(pPager) ){
iHdrOff = pSavepoint->iHdrOffset ? pSavepoint->iHdrOffset : szJ;
pPager->journalOff = pSavepoint->iOffset;
while( rc==SQLITE_OK && pPager->journalOff<iHdrOff ){
@@ -2558,7 +2687,7 @@ int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){
** and *pnPage is set to the number of pages in the database.
*/
int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
Pgno nPage; /* Value to return via *pnPage */
Pgno nPage = 0; /* Value to return via *pnPage */
/* Determine the number of pages in the file. Store this in nPage. */
if( pPager->dbSizeValid ){
@@ -2567,15 +2696,23 @@ int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
int rc; /* Error returned by OsFileSize() */
i64 n = 0; /* File size in bytes returned by OsFileSize() */
assert( isOpen(pPager->fd) || pPager->tempFile );
if( isOpen(pPager->fd) && (0 != (rc = sqlite3OsFileSize(pPager->fd, &n))) ){
pager_error(pPager, rc);
return rc;
if( pagerUseLog(pPager) ){
sqlite3LogMaxpgno(pPager->pLog, &nPage);
}
if( n>0 && n<pPager->pageSize ){
nPage = 1;
}else{
nPage = (Pgno)(n / pPager->pageSize);
if( nPage==0 ){
assert( isOpen(pPager->fd) || pPager->tempFile );
if( isOpen(pPager->fd) ){
if( SQLITE_OK!=(rc = sqlite3OsFileSize(pPager->fd, &n)) ){
pager_error(pPager, rc);
return rc;
}
}
if( n>0 && n<pPager->pageSize ){
nPage = 1;
}else{
nPage = (Pgno)(n / pPager->pageSize);
}
}
if( pPager->state!=PAGER_UNLOCK ){
pPager->dbSize = nPage;
@@ -2698,6 +2835,7 @@ void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
assertTruncateConstraint(pPager);
}
/*
** This function is called before attempting a hot-journal rollback. It
** syncs the journal file to disk, then sets pPager->journalHdr to the
@@ -2738,10 +2876,14 @@ static int pagerSyncHotJournal(Pager *pPager){
** to the caller.
*/
int sqlite3PagerClose(Pager *pPager){
u8 *pTmp = (u8 *)pPager->pTmpSpace;
disable_simulated_io_errors();
sqlite3BeginBenignMalloc();
pPager->errCode = 0;
pPager->exclusiveMode = 0;
sqlite3LogClose(pPager->pLog, pPager->fd, pTmp);
pPager->pLog = 0;
pager_reset(pPager);
if( MEMDB ){
pager_unlock(pPager);
@@ -2762,7 +2904,7 @@ int sqlite3PagerClose(Pager *pPager){
PAGERTRACE(("CLOSE %d\n", PAGERID(pPager)));
IOTRACE(("CLOSE %p\n", pPager))
sqlite3OsClose(pPager->fd);
sqlite3PageFree(pPager->pTmpSpace);
sqlite3PageFree(pTmp);
sqlite3PcacheClose(pPager->pPCache);
#ifdef SQLITE_HAS_CODEC
@@ -3066,7 +3208,10 @@ static int subjournalPage(PgHdr *pPg){
CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
assert( pagerUseLog(pPager)
|| pageInJournal(pPg)
|| pPg->pgno>pPager->dbOrigSize
);
rc = write32bits(pPager->sjfd, offset, pPg->pgno);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
@@ -3107,6 +3252,8 @@ static int pagerStress(void *p, PgHdr *pPg){
assert( pPg->pPager==pPager );
assert( pPg->flags&PGHDR_DIRTY );
if( pagerUseLog(pPager) ) return SQLITE_OK;
/* The doNotSync flag is set by the sqlite3PagerWrite() function while it
** is journalling a set of two or more database pages that are stored
** on the same disk sector. Syncing the journal is not allowed while
@@ -3582,67 +3729,6 @@ static int hasHotJournal(Pager *pPager, int *pExists){
return rc;
}
/*
** Read the content for page pPg out of the database file and into
** pPg->pData. A shared lock or greater must be held on the database
** file before this function is called.
**
** If page 1 is read, then the value of Pager.dbFileVers[] is set to
** the value read from the database file.
**
** If an IO error occurs, then the IO error is returned to the caller.
** Otherwise, SQLITE_OK is returned.
*/
static int readDbPage(PgHdr *pPg){
Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
Pgno pgno = pPg->pgno; /* Page number to read */
int rc; /* Return code */
i64 iOffset; /* Byte offset of file to read from */
assert( pPager->state>=PAGER_SHARED && !MEMDB );
assert( isOpen(pPager->fd) );
if( NEVER(!isOpen(pPager->fd)) ){
assert( pPager->tempFile );
memset(pPg->pData, 0, pPager->pageSize);
return SQLITE_OK;
}
iOffset = (pgno-1)*(i64)pPager->pageSize;
rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
if( pgno==1 ){
if( rc ){
/* If the read is unsuccessful, set the dbFileVers[] to something
** that will never be a valid file version. dbFileVers[] is a copy
** of bytes 24..39 of the database. Bytes 28..31 should always be
** zero. Bytes 32..35 and 35..39 should be page numbers which are
** never 0xffffffff. So filling pPager->dbFileVers[] with all 0xff
** bytes should suffice.
**
** For an encrypted database, the situation is more complex: bytes
** 24..39 of the database are white noise. But the probability of
** white noising equaling 16 bytes of 0xff is vanishingly small so
** we should still be ok.
*/
memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers));
}else{
u8 *dbFileVers = &((u8*)pPg->pData)[24];
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
}
}
CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
PAGER_INCR(sqlite3_pager_readdb_count);
PAGER_INCR(pPager->nRead);
IOTRACE(("PGIN %p %d\n", pPager, pgno));
PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
PAGERID(pPager), pgno, pager_pagehash(pPg)));
return rc;
}
/*
** This function is called to obtain a shared lock on the database file.
** It is illegal to call sqlite3PagerAcquire() until after this function
@@ -3696,22 +3782,34 @@ int sqlite3PagerSharedLock(Pager *pPager){
pager_reset(pPager);
}
if( pPager->state==PAGER_UNLOCK || isErrorReset ){
if( pPager->noReadlock ){
assert( pPager->readOnly );
pPager->state = PAGER_SHARED;
}else{
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
if( rc!=SQLITE_OK ){
assert( pPager->state==PAGER_UNLOCK );
return pager_error(pPager, rc);
}
}
assert( pPager->state>=SHARED_LOCK );
if( pagerUseLog(pPager) ){
int changed = 0;
rc = sqlite3LogOpenSnapshot(pPager->pLog, &changed);
if( rc==SQLITE_OK ){
if( changed ){
pager_reset(pPager);
assert( pPager->errCode || pPager->dbSizeValid==0 );
}
pPager->state = PAGER_SHARED;
rc = sqlite3PagerPagecount(pPager, &changed);
}
}else if( pPager->state==PAGER_UNLOCK || isErrorReset ){
sqlite3_vfs * const pVfs = pPager->pVfs;
int isHotJournal = 0;
assert( !MEMDB );
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
if( pPager->noReadlock ){
assert( pPager->readOnly );
pPager->state = PAGER_SHARED;
}else{
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
if( rc!=SQLITE_OK ){
assert( pPager->state==PAGER_UNLOCK );
return pager_error(pPager, rc);
}
}
assert( pPager->state>=SHARED_LOCK );
/* If a journal file exists, and there is no RESERVED lock on the
** database file, then it either needs to be played back or deleted.
@@ -3785,7 +3883,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
pPager->journalOff = 0;
pPager->setMaster = 0;
pPager->journalHdr = 0;
/* Make sure the journal file has been synced to disk. */
/* Playback and delete the journal. Drop the database write
@@ -3992,8 +4090,8 @@ int sqlite3PagerAcquire(
if( MEMDB || nMax<(int)pgno || noContent || !isOpen(pPager->fd) ){
if( pgno>pPager->mxPgno ){
rc = SQLITE_FULL;
goto pager_acquire_err;
rc = SQLITE_FULL;
goto pager_acquire_err;
}
if( noContent ){
/* Failure to set the bits in the InJournal bit-vectors is benign.
@@ -4088,7 +4186,7 @@ void sqlite3PagerUnref(DbPage *pPg){
*/
static int openSubJournal(Pager *pPager){
int rc = SQLITE_OK;
if( isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ){
if( (pagerUseLog(pPager) || isOpen(pPager->jfd)) && !isOpen(pPager->sjfd) ){
if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
sqlite3MemJournalOpen(pPager->sjfd);
}else{
@@ -4237,6 +4335,18 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
}
}
if( rc==SQLITE_OK && pagerUseLog(pPager) ){
/* Grab the write lock on the log file. If successful, upgrade to
** PAGER_EXCLUSIVE state. Otherwise, return an error code to the caller.
** The busy-handler is not invoked if another connection already
** holds the write-lock. If possible, the upper layer will call it.
*/
rc = sqlite3LogWriteLock(pPager->pLog, 1);
if( rc==SQLITE_OK ){
pPager->dbOrigSize = pPager->dbSize;
}
}
/* No need to open the journal file at this time. It will be
** opened before it is written to. If we defer opening the journal,
** we might save the work of creating a file if the transaction
@@ -4249,6 +4359,7 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
** kept open and either was truncated to 0 bytes or its header was
** overwritten with zeros.
*/
assert( pagerUseLog(pPager)==0 );
assert( pPager->nRec==0 );
assert( pPager->dbOrigSize==0 );
assert( pPager->pInJournal==0 );
@@ -4303,6 +4414,7 @@ static int pager_write(PgHdr *pPg){
*/
sqlite3PcacheMakeDirty(pPg);
if( pageInJournal(pPg) && !subjRequiresPage(pPg) ){
assert( !pagerUseLog(pPager) );
pPager->dbModified = 1;
}else{
@@ -4318,7 +4430,10 @@ static int pager_write(PgHdr *pPg){
if( rc!=SQLITE_OK ){
return rc;
}
if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
if( !isOpen(pPager->jfd)
&& pPager->journalMode!=PAGER_JOURNALMODE_OFF
&& pPager->journalMode!=PAGER_JOURNALMODE_WAL
){
assert( pPager->useJournal );
rc = pager_open_journal(pPager);
if( rc!=SQLITE_OK ) return rc;
@@ -4330,6 +4445,7 @@ static int pager_write(PgHdr *pPg){
** the transaction journal if it is not there already.
*/
if( !pageInJournal(pPg) && isOpen(pPager->jfd) ){
assert( !pagerUseLog(pPager) );
if( pPg->pgno<=pPager->dbOrigSize ){
u32 cksum;
char *pData2;
@@ -4710,129 +4826,138 @@ int sqlite3PagerCommitPhaseOne(
*/
sqlite3BackupRestart(pPager->pBackup);
}else if( pPager->state!=PAGER_SYNCED && pPager->dbModified ){
/* The following block updates the change-counter. Exactly how it
** does this depends on whether or not the atomic-update optimization
** was enabled at compile time, and if this transaction meets the
** runtime criteria to use the operation:
**
** * The file-system supports the atomic-write property for
** blocks of size page-size, and
** * This commit is not part of a multi-file transaction, and
** * Exactly one page has been modified and store in the journal file.
**
** If the optimization was not enabled at compile time, then the
** pager_incr_changecounter() function is called to update the change
** counter in 'indirect-mode'. If the optimization is compiled in but
** is not applicable to this transaction, call sqlite3JournalCreate()
** to make sure the journal file has actually been created, then call
** pager_incr_changecounter() to update the change-counter in indirect
** mode.
**
** Otherwise, if the optimization is both enabled and applicable,
** then call pager_incr_changecounter() to update the change-counter
** in 'direct' mode. In this case the journal file will never be
** created for this transaction.
*/
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
PgHdr *pPg;
assert( isOpen(pPager->jfd) || pPager->journalMode==PAGER_JOURNALMODE_OFF );
if( !zMaster && isOpen(pPager->jfd)
&& pPager->journalOff==jrnlBufferSize(pPager)
&& pPager->dbSize>=pPager->dbFileSize
&& (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
){
/* Update the db file change counter via the direct-write method. The
** following call will modify the in-memory representation of page 1
** to include the updated change counter and then write page 1
** directly to the database file. Because of the atomic-write
** property of the host file-system, this is safe.
*/
rc = pager_incr_changecounter(pPager, 1);
}else{
rc = sqlite3JournalCreate(pPager->jfd);
if( rc==SQLITE_OK ){
rc = pager_incr_changecounter(pPager, 0);
if( pagerUseLog(pPager) ){
PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
if( pList ){
rc = sqlite3LogFrames(pPager->pLog, pPager->pageSize, pList,
pPager->dbSize, 1, 1
);
}
}
#else
rc = pager_incr_changecounter(pPager, 0);
#endif
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
/* If this transaction has made the database smaller, then all pages
** being discarded by the truncation must be written to the journal
** file. This can only happen in auto-vacuum mode.
**
** Before reading the pages with page numbers larger than the
** current value of Pager.dbSize, set dbSize back to the value
** that it took at the start of the transaction. Otherwise, the
** calls to sqlite3PagerGet() return zeroed pages instead of
** reading data from the database file.
**
** When journal_mode==OFF the dbOrigSize is always zero, so this
** block never runs if journal_mode=OFF.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pPager->dbSize<pPager->dbOrigSize
&& ALWAYS(pPager->journalMode!=PAGER_JOURNALMODE_OFF)
){
Pgno i; /* Iterator variable */
const Pgno iSkip = PAGER_MJ_PGNO(pPager); /* Pending lock page */
const Pgno dbSize = pPager->dbSize; /* Database image size */
pPager->dbSize = pPager->dbOrigSize;
for( i=dbSize+1; i<=pPager->dbOrigSize; i++ ){
if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
PgHdr *pPage; /* Page to journal */
rc = sqlite3PagerGet(pPager, i, &pPage);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
rc = sqlite3PagerWrite(pPage);
sqlite3PagerUnref(pPage);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
sqlite3PcacheCleanAll(pPager->pPCache);
}else{
/* The following block updates the change-counter. Exactly how it
** does this depends on whether or not the atomic-update optimization
** was enabled at compile time, and if this transaction meets the
** runtime criteria to use the operation:
**
** * The file-system supports the atomic-write property for
** blocks of size page-size, and
** * This commit is not part of a multi-file transaction, and
** * Exactly one page has been modified and store in the journal file.
**
** If the optimization was not enabled at compile time, then the
** pager_incr_changecounter() function is called to update the change
** counter in 'indirect-mode'. If the optimization is compiled in but
** is not applicable to this transaction, call sqlite3JournalCreate()
** to make sure the journal file has actually been created, then call
** pager_incr_changecounter() to update the change-counter in indirect
** mode.
**
** Otherwise, if the optimization is both enabled and applicable,
** then call pager_incr_changecounter() to update the change-counter
** in 'direct' mode. In this case the journal file will never be
** created for this transaction.
*/
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
PgHdr *pPg;
assert( isOpen(pPager->jfd) || pPager->journalMode==PAGER_JOURNALMODE_OFF );
if( !zMaster && isOpen(pPager->jfd)
&& pPager->journalOff==jrnlBufferSize(pPager)
&& pPager->dbSize>=pPager->dbFileSize
&& (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
){
/* Update the db file change counter via the direct-write method. The
** following call will modify the in-memory representation of page 1
** to include the updated change counter and then write page 1
** directly to the database file. Because of the atomic-write
** property of the host file-system, this is safe.
*/
rc = pager_incr_changecounter(pPager, 1);
}else{
rc = sqlite3JournalCreate(pPager->jfd);
if( rc==SQLITE_OK ){
rc = pager_incr_changecounter(pPager, 0);
}
}
pPager->dbSize = dbSize;
}
#endif
/* Write the master journal name into the journal file. If a master
** journal file name has already been written to the journal file,
** or if zMaster is NULL (no master journal), then this call is a no-op.
*/
rc = writeMasterJournal(pPager, zMaster);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
/* Sync the journal file. If the atomic-update optimization is being
** used, this call will not create the journal file or perform any
** real IO.
*/
rc = syncJournal(pPager);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
/* Write all dirty pages to the database file. */
rc = pager_write_pagelist(sqlite3PcacheDirtyList(pPager->pPCache));
if( rc!=SQLITE_OK ){
assert( rc!=SQLITE_IOERR_BLOCKED );
goto commit_phase_one_exit;
}
sqlite3PcacheCleanAll(pPager->pPCache);
/* If the file on disk is not the same size as the database image,
** then use pager_truncate to grow or shrink the file here.
*/
if( pPager->dbSize!=pPager->dbFileSize ){
Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
assert( pPager->state>=PAGER_EXCLUSIVE );
rc = pager_truncate(pPager, nNew);
}
#else
rc = pager_incr_changecounter(pPager, 0);
#endif
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
/* If this transaction has made the database smaller, then all pages
** being discarded by the truncation must be written to the journal
** file. This can only happen in auto-vacuum mode.
**
** Before reading the pages with page numbers larger than the
** current value of Pager.dbSize, set dbSize back to the value
** that it took at the start of the transaction. Otherwise, the
** calls to sqlite3PagerGet() return zeroed pages instead of
** reading data from the database file.
**
** When journal_mode==OFF the dbOrigSize is always zero, so this
** block never runs if journal_mode=OFF.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pPager->dbSize<pPager->dbOrigSize
&& ALWAYS(pPager->journalMode!=PAGER_JOURNALMODE_OFF)
){
Pgno i; /* Iterator variable */
const Pgno iSkip = PAGER_MJ_PGNO(pPager); /* Pending lock page */
const Pgno dbSize = pPager->dbSize; /* Database image size */
pPager->dbSize = pPager->dbOrigSize;
for( i=dbSize+1; i<=pPager->dbOrigSize; i++ ){
if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
PgHdr *pPage; /* Page to journal */
rc = sqlite3PagerGet(pPager, i, &pPage);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
rc = sqlite3PagerWrite(pPage);
sqlite3PagerUnref(pPage);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
}
}
pPager->dbSize = dbSize;
}
#endif
/* Write the master journal name into the journal file. If a master
** journal file name has already been written to the journal file,
** or if zMaster is NULL (no master journal), then this call is a no-op.
*/
rc = writeMasterJournal(pPager, zMaster);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
/* Sync the journal file. If the atomic-update optimization is being
** used, this call will not create the journal file or perform any
** real IO.
*/
rc = syncJournal(pPager);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
/* Write all dirty pages to the database file. */
rc = pager_write_pagelist(sqlite3PcacheDirtyList(pPager->pPCache));
if( rc!=SQLITE_OK ){
assert( rc!=SQLITE_IOERR_BLOCKED );
goto commit_phase_one_exit;
}
sqlite3PcacheCleanAll(pPager->pPCache);
/* If the file on disk is not the same size as the database image,
** then use pager_truncate to grow or shrink the file here.
*/
if( pPager->dbSize!=pPager->dbFileSize ){
Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
assert( pPager->state>=PAGER_EXCLUSIVE );
rc = pager_truncate(pPager, nNew);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
}
/* Finally, sync the database file. */
if( !pPager->noSync && !noSync ){
rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
}
IOTRACE(("DBSYNC %p\n", pPager))
}
/* Finally, sync the database file. */
if( !pPager->noSync && !noSync ){
rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
}
IOTRACE(("DBSYNC %p\n", pPager))
pPager->state = PAGER_SYNCED;
}
@@ -4940,7 +5065,12 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
int sqlite3PagerRollback(Pager *pPager){
int rc = SQLITE_OK; /* Return code */
PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager)));
if( !pPager->dbModified || !isOpen(pPager->jfd) ){
if( pagerUseLog(pPager) ){
int rc2;
rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
rc2 = pager_end_transaction(pPager, pPager->setMaster);
if( rc==SQLITE_OK ) rc = rc2;
}else if( !pPager->dbModified || !isOpen(pPager->jfd) ){
rc = pager_end_transaction(pPager, pPager->setMaster);
}else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
if( pPager->state>=PAGER_EXCLUSIVE ){
@@ -5158,7 +5288,7 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
** not yet been opened. In this case there have been no changes to
** the database file, so the playback operation can be skipped.
*/
else if( isOpen(pPager->jfd) ){
else if( pagerUseLog(pPager) || isOpen(pPager->jfd) ){
PagerSavepoint *pSavepoint = (nNew==0)?0:&pPager->aSavepoint[nNew-1];
rc = pagerPlaybackSavepoint(pPager, pSavepoint);
assert(rc!=SQLITE_DONE);
@@ -5435,6 +5565,7 @@ int sqlite3PagerLockingMode(Pager *pPager, int eMode){
** PAGER_JOURNALMODE_PERSIST
** PAGER_JOURNALMODE_OFF
** PAGER_JOURNALMODE_MEMORY
** PAGER_JOURNALMODE_WAL
**
** If the parameter is not _QUERY, then the journal_mode is set to the
** value specified if the change is allowed. The change is disallowed
@@ -5453,11 +5584,12 @@ int sqlite3PagerJournalMode(Pager *pPager, int eMode){
|| eMode==PAGER_JOURNALMODE_TRUNCATE
|| eMode==PAGER_JOURNALMODE_PERSIST
|| eMode==PAGER_JOURNALMODE_OFF
|| eMode==PAGER_JOURNALMODE_WAL
|| eMode==PAGER_JOURNALMODE_MEMORY );
assert( PAGER_JOURNALMODE_QUERY<0 );
if( eMode>=0
&& (!MEMDB || eMode==PAGER_JOURNALMODE_MEMORY
|| eMode==PAGER_JOURNALMODE_OFF)
&& (pPager->tempFile==0 || eMode!=PAGER_JOURNALMODE_WAL)
&& (!MEMDB || eMode==PAGER_JOURNALMODE_MEMORY||eMode==PAGER_JOURNALMODE_OFF)
&& !pPager->dbModified
&& (!isOpen(pPager->jfd) || 0==pPager->journalOff)
){
@@ -5473,6 +5605,16 @@ int sqlite3PagerJournalMode(Pager *pPager, int eMode){
&& !pPager->exclusiveMode ){
sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
}
if( eMode==PAGER_JOURNALMODE_WAL ){
int rc = pagerOpenLog(pPager);
if( rc!=SQLITE_OK ){
/* TODO: The error code should not just get dropped here. Change
** this to set a flag to force the log to be opened the first time
** it is actually required. */
return (int)pPager->journalMode;
}
}
pPager->journalMode = (u8)eMode;
}
return (int)pPager->journalMode;
@@ -5501,4 +5643,19 @@ sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
return &pPager->pBackup;
}
/*
** This function is called when the user invokes "PRAGMA checkpoint".
*/
int sqlite3PagerCheckpoint(Pager *pPager, int nMin, int nMax, int doSync){
int rc = SQLITE_OK;
if( pPager->pLog ){
rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
if( rc==SQLITE_OK ){
u8 *zBuf = (u8 *)pPager->pTmpSpace;
rc = sqlite3LogCheckpoint(pPager->pLog, pPager->fd, zBuf);
}
}
return rc;
}
#endif /* SQLITE_OMIT_DISKIO */