📄 pager.c
字号:
u32 *pDbSize){ int rc; unsigned char aMagic[8]; /* A buffer to hold the magic header */ i64 jrnlOff; int iPageSize; seekJournalHdr(pPager); if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){ return SQLITE_DONE; } jrnlOff = pPager->journalOff; rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic), jrnlOff); if( rc ) return rc; jrnlOff += sizeof(aMagic); if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){ return SQLITE_DONE; } rc = read32bits(pPager->jfd, jrnlOff, pNRec); if( rc ) return rc; rc = read32bits(pPager->jfd, jrnlOff+4, &pPager->cksumInit); if( rc ) return rc; rc = read32bits(pPager->jfd, jrnlOff+8, pDbSize); if( rc ) return rc; rc = read32bits(pPager->jfd, jrnlOff+16, (u32 *)&iPageSize); if( rc==SQLITE_OK && iPageSize>=512 && iPageSize<=SQLITE_MAX_PAGE_SIZE && ((iPageSize-1)&iPageSize)==0 ){ u16 pagesize = iPageSize; rc = sqlite3PagerSetPagesize(pPager, &pagesize); } if( rc ) return rc; /* Update the assumed sector-size to match the value used by ** the process that created this journal. If this journal was ** created by a process other than this one, then this routine ** is being called from within pager_playback(). The local value ** of Pager.sectorSize is restored at the end of that routine. */ rc = read32bits(pPager->jfd, jrnlOff+12, (u32 *)&pPager->sectorSize); if( rc ) return rc; pPager->journalOff += JOURNAL_HDR_SZ(pPager); return SQLITE_OK;}/*** Write the supplied master journal name into the journal file for pager** pPager at the current location. The master journal name must be the last** thing written to a journal file. If the pager is in full-sync mode, the** journal file descriptor is advanced to the next sector boundary before** anything is written. The format is:**** + 4 bytes: PAGER_MJ_PGNO.** + N bytes: length of master journal name.** + 4 bytes: N** + 4 bytes: Master journal name checksum.** + 8 bytes: aJournalMagic[].**** The master journal page checksum is the sum of the bytes in the master** journal name.**** If zMaster is a NULL pointer (occurs for a single database transaction), ** this call is a no-op.*/static int writeMasterJournal(Pager *pPager, const char *zMaster){ int rc; int len; int i; i64 jrnlOff; i64 jrnlSize; u32 cksum = 0; char zBuf[sizeof(aJournalMagic)+2*4]; if( !zMaster || pPager->setMaster) return SQLITE_OK; pPager->setMaster = 1; len = strlen(zMaster); for(i=0; i<len; i++){ cksum += zMaster[i]; } /* 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 ){ seekJournalHdr(pPager); } jrnlOff = pPager->journalOff; pPager->journalOff += (len+20); rc = write32bits(pPager->jfd, jrnlOff, PAGER_MJ_PGNO(pPager)); if( rc!=SQLITE_OK ) return rc; jrnlOff += 4; rc = sqlite3OsWrite(pPager->jfd, zMaster, len, jrnlOff); if( rc!=SQLITE_OK ) return rc; jrnlOff += len; put32bits(zBuf, len); put32bits(&zBuf[4], cksum); memcpy(&zBuf[8], aJournalMagic, sizeof(aJournalMagic)); rc = sqlite3OsWrite(pPager->jfd, zBuf, 8+sizeof(aJournalMagic), jrnlOff); jrnlOff += 8+sizeof(aJournalMagic); 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( (rc==SQLITE_OK) && (rc = sqlite3OsFileSize(pPager->jfd, &jrnlSize))==SQLITE_OK && jrnlSize>jrnlOff ){ rc = sqlite3OsTruncate(pPager->jfd, jrnlOff); } return rc;}/*** Find a page in the hash table given its page number. Return** a pointer to the page or NULL if not found.*/static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){ PgHdr *p; sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &p); return p;}/*** Clear the in-memory cache. This routine** sets the state of the pager back to what it was when it was first** opened. Any outstanding pages are invalidated and subsequent attempts** to access those pages will likely result in a coredump.*/static void pager_reset(Pager *pPager){ if( pPager->errCode ) return; sqlite3PcacheClear(pPager->pPCache);}/*** Unlock the database file. **** 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 ){ if( !MEMDB ){ int rc = osUnlock(pPager->fd, NO_LOCK); if( rc ) pPager->errCode = rc; pPager->dbSize = -1; IOTRACE(("UNLOCK %p\n", pPager)) /* 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. */ if( pPager->journalOpen ){ sqlite3OsClose(pPager->jfd); pPager->journalOpen = 0; sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; sqlite3BitvecDestroy(pPager->pAlwaysRollback); pPager->pAlwaysRollback = 0; } /* 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); if( pPager->stmtOpen ){ sqlite3OsClose(pPager->stfd); sqlite3BitvecDestroy(pPager->pInStmt); pPager->pInStmt = 0; } pPager->stmtOpen = 0; pPager->stmtInUse = 0; pPager->journalOff = 0; pPager->journalStarted = 0; pPager->stmtAutoopen = 0; pPager->origDbSize = 0; } } if( !MEMDB || pPager->errCode==SQLITE_OK ){ pPager->state = PAGER_UNLOCK; pPager->changeCountDone = 0; } }}/*** 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.*/static void pagerUnlockAndRollback(Pager *p){ if( p->errCode==SQLITE_OK && p->state>=PAGER_RESERVED ){ sqlite3BeginBenignMalloc(); sqlite3PagerRollback(p); sqlite3EndBenignMalloc(); } pager_unlock(p);}/*** This routine ends a transaction. A transaction is ended by either** a COMMIT or a ROLLBACK.**** When this routine is called, the pager has the journal file open and** a RESERVED or EXCLUSIVE lock on the database. This routine will release** the database lock and acquires a SHARED lock in its place if that is** the appropriate thing to do. Release locks usually is appropriate,** unless we are in exclusive access mode or unless this is a ** COMMIT AND BEGIN or ROLLBACK AND BEGIN operation.**** The journal file is either deleted or truncated.**** TODO: Consider keeping the journal file open for temporary databases.** This might give a performance improvement on windows where opening** a file is an expensive operation.*/static int pager_end_transaction(Pager *pPager, int hasMaster){ int rc = SQLITE_OK; int rc2 = SQLITE_OK; assert( !MEMDB ); if( pPager->state<PAGER_RESERVED ){ return SQLITE_OK; } sqlite3PagerStmtCommit(pPager); if( pPager->stmtOpen && !pPager->exclusiveMode ){ sqlite3OsClose(pPager->stfd); pPager->stmtOpen = 0; } if( pPager->journalOpen ){ if( pPager->exclusiveMode || pPager->journalMode==PAGER_JOURNALMODE_PERSIST ){ rc = zeroJournalHdr(pPager, hasMaster); pager_error(pPager, rc); pPager->journalOff = 0; pPager->journalStarted = 0; }else{ sqlite3OsClose(pPager->jfd); pPager->journalOpen = 0; if( rc==SQLITE_OK && !pPager->tempFile ){ rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); } } sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; sqlite3BitvecDestroy(pPager->pAlwaysRollback); pPager->pAlwaysRollback = 0; sqlite3PcacheCleanAll(pPager->pPCache);#ifdef SQLITE_CHECK_PAGES sqlite3PcacheIterate(pPager->pPCache, pager_set_pagehash);#endif sqlite3PcacheSetFlags(pPager->pPCache, ~(PGHDR_IN_JOURNAL | PGHDR_NEED_SYNC), 0 ); pPager->dirtyCache = 0; pPager->nRec = 0; }else{ assert( pPager->pInJournal==0 ); } if( !pPager->exclusiveMode ){ rc2 = osUnlock(pPager->fd, SHARED_LOCK); pPager->state = PAGER_SHARED; }else if( pPager->state==PAGER_SYNCED ){ pPager->state = PAGER_EXCLUSIVE; } pPager->origDbSize = 0; pPager->setMaster = 0; pPager->needSync = 0; /* lruListSetFirstSynced(pPager); */ pPager->dbSize = -1; pPager->dbModified = 0; return (rc==SQLITE_OK?rc2:rc);}/*** Compute and return a checksum for the page of data.**** This is not a real checksum. It is really just the sum of the ** random initial value and the page number. We experimented with** a checksum of the entire data, but that was found to be too slow.**** Note that the page number is stored at the beginning of data and** the checksum is stored at the end. This is important. If journal** corruption occurs due to a power failure, the most likely scenario** is that one end or the other of the record will be changed. It is** much less likely that the two ends of the journal record will be** correct and the middle be corrupt. Thus, this "checksum" scheme,** though fast and simple, catches the mostly likely kind of corruption.**** FIX ME: Consider adding every 200th (or so) byte of the data to the** checksum. That way if a single page spans 3 or more disk sectors and** only the middle sector is corrupt, we will still have a reasonable** chance of failing the checksum and thus detecting the problem.*/static u32 pager_cksum(Pager *pPager, const u8 *aData){ u32 cksum = pPager->cksumInit; int i = pPager->pageSize-200; while( i>0 ){ cksum += aData[i]; i -= 200; } return cksum;}/* Forward declaration */static void makeClean(PgHdr*);/*** Read a single page from the journal file opened on file descriptor** jfd. Playback this one page.**** The isMainJrnl flag is true if this is the main rollback journal and** false for the statement journal. The main rollback journal uses** checksums - the statement journal does not.*/static int pager_playback_one_page( Pager *pPager, /* The pager being played back */ sqlite3_file *jfd, /* The file that is the journal being rolled back */ i64 offset, /* Offset of the page within the journal */ int isMainJrnl /* True for main rollback journal. False for Stmt jrnl */){ int rc; PgHdr *pPg; /* An existing page in the cache */ Pgno pgno; /* The page number of a page in journal */ u32 cksum; /* Checksum used for sanity checking */ u8 *aData = (u8 *)pPager->pTmpSpace; /* Temp storage for a page */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -