⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pager.c

📁 sqlite 嵌入式数据库的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
  rc = write32bits(&pPager->jfd, PAGER_MJ_PGNO(pPager));  if( rc!=SQLITE_OK ) return rc;  rc = sqlite3OsWrite(&pPager->jfd, zMaster, len);  if( rc!=SQLITE_OK ) return rc;  rc = write32bits(&pPager->jfd, len);  if( rc!=SQLITE_OK ) return rc;  rc = write32bits(&pPager->jfd, cksum);  if( rc!=SQLITE_OK ) return rc;  rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));  pPager->needSync = 1;  return rc;}/*** Add or remove a page from the list of all pages that are in the** statement journal.**** The Pager keeps a separate list of pages that are currently in** the statement journal.  This helps the sqlite3pager_stmt_commit()** routine run MUCH faster for the common case where there are many** pages in memory but only a few are in the statement journal.*/static void page_add_to_stmt_list(PgHdr *pPg){  Pager *pPager = pPg->pPager;  if( pPg->inStmt ) return;  assert( pPg->pPrevStmt==0 && pPg->pNextStmt==0 );  pPg->pPrevStmt = 0;  if( pPager->pStmt ){    pPager->pStmt->pPrevStmt = pPg;  }  pPg->pNextStmt = pPager->pStmt;  pPager->pStmt = pPg;  pPg->inStmt = 1;}static void page_remove_from_stmt_list(PgHdr *pPg){  if( !pPg->inStmt ) return;  if( pPg->pPrevStmt ){    assert( pPg->pPrevStmt->pNextStmt==pPg );    pPg->pPrevStmt->pNextStmt = pPg->pNextStmt;  }else{    assert( pPg->pPager->pStmt==pPg );    pPg->pPager->pStmt = pPg->pNextStmt;  }  if( pPg->pNextStmt ){    assert( pPg->pNextStmt->pPrevStmt==pPg );    pPg->pNextStmt->pPrevStmt = pPg->pPrevStmt;  }  pPg->pNextStmt = 0;  pPg->pPrevStmt = 0;  pPg->inStmt = 0;}/*** Find a page in the hash table given its page number.  Return** a pointer to the page or NULL if not found.*/static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){  PgHdr *p = pPager->aHash[pager_hash(pgno)];  while( p && p->pgno!=pgno ){    p = p->pNextHash;  }  return p;}/*** Unlock the database and clear the in-memory cache.  This routine** sets the state of the pager back to what it was when it was first** opened.  Any outstanding pages are invalidated and subsequent attempts** to access those pages will likely result in a coredump.*/static void pager_reset(Pager *pPager){  PgHdr *pPg, *pNext;  if( pPager->errMask ) return;  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>=PAGER_RESERVED ){    sqlite3pager_rollback(pPager);  }  sqlite3OsUnlock(&pPager->fd, NO_LOCK);  pPager->state = PAGER_UNLOCK;  pPager->dbSize = -1;  pPager->nRef = 0;  assert( pPager->journalOpen==0 );}/*** This function is used to reset the pager after a malloc() failure. This** doesn't work with in-memory databases. If a malloc() fails when an ** in-memory database is in use it is not possible to recover.**** If a transaction or statement transaction is active, it is rolled back.**** It is an error to call this function if any pages are in use.*/#ifndef SQLITE_OMIT_GLOBALRECOVERint sqlite3pager_reset(Pager *pPager){  if( pPager ){    if( pPager->nRef || MEMDB ){      return SQLITE_ERROR;    }    pPager->errMask &= ~(PAGER_ERR_MEM);    pager_reset(pPager);  }  return SQLITE_OK;}#endif/*** When this routine is called, the pager has the journal file open and** a RESERVED or EXCLUSIVE lock on the database.  This routine releases** the database lock and acquires a SHARED lock in its place.  The journal** file is deleted and closed.**** TODO: Consider keeping the journal file open for temporary databases.** This might give a performance improvement on windows where opening** a file is an expensive operation.*/static int pager_unwritelock(Pager *pPager){  PgHdr *pPg;  int rc;  assert( !MEMDB );  if( pPager->state<PAGER_RESERVED ){    return SQLITE_OK;  }  sqlite3pager_stmt_commit(pPager);  if( pPager->stmtOpen ){    sqlite3OsClose(&pPager->stfd);    pPager->stmtOpen = 0;  }  if( pPager->journalOpen ){    sqlite3OsClose(&pPager->jfd);    pPager->journalOpen = 0;    sqlite3OsDelete(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;#ifdef SQLITE_CHECK_PAGES      pPg->pageHash = pager_pagehash(pPg);#endif    }    pPager->dirtyCache = 0;    pPager->nRec = 0;  }else{    assert( pPager->aInJournal==0 );    assert( pPager->dirtyCache==0 || pPager->useJournal==0 );  }  rc = sqlite3OsUnlock(&pPager->fd, SHARED_LOCK);  pPager->state = PAGER_SHARED;  pPager->origDbSize = 0;  pPager->setMaster = 0;  return rc;}/*** Compute and return a checksum for the page of data.**** This is not a real checksum.  It is really just the sum of the ** random initial value and the page number.  We experimented with** a checksum of the entire data, but that was found to be too slow.**** Note that the page number is stored at the beginning of data and** the checksum is stored at the end.  This is important.  If journal** corruption occurs due to a power failure, the most likely scenario** is that one end or the other of the record will be changed.  It is** much less likely that the two ends of the journal record will be** correct and the middle be corrupt.  Thus, this "checksum" scheme,** though fast and simple, catches the mostly likely kind of corruption.**** FIX ME:  Consider adding every 200th (or so) byte of the data to the** checksum.  That way if a single page spans 3 or more disk sectors and** only the middle sector is corrupt, we will still have a reasonable** chance of failing the checksum and thus detecting the problem.*/static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){  u32 cksum = pPager->cksumInit;  int i = pPager->pageSize-200;  while( i>0 ){    cksum += aData[i];    i -= 200;  }  return cksum;}/*** Read a single page from the journal file opened on file descriptor** jfd.  Playback this one page.**** If useCksum==0 it means this journal does not use checksums.  Checksums** are not used in statement journals because statement journals do not** need to survive power failures.*/static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){  int rc;  PgHdr *pPg;                   /* An existing page in the cache */  Pgno pgno;                    /* The page number of a page in journal */  u32 cksum;                    /* Checksum used for sanity checking */  u8 aData[SQLITE_MAX_PAGE_SIZE];  /* Temp storage for a page */  /* useCksum should be true for the main journal and false for  ** statement journals.  Verify that this is always the case  */  assert( jfd == (useCksum ? &pPager->jfd : &pPager->stfd) );  rc = read32bits(jfd, &pgno);  if( rc!=SQLITE_OK ) return rc;  rc = sqlite3OsRead(jfd, &aData, pPager->pageSize);  if( rc!=SQLITE_OK ) return rc;  pPager->journalOff += pPager->pageSize + 4;  /* 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( pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){    return SQLITE_DONE;  }  if( pgno>(unsigned)pPager->dbSize ){    return SQLITE_OK;  }  if( useCksum ){    rc = read32bits(jfd, &cksum);    if( rc ) return rc;    pPager->journalOff += 4;    if( pager_cksum(pPager, pgno, aData)!=cksum ){      return SQLITE_DONE;    }  }  assert( pPager->state==PAGER_RESERVED || pPager->state>=PAGER_EXCLUSIVE );  /* If the pager is in RESERVED state, then there must be a copy of this  ** page in the pager cache. In this case just update the pager cache,  ** not the database file. The page is left marked dirty in this case.  **  ** If in EXCLUSIVE state, then we update the pager cache if it exists  ** and the main file. The page is then marked not dirty.  **  ** Ticket #1171:  The statement journal might contain page content that is  ** different from the page content at the start of the transaction.  ** This occurs when a page is changed prior to the start of a statement  ** then changed again within the statement.  When rolling back such a  ** statement we must not write to the original database unless we know  ** for certain that original page contents are in the main rollback  ** journal.  Otherwise, if a full ROLLBACK occurs after the statement  ** rollback the full ROLLBACK will not restore the page to its original  ** content.  Two conditions must be met before writing to the database  ** files. (1) the database must be locked.  (2) we know that the original  ** page content is in the main journal either because the page is not in  ** cache or else it is marked as needSync==0.  */  pPg = pager_lookup(pPager, pgno);  assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 );  TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno);  if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){    sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);    rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);    if( pPg ) pPg->dirty = 0;  }  if( pPg ){    /* No page should ever be explicitly rolled back that is in use, except    ** for page 1 which is held in use in order to keep the lock on the    ** database active. However such a page may be rolled back as a result    ** of an internal error resulting in an automatic call to    ** sqlite3pager_rollback().    */    void *pData;    /* assert( pPg->nRef==0 || pPg->pgno==1 ); */    pData = PGHDR_TO_DATA(pPg);    memcpy(pData, aData, pPager->pageSize);    if( pPager->xDestructor ){  /*** FIX ME:  Should this be xReinit? ***/      pPager->xDestructor(pData, pPager->pageSize);    }#ifdef SQLITE_CHECK_PAGES    pPg->pageHash = pager_pagehash(pPg);#endif    CODEC(pPager, pData, pPg->pgno, 3);  }  return rc;}/*** Parameter zMaster is the name of a master journal file. A single journal** file that referred to the master journal file has just been rolled back.** This routine checks if it is possible to delete the master journal file,** and does so if it is.**** The master journal file contains the names of all child journals.** To tell if a master journal can be deleted, check to each of the** children.  If all children are either missing or do not refer to** a different master journal, then this master journal can be deleted.*/static int pager_delmaster(const char *zMaster){  int rc;  int master_open = 0;  OsFile master;  char *zMasterJournal = 0; /* Contents of master journal file */  i64 nMasterJournal;       /* Size of master journal file */  /* Open the master journal file exclusively in case some other process  ** is running this routine also. Not that it makes too much difference.  */  memset(&master, 0, sizeof(master));  rc = sqlite3OsOpenReadOnly(zMaster, &master);  if( rc!=SQLITE_OK ) goto delmaster_out;  master_open = 1;  rc = sqlite3OsFileSize(&master, &nMasterJournal);  if( rc!=SQLITE_OK ) goto delmaster_out;  if( nMasterJournal>0 ){    char *zJournal;    char *zMasterPtr = 0;    /* Load the entire master journal file into space obtained from    ** sqliteMalloc() and pointed to by zMasterJournal.     */    zMasterJournal = (char *)sqliteMalloc(nMasterJournal);    if( !zMasterJournal ){      rc = SQLITE_NOMEM;      goto delmaster_out;    }    rc = sqlite3OsRead(&master, zMasterJournal, nMasterJournal);    if( rc!=SQLITE_OK ) goto delmaster_out;    zJournal = zMasterJournal;    while( (zJournal-zMasterJournal)<nMasterJournal ){      if( sqlite3OsFileExists(zJournal) ){        /* One of the journals pointed to by the master journal exists.        ** Open it and check if it points at the master journal. If        ** so, return without deleting the master journal file.        */        OsFile journal;        int c;        memset(&journal, 0, sizeof(journal));        rc = sqlite3OsOpenReadOnly(zJournal, &journal);        if( rc!=SQLITE_OK ){          goto delmaster_out;        }        rc = readMasterJournal(&journal, &zMasterPtr);        sqlite3OsClose(&journal);        if( rc!=SQLITE_OK ){          goto delmaster_out;        }        c = zMasterPtr!=0 && strcmp(zMasterPtr, zMaster)==0;        sqliteFree(zMasterPtr);        if( c ){          /* We have a match. Do not delete the master journal file. */          goto delmaster_out;        }      }      zJournal += (strlen(zJournal)+1);    }  }    sqlite3OsDelete(zMaster);delmaster_out:  if( zMasterJournal ){    sqliteFree(zMasterJournal);  }    if( master_open ){    sqlite3OsClose(&master);  }  return rc;

⌨️ 快捷键说明

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