pager.c

来自「sqlite最新源码」· C语言 代码 · 共 1,620 行 · 第 1/5 页

C
1,620
字号
/*** 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 being** 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 of each page record in the journal is given by** the following macro.*/#define JOURNAL_PG_SZ(pPager)  ((pPager->pageSize) + 8)/*** The journal header size for this pager. This is usually the same ** size as a single disk sector. See also setSectorSize().*/#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/*** The maximum legal page number is (2^31 - 1).*/#define PAGER_MAX_PGNO 2147483647#ifndef NDEBUG /*** Usage:****   assert( assert_pager_state(pPager) );*/static int assert_pager_state(Pager *pPager){  /* A temp-file is always in PAGER_EXCLUSIVE or PAGER_SYNCED state. */  assert( pPager->tempFile==0 || pPager->state>=PAGER_EXCLUSIVE );  /* The changeCountDone flag is always set for temp-files */  assert( pPager->tempFile==0 || pPager->changeCountDone );  return 1;}#endif/*** Return true if it is necessary to write page *pPg into the sub-journal.** A page needs to be written into the sub-journal if there exists one** or more open savepoints for which:****   * The page-number is less than or equal to PagerSavepoint.nOrig, and**   * The bit corresponding to the page-number is not set in**     PagerSavepoint.pInSavepoint.*/static int subjRequiresPage(PgHdr *pPg){  Pgno pgno = pPg->pgno;  Pager *pPager = pPg->pPager;  int i;  for(i=0; i<pPager->nSavepoint; i++){    PagerSavepoint *p = &pPager->aSavepoint[i];    if( p->nOrig>=pgno && 0==sqlite3BitvecTest(p->pInSavepoint, pgno) ){      return 1;    }  }  return 0;}/*** Return true if the page is already in the journal file.*/static int pageInJournal(PgHdr *pPg){  return sqlite3BitvecTest(pPg->pPager->pInJournal, pPg->pgno);}/*** 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(sqlite3_file *fd, i64 offset, u32 *pRes){  unsigned char ac[4];  int rc = sqlite3OsRead(fd, ac, sizeof(ac), offset);  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(sqlite3_file *fd, i64 offset, u32 val){  char ac[4];  put32bits(ac, val);  return sqlite3OsWrite(fd, ac, 4, offset);}/*** The argument to this macro is a file descriptor (type sqlite3_file*).** Return 0 if it is not open, or non-zero (but not 1) if it is.**** This is so that expressions can be written as:****   if( isOpen(pPager->jfd) ){ ...**** instead of****   if( pPager->jfd->pMethods ){ ...*/#define isOpen(pFd) ((pFd)->pMethods)/*** If file pFd is open, call sqlite3OsUnlock() on it.*/static int osUnlock(sqlite3_file *pFd, int eLock){  if( !isOpen(pFd) ){    return SQLITE_OK;  }  return sqlite3OsUnlock(pFd, eLock);}/*** 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.**** The optimization is also always enabled for temporary files. It is** an error to call this function if pPager is opened on an in-memory** database.**** 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){  assert( !MEMDB );  if( !pPager->tempFile ){    int dc;                           /* Device characteristics */    int nSector;                      /* Sector size */    int szPage;                       /* Page size */    assert( isOpen(pPager->fd) );    dc = sqlite3OsDeviceCharacteristics(pPager->fd);    nSector = pPager->sectorSize;    szPage = pPager->pageSize;    assert(SQLITE_IOCAP_ATOMIC512==(512>>8));    assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));    if( 0==(dc&(SQLITE_IOCAP_ATOMIC|(szPage>>8)) || nSector>szPage) ){      return 0;    }  }  return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);}#endif/*** 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 void 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      || (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.** This function attempts to read a master journal file name from the ** end of the file and, if successful, copies it into memory supplied ** by the caller. See comments above writeMasterJournal() for the format** used to store a master journal file name at the end of a journal file.**** 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 a master journal file name is present at the end of the journal** file, then it is copied into the buffer pointed to by zMaster. A** nul-terminator byte is appended to the buffer following the master** journal file name.**** If it is determined that no master journal file name is present ** zMaster[0] is set to 0 and SQLITE_OK returned.**** If an error occurs while reading from the journal file, an SQLite** error code is returned.*/static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){  int rc;                    /* Return code */  u32 len;                   /* Length in bytes of master journal name */  i64 szJ;                   /* Total size in bytes of journal file pJrnl */  u32 cksum;                 /* MJ checksum value read from journal */  u32 u;                     /* Unsigned loop counter */  unsigned char aMagic[8];   /* A buffer to hold the magic header */  zMaster[0] = '\0';  if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ))   || szJ<16   || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))   || len>=nMaster    || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))   || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))   || memcmp(aMagic, aJournalMagic, 8)   || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len))  ){    return rc;  }  /* 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.    */    len = 0;  }  zMaster[len] = '\0';     return SQLITE_OK;}/*** Return the offset of the sector boundary at or immediately ** following the value in pPager->journalOff, assuming a sector ** size of pPager->sectorSize bytes.**** i.e for a sector size of 512:****   Pager.journalOff          Return value**   ---------------------------------------**   0                         0**   512                       512**   100                       512**   2000                      2048** */static i64 journalHdrOffset(Pager *pPager){  i64 offset = 0;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?