📄 pager.c
字号:
*/
static int pager_delmaster(const char *zMaster){
int rc;
int master_open = 0;
OsFile *master = 0;
char *zMasterJournal = 0; /* Contents of master journal file */
i64 nMasterJournal; /* Size of master journal file */
/* Open the master journal file exclusively in case some other process
** is running this routine also. Not that it makes too much difference.
*/
rc = sqlite3OsOpenReadOnly(zMaster, &master);
if( rc!=SQLITE_OK ) goto delmaster_out;
master_open = 1;
rc = sqlite3OsFileSize(master, &nMasterJournal);
if( rc!=SQLITE_OK ) goto delmaster_out;
if( nMasterJournal>0 ){
char *zJournal;
char *zMasterPtr = 0;
/* Load the entire master journal file into space obtained from
** sqliteMalloc() and pointed to by zMasterJournal.
*/
zMasterJournal = (char *)sqliteMalloc(nMasterJournal);
if( !zMasterJournal ){
rc = SQLITE_NOMEM;
goto delmaster_out;
}
rc = sqlite3OsRead(master, zMasterJournal, nMasterJournal);
if( rc!=SQLITE_OK ) goto delmaster_out;
zJournal = zMasterJournal;
while( (zJournal-zMasterJournal)<nMasterJournal ){
if( sqlite3OsFileExists(zJournal) ){
/* One of the journals pointed to by the master journal exists.
** Open it and check if it points at the master journal. If
** so, return without deleting the master journal file.
*/
OsFile *journal = 0;
int c;
rc = sqlite3OsOpenReadOnly(zJournal, &journal);
if( rc!=SQLITE_OK ){
goto delmaster_out;
}
rc = readMasterJournal(journal, &zMasterPtr);
sqlite3OsClose(&journal);
if( rc!=SQLITE_OK ){
goto delmaster_out;
}
c = zMasterPtr!=0 && strcmp(zMasterPtr, zMaster)==0;
sqliteFree(zMasterPtr);
if( c ){
/* We have a match. Do not delete the master journal file. */
goto delmaster_out;
}
}
zJournal += (strlen(zJournal)+1);
}
}
sqlite3OsDelete(zMaster);
delmaster_out:
if( zMasterJournal ){
sqliteFree(zMasterJournal);
}
if( master_open ){
sqlite3OsClose(&master);
}
return rc;
}
/*
** Make every page in the cache agree with what is on disk. In other words,
** reread the disk to reset the state of the cache.
**
** This routine is called after a rollback in which some of the dirty cache
** pages had never been written out to disk. We need to roll back the
** cache content and the easiest way to do that is to reread the old content
** back from the disk.
*/
static int pager_reload_cache(Pager *pPager){
PgHdr *pPg;
int rc = SQLITE_OK;
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
char zBuf[SQLITE_MAX_PAGE_SIZE];
if( !pPg->dirty ) continue;
if( (int)pPg->pgno <= pPager->origDbSize ){
rc = sqlite3OsSeek(pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
if( rc==SQLITE_OK ){
rc = sqlite3OsRead(pPager->fd, zBuf, pPager->pageSize);
}
TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
if( rc ) break;
CODEC1(pPager, zBuf, pPg->pgno, 2);
}else{
memset(zBuf, 0, pPager->pageSize);
}
if( pPg->nRef==0 || memcmp(zBuf, PGHDR_TO_DATA(pPg), pPager->pageSize) ){
memcpy(PGHDR_TO_DATA(pPg), zBuf, pPager->pageSize);
if( pPager->xReiniter ){
pPager->xReiniter(PGHDR_TO_DATA(pPg), pPager->pageSize);
}else{
memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
}
}
pPg->needSync = 0;
pPg->dirty = 0;
#ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg);
#endif
}
pPager->pDirty = 0;
return rc;
}
/*
** Truncate the main file of the given pager to the number of pages
** indicated.
*/
static int pager_truncate(Pager *pPager, int nPage){
assert( pPager->state>=PAGER_EXCLUSIVE );
return sqlite3OsTruncate(pPager->fd, pPager->pageSize*(i64)nPage);
}
/*
** Playback the journal and thus restore the database file to
** the state it was in before we started making changes.
**
** The journal file format is as follows:
**
** (1) 8 byte prefix. A copy of aJournalMagic[].
** (2) 4 byte big-endian integer which is the number of valid page records
** in the journal. If this value is 0xffffffff, then compute the
** number of page records from the journal size.
** (3) 4 byte big-endian integer which is the initial value for the
** sanity checksum.
** (4) 4 byte integer which is the number of pages to truncate the
** database to during a rollback.
** (5) 4 byte integer which is the number of bytes in the master journal
** name. The value may be zero (indicate that there is no master
** journal.)
** (6) N bytes of the master journal name. The name will be nul-terminated
** and might be shorter than the value read from (5). If the first byte
** of the name is \000 then there is no master journal. The master
** journal name is stored in UTF-8.
** (7) Zero or more pages instances, each as follows:
** + 4 byte page number.
** + pPager->pageSize bytes of data.
** + 4 byte checksum
**
** When we speak of the journal header, we mean the first 6 items above.
** Each entry in the journal is an instance of the 7th item.
**
** Call the value from the second bullet "nRec". nRec is the number of
** valid page entries in the journal. In most cases, you can compute the
** value of nRec from the size of the journal file. But if a power
** failure occurred while the journal was being written, it could be the
** case that the size of the journal file had already been increased but
** the extra entries had not yet made it safely to disk. In such a case,
** the value of nRec computed from the file size would be too large. For
** that reason, we always use the nRec value in the header.
**
** If the nRec value is 0xffffffff it means that nRec should be computed
** from the file size. This value is used when the user selects the
** no-sync option for the journal. A power failure could lead to corruption
** in this case. But for things like temporary table (which will be
** deleted when the power is restored) we don't care.
**
** If the file opened as the journal file is not a well-formed
** journal file then all pages up to the first corrupted page are rolled
** back (or no pages if the journal header is corrupted). The journal file
** is then deleted and SQLITE_OK returned, just as if no corruption had
** been encountered.
**
** If an I/O or malloc() error occurs, the journal-file is not deleted
** and an error code is returned.
*/
static int pager_playback(Pager *pPager){
i64 szJ; /* Size of the journal file in bytes */
u32 nRec; /* Number of Records in the journal */
int i; /* Loop counter */
Pgno mxPg = 0; /* Size of the original file in pages */
int rc; /* Result code of a subroutine */
char *zMaster = 0; /* Name of master journal file if any */
/* Figure out how many records are in the journal. Abort early if
** the journal is empty.
*/
assert( pPager->journalOpen );
rc = sqlite3OsFileSize(pPager->jfd, &szJ);
if( rc!=SQLITE_OK ){
goto end_playback;
}
/* Read the master journal name from the journal, if it is present.
** If a master journal file name is specified, but the file is not
** present on disk, then the journal is not hot and does not need to be
** played back.
*/
rc = readMasterJournal(pPager->jfd, &zMaster);
assert( rc!=SQLITE_DONE );
if( rc!=SQLITE_OK || (zMaster && !sqlite3OsFileExists(zMaster)) ){
sqliteFree(zMaster);
zMaster = 0;
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
goto end_playback;
}
sqlite3OsSeek(pPager->jfd, 0);
pPager->journalOff = 0;
/* This loop terminates either when the readJournalHdr() call returns
** SQLITE_DONE or an IO error occurs. */
while( 1 ){
/* Read the next journal header from the journal file. If there are
** not enough bytes left in the journal file for a complete header, or
** it is corrupted, then a process must of failed while writing it.
** This indicates nothing more needs to be rolled back.
*/
rc = readJournalHdr(pPager, szJ, &nRec, &mxPg);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
}
goto end_playback;
}
/* If nRec is 0xffffffff, then this journal was created by a process
** working in no-sync mode. This means that the rest of the journal
** file consists of pages, there are no more journal headers. Compute
** the value of nRec based on this assumption.
*/
if( nRec==0xffffffff ){
assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) );
nRec = (szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager);
}
/* If this is the first header read from the journal, truncate the
** database file back to it's original size.
*/
if( pPager->state>=PAGER_EXCLUSIVE &&
pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){
assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg );
rc = pager_truncate(pPager, mxPg);
if( rc!=SQLITE_OK ){
goto end_playback;
}
pPager->dbSize = mxPg;
}
/* Copy original pages out of the journal and back into the database file.
*/
for(i=0; i<nRec; i++){
rc = pager_playback_one_page(pPager, pPager->jfd, 1);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
pPager->journalOff = szJ;
break;
}else{
goto end_playback;
}
}
}
}
/*NOTREACHED*/
assert( 0 );
end_playback:
if( rc==SQLITE_OK ){
rc = pager_unwritelock(pPager);
}
if( zMaster ){
/* If there was a master journal and this routine will return true,
** see if it is possible to delete the master journal.
*/
if( rc==SQLITE_OK ){
rc = pager_delmaster(zMaster);
}
sqliteFree(zMaster);
}
/* The Pager.sectorSize variable may have been updated while rolling
** back a journal created by a process with a different PAGER_SECTOR_SIZE
** value. Reset it to the correct value for this process.
*/
pPager->sectorSize = PAGER_SECTOR_SIZE;
return rc;
}
/*
** Playback the statement journal.
**
** This is similar to playing back the transaction journal but with
** a few extra twists.
**
** (1) The number of pages in the database file at the start of
** the statement is stored in pPager->stmtSize, not in the
** journal file itself.
**
** (2) In addition to playing back the statement journal, also
** playback all pages of the transaction journal beginning
** at offset pPager->stmtJSize.
*/
static int pager_stmt_playback(Pager *pPager){
i64 szJ; /* Size of the full journal */
i64 hdrOff;
int nRec; /* Number of Records */
int i; /* Loop counter */
int rc;
szJ = pPager->journalOff;
#ifndef NDEBUG
{
i64 os_szJ;
rc = sqlite3OsFileSize(pPager->jfd, &os_szJ);
if( rc!=SQLITE_OK ) return rc;
assert( szJ==os_szJ );
}
#endif
/* Set hdrOff to be the offset to the first journal header written
** this statement transaction, or the end of the file if no journal
** header was written.
*/
hdrOff = pPager->stmtHdrOff;
assert( pPager->fullSync || !hdrOff );
if( !hdrOff ){
hdrOff = szJ;
}
/* Truncate the database back to its original size.
*/
if( pPager->state>=PAGER_EXCLUSIVE ){
rc = pager_truncate(pPager, pPager->stmtSize);
}
pPager->dbSize = pPager->stmtSize;
/* Figure out how many records are in the statement journal.
*/
assert( pPager->stmtInUse && pPager->journalOpen );
sqlite3OsSeek(pPager->stfd, 0);
nRec = pPager->stmtNRec;
/* Copy original pages out of the statement journal and back into the
** database file. Note that the statement journal omits checksums from
** each record since power-failure recovery is not important to statement
** journals.
*/
for(i=nRec-1; i>=0; i--){
rc = pager_playback_one_page(pPager, pPager->stfd, 0);
assert( rc!=SQLITE_DONE );
if( rc!=SQLITE_OK ) goto end_stmt_playback;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -