📄 pager.c
字号:
** rollback the full ROLLBACK will not restore the page to its original ** content. Two conditions must be met before writing to the database ** files. (1) the database must be locked. (2) we know that the original ** page content is in the main journal either because the page is not in ** cache or else it is marked as needSync==0. */ pPg = pager_lookup(pPager, pgno); assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 ); PAGERTRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno); if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){ rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize); if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize); } if( pPg ){ makeClean(pPg); } } if( pPg ){ /* No page should ever be explicitly rolled back that is in use, except ** for page 1 which is held in use in order to keep the lock on the ** database active. However such a page may be rolled back as a result ** of an internal error resulting in an automatic call to ** sqlite3PagerRollback(). */ void *pData; /* assert( pPg->nRef==0 || pPg->pgno==1 ); */ pData = PGHDR_TO_DATA(pPg); memcpy(pData, aData, pPager->pageSize); if( pPager->xReiniter ){ pPager->xReiniter(pPg, pPager->pageSize); }#ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg);#endif /* If this was page 1, then restore the value of Pager.dbFileVers. ** Do this before any decoding. */ if( pgno==1 ){ memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); } /* Decode the page just read from disk */ CODEC1(pPager, pData, pPg->pgno, 3); } return rc;}/*** Parameter zMaster is the name of a master journal file. A single journal** file that referred to the master journal file has just been rolled back.** This routine checks if it is possible to delete the master journal file,** and does so if it is.**** The master journal file contains the names of all child journals.** To tell if a master journal can be deleted, check to each of the** children. If all children are either missing or do not refer to** a different master journal, then this master journal can be deleted.*/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); assert( rc!=SQLITE_OK || 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); assert( rc!=SQLITE_OK || 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); } } rc = sqlite3OsDelete(zMaster);delmaster_out: if( zMasterJournal ){ sqliteFree(zMasterJournal); } if( master_open ){ sqlite3OsClose(&master); } return rc;}static void pager_truncate_cache(Pager *pPager);/*** Truncate the main file of the given pager to the number of pages** indicated. Also truncate the cached representation of the file.*/static int pager_truncate(Pager *pPager, int nPage){ int rc = SQLITE_OK; if( pPager->state>=PAGER_EXCLUSIVE ){ rc = sqlite3OsTruncate(pPager->fd, pPager->pageSize*(i64)nPage); } if( rc==SQLITE_OK ){ pPager->dbSize = nPage; pager_truncate_cache(pPager); } return rc;}/*** 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, int isHot){ 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 || szJ==0 ){ 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 nRec is 0 and this rollback is of a transaction created by this ** process. In this case the rest of the journal file consists of ** journalled copies of pages that need to be read back into the cache. */ if( nRec==0 && !isHot ){ nRec = (szJ - pPager->journalOff) / 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->journalOff==JOURNAL_HDR_SZ(pPager) ){ rc = pager_truncate(pPager, mxPg); if( rc!=SQLITE_OK ){ goto end_playback; } } /* 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_end_transaction(pPager); } if( zMaster ){ /* If there was a master journal and this routine will return success, ** 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 sector size ** value. Reset it to the correct value for this process. */ pPager->sectorSize = sqlite3OsSectorSize(pPager->fd); 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 just after the end of the last journal ** page written before the first journal-header for this statement ** transaction was written, or the end of the file if no journal ** header was written. */ hdrOff = pPager->stmtHdrOff; assert( pPager->fullSync || !hdrOff ); if( !hdrOff ){ hdrOff = szJ; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -