pager.c

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

C
1,620
字号
  ){    return SQLITE_OK;  }  pPager->setMaster = 1;  assert( isOpen(pPager->jfd) );  /* Calculate the length in bytes and the checksum of zMaster */  for(nMaster=0; zMaster[nMaster]; nMaster++){    cksum += zMaster[nMaster];  }  /* 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 ){    pPager->journalOff = journalHdrOffset(pPager);  }  iHdrOff = pPager->journalOff;  /* Write the master journal data to the end of the journal file. If  ** an error occurs, return the error code to the caller.  */  if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager))))   || (0 != (rc = sqlite3OsWrite(pPager->jfd, zMaster, nMaster, iHdrOff+4)))   || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster, nMaster)))   || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster+4, cksum)))   || (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8, iHdrOff+4+nMaster+8)))  ){    return rc;  }  pPager->journalOff += (nMaster+20);  pPager->needSync = !pPager->noSync;  /* If the pager is in peristent-journal mode, then the physical   ** journal-file may extend past the end of the master-journal name  ** and 8 bytes of magic data just written to the file. This is   ** dangerous because the code to rollback a hot-journal file  ** will not be able to find the master-journal name to determine   ** whether or not the journal is hot.   **  ** Easiest thing to do in this scenario is to truncate the journal   ** file to the required size.  */   if( SQLITE_OK==(rc = sqlite3OsFileSize(pPager->jfd, &jrnlSize))   && jrnlSize>pPager->journalOff  ){    rc = sqlite3OsTruncate(pPager->jfd, pPager->journalOff);  }  return rc;}/*** Find a page in the hash table given its page number. Return** a pointer to the page or NULL if the requested page is not ** already in memory.*/static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){  PgHdr *p;                         /* Return value */  /* It is not possible for a call to PcacheFetch() with createFlag==0 to  ** fail, since no attempt to allocate dynamic memory will be made.  */  (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &p);  return p;}/*** Unless the pager is in error-state, discard all in-memory pages. If** the pager is in error-state, then this call is a no-op.**** TODO: Why can we not reset the pager while in error state?*/static void pager_reset(Pager *pPager){  if( SQLITE_OK==pPager->errCode ){    sqlite3BackupRestart(pPager->pBackup);    sqlite3PcacheClear(pPager->pPCache);  }}/*** Free all structures in the Pager.aSavepoint[] array and set both** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal** if it is open and the pager is not in exclusive mode.*/static void releaseAllSavepoints(Pager *pPager){  int ii;               /* Iterator for looping through Pager.aSavepoint */  for(ii=0; ii<pPager->nSavepoint; ii++){    sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);  }  if( !pPager->exclusiveMode ){    sqlite3OsClose(pPager->sjfd);  }  sqlite3_free(pPager->aSavepoint);  pPager->aSavepoint = 0;  pPager->nSavepoint = 0;  pPager->nSubRec = 0;}/*** Set the bit number pgno in the PagerSavepoint.pInSavepoint ** bitvecs of all open savepoints. Return SQLITE_OK if successful** or SQLITE_NOMEM if a malloc failure occurs.*/static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){  int ii;                   /* Loop counter */  int rc = SQLITE_OK;       /* Result code */  for(ii=0; ii<pPager->nSavepoint; ii++){    PagerSavepoint *p = &pPager->aSavepoint[ii];    if( pgno<=p->nOrig ){      rc |= sqlite3BitvecSet(p->pInSavepoint, pgno);      testcase( rc==SQLITE_NOMEM );      assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );    }  }  return rc;}/*** Unlock the database file. This function is a no-op if the pager** is in exclusive mode.**** If the pager is currently in error state, discard the contents of ** the cache and reset the Pager structure internal state. If there is** an open journal-file, then the next time a shared-lock is obtained** on the pager file (by this or any other process), it will be** treated as a hot-journal and rolled back.*/static void pager_unlock(Pager *pPager){  if( !pPager->exclusiveMode ){    int rc;                      /* Return code */    /* Always close the journal file when dropping the database lock.    ** Otherwise, another connection with journal_mode=delete might    ** delete the file out from under us.    */    sqlite3OsClose(pPager->jfd);    sqlite3BitvecDestroy(pPager->pInJournal);    pPager->pInJournal = 0;    releaseAllSavepoints(pPager);    /* If the file is unlocked, somebody else might change it. The    ** values stored in Pager.dbSize etc. might become invalid if    ** this happens. TODO: Really, this doesn't need to be cleared    ** until the change-counter check fails in pagerSharedLock().    */    pPager->dbSizeValid = 0;    rc = osUnlock(pPager->fd, NO_LOCK);    if( rc ){      pPager->errCode = rc;    }    IOTRACE(("UNLOCK %p\n", pPager))    /* If Pager.errCode is set, the contents of the pager cache cannot be    ** trusted. Now that the pager file is unlocked, the contents of the    ** cache can be discarded and the error code safely cleared.    */    if( pPager->errCode ){      if( rc==SQLITE_OK ){        pPager->errCode = SQLITE_OK;      }      pager_reset(pPager);    }    pPager->changeCountDone = 0;    pPager->state = PAGER_UNLOCK;  }}/*** This function should be called when an IOERR, CORRUPT or FULL error** may have occured. 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. Until the persisten error is cleared,** subsequent API calls on this Pager will immediately return the same ** error code.**** A persistent error indicates that the contents of the pager-cache ** cannot be trusted. This state can be cleared by completely discarding ** the contents of the pager-cache. If a transaction was active when** the persistent error occured, then the rollback journal may need** to be replayed to restore the contents of the database file (as if** it were a hot-journal).*/static int pager_error(Pager *pPager, int rc){  int rc2 = rc & 0xff;  assert(       pPager->errCode==SQLITE_FULL ||       pPager->errCode==SQLITE_OK ||       (pPager->errCode & 0xff)==SQLITE_IOERR  );  if(    rc2==SQLITE_FULL ||    rc2==SQLITE_IOERR ||    rc2==SQLITE_CORRUPT  ){    pPager->errCode = rc;    if( pPager->state==PAGER_UNLOCK      && sqlite3PcacheRefCount(pPager->pPCache)==0     ){      /* If the pager is already unlocked, call pager_unlock() now to      ** clear the error state and ensure that the pager-cache is       ** completely empty.      */      pager_unlock(pPager);    }  }  return rc;}/*** Execute a rollback if a transaction is active and unlock the ** database file. **** If the pager has already entered the error state, do not attempt ** the rollback at this time. Instead, pager_unlock() is called. The** call to pager_unlock() will discard all in-memory pages, unlock** the database file and clear the error state. If this means that** there is a hot-journal left in the file-system, the next connection** to obtain a shared lock on the pager (which may be this one) will** roll it back.**** If the pager has not already entered the error state, but an IO or** malloc error occurs during a rollback, then this will itself cause ** the pager to enter the error state. Which will be cleared by the** call to pager_unlock(), as described above.*/static void pagerUnlockAndRollback(Pager *pPager){  if( pPager->errCode==SQLITE_OK && pPager->state>=PAGER_RESERVED ){    sqlite3BeginBenignMalloc();    sqlite3PagerRollback(pPager);    sqlite3EndBenignMalloc();  }  pager_unlock(pPager);}/*** This routine ends a transaction. A transaction is usually ended by ** either a COMMIT or a ROLLBACK operation. This routine may be called ** after rollback of a hot-journal, or if an error occurs while opening** the journal file or writing the very first journal-header of a** database transaction.** ** If the pager is in PAGER_SHARED or PAGER_UNLOCK state when this** routine is called, it is a no-op (returns SQLITE_OK).**** Otherwise, any active savepoints are released.**** If the journal file is open, then it is "finalized". Once a journal ** file has been finalized it is not possible to use it to roll back a ** transaction. Nor will it be considered to be a hot-journal by this** or any other database connection. Exactly how a journal is finalized** depends on whether or not the pager is running in exclusive mode and** the current journal-mode (Pager.journalMode value), as follows:****   journalMode==MEMORY**     Journal file descriptor is simply closed. This destroys an **     in-memory journal.****   journalMode==TRUNCATE**     Journal file is truncated to zero bytes in size.****   journalMode==PERSIST**     The first 28 bytes of the journal file are zeroed. This invalidates**     the first journal header in the file, and hence the entire journal**     file. An invalid journal file cannot be rolled back.****   journalMode==DELETE**     The journal file is closed and deleted using sqlite3OsDelete().****     If the pager is running in exclusive mode, this method of finalizing**     the journal file is never used. Instead, if the journalMode is**     DELETE and the pager is in exclusive mode, the method described under**     journalMode==PERSIST is used instead.**** After the journal is finalized, if running in non-exclusive mode, the** pager moves to PAGER_SHARED state (and downgrades the lock on the** database file accordingly).**** If the pager is running in exclusive mode and is in PAGER_SYNCED state,** it moves to PAGER_EXCLUSIVE. No locks are downgraded when running in** exclusive mode.**** SQLITE_OK is returned if no error occurs. If an error occurs during** any of the IO operations to finalize the journal file or unlock the** database then the IO error code is returned to the user. If the ** operation to finalize the journal file fails, then the code still** tries to unlock the database file if not in exclusive mode. If the** unlock operation fails as well, then the first error code related** to the first error encountered (the journal finalization one) is** returned.*/static int pager_end_transaction(Pager *pPager, int hasMaster){  int rc = SQLITE_OK;      /* Error code from journal finalization operation */  int rc2 = SQLITE_OK;     /* Error code from db file unlock operation */  if( pPager->state<PAGER_RESERVED ){    return SQLITE_OK;  }  releaseAllSavepoints(pPager);  assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );  if( isOpen(pPager->jfd) ){    /* TODO: There's a problem here if a journal-file was opened in MEMORY    ** mode and then the journal-mode is changed to TRUNCATE or PERSIST    ** during the transaction. This code should be changed to assume    ** that the journal mode has not changed since the transaction was    ** started. And the sqlite3PagerJournalMode() function should be    ** changed to make sure that this is the case too.    */    /* Finalize the journal file. */    if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){      int isMemoryJournal = sqlite3IsMemJournal(pPager->jfd);      sqlite3OsClose(pPager->jfd);      if( !isMemoryJournal ){        rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);

⌨️ 快捷键说明

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