pager.c
来自「sqlite最新源码」· C语言 代码 · 共 1,620 行 · 第 1/5 页
C
1,620 行
){ return SQLITE_OK; } pPager->setMaster = 1; assert( isOpen(pPager->jfd) ); /* Calculate the length in bytes and the checksum of zMaster */ for(nMaster=0; zMaster[nMaster]; nMaster++){ cksum += zMaster[nMaster]; } /* If in full-sync mode, advance to the next disk sector before writing ** the master journal name. This is in case the previous page written to ** the journal has already been synced. */ if( pPager->fullSync ){ pPager->journalOff = journalHdrOffset(pPager); } iHdrOff = pPager->journalOff; /* Write the master journal data to the end of the journal file. If ** an error occurs, return the error code to the caller. */ if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager)))) || (0 != (rc = sqlite3OsWrite(pPager->jfd, zMaster, nMaster, iHdrOff+4))) || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster, nMaster))) || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster+4, cksum))) || (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8, iHdrOff+4+nMaster+8))) ){ return rc; } pPager->journalOff += (nMaster+20); pPager->needSync = !pPager->noSync; /* If the pager is in peristent-journal mode, then the physical ** journal-file may extend past the end of the master-journal name ** and 8 bytes of magic data just written to the file. This is ** dangerous because the code to rollback a hot-journal file ** will not be able to find the master-journal name to determine ** whether or not the journal is hot. ** ** Easiest thing to do in this scenario is to truncate the journal ** file to the required size. */ if( SQLITE_OK==(rc = sqlite3OsFileSize(pPager->jfd, &jrnlSize)) && jrnlSize>pPager->journalOff ){ rc = sqlite3OsTruncate(pPager->jfd, pPager->journalOff); } return rc;}/*** Find a page in the hash table given its page number. Return** a pointer to the page or NULL if the requested page is not ** already in memory.*/static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){ PgHdr *p; /* Return value */ /* It is not possible for a call to PcacheFetch() with createFlag==0 to ** fail, since no attempt to allocate dynamic memory will be made. */ (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &p); return p;}/*** Unless the pager is in error-state, discard all in-memory pages. If** the pager is in error-state, then this call is a no-op.**** TODO: Why can we not reset the pager while in error state?*/static void pager_reset(Pager *pPager){ if( SQLITE_OK==pPager->errCode ){ sqlite3BackupRestart(pPager->pBackup); sqlite3PcacheClear(pPager->pPCache); }}/*** Free all structures in the Pager.aSavepoint[] array and set both** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal** if it is open and the pager is not in exclusive mode.*/static void releaseAllSavepoints(Pager *pPager){ int ii; /* Iterator for looping through Pager.aSavepoint */ for(ii=0; ii<pPager->nSavepoint; ii++){ sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint); } if( !pPager->exclusiveMode ){ sqlite3OsClose(pPager->sjfd); } sqlite3_free(pPager->aSavepoint); pPager->aSavepoint = 0; pPager->nSavepoint = 0; pPager->nSubRec = 0;}/*** Set the bit number pgno in the PagerSavepoint.pInSavepoint ** bitvecs of all open savepoints. Return SQLITE_OK if successful** or SQLITE_NOMEM if a malloc failure occurs.*/static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){ int ii; /* Loop counter */ int rc = SQLITE_OK; /* Result code */ for(ii=0; ii<pPager->nSavepoint; ii++){ PagerSavepoint *p = &pPager->aSavepoint[ii]; if( pgno<=p->nOrig ){ rc |= sqlite3BitvecSet(p->pInSavepoint, pgno); testcase( rc==SQLITE_NOMEM ); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); } } return rc;}/*** Unlock the database file. This function is a no-op if the pager** is in exclusive mode.**** If the pager is currently in error state, discard the contents of ** the cache and reset the Pager structure internal state. If there is** an open journal-file, then the next time a shared-lock is obtained** on the pager file (by this or any other process), it will be** treated as a hot-journal and rolled back.*/static void pager_unlock(Pager *pPager){ if( !pPager->exclusiveMode ){ int rc; /* Return code */ /* Always close the journal file when dropping the database lock. ** Otherwise, another connection with journal_mode=delete might ** delete the file out from under us. */ sqlite3OsClose(pPager->jfd); sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; releaseAllSavepoints(pPager); /* If the file is unlocked, somebody else might change it. The ** values stored in Pager.dbSize etc. might become invalid if ** this happens. TODO: Really, this doesn't need to be cleared ** until the change-counter check fails in pagerSharedLock(). */ pPager->dbSizeValid = 0; rc = osUnlock(pPager->fd, NO_LOCK); if( rc ){ pPager->errCode = rc; } IOTRACE(("UNLOCK %p\n", pPager)) /* If Pager.errCode is set, the contents of the pager cache cannot be ** trusted. Now that the pager file is unlocked, the contents of the ** cache can be discarded and the error code safely cleared. */ if( pPager->errCode ){ if( rc==SQLITE_OK ){ pPager->errCode = SQLITE_OK; } pager_reset(pPager); } pPager->changeCountDone = 0; pPager->state = PAGER_UNLOCK; }}/*** This function should be called when an IOERR, CORRUPT or FULL error** may have occured. The first argument is a pointer to the pager ** structure, the second the error-code about to be returned by a pager ** API function. The value returned is a copy of the second argument ** to this function. **** If the second argument is SQLITE_IOERR, SQLITE_CORRUPT, or SQLITE_FULL** the error becomes persistent. Until the persisten error is cleared,** subsequent API calls on this Pager will immediately return the same ** error code.**** A persistent error indicates that the contents of the pager-cache ** cannot be trusted. This state can be cleared by completely discarding ** the contents of the pager-cache. If a transaction was active when** the persistent error occured, then the rollback journal may need** to be replayed to restore the contents of the database file (as if** it were a hot-journal).*/static int pager_error(Pager *pPager, int rc){ int rc2 = rc & 0xff; assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK || (pPager->errCode & 0xff)==SQLITE_IOERR ); if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR || rc2==SQLITE_CORRUPT ){ pPager->errCode = rc; if( pPager->state==PAGER_UNLOCK && sqlite3PcacheRefCount(pPager->pPCache)==0 ){ /* If the pager is already unlocked, call pager_unlock() now to ** clear the error state and ensure that the pager-cache is ** completely empty. */ pager_unlock(pPager); } } return rc;}/*** Execute a rollback if a transaction is active and unlock the ** database file. **** If the pager has already entered the error state, do not attempt ** the rollback at this time. Instead, pager_unlock() is called. The** call to pager_unlock() will discard all in-memory pages, unlock** the database file and clear the error state. If this means that** there is a hot-journal left in the file-system, the next connection** to obtain a shared lock on the pager (which may be this one) will** roll it back.**** If the pager has not already entered the error state, but an IO or** malloc error occurs during a rollback, then this will itself cause ** the pager to enter the error state. Which will be cleared by the** call to pager_unlock(), as described above.*/static void pagerUnlockAndRollback(Pager *pPager){ if( pPager->errCode==SQLITE_OK && pPager->state>=PAGER_RESERVED ){ sqlite3BeginBenignMalloc(); sqlite3PagerRollback(pPager); sqlite3EndBenignMalloc(); } pager_unlock(pPager);}/*** This routine ends a transaction. A transaction is usually ended by ** either a COMMIT or a ROLLBACK operation. This routine may be called ** after rollback of a hot-journal, or if an error occurs while opening** the journal file or writing the very first journal-header of a** database transaction.** ** If the pager is in PAGER_SHARED or PAGER_UNLOCK state when this** routine is called, it is a no-op (returns SQLITE_OK).**** Otherwise, any active savepoints are released.**** If the journal file is open, then it is "finalized". Once a journal ** file has been finalized it is not possible to use it to roll back a ** transaction. Nor will it be considered to be a hot-journal by this** or any other database connection. Exactly how a journal is finalized** depends on whether or not the pager is running in exclusive mode and** the current journal-mode (Pager.journalMode value), as follows:**** journalMode==MEMORY** Journal file descriptor is simply closed. This destroys an ** in-memory journal.**** journalMode==TRUNCATE** Journal file is truncated to zero bytes in size.**** journalMode==PERSIST** The first 28 bytes of the journal file are zeroed. This invalidates** the first journal header in the file, and hence the entire journal** file. An invalid journal file cannot be rolled back.**** journalMode==DELETE** The journal file is closed and deleted using sqlite3OsDelete().**** If the pager is running in exclusive mode, this method of finalizing** the journal file is never used. Instead, if the journalMode is** DELETE and the pager is in exclusive mode, the method described under** journalMode==PERSIST is used instead.**** After the journal is finalized, if running in non-exclusive mode, the** pager moves to PAGER_SHARED state (and downgrades the lock on the** database file accordingly).**** If the pager is running in exclusive mode and is in PAGER_SYNCED state,** it moves to PAGER_EXCLUSIVE. No locks are downgraded when running in** exclusive mode.**** SQLITE_OK is returned if no error occurs. If an error occurs during** any of the IO operations to finalize the journal file or unlock the** database then the IO error code is returned to the user. If the ** operation to finalize the journal file fails, then the code still** tries to unlock the database file if not in exclusive mode. If the** unlock operation fails as well, then the first error code related** to the first error encountered (the journal finalization one) is** returned.*/static int pager_end_transaction(Pager *pPager, int hasMaster){ int rc = SQLITE_OK; /* Error code from journal finalization operation */ int rc2 = SQLITE_OK; /* Error code from db file unlock operation */ if( pPager->state<PAGER_RESERVED ){ return SQLITE_OK; } releaseAllSavepoints(pPager); assert( isOpen(pPager->jfd) || pPager->pInJournal==0 ); if( isOpen(pPager->jfd) ){ /* TODO: There's a problem here if a journal-file was opened in MEMORY ** mode and then the journal-mode is changed to TRUNCATE or PERSIST ** during the transaction. This code should be changed to assume ** that the journal mode has not changed since the transaction was ** started. And the sqlite3PagerJournalMode() function should be ** changed to make sure that this is the case too. */ /* Finalize the journal file. */ if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){ int isMemoryJournal = sqlite3IsMemJournal(pPager->jfd); sqlite3OsClose(pPager->jfd); if( !isMemoryJournal ){ rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?