📄 pager.c
字号:
}/*** This function determines whether or not the atomic-write optimization** can be used with this pager. The optimization can be used if:**** (a) the value returned by OsDeviceCharacteristics() indicates that** a database page may be written atomically, and** (b) the value returned by OsSectorSize() is less than or equal** to the page size.**** If the optimization cannot be used, 0 is returned. If it can be used,** then the value returned is the size of the journal file when it** contains rollback data for exactly one page.*/#ifdef SQLITE_ENABLE_ATOMIC_WRITEstatic int jrnlBufferSize(Pager *pPager){ int dc; /* Device characteristics */ int nSector; /* Sector size */ int szPage; /* Page size */ sqlite3_file *fd = pPager->fd; if( fd->pMethods ){ dc = sqlite3OsDeviceCharacteristics(fd); nSector = sqlite3OsSectorSize(fd); szPage = pPager->pageSize; } assert(SQLITE_IOCAP_ATOMIC512==(512>>8)); assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8)); if( !fd->pMethods || (dc & (SQLITE_IOCAP_ATOMIC|(szPage>>8)) && nSector<=szPage) ){ return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager); } return 0;}#endif/*** This function should be called when an error occurs within the pager** code. 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.*/static void pager_unlock(Pager *pPager);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;}/*** If SQLITE_CHECK_PAGES is defined then we do some sanity checking** on the cache using a hash function. This is used for testing** and debugging only.*/#ifdef SQLITE_CHECK_PAGES/*** Return a 32-bit hash of the page data for pPage.*/static u32 pager_datahash(int nByte, unsigned char *pData){ u32 hash = 0; int i; for(i=0; i<nByte; i++){ hash = (hash*1039) + pData[i]; } return hash;}static u32 pager_pagehash(PgHdr *pPage){ return pager_datahash(pPage->pPager->pageSize, (unsigned char *)pPage->pData);}static u32 pager_set_pagehash(PgHdr *pPage){ pPage->pageHash = pager_pagehash(pPage);}/*** The CHECK_PAGE macro takes a PgHdr* as an argument. If SQLITE_CHECK_PAGES** is defined, and NDEBUG is not defined, an assert() statement checks** that the page is either dirty or still matches the calculated page-hash.*/#define CHECK_PAGE(x) checkPage(x)static void checkPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; assert( !pPg->pageHash || pPager->errCode || MEMDB || (pPg->flags&PGHDR_DIRTY) || pPg->pageHash==pager_pagehash(pPg) );}#else#define pager_datahash(X,Y) 0#define pager_pagehash(X) 0#define CHECK_PAGE(x)#endif /* SQLITE_CHECK_PAGES *//*** When this is called the journal file for pager pPager must be open.** The master journal file name is read from the end of the file and ** written into memory supplied by the caller. **** zMaster must point to a buffer of at least nMaster bytes allocated by** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is** enough space to write the master journal name). If the master journal** name in the journal is longer than nMaster bytes (including a** nul-terminator), then this is handled as if no master journal name** were present in the journal.**** If no master journal file name is present zMaster[0] is set to 0 and** SQLITE_OK returned.*/static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, int nMaster){ int rc; u32 len; i64 szJ; u32 cksum; u32 u; /* Unsigned loop counter */ unsigned char aMagic[8]; /* A buffer to hold the magic header */ zMaster[0] = '\0'; rc = sqlite3OsFileSize(pJrnl, &szJ); if( rc!=SQLITE_OK || szJ<16 ) return rc; rc = read32bits(pJrnl, szJ-16, &len); if( rc!=SQLITE_OK ) return rc; if( len>=nMaster ){ return SQLITE_OK; } rc = read32bits(pJrnl, szJ-12, &cksum); if( rc!=SQLITE_OK ) return rc; rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8); if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, 8) ) return rc; rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len); if( rc!=SQLITE_OK ){ return rc; } zMaster[len] = '\0'; /* See if the checksum matches the master journal name */ for(u=0; u<len; u++){ cksum -= zMaster[u]; } if( cksum ){ /* If the checksum doesn't add up, then one or more of the disk sectors ** containing the master journal filename is corrupted. This means ** definitely roll back, so just return SQLITE_OK and report a (nul) ** master-journal filename. */ zMaster[0] = '\0'; } return SQLITE_OK;}/*** Seek the journal file descriptor to the next sector boundary where a** journal header may be read or written. Pager.journalOff is updated with** the new seek offset.**** i.e for a sector size of 512:**** Input Offset Output Offset** ---------------------------------------** 0 0** 512 512** 100 512** 2000 2048** */static void seekJournalHdr(Pager *pPager){ i64 offset = 0; i64 c = pPager->journalOff; if( c ){ offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager); } assert( offset%JOURNAL_HDR_SZ(pPager)==0 ); assert( offset>=c ); assert( (offset-c)<JOURNAL_HDR_SZ(pPager) ); pPager->journalOff = offset;}/*** Write zeros over the header of the journal file. This has the** effect of invalidating the journal file and committing the** transaction.*/static int zeroJournalHdr(Pager *pPager, int doTruncate){ int rc = SQLITE_OK; static const char zeroHdr[28]; if( pPager->journalOff ){ i64 iLimit = pPager->journalSizeLimit; IOTRACE(("JZEROHDR %p\n", pPager)) if( doTruncate || iLimit==0 ){ rc = sqlite3OsTruncate(pPager->jfd, 0); }else{ rc = sqlite3OsWrite(pPager->jfd, zeroHdr, sizeof(zeroHdr), 0); } if( rc==SQLITE_OK && !pPager->noSync ){ rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_DATAONLY|pPager->sync_flags); } /* At this point the transaction is committed but the write lock ** is still held on the file. If there is a size limit configured for ** the persistent journal and the journal file currently consumes more ** space than that limit allows for, truncate it now. There is no need ** to sync the file following this operation. */ if( rc==SQLITE_OK && iLimit>0 ){ i64 sz; rc = sqlite3OsFileSize(pPager->jfd, &sz); if( rc==SQLITE_OK && sz>iLimit ){ rc = sqlite3OsTruncate(pPager->jfd, iLimit); } } } return rc;}/*** The journal file must be open when this routine is called. A journal** header (JOURNAL_HDR_SZ bytes) is written into the journal file at the** current location.**** The format for the journal header is as follows:** - 8 bytes: Magic identifying journal format.** - 4 bytes: Number of records in journal, or -1 no-sync mode is on.** - 4 bytes: Random number used for page hash.** - 4 bytes: Initial database page count.** - 4 bytes: Sector size used by the process that wrote this journal.** - 4 bytes: Database page size.** ** Followed by (JOURNAL_HDR_SZ - 28) bytes of unused space.*/static int writeJournalHdr(Pager *pPager){ int rc = SQLITE_OK; char *zHeader = pPager->pTmpSpace; int nHeader = pPager->pageSize; int nWrite; if( nHeader>JOURNAL_HDR_SZ(pPager) ){ nHeader = JOURNAL_HDR_SZ(pPager); } if( pPager->stmtHdrOff==0 ){ pPager->stmtHdrOff = pPager->journalOff; } seekJournalHdr(pPager); pPager->journalHdr = pPager->journalOff; memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); /* ** Write the nRec Field - the number of page records that follow this ** journal header. Normally, zero is written to this value at this time. ** After the records are added to the journal (and the journal synced, ** if in full-sync mode), the zero is overwritten with the true number ** of records (see syncJournal()). ** ** A faster alternative is to write 0xFFFFFFFF to the nRec field. When ** reading the journal this value tells SQLite to assume that the ** rest of the journal file contains valid page records. This assumption ** is dangerous, as if a failure occured whilst writing to the journal ** file it may contain some garbage data. There are two scenarios ** where this risk can be ignored: ** ** * When the pager is in no-sync mode. Corruption can follow a ** power failure in this case anyway. ** ** * When the SQLITE_IOCAP_SAFE_APPEND flag is set. This guarantees ** that garbage data is never appended to the journal file. */ assert(pPager->fd->pMethods||pPager->noSync); if( (pPager->noSync) || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND) ){ put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff); }else{ put32bits(&zHeader[sizeof(aJournalMagic)], 0); } /* The random check-hash initialiser */ sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit); /* The initial database size */ put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbSize); /* The assumed sector size for this process */ put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize); if( pPager->journalHdr==0 ){ /* The page size */ put32bits(&zHeader[sizeof(aJournalMagic)+16], pPager->pageSize); } for(nWrite=0; rc==SQLITE_OK&&nWrite<JOURNAL_HDR_SZ(pPager); nWrite+=nHeader){ IOTRACE(("JHDR %p %lld %d\n", pPager, pPager->journalHdr, nHeader)) rc = sqlite3OsWrite(pPager->jfd, zHeader, nHeader, pPager->journalOff); pPager->journalOff += nHeader; } return rc;}/*** The journal file must be open when this is called. A journal header file** (JOURNAL_HDR_SZ bytes) is read from the current location in the journal** file. See comments above function writeJournalHdr() for a description of** the journal header format.**** If the header is read successfully, *nRec is set to the number of** page records following this header and *dbSize is set to the size of the** database before the transaction began, in pages. Also, pPager->cksumInit** is set to the value read from the journal header. SQLITE_OK is returned** in this case.**** If the journal header file appears to be corrupted, SQLITE_DONE is** returned and *nRec and *dbSize are not set. If JOURNAL_HDR_SZ bytes** cannot be read from the journal file an error code is returned.*/static int readJournalHdr( Pager *pPager, i64 journalSize, u32 *pNRec,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -