📄 pager.c
字号:
/* isMainJrnl should be true for the main journal and false for ** statement journals. Verify that this is always the case */ assert( jfd == (isMainJrnl ? pPager->jfd : pPager->stfd) ); assert( aData ); rc = read32bits(jfd, offset, &pgno); if( rc!=SQLITE_OK ) return rc; rc = sqlite3OsRead(jfd, aData, pPager->pageSize, offset+4); if( rc!=SQLITE_OK ) return rc; pPager->journalOff += pPager->pageSize + 4; /* Sanity checking on the page. This is more important that I originally ** thought. If a power failure occurs while the journal is being written, ** it could cause invalid data to be written into the journal. We need to ** detect this invalid data (with high probability) and ignore it. */ if( pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){ return SQLITE_DONE; } if( pgno>(unsigned)pPager->dbSize ){ return SQLITE_OK; } if( isMainJrnl ){ rc = read32bits(jfd, offset+pPager->pageSize+4, &cksum); if( rc ) return rc; pPager->journalOff += 4; if( pager_cksum(pPager, aData)!=cksum ){ return SQLITE_DONE; } } assert( pPager->state==PAGER_RESERVED || pPager->state>=PAGER_EXCLUSIVE ); /* If the pager is in RESERVED state, then there must be a copy of this ** page in the pager cache. In this case just update the pager cache, ** not the database file. The page is left marked dirty in this case. ** ** An exception to the above rule: If the database is in no-sync mode ** and a page is moved during an incremental vacuum then the page may ** not be in the pager cache. Later: if a malloc() or IO error occurs ** during a Movepage() call, then the page may not be in the cache ** either. So the condition described in the above paragraph is not ** assert()able. ** ** If in EXCLUSIVE state, then we update the pager cache if it exists ** and the main file. The page is then marked not dirty. ** ** Ticket #1171: The statement journal might contain page content that is ** different from the page content at the start of the transaction. ** This occurs when a page is changed prior to the start of a statement ** then changed again within the statement. When rolling back such a ** statement we must not write to the original database unless we know ** for certain that original page contents are synced into the main rollback ** journal. Otherwise, a power loss might leave modified data in the ** database file without an entry in the rollback journal that can ** restore the database to its original form. 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 fully synced ** in the main journal either because the page is not in cache or else ** the page is marked as needSync==0. ** ** 2008-04-14: When attempting to vacuum a corrupt database file, it ** is possible to fail a statement on a database that does not yet exist. ** Do not attempt to write if database file has never been opened. */ pPg = pager_lookup(pPager, pgno); PAGERTRACE4("PLAYBACK %d page %d hash(%08x)\n", PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, aData)); if( (pPager->state>=PAGER_EXCLUSIVE) && (pPg==0 || 0==(pPg->flags&PGHDR_NEED_SYNC)) && (pPager->fd->pMethods) ){ i64 ofst = (pgno-1)*(i64)pPager->pageSize; rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize, ofst); } 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; pData = pPg->pData; memcpy(pData, aData, pPager->pageSize); if( pPager->xReiniter ){ pPager->xReiniter(pPg, pPager->pageSize); } if( isMainJrnl ) makeClean(pPg);#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); sqlite3PcacheRelease(pPg); } 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.**** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not ** available for use within this function.****** 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(Pager *pPager, const char *zMaster){ sqlite3_vfs *pVfs = pPager->pVfs; int rc; int master_open = 0; sqlite3_file *pMaster; sqlite3_file *pJournal; 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. */ pMaster = (sqlite3_file *)sqlite3Malloc(pVfs->szOsFile * 2); pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile); if( !pMaster ){ rc = SQLITE_NOMEM; }else{ int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL); rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0); } if( rc!=SQLITE_OK ) goto delmaster_out; master_open = 1; rc = sqlite3OsFileSize(pMaster, &nMasterJournal); if( rc!=SQLITE_OK ) goto delmaster_out; if( nMasterJournal>0 ){ char *zJournal; char *zMasterPtr = 0; int nMasterPtr = pPager->pVfs->mxPathname+1; /* Load the entire master journal file into space obtained from ** sqlite3_malloc() and pointed to by zMasterJournal. */ zMasterJournal = (char *)sqlite3Malloc(nMasterJournal + nMasterPtr); if( !zMasterJournal ){ rc = SQLITE_NOMEM; goto delmaster_out; } zMasterPtr = &zMasterJournal[nMasterJournal]; rc = sqlite3OsRead(pMaster, zMasterJournal, nMasterJournal, 0); if( rc!=SQLITE_OK ) goto delmaster_out; zJournal = zMasterJournal; while( (zJournal-zMasterJournal)<nMasterJournal ){ int exists; rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists); if( rc!=SQLITE_OK ){ goto delmaster_out; } if( exists ){ /* 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. */ int c; int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL); rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0); if( rc!=SQLITE_OK ){ goto delmaster_out; } rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr); sqlite3OsClose(pJournal); if( rc!=SQLITE_OK ){ goto delmaster_out; } c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0; if( c ){ /* We have a match. Do not delete the master journal file. */ goto delmaster_out; } } zJournal += (strlen(zJournal)+1); } } rc = sqlite3OsDelete(pVfs, zMaster, 0);delmaster_out: if( zMasterJournal ){ sqlite3_free(zMasterJournal); } if( master_open ){ sqlite3OsClose(pMaster); } sqlite3_free(pMaster); 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.**** Might might be the case that the file on disk is smaller than nPage.** This can happen, for example, if we are in the middle of a transaction** which has extended the file size and the new pages are still all held** in cache, then an INSERT or UPDATE does a statement rollback. Some** operating system implementations can get confused if you try to** truncate a file to some size that is larger than it currently is,** so detect this case and write a single zero byte to the end of the new** file instead.*/static int pager_truncate(Pager *pPager, int nPage){ int rc = SQLITE_OK; if( pPager->state>=PAGER_EXCLUSIVE && pPager->fd->pMethods ){ i64 currentSize, newSize; rc = sqlite3OsFileSize(pPager->fd, ¤tSize); newSize = pPager->pageSize*(i64)nPage; if( rc==SQLITE_OK && currentSize!=newSize ){ if( currentSize>newSize ){ rc = sqlite3OsTruncate(pPager->fd, newSize); }else{ rc = sqlite3OsWrite(pPager->fd, "", 1, newSize-1); } } } if( rc==SQLITE_OK ){ pPager->dbSize = nPage; pager_truncate_cache(pPager); } return rc;}/*** Set the sectorSize for the given pager.**** The sector size is at least as big as the sector size reported** by sqlite3OsSectorSize(). The minimum sector size is 512.*/static void setSectorSize(Pager *pPager){ assert(pPager->fd->pMethods||pPager->tempFile); if( !pPager->tempFile ){ /* Sector size doesn't matter for temporary files. Also, the file ** may not have been opened yet, in whcih case the OsSectorSize() ** call will segfault. */ pPager->sectorSize = sqlite3OsSectorSize(pPager->fd); } if( pPager->sectorSize<512 ){ pPager->sectorSize = 512; }}/*** 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 big-endian integer which is the sector size. The header** is this many bytes in size.** (6) 4 byte big-endian integer which is the page case.** (7) 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.)** (8) 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.** (9) 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 8 items above.** Each entry in the journal is an instance of the 9th 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){ sqlite3_vfs *pVfs = pPager->pVfs; i64 szJ; /* Size of the journal file in bytes */ u32 nRec; /* Number of Records in the journal */ u32 u; /* Unsigned loop counter */ Pgno mxPg = 0; /* Size of the original file in pages */ int rc; /* Result code of a subroutine */ int res = 1; /* Value returned by sqlite3OsAccess() */ 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. */ zMaster = pPager->pTmpSpace; rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1); if( rc==SQLITE_OK && zMaster[0] ){ rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res); } zMaster = 0; if( rc!=SQLITE_OK || !res ){ goto end_playback; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -