📄 pager.c
字号:
#ifdef SQLITE_HAS_CODEC void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ void *pCodecArg; /* First argument to xCodec() */#endif int nHash; /* Size of the pager hash table */ PgHdr **aHash; /* Hash table to map page number to PgHdr */#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Pager *pNext; /* Linked list of pagers in this thread */#endif char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ char dbFileVers[16]; /* Changes whenever database file changes */};/*** The following global variables hold counters used for** testing purposes only. These variables do not exist in** a non-testing build. These variables are not thread-safe.*/#ifdef SQLITE_TESTint sqlite3_pager_readdb_count = 0; /* Number of full pages read from DB */int sqlite3_pager_writedb_count = 0; /* Number of full pages written to DB */int sqlite3_pager_writej_count = 0; /* Number of pages written to journal */int sqlite3_pager_pgfree_count = 0; /* Number of cache pages freed */# define PAGER_INCR(v) v++#else# define PAGER_INCR(v)#endif/*** Journal files begin with the following magic string. The data** was obtained from /dev/random. It is used only as a sanity check.**** Since version 2.8.0, the journal format contains additional sanity** checking information. If the power fails while the journal is begin** written, semi-random garbage data might appear in the journal** file after power is restored. If an attempt is then made** to roll the journal back, the database could be corrupted. The additional** sanity checking data is an attempt to discover the garbage in the** journal and ignore it.**** The sanity checking information for the new journal format consists** of a 32-bit checksum on each page of data. The checksum covers both** the page number and the pPager->pageSize bytes of data for the page.** This cksum is initialized to a 32-bit random value that appears in the** journal file right after the header. The random initializer is important,** because garbage data that appears at the end of a journal is likely** data that was once in other files that have now been deleted. If the** garbage data came from an obsolete journal file, the checksums might** be correct. But by initializing the checksum to random value which** is different for every journal, we minimize that risk.*/static const unsigned char aJournalMagic[] = { 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd7,};/*** The size of the header and of each page in the journal is determined** by the following macros.*/#define JOURNAL_PG_SZ(pPager) ((pPager->pageSize) + 8)/*** The journal header size for this pager. In the future, this could be** set to some value read from the disk controller. The important** characteristic is that it is the same size as a disk sector.*/#define JOURNAL_HDR_SZ(pPager) (pPager->sectorSize)/*** The macro MEMDB is true if we are dealing with an in-memory database.** We do this as a macro so that if the SQLITE_OMIT_MEMORYDB macro is set,** the value of MEMDB will be a constant and the compiler will optimize** out code that would never execute.*/#ifdef SQLITE_OMIT_MEMORYDB# define MEMDB 0#else# define MEMDB pPager->memDb#endif/*** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is** reserved for working around a windows/posix incompatibility). It is** used in the journal to signify that the remainder of the journal file ** is devoted to storing a master journal name - there are no more pages to** roll back. See comments for function writeMasterJournal() for details.*//* #define PAGER_MJ_PGNO(x) (PENDING_BYTE/((x)->pageSize)) */#define PAGER_MJ_PGNO(x) ((PENDING_BYTE/((x)->pageSize))+1)/*** The maximum legal page number is (2^31 - 1).*/#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=%-3d total=%d\n", p->pgno, PGHDR_TO_DATA(p), p->nRef, p->pPager->nRef ); cnt++; /* Something to set a breakpoint on */ }# define REFINFO(X) pager_refinfo(X)#else# define REFINFO(X)#endif/*** Return true if page *pPg has already been written to the statement** journal (or statement snapshot has been created, if *pPg is part** of an in-memory database).*/static int pageInStatement(PgHdr *pPg){ Pager *pPager = pPg->pPager; if( MEMDB ){ return PGHDR_TO_HIST(pPg, pPager)->inStmt; }else{ Pgno pgno = pPg->pgno; u8 *a = pPager->aInStmt; return (a && (int)pgno<=pPager->stmtSize && (a[pgno/8] & (1<<(pgno&7)))); }}/*** Change the size of the pager hash table to N. N must be a power** of two.*/static void pager_resize_hash_table(Pager *pPager, int N){ PgHdr **aHash, *pPg; assert( N>0 && (N&(N-1))==0 ); aHash = sqliteMalloc( sizeof(aHash[0])*N ); if( aHash==0 ){ /* Failure to rehash is not an error. It is only a performance hit. */ return; } sqliteFree(pPager->aHash); pPager->nHash = N; pPager->aHash = aHash; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ int h; if( pPg->pgno==0 ){ assert( pPg->pNextHash==0 && pPg->pPrevHash==0 ); continue; } h = pPg->pgno & (N-1); pPg->pNextHash = aHash[h]; if( aHash[h] ){ aHash[h]->pPrevHash = pPg; } aHash[h] = pPg; pPg->pPrevHash = 0; }}/*** 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){ unsigned char ac[4]; int rc = sqlite3OsRead(fd, ac, sizeof(ac)); if( rc==SQLITE_OK ){ *pRes = sqlite3Get4byte(ac); } return rc;}/*** Write a 32-bit integer into a string buffer in big-endian byte order.*/#define put32bits(A,B) sqlite3Put4byte((u8*)A,B)/*** 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){ char ac[4]; put32bits(ac, val); return sqlite3OsWrite(fd, ac, 4);}/*** 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. All subsequent API calls on this Pager** will immediately return the same error code.*/static int pager_error(Pager *pPager, int rc){ int rc2 = rc & 0xff; assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK ); if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR || rc2==SQLITE_CORRUPT ){ pPager->errCode = rc; } 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 *)PGHDR_TO_DATA(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->dirty || pPg->pageHash==pager_pagehash(pPg) );}#else#define pager_datahash(X,Y) 0#define pager_pagehash(X) 0#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.**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -