📄 pager.c
字号:
#define PAGER_MAX_PGNO 2147483647/*** Enable reference count tracking (for debugging) here:*/#ifdef SQLITE_DEBUG int pager3_refinfo_enable = 0; static void pager_refinfo(PgHdr *p){ static int cnt = 0; if( !pager3_refinfo_enable ) return; sqlite3DebugPrintf( "REFCNT: %4d addr=%p nRef=%d\n", p->pgno, PGHDR_TO_DATA(p), p->nRef ); cnt++; /* Something to set a breakpoint on */ }# define REFINFO(X) pager_refinfo(X)#else# define REFINFO(X)#endif/*** Read a 32-bit integer from the given file descriptor. Store the integer** that is read in *pRes. Return SQLITE_OK if everything worked, or an** error code is something goes wrong.**** All values are stored on disk as big-endian.*/static int read32bits(OsFile *fd, u32 *pRes){ u32 res; int rc; rc = sqlite3OsRead(fd, &res, sizeof(res)); if( rc==SQLITE_OK ){ unsigned char ac[4]; memcpy(ac, &res, 4); res = (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3]; } *pRes = res; return rc;}/*** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK** on success or an error code is something goes wrong.*/static int write32bits(OsFile *fd, u32 val){ unsigned char ac[4]; ac[0] = (val>>24) & 0xff; ac[1] = (val>>16) & 0xff; ac[2] = (val>>8) & 0xff; ac[3] = val & 0xff; return sqlite3OsWrite(fd, ac, 4);}/*** Write the 32-bit integer 'val' into the page identified by page header** 'p' at offset 'offset'.*/static void store32bits(u32 val, PgHdr *p, int offset){ unsigned char *ac; ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset]; ac[0] = (val>>24) & 0xff; ac[1] = (val>>16) & 0xff; ac[2] = (val>>8) & 0xff; ac[3] = val & 0xff;}/*** Read a 32-bit integer at offset 'offset' from the page identified by** page header 'p'.*/static u32 retrieve32bits(PgHdr *p, int offset){ unsigned char *ac; ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset]; return (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3];}/*** Convert the bits in the pPager->errMask into an approprate** return code.*/static int pager_errcode(Pager *pPager){ int rc = SQLITE_OK; if( pPager->errMask & PAGER_ERR_LOCK ) rc = SQLITE_PROTOCOL; if( pPager->errMask & PAGER_ERR_DISK ) rc = SQLITE_IOERR; if( pPager->errMask & PAGER_ERR_FULL ) rc = SQLITE_FULL; if( pPager->errMask & PAGER_ERR_MEM ) rc = SQLITE_NOMEM; if( pPager->errMask & PAGER_ERR_CORRUPT ) rc = SQLITE_CORRUPT; return rc;}#ifdef SQLITE_CHECK_PAGES/*** Return a 32-bit hash of the page data for pPage.*/static u32 pager_pagehash(PgHdr *pPage){ u32 hash = 0; int i; unsigned char *pData = (unsigned char *)PGHDR_TO_DATA(pPage); for(i=0; i<pPage->pPager->pageSize; i++){ hash = (hash+i)^pData[i]; } return hash;}/*** 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->errMask || MEMDB || pPg->dirty || pPg->pageHash==pager_pagehash(pPg) );}#else#define CHECK_PAGE(x)#endif/*** 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 obtained from sqliteMalloc(). *pzMaster is** set to point at the memory and SQLITE_OK returned. The caller must** sqliteFree() *pzMaster.**** If no master journal file name is present *pzMaster is set to 0 and** SQLITE_OK returned.*/static int readMasterJournal(OsFile *pJrnl, char **pzMaster){ int rc; u32 len; i64 szJ; u32 cksum; int i; unsigned char aMagic[8]; /* A buffer to hold the magic header */ *pzMaster = 0; rc = sqlite3OsFileSize(pJrnl, &szJ); if( rc!=SQLITE_OK || szJ<16 ) return rc; rc = sqlite3OsSeek(pJrnl, szJ-16); if( rc!=SQLITE_OK ) return rc; rc = read32bits(pJrnl, &len); if( rc!=SQLITE_OK ) return rc; rc = read32bits(pJrnl, &cksum); if( rc!=SQLITE_OK ) return rc; rc = sqlite3OsRead(pJrnl, aMagic, 8); if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, 8) ) return rc; rc = sqlite3OsSeek(pJrnl, szJ-16-len); if( rc!=SQLITE_OK ) return rc; *pzMaster = (char *)sqliteMalloc(len+1); if( !*pzMaster ){ return SQLITE_NOMEM; } rc = sqlite3OsRead(pJrnl, *pzMaster, len); if( rc!=SQLITE_OK ){ sqliteFree(*pzMaster); *pzMaster = 0; return rc; } /* See if the checksum matches the master journal name */ for(i=0; i<len; i++){ cksum -= (*pzMaster)[i]; } 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. */ sqliteFree(*pzMaster); *pzMaster = 0; }else{ (*pzMaster)[len] = '\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 int 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; return sqlite3OsSeek(&pPager->jfd, pPager->journalOff);}/*** 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.** ** Followed by (JOURNAL_HDR_SZ - 24) bytes of unused space.*/static int writeJournalHdr(Pager *pPager){ int rc = seekJournalHdr(pPager); if( rc ) return rc; pPager->journalHdr = pPager->journalOff; if( pPager->stmtHdrOff==0 ){ pPager->stmtHdrOff = pPager->journalHdr; } pPager->journalOff += JOURNAL_HDR_SZ(pPager); /* FIX ME: ** ** Possibly for a pager not in no-sync mode, the journal magic should not ** be written until nRec is filled in as part of next syncJournal(). ** ** Actually maybe the whole journal header should be delayed until that ** point. Think about this. */ rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic)); if( rc==SQLITE_OK ){ /* The nRec Field. 0xFFFFFFFF for no-sync journals. */ rc = write32bits(&pPager->jfd, pPager->noSync ? 0xffffffff : 0); } if( rc==SQLITE_OK ){ /* The random check-hash initialiser */ sqlite3Randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); rc = write32bits(&pPager->jfd, pPager->cksumInit); } if( rc==SQLITE_OK ){ /* The initial database size */ rc = write32bits(&pPager->jfd, pPager->dbSize); } if( rc==SQLITE_OK ){ /* The assumed sector size for this process */ rc = write32bits(&pPager->jfd, pPager->sectorSize); } /* The journal header has been written successfully. Seek the journal ** file descriptor to the end of the journal header sector. */ if( rc==SQLITE_OK ){ sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1); rc = sqlite3OsWrite(&pPager->jfd, "\000", 1); } 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, u32 *pDbSize){ int rc; unsigned char aMagic[8]; /* A buffer to hold the magic header */ rc = seekJournalHdr(pPager); if( rc ) return rc; if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){ return SQLITE_DONE; } rc = sqlite3OsRead(&pPager->jfd, aMagic, sizeof(aMagic)); if( rc ) return rc; if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){ return SQLITE_DONE; } rc = read32bits(&pPager->jfd, pNRec); if( rc ) return rc; rc = read32bits(&pPager->jfd, &pPager->cksumInit); if( rc ) return rc; rc = read32bits(&pPager->jfd, pDbSize); 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, (u32 *)&pPager->sectorSize); if( rc ) return rc; pPager->journalOff += JOURNAL_HDR_SZ(pPager); rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff); return rc;}/*** 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.*/static int writeMasterJournal(Pager *pPager, const char *zMaster){ int rc; int len; int i; u32 cksum = 0; 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 ){ rc = seekJournalHdr(pPager); if( rc!=SQLITE_OK ) return rc; } pPager->journalOff += (len+20);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -