pager.c

来自「SQLite 2.8.6 源代码,用来在Linux/Unix/Windows上编」· C语言 代码 · 共 2,008 行 · 第 1/5 页

C
2,008
字号
  PgHdr *pPg, *pNext;  for(pPg=pPager->pAll; pPg; pPg=pNext){    pNext = pPg->pNextAll;    sqliteFree(pPg);  }  pPager->pFirst = 0;  pPager->pFirstSynced = 0;  pPager->pLast = 0;  pPager->pAll = 0;  memset(pPager->aHash, 0, sizeof(pPager->aHash));  pPager->nPage = 0;  if( pPager->state>=SQLITE_WRITELOCK ){    sqlitepager_rollback(pPager);  }  sqliteOsUnlock(&pPager->fd);  pPager->state = SQLITE_UNLOCK;  pPager->dbSize = -1;  pPager->nRef = 0;  assert( pPager->journalOpen==0 );}/*** When this routine is called, the pager has the journal file open and** a write lock on the database.  This routine releases the database** write lock and acquires a read lock in its place.  The journal file** is deleted and closed.*/static int pager_unwritelock(Pager *pPager){  int rc;  PgHdr *pPg;  if( pPager->state<SQLITE_WRITELOCK ) return SQLITE_OK;  sqlitepager_ckpt_commit(pPager);  if( pPager->ckptOpen ){    sqliteOsClose(&pPager->cpfd);    pPager->ckptOpen = 0;  }  if( pPager->journalOpen ){    sqliteOsClose(&pPager->jfd);    pPager->journalOpen = 0;    sqliteOsDelete(pPager->zJournal);    sqliteFree( pPager->aInJournal );    pPager->aInJournal = 0;    for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){      pPg->inJournal = 0;      pPg->dirty = 0;      pPg->needSync = 0;    }  }else{    assert( pPager->dirtyFile==0 || pPager->useJournal==0 );  }  rc = sqliteOsReadLock(&pPager->fd);  if( rc==SQLITE_OK ){    pPager->state = SQLITE_READLOCK;  }else{    /* This can only happen if a process does a BEGIN, then forks and the    ** child process does the COMMIT.  Because of the semantics of unix    ** file locking, the unlock will fail.    */    pPager->state = SQLITE_UNLOCK;  }  return rc;}/*** Compute and return a checksum for the page of data.*/static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){  u32 cksum = pPager->cksumInit + pgno;  return cksum;}/*** Read a single page from the journal file opened on file descriptor** jfd.  Playback this one page.**** There are three different journal formats.  The format parameter determines** which format is used by the journal that is played back.*/static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int format){  int rc;  PgHdr *pPg;              /* An existing page in the cache */  PageRecord pgRec;  u32 cksum;  rc = read32bits(format, jfd, &pgRec.pgno);  if( rc!=SQLITE_OK ) return rc;  rc = sqliteOsRead(jfd, &pgRec.aData, sizeof(pgRec.aData));  if( rc!=SQLITE_OK ) return rc;  /* Sanity checking on the page.  This is more important that I originally  ** thought.  If a power failure occurs while the journal is being written,  ** it could cause invalid data to be written into the journal.  We need to  ** detect this invalid data (with high probability) and ignore it.  */  if( pgRec.pgno==0 ){    return SQLITE_DONE;  }  if( pgRec.pgno>(unsigned)pPager->dbSize ){    return SQLITE_OK;  }  if( format>=JOURNAL_FORMAT_3 ){    rc = read32bits(format, jfd, &cksum);    if( rc ) return rc;    if( pager_cksum(pPager, pgRec.pgno, pgRec.aData)!=cksum ){      return SQLITE_DONE;    }  }  /* Playback the page.  Update the in-memory copy of the page  ** at the same time, if there is one.  */  pPg = pager_lookup(pPager, pgRec.pgno);  TRACE2("PLAYBACK %d\n", pgRec.pgno);  sqliteOsSeek(&pPager->fd, (pgRec.pgno-1)*(off_t)SQLITE_PAGE_SIZE);  rc = sqliteOsWrite(&pPager->fd, pgRec.aData, SQLITE_PAGE_SIZE);  if( pPg ){    if( pPg->nRef==0 ||        memcmp(PGHDR_TO_DATA(pPg), pgRec.aData, SQLITE_PAGE_SIZE)==0    ){      /* Do not update the data on this page if the page is in use      ** and the page has never been modified.  This avoids resetting      ** the "extra" data.  That in turn avoids invalidating BTree cursors      ** in trees that have never been modified.  The end result is that      ** you can have a SELECT going on in one table and ROLLBACK changes      ** to a different table and the SELECT is unaffected by the ROLLBACK.      */      memcpy(PGHDR_TO_DATA(pPg), pgRec.aData, SQLITE_PAGE_SIZE);      memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);    }    pPg->dirty = 0;    pPg->needSync = 0;  }  return rc;}/*** Playback the journal and thus restore the database file to** the state it was in before we started making changes.  **** The journal file format is as follows:  There is an initial** file-type string for sanity checking.  Then there is a single** Pgno number which is the number of pages in the database before** changes were made.  The database is truncated to this size.** Next come zero or more page records where each page record** consists of a Pgno and SQLITE_PAGE_SIZE bytes of data.  See** the PageRecord structure for details.**** If the file opened as the journal file is not a well-formed** journal file (as determined by looking at the magic number** at the beginning) then this routine returns SQLITE_PROTOCOL.** If any other errors occur during playback, the database will** likely be corrupted, so the PAGER_ERR_CORRUPT bit is set in** pPager->errMask and SQLITE_CORRUPT is returned.  If it all** works, then this routine returns SQLITE_OK.*/static int pager_playback(Pager *pPager, int useJournalSize){  off_t szJ;               /* Size of the journal file in bytes */  int nRec;                /* Number of Records in the journal */  int i;                   /* Loop counter */  Pgno mxPg = 0;           /* Size of the original file in pages */  int format;              /* Format of the journal file. */  unsigned char aMagic[sizeof(aJournalMagic1)];  int rc;  /* Figure out how many records are in the journal.  Abort early if  ** the journal is empty.  */  assert( pPager->journalOpen );  sqliteOsSeek(&pPager->jfd, 0);  rc = sqliteOsFileSize(&pPager->jfd, &szJ);  if( rc!=SQLITE_OK ){    goto end_playback;  }  if( szJ < sizeof(aMagic)+sizeof(Pgno) ){    goto end_playback;  }  /* Read the beginning of the journal and truncate the  ** database file back to its original size.  */  rc = sqliteOsRead(&pPager->jfd, aMagic, sizeof(aMagic));  if( rc!=SQLITE_OK ){    rc = SQLITE_PROTOCOL;    goto end_playback;  }  if( memcmp(aMagic, aJournalMagic3, sizeof(aMagic))==0 ){    format = JOURNAL_FORMAT_3;  }else if( memcmp(aMagic, aJournalMagic2, sizeof(aMagic))==0 ){    format = JOURNAL_FORMAT_2;  }else if( memcmp(aMagic, aJournalMagic1, sizeof(aMagic))==0 ){    format = JOURNAL_FORMAT_1;  }else{    rc = SQLITE_PROTOCOL;    goto end_playback;  }  if( format>=JOURNAL_FORMAT_3 ){    rc = read32bits(format, &pPager->jfd, &nRec);    if( rc ) goto end_playback;    rc = read32bits(format, &pPager->jfd, &pPager->cksumInit);    if( rc ) goto end_playback;    if( nRec==0xffffffff || useJournalSize ){      nRec = (szJ - JOURNAL_HDR_SZ(3))/JOURNAL_PG_SZ(3);    }  }else{    nRec = (szJ - JOURNAL_HDR_SZ(2))/JOURNAL_PG_SZ(2);    assert( nRec*JOURNAL_PG_SZ(2)+JOURNAL_HDR_SZ(2)==szJ );  }  rc = read32bits(format, &pPager->jfd, &mxPg);  if( rc!=SQLITE_OK ){    goto end_playback;  }  assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg );  rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)mxPg);  if( rc!=SQLITE_OK ){    goto end_playback;  }  pPager->dbSize = mxPg;    /* Copy original pages out of the journal and back into the database file.  */  for(i=0; i<nRec; i++){    rc = pager_playback_one_page(pPager, &pPager->jfd, format);    if( rc!=SQLITE_OK ){      if( rc==SQLITE_DONE ){        rc = SQLITE_OK;      }      break;    }  }  /* Pages that have been written to the journal but never synced  ** where not restored by the loop above.  We have to restore those  ** pages by reading the back from the original database.  */  if( rc==SQLITE_OK ){    PgHdr *pPg;    for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){      char zBuf[SQLITE_PAGE_SIZE];      if( !pPg->dirty ) continue;      if( (int)pPg->pgno <= pPager->origDbSize ){        sqliteOsSeek(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)(pPg->pgno-1));        rc = sqliteOsRead(&pPager->fd, zBuf, SQLITE_PAGE_SIZE);        if( rc ) break;      }else{        memset(zBuf, 0, SQLITE_PAGE_SIZE);      }      if( pPg->nRef==0 || memcmp(zBuf, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE) ){        memcpy(PGHDR_TO_DATA(pPg), zBuf, SQLITE_PAGE_SIZE);        memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);      }      pPg->needSync = 0;      pPg->dirty = 0;    }  }end_playback:  if( rc!=SQLITE_OK ){    pager_unwritelock(pPager);    pPager->errMask |= PAGER_ERR_CORRUPT;    rc = SQLITE_CORRUPT;  }else{    rc = pager_unwritelock(pPager);  }  return rc;}/*** Playback the checkpoint journal.**** This is similar to playing back the transaction journal but with** a few extra twists.****    (1)  The number of pages in the database file at the start of**         the checkpoint is stored in pPager->ckptSize, not in the**         journal file itself.****    (2)  In addition to playing back the checkpoint journal, also**         playback all pages of the transaction journal beginning**         at offset pPager->ckptJSize.*/static int pager_ckpt_playback(Pager *pPager){  off_t szJ;               /* Size of the full journal */  int nRec;                /* Number of Records */  int i;                   /* Loop counter */  int rc;  /* Truncate the database back to its original size.  */  rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)pPager->ckptSize);  pPager->dbSize = pPager->ckptSize;  /* Figure out how many records are in the checkpoint journal.  */  assert( pPager->ckptInUse && pPager->journalOpen );  sqliteOsSeek(&pPager->cpfd, 0);  nRec = pPager->ckptNRec;    /* Copy original pages out of the checkpoint journal and back into the  ** database file.  Note that the checkpoint journal always uses format  ** 2 instead of format 3 since it does not need to be concerned with  ** power failures corrupting the journal and can thus omit the checksums.  */  for(i=nRec-1; i>=0; i--){    rc = pager_playback_one_page(pPager, &pPager->cpfd, 2);    assert( rc!=SQLITE_DONE );    if( rc!=SQLITE_OK ) goto end_ckpt_playback;  }  /* Figure out how many pages need to be copied out of the transaction  ** journal.  */  rc = sqliteOsSeek(&pPager->jfd, pPager->ckptJSize);  if( rc!=SQLITE_OK ){    goto end_ckpt_playback;  }  rc = sqliteOsFileSize(&pPager->jfd, &szJ);  if( rc!=SQLITE_OK ){    goto end_ckpt_playback;  }  nRec = (szJ - pPager->ckptJSize)/JOURNAL_PG_SZ(journal_format);  for(i=nRec-1; i>=0; i--){    rc = pager_playback_one_page(pPager, &pPager->jfd, journal_format);    if( rc!=SQLITE_OK ){      assert( rc!=SQLITE_DONE );      goto end_ckpt_playback;    }  }  end_ckpt_playback:  if( rc!=SQLITE_OK ){    pPager->errMask |= PAGER_ERR_CORRUPT;    rc = SQLITE_CORRUPT;  }  return rc;}/*** Change the maximum number of in-memory pages that are allowed.**** The maximum number is the absolute value of the mxPage parameter.** If mxPage is negative, the noSync flag is also set.  noSync bypasses** calls to sqliteOsSync().  The pager runs much faster with noSync on,** but if the operating system crashes or there is an abrupt power ** failure, the database file might be left in an inconsistent and** unrepairable state.  */void sqlitepager_set_cachesize(Pager *pPager, int mxPage){  if( mxPage>=0 ){    pPager->noSync = pPager->tempFile;  }else{    pPager->noSync = 1;    mxPage = -mxPage;  }  if( mxPage>10 ){    pPager->mxPage = mxPage;  }}/*** Adjust the robustness of the database to damage due to OS crashes** or power failures by changing the number of syncs()s when writing** the rollback journal.  There are three levels:****    OFF       sqliteOsSync() is never called.  This is the default**              for temporary and transient files.****    NORMAL    The journal is synced once before writes begin on the**              database.  This is normally adequate protection, but**              it is theoretically possible, though very unlikely,**              that an inopertune power failure could leave the journal**              in a state which would cause damage to the database**              when it is rolled back.****    FULL      The journal is synced twice before writes begin on the**              database (with some additional information being written**              in between the two syncs.  If we assume that writing a**              single disk sector is atomic, then this mode provides**              assurance that the journal will not be corrupted to the**              point of causing damage to the database during rollback.**** Numeric values associated with these states are OFF==1, NORMAL=2,** and FULL=3.*/void sqlitepager_set_safety_level(Pager *pPager, int level){  pPager->noSync =  level==1 || pPager->tempFile;  pPager->fullSync = level==3 && !pPager->tempFile;}/*** Open a temporary file.  Write the name of the file into zName** (zName must be at least SQLITE_TEMPNAME_SIZE bytes long.)  Write** the file descriptor into *fd.  Return SQLITE_OK on success or some** other error code if we fail.**** The OS will automatically delete the temporary file when it is** closed.*/static int sqlitepager_opentemp(char *zFile, OsFile *fd){  int cnt = 8;  int rc;  do{    cnt--;

⌨️ 快捷键说明

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