pager.c
上传用户:sunhongbo
上传日期:2022-01-25
资源大小:3010k
文件大小:172k
- assert( pPager->state>=PAGER_SHARED || pPager->dbSize<0 || MEMDB );
- if( pPager->state>=locktype ){
- rc = SQLITE_OK;
- }else{
- if( pPager->pBusyHandler ) pPager->pBusyHandler->nBusy = 0;
- do {
- rc = sqlite3OsLock(pPager->fd, locktype);
- }while( rc==SQLITE_BUSY && sqlite3InvokeBusyHandler(pPager->pBusyHandler) );
- if( rc==SQLITE_OK ){
- pPager->state = locktype;
- IOTRACE(("LOCK %p %dn", pPager, locktype))
- }
- }
- return rc;
- }
- /*
- ** Truncate the file to the number of pages specified.
- */
- int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){
- int rc;
- assert( pPager->state>=PAGER_SHARED || MEMDB );
- sqlite3PagerPagecount(pPager);
- if( pPager->errCode ){
- rc = pPager->errCode;
- return rc;
- }
- if( nPage>=(unsigned)pPager->dbSize ){
- return SQLITE_OK;
- }
- if( MEMDB ){
- pPager->dbSize = nPage;
- pager_truncate_cache(pPager);
- return SQLITE_OK;
- }
- pagerEnter(pPager);
- rc = syncJournal(pPager);
- pagerLeave(pPager);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- /* Get an exclusive lock on the database before truncating. */
- pagerEnter(pPager);
- rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
- pagerLeave(pPager);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- rc = pager_truncate(pPager, nPage);
- return rc;
- }
- /*
- ** Shutdown the page cache. Free all memory and close all files.
- **
- ** If a transaction was in progress when this routine is called, that
- ** transaction is rolled back. All outstanding pages are invalidated
- ** and their memory is freed. Any attempt to use a page associated
- ** with this page cache after this function returns will likely
- ** result in a coredump.
- **
- ** This function always succeeds. If a transaction is active an attempt
- ** is made to roll it back. If an error occurs during the rollback
- ** a hot journal may be left in the filesystem but no error is returned
- ** to the caller.
- */
- int sqlite3PagerClose(Pager *pPager){
- #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
- if( !MEMDB ){
- sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2);
- sqlite3_mutex_enter(mutex);
- if( pPager->pPrev ){
- pPager->pPrev->pNext = pPager->pNext;
- }else{
- sqlite3PagerList = pPager->pNext;
- }
- if( pPager->pNext ){
- pPager->pNext->pPrev = pPager->pPrev;
- }
- sqlite3_mutex_leave(mutex);
- }
- #endif
- disable_simulated_io_errors();
- pPager->errCode = 0;
- pPager->exclusiveMode = 0;
- pager_reset(pPager);
- pagerUnlockAndRollback(pPager);
- enable_simulated_io_errors();
- PAGERTRACE2("CLOSE %dn", PAGERID(pPager));
- IOTRACE(("CLOSE %pn", pPager))
- assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
- if( pPager->journalOpen ){
- sqlite3OsClose(pPager->jfd);
- }
- sqlite3BitvecDestroy(pPager->pInJournal);
- if( pPager->stmtOpen ){
- sqlite3OsClose(pPager->stfd);
- }
- sqlite3OsClose(pPager->fd);
- /* Temp files are automatically deleted by the OS
- ** if( pPager->tempFile ){
- ** sqlite3OsDelete(pPager->zFilename);
- ** }
- */
- sqlite3_free(pPager->aHash);
- sqlite3_free(pPager->pTmpSpace);
- sqlite3_free(pPager);
- return SQLITE_OK;
- }
- #if !defined(NDEBUG) || defined(SQLITE_TEST)
- /*
- ** Return the page number for the given page data.
- */
- Pgno sqlite3PagerPagenumber(DbPage *p){
- return p->pgno;
- }
- #endif
- /*
- ** The page_ref() function increments the reference count for a page.
- ** If the page is currently on the freelist (the reference count is zero) then
- ** remove it from the freelist.
- **
- ** For non-test systems, page_ref() is a macro that calls _page_ref()
- ** online of the reference count is zero. For test systems, page_ref()
- ** is a real function so that we can set breakpoints and trace it.
- */
- static void _page_ref(PgHdr *pPg){
- if( pPg->nRef==0 ){
- /* The page is currently on the freelist. Remove it. */
- lruListRemove(pPg);
- pPg->pPager->nRef++;
- }
- pPg->nRef++;
- }
- #ifdef SQLITE_DEBUG
- static void page_ref(PgHdr *pPg){
- if( pPg->nRef==0 ){
- _page_ref(pPg);
- }else{
- pPg->nRef++;
- }
- }
- #else
- # define page_ref(P) ((P)->nRef==0?_page_ref(P):(void)(P)->nRef++)
- #endif
- /*
- ** Increment the reference count for a page. The input pointer is
- ** a reference to the page data.
- */
- int sqlite3PagerRef(DbPage *pPg){
- pagerEnter(pPg->pPager);
- page_ref(pPg);
- pagerLeave(pPg->pPager);
- return SQLITE_OK;
- }
- /*
- ** Sync the journal. In other words, make sure all the pages that have
- ** been written to the journal have actually reached the surface of the
- ** disk. It is not safe to modify the original database file until after
- ** the journal has been synced. If the original database is modified before
- ** the journal is synced and a power failure occurs, the unsynced journal
- ** data would be lost and we would be unable to completely rollback the
- ** database changes. Database corruption would occur.
- **
- ** This routine also updates the nRec field in the header of the journal.
- ** (See comments on the pager_playback() routine for additional information.)
- ** If the sync mode is FULL, two syncs will occur. First the whole journal
- ** is synced, then the nRec field is updated, then a second sync occurs.
- **
- ** For temporary databases, we do not care if we are able to rollback
- ** after a power failure, so no sync occurs.
- **
- ** If the IOCAP_SEQUENTIAL flag is set for the persistent media on which
- ** the database is stored, then OsSync() is never called on the journal
- ** file. In this case all that is required is to update the nRec field in
- ** the journal header.
- **
- ** This routine clears the needSync field of every page current held in
- ** memory.
- */
- static int syncJournal(Pager *pPager){
- PgHdr *pPg;
- int rc = SQLITE_OK;
- /* Sync the journal before modifying the main database
- ** (assuming there is a journal and it needs to be synced.)
- */
- if( pPager->needSync ){
- if( !pPager->tempFile ){
- int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
- assert( pPager->journalOpen );
- /* assert( !pPager->noSync ); // noSync might be set if synchronous
- ** was turned off after the transaction was started. Ticket #615 */
- #ifndef NDEBUG
- {
- /* Make sure the pPager->nRec counter we are keeping agrees
- ** with the nRec computed from the size of the journal file.
- */
- i64 jSz;
- rc = sqlite3OsFileSize(pPager->jfd, &jSz);
- if( rc!=0 ) return rc;
- assert( pPager->journalOff==jSz );
- }
- #endif
- if( 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){
- /* Write the nRec value into the journal file header. If in
- ** full-synchronous mode, sync the journal first. This ensures that
- ** all data has really hit the disk before nRec is updated to mark
- ** it as a candidate for rollback.
- **
- ** This is not required if the persistent media supports the
- ** SAFE_APPEND property. Because in this case it is not possible
- ** for garbage data to be appended to the file, the nRec field
- ** is populated with 0xFFFFFFFF when the journal header is written
- ** and never needs to be updated.
- */
- i64 jrnlOff;
- if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
- PAGERTRACE2("SYNC journal of %dn", PAGERID(pPager));
- IOTRACE(("JSYNC %pn", pPager))
- rc = sqlite3OsSync(pPager->jfd, pPager->sync_flags);
- if( rc!=0 ) return rc;
- }
- jrnlOff = pPager->journalHdr + sizeof(aJournalMagic);
- IOTRACE(("JHDR %p %lld %dn", pPager, jrnlOff, 4));
- rc = write32bits(pPager->jfd, jrnlOff, pPager->nRec);
- if( rc ) return rc;
- }
- if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
- PAGERTRACE2("SYNC journal of %dn", PAGERID(pPager));
- IOTRACE(("JSYNC %pn", pPager))
- rc = sqlite3OsSync(pPager->jfd, pPager->sync_flags|
- (pPager->sync_flags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0)
- );
- if( rc!=0 ) return rc;
- }
- pPager->journalStarted = 1;
- }
- pPager->needSync = 0;
- /* Erase the needSync flag from every page.
- */
- for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
- pPg->needSync = 0;
- }
- lruListSetFirstSynced(pPager);
- }
- #ifndef NDEBUG
- /* If the Pager.needSync flag is clear then the PgHdr.needSync
- ** flag must also be clear for all pages. Verify that this
- ** invariant is true.
- */
- else{
- for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
- assert( pPg->needSync==0 );
- }
- assert( pPager->lru.pFirstSynced==pPager->lru.pFirst );
- }
- #endif
- return rc;
- }
- /*
- ** Merge two lists of pages connected by pDirty and in pgno order.
- ** Do not both fixing the pPrevDirty pointers.
- */
- static PgHdr *merge_pagelist(PgHdr *pA, PgHdr *pB){
- PgHdr result, *pTail;
- pTail = &result;
- while( pA && pB ){
- if( pA->pgno<pB->pgno ){
- pTail->pDirty = pA;
- pTail = pA;
- pA = pA->pDirty;
- }else{
- pTail->pDirty = pB;
- pTail = pB;
- pB = pB->pDirty;
- }
- }
- if( pA ){
- pTail->pDirty = pA;
- }else if( pB ){
- pTail->pDirty = pB;
- }else{
- pTail->pDirty = 0;
- }
- return result.pDirty;
- }
- /*
- ** Sort the list of pages in accending order by pgno. Pages are
- ** connected by pDirty pointers. The pPrevDirty pointers are
- ** corrupted by this sort.
- */
- #define N_SORT_BUCKET_ALLOC 25
- #define N_SORT_BUCKET 25
- #ifdef SQLITE_TEST
- int sqlite3_pager_n_sort_bucket = 0;
- #undef N_SORT_BUCKET
- #define N_SORT_BUCKET
- (sqlite3_pager_n_sort_bucket?sqlite3_pager_n_sort_bucket:N_SORT_BUCKET_ALLOC)
- #endif
- static PgHdr *sort_pagelist(PgHdr *pIn){
- PgHdr *a[N_SORT_BUCKET_ALLOC], *p;
- int i;
- memset(a, 0, sizeof(a));
- while( pIn ){
- p = pIn;
- pIn = p->pDirty;
- p->pDirty = 0;
- for(i=0; i<N_SORT_BUCKET-1; i++){
- if( a[i]==0 ){
- a[i] = p;
- break;
- }else{
- p = merge_pagelist(a[i], p);
- a[i] = 0;
- }
- }
- if( i==N_SORT_BUCKET-1 ){
- /* Coverage: To get here, there need to be 2^(N_SORT_BUCKET)
- ** elements in the input list. This is possible, but impractical.
- ** Testing this line is the point of global variable
- ** sqlite3_pager_n_sort_bucket.
- */
- a[i] = merge_pagelist(a[i], p);
- }
- }
- p = a[0];
- for(i=1; i<N_SORT_BUCKET; i++){
- p = merge_pagelist(p, a[i]);
- }
- return p;
- }
- /*
- ** Given a list of pages (connected by the PgHdr.pDirty pointer) write
- ** every one of those pages out to the database file and mark them all
- ** as clean.
- */
- static int pager_write_pagelist(PgHdr *pList){
- Pager *pPager;
- PgHdr *p;
- int rc;
- if( pList==0 ) return SQLITE_OK;
- pPager = pList->pPager;
- /* At this point there may be either a RESERVED or EXCLUSIVE lock on the
- ** database file. If there is already an EXCLUSIVE lock, the following
- ** calls to sqlite3OsLock() are no-ops.
- **
- ** Moving the lock from RESERVED to EXCLUSIVE actually involves going
- ** through an intermediate state PENDING. A PENDING lock prevents new
- ** readers from attaching to the database but is unsufficient for us to
- ** write. The idea of a PENDING lock is to prevent new readers from
- ** coming in while we wait for existing readers to clear.
- **
- ** While the pager is in the RESERVED state, the original database file
- ** is unchanged and we can rollback without having to playback the
- ** journal into the original database file. Once we transition to
- ** EXCLUSIVE, it means the database file has been changed and any rollback
- ** will require a journal playback.
- */
- rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- pList = sort_pagelist(pList);
- for(p=pList; p; p=p->pDirty){
- assert( p->dirty );
- p->dirty = 0;
- }
- while( pList ){
- /* If the file has not yet been opened, open it now. */
- if( !pPager->fd->pMethods ){
- assert(pPager->tempFile);
- rc = sqlite3PagerOpentemp(pPager->pVfs, pPager->fd, pPager->zFilename,
- pPager->vfsFlags);
- if( rc ) return rc;
- }
- /* If there are dirty pages in the page cache with page numbers greater
- ** than Pager.dbSize, this means sqlite3PagerTruncate() was called to
- ** make the file smaller (presumably by auto-vacuum code). Do not write
- ** any such pages to the file.
- */
- if( pList->pgno<=pPager->dbSize ){
- i64 offset = (pList->pgno-1)*(i64)pPager->pageSize;
- char *pData = CODEC2(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
- PAGERTRACE4("STORE %d page %d hash(%08x)n",
- PAGERID(pPager), pList->pgno, pager_pagehash(pList));
- IOTRACE(("PGOUT %p %dn", pPager, pList->pgno));
- rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
- PAGER_INCR(sqlite3_pager_writedb_count);
- PAGER_INCR(pPager->nWrite);
- if( pList->pgno==1 ){
- memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers));
- }
- }
- #ifndef NDEBUG
- else{
- PAGERTRACE3("NOSTORE %d page %dn", PAGERID(pPager), pList->pgno);
- }
- #endif
- if( rc ) return rc;
- #ifdef SQLITE_CHECK_PAGES
- pList->pageHash = pager_pagehash(pList);
- #endif
- pList = pList->pDirty;
- }
- return SQLITE_OK;
- }
- /*
- ** Collect every dirty page into a dirty list and
- ** return a pointer to the head of that list. All pages are
- ** collected even if they are still in use.
- */
- static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
- #ifndef NDEBUG
- /* Verify the sanity of the dirty list when we are running
- ** in debugging mode. This is expensive, so do not
- ** do this on a normal build. */
- int n1 = 0;
- int n2 = 0;
- PgHdr *p;
- for(p=pPager->pAll; p; p=p->pNextAll){ if( p->dirty ) n1++; }
- for(p=pPager->pDirty; p; p=p->pDirty){ n2++; }
- assert( n1==n2 );
- #endif
- return pPager->pDirty;
- }
- /*
- ** Return 1 if there is a hot journal on the given pager.
- ** A hot journal is one that needs to be played back.
- **
- ** If the current size of the database file is 0 but a journal file
- ** exists, that is probably an old journal left over from a prior
- ** database with the same name. Just delete the journal.
- **
- ** Return negative if unable to determine the status of the journal.
- */
- static int hasHotJournal(Pager *pPager){
- sqlite3_vfs *pVfs = pPager->pVfs;
- int rc;
- if( !pPager->useJournal ) return 0;
- if( !pPager->fd->pMethods ) return 0;
- rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS);
- if( rc<=0 ){
- return rc;
- }
- if( sqlite3OsCheckReservedLock(pPager->fd) ){
- return 0;
- }
- if( sqlite3PagerPagecount(pPager)==0 ){
- sqlite3OsDelete(pVfs, pPager->zJournal, 0);
- return 0;
- }else{
- return 1;
- }
- }
- /*
- ** Try to find a page in the cache that can be recycled.
- **
- ** This routine may return SQLITE_IOERR, SQLITE_FULL or SQLITE_OK. It
- ** does not set the pPager->errCode variable.
- */
- static int pager_recycle(Pager *pPager, PgHdr **ppPg){
- PgHdr *pPg;
- *ppPg = 0;
- /* It is illegal to call this function unless the pager object
- ** pointed to by pPager has at least one free page (page with nRef==0).
- */
- assert(!MEMDB);
- assert(pPager->lru.pFirst);
- /* Find a page to recycle. Try to locate a page that does not
- ** require us to do an fsync() on the journal.
- */
- pPg = pPager->lru.pFirstSynced;
- /* If we could not find a page that does not require an fsync()
- ** on the journal file then fsync the journal file. This is a
- ** very slow operation, so we work hard to avoid it. But sometimes
- ** it can't be helped.
- */
- if( pPg==0 && pPager->lru.pFirst){
- int iDc = sqlite3OsDeviceCharacteristics(pPager->fd);
- int rc = syncJournal(pPager);
- if( rc!=0 ){
- return rc;
- }
- if( pPager->fullSync && 0==(iDc&SQLITE_IOCAP_SAFE_APPEND) ){
- /* If in full-sync mode, write a new journal header into the
- ** journal file. This is done to avoid ever modifying a journal
- ** header that is involved in the rollback of pages that have
- ** already been written to the database (in case the header is
- ** trashed when the nRec field is updated).
- */
- pPager->nRec = 0;
- assert( pPager->journalOff > 0 );
- assert( pPager->doNotSync==0 );
- rc = writeJournalHdr(pPager);
- if( rc!=0 ){
- return rc;
- }
- }
- pPg = pPager->lru.pFirst;
- }
- assert( pPg->nRef==0 );
- /* Write the page to the database file if it is dirty.
- */
- if( pPg->dirty ){
- int rc;
- assert( pPg->needSync==0 );
- makeClean(pPg);
- pPg->dirty = 1;
- pPg->pDirty = 0;
- rc = pager_write_pagelist( pPg );
- pPg->dirty = 0;
- if( rc!=SQLITE_OK ){
- return rc;
- }
- }
- assert( pPg->dirty==0 );
- /* If the page we are recycling is marked as alwaysRollback, then
- ** set the global alwaysRollback flag, thus disabling the
- ** sqlite3PagerDontRollback() optimization for the rest of this transaction.
- ** It is necessary to do this because the page marked alwaysRollback
- ** might be reloaded at a later time but at that point we won't remember
- ** that is was marked alwaysRollback. This means that all pages must
- ** be marked as alwaysRollback from here on out.
- */
- if( pPg->alwaysRollback ){
- IOTRACE(("ALWAYS_ROLLBACK %pn", pPager))
- pPager->alwaysRollback = 1;
- }
- /* Unlink the old page from the free list and the hash table
- */
- unlinkPage(pPg);
- assert( pPg->pgno==0 );
- *ppPg = pPg;
- return SQLITE_OK;
- }
- #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
- /*
- ** This function is called to free superfluous dynamically allocated memory
- ** held by the pager system. Memory in use by any SQLite pager allocated
- ** by the current thread may be sqlite3_free()ed.
- **
- ** nReq is the number of bytes of memory required. Once this much has
- ** been released, the function returns. The return value is the total number
- ** of bytes of memory released.
- */
- int sqlite3PagerReleaseMemory(int nReq){
- int nReleased = 0; /* Bytes of memory released so far */
- sqlite3_mutex *mutex; /* The MEM2 mutex */
- Pager *pPager; /* For looping over pagers */
- BusyHandler *savedBusy; /* Saved copy of the busy handler */
- int rc = SQLITE_OK;
- /* Acquire the memory-management mutex
- */
- mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM2);
- sqlite3_mutex_enter(mutex);
- /* Signal all database connections that memory management wants
- ** to have access to the pagers.
- */
- for(pPager=sqlite3PagerList; pPager; pPager=pPager->pNext){
- pPager->iInUseMM = 1;
- }
- while( rc==SQLITE_OK && (nReq<0 || nReleased<nReq) ){
- PgHdr *pPg;
- PgHdr *pRecycled;
-
- /* Try to find a page to recycle that does not require a sync(). If
- ** this is not possible, find one that does require a sync().
- */
- sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU));
- pPg = sqlite3LruPageList.pFirstSynced;
- while( pPg && (pPg->needSync || pPg->pPager->iInUseDB) ){
- pPg = pPg->gfree.pNext;
- }
- if( !pPg ){
- pPg = sqlite3LruPageList.pFirst;
- while( pPg && pPg->pPager->iInUseDB ){
- pPg = pPg->gfree.pNext;
- }
- }
- sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU));
- /* If pPg==0, then the block above has failed to find a page to
- ** recycle. In this case return early - no further memory will
- ** be released.
- */
- if( !pPg ) break;
- pPager = pPg->pPager;
- assert(!pPg->needSync || pPg==pPager->lru.pFirst);
- assert(pPg->needSync || pPg==pPager->lru.pFirstSynced);
-
- savedBusy = pPager->pBusyHandler;
- pPager->pBusyHandler = 0;
- rc = pager_recycle(pPager, &pRecycled);
- pPager->pBusyHandler = savedBusy;
- assert(pRecycled==pPg || rc!=SQLITE_OK);
- if( rc==SQLITE_OK ){
- /* We've found a page to free. At this point the page has been
- ** removed from the page hash-table, free-list and synced-list
- ** (pFirstSynced). It is still in the all pages (pAll) list.
- ** Remove it from this list before freeing.
- **
- ** Todo: Check the Pager.pStmt list to make sure this is Ok. It
- ** probably is though.
- */
- PgHdr *pTmp;
- assert( pPg );
- if( pPg==pPager->pAll ){
- pPager->pAll = pPg->pNextAll;
- }else{
- for( pTmp=pPager->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ){}
- pTmp->pNextAll = pPg->pNextAll;
- }
- nReleased += (
- sizeof(*pPg) + pPager->pageSize
- + sizeof(u32) + pPager->nExtra
- + MEMDB*sizeof(PgHistory)
- );
- IOTRACE(("PGFREE %p %d *n", pPager, pPg->pgno));
- PAGER_INCR(sqlite3_pager_pgfree_count);
- sqlite3_free(pPg->pData);
- sqlite3_free(pPg);
- pPager->nPage--;
- }else{
- /* An error occured whilst writing to the database file or
- ** journal in pager_recycle(). The error is not returned to the
- ** caller of this function. Instead, set the Pager.errCode variable.
- ** The error will be returned to the user (or users, in the case
- ** of a shared pager cache) of the pager for which the error occured.
- */
- assert(
- (rc&0xff)==SQLITE_IOERR ||
- rc==SQLITE_FULL ||
- rc==SQLITE_BUSY
- );
- assert( pPager->state>=PAGER_RESERVED );
- pager_error(pPager, rc);
- }
- }
- /* Clear the memory management flags and release the mutex
- */
- for(pPager=sqlite3PagerList; pPager; pPager=pPager->pNext){
- pPager->iInUseMM = 0;
- }
- sqlite3_mutex_leave(mutex);
- /* Return the number of bytes released
- */
- return nReleased;
- }
- #endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
- /*
- ** Read the content of page pPg out of the database file.
- */
- static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){
- int rc;
- i64 offset;
- assert( MEMDB==0 );
- assert(pPager->fd->pMethods||pPager->tempFile);
- if( !pPager->fd->pMethods ){
- return SQLITE_IOERR_SHORT_READ;
- }
- offset = (pgno-1)*(i64)pPager->pageSize;
- rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize, offset);
- PAGER_INCR(sqlite3_pager_readdb_count);
- PAGER_INCR(pPager->nRead);
- IOTRACE(("PGIN %p %dn", pPager, pgno));
- if( pgno==1 ){
- memcpy(&pPager->dbFileVers, &((u8*)PGHDR_TO_DATA(pPg))[24],
- sizeof(pPager->dbFileVers));
- }
- CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
- PAGERTRACE4("FETCH %d page %d hash(%08x)n",
- PAGERID(pPager), pPg->pgno, pager_pagehash(pPg));
- return rc;
- }
- /*
- ** This function is called to obtain the shared lock required before
- ** data may be read from the pager cache. If the shared lock has already
- ** been obtained, this function is a no-op.
- **
- ** Immediately after obtaining the shared lock (if required), this function
- ** checks for a hot-journal file. If one is found, an emergency rollback
- ** is performed immediately.
- */
- static int pagerSharedLock(Pager *pPager){
- int rc = SQLITE_OK;
- int isHot = 0;
- /* If this database is opened for exclusive access, has no outstanding
- ** page references and is in an error-state, now is the chance to clear
- ** the error. Discard the contents of the pager-cache and treat any
- ** open journal file as a hot-journal.
- */
- if( !MEMDB && pPager->exclusiveMode && pPager->nRef==0 && pPager->errCode ){
- if( pPager->journalOpen ){
- isHot = 1;
- }
- pager_reset(pPager);
- pPager->errCode = SQLITE_OK;
- }
- /* If the pager is still in an error state, do not proceed. The error
- ** state will be cleared at some point in the future when all page
- ** references are dropped and the cache can be discarded.
- */
- if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
- return pPager->errCode;
- }
- if( pPager->state==PAGER_UNLOCK || isHot ){
- sqlite3_vfs *pVfs = pPager->pVfs;
- if( !MEMDB ){
- assert( pPager->nRef==0 );
- if( !pPager->noReadlock ){
- rc = pager_wait_on_lock(pPager, SHARED_LOCK);
- if( rc!=SQLITE_OK ){
- return pager_error(pPager, rc);
- }
- assert( pPager->state>=SHARED_LOCK );
- }
-
- /* If a journal file exists, and there is no RESERVED lock on the
- ** database file, then it either needs to be played back or deleted.
- */
- rc = hasHotJournal(pPager);
- if( rc<0 ){
- return SQLITE_IOERR_NOMEM;
- }
- if( rc==1 || isHot ){
- /* Get an EXCLUSIVE lock on the database file. At this point it is
- ** important that a RESERVED lock is not obtained on the way to the
- ** EXCLUSIVE lock. If it were, another process might open the
- ** database file, detect the RESERVED lock, and conclude that the
- ** database is safe to read while this process is still rolling it
- ** back.
- **
- ** Because the intermediate RESERVED lock is not requested, the
- ** second process will get to this point in the code and fail to
- ** obtain its own EXCLUSIVE lock on the database file.
- */
- if( pPager->state<EXCLUSIVE_LOCK ){
- rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
- if( rc!=SQLITE_OK ){
- pager_unlock(pPager);
- return pager_error(pPager, rc);
- }
- pPager->state = PAGER_EXCLUSIVE;
- }
-
- /* Open the journal for reading only. Return SQLITE_BUSY if
- ** we are unable to open the journal file.
- **
- ** The journal file does not need to be locked itself. The
- ** journal file is never open unless the main database file holds
- ** a write lock, so there is never any chance of two or more
- ** processes opening the journal at the same time.
- **
- ** Open the journal for read/write access. This is because in
- ** exclusive-access mode the file descriptor will be kept open and
- ** possibly used for a transaction later on. On some systems, the
- ** OsTruncate() call used in exclusive-access mode also requires
- ** a read/write file handle.
- */
- if( !isHot ){
- int res = sqlite3OsAccess(pVfs,pPager->zJournal,SQLITE_ACCESS_EXISTS);
- if( res==1 ){
- int fout = 0;
- int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
- assert( !pPager->tempFile );
- rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout);
- assert( rc!=SQLITE_OK || pPager->jfd->pMethods );
- if( fout&SQLITE_OPEN_READONLY ){
- rc = SQLITE_BUSY;
- sqlite3OsClose(pPager->jfd);
- }
- }else{
- rc = (res==0?SQLITE_BUSY:SQLITE_IOERR_NOMEM);
- }
- }
- if( rc!=SQLITE_OK ){
- pager_unlock(pPager);
- switch( rc ){
- case SQLITE_NOMEM:
- case SQLITE_IOERR_UNLOCK:
- case SQLITE_IOERR_NOMEM:
- return rc;
- default:
- return SQLITE_BUSY;
- }
- }
- pPager->journalOpen = 1;
- pPager->journalStarted = 0;
- pPager->journalOff = 0;
- pPager->setMaster = 0;
- pPager->journalHdr = 0;
-
- /* Playback and delete the journal. Drop the database write
- ** lock and reacquire the read lock.
- */
- rc = pager_playback(pPager, 1);
- if( rc!=SQLITE_OK ){
- return pager_error(pPager, rc);
- }
- assert(pPager->state==PAGER_SHARED ||
- (pPager->exclusiveMode && pPager->state>PAGER_SHARED)
- );
- }
- if( pPager->pAll ){
- /* The shared-lock has just been acquired on the database file
- ** and there are already pages in the cache (from a previous
- ** read or write transaction). Check to see if the database
- ** has been modified. If the database has changed, flush the
- ** cache.
- **
- ** Database changes is detected by looking at 15 bytes beginning
- ** at offset 24 into the file. The first 4 of these 16 bytes are
- ** a 32-bit counter that is incremented with each change. The
- ** other bytes change randomly with each file change when
- ** a codec is in use.
- **
- ** There is a vanishingly small chance that a change will not be
- ** detected. The chance of an undetected change is so small that
- ** it can be neglected.
- */
- char dbFileVers[sizeof(pPager->dbFileVers)];
- sqlite3PagerPagecount(pPager);
- if( pPager->errCode ){
- return pPager->errCode;
- }
- if( pPager->dbSize>0 ){
- IOTRACE(("CKVERS %p %dn", pPager, sizeof(dbFileVers)));
- rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- }else{
- memset(dbFileVers, 0, sizeof(dbFileVers));
- }
- if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
- pager_reset(pPager);
- }
- }
- }
- assert( pPager->exclusiveMode || pPager->state<=PAGER_SHARED );
- if( pPager->state==PAGER_UNLOCK ){
- pPager->state = PAGER_SHARED;
- }
- }
- return rc;
- }
- /*
- ** Allocate a PgHdr object. Either create a new one or reuse
- ** an existing one that is not otherwise in use.
- **
- ** A new PgHdr structure is created if any of the following are
- ** true:
- **
- ** (1) We have not exceeded our maximum allocated cache size
- ** as set by the "PRAGMA cache_size" command.
- **
- ** (2) There are no unused PgHdr objects available at this time.
- **
- ** (3) This is an in-memory database.
- **
- ** (4) There are no PgHdr objects that do not require a journal
- ** file sync and a sync of the journal file is currently
- ** prohibited.
- **
- ** Otherwise, reuse an existing PgHdr. In other words, reuse an
- ** existing PgHdr if all of the following are true:
- **
- ** (1) We have reached or exceeded the maximum cache size
- ** allowed by "PRAGMA cache_size".
- **
- ** (2) There is a PgHdr available with PgHdr->nRef==0
- **
- ** (3) We are not in an in-memory database
- **
- ** (4) Either there is an available PgHdr that does not need
- ** to be synced to disk or else disk syncing is currently
- ** allowed.
- */
- static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){
- int rc = SQLITE_OK;
- PgHdr *pPg;
- int nByteHdr;
- /* Create a new PgHdr if any of the four conditions defined
- ** above are met: */
- if( pPager->nPage<pPager->mxPage
- || pPager->lru.pFirst==0
- || MEMDB
- || (pPager->lru.pFirstSynced==0 && pPager->doNotSync)
- ){
- void *pData;
- if( pPager->nPage>=pPager->nHash ){
- pager_resize_hash_table(pPager,
- pPager->nHash<256 ? 256 : pPager->nHash*2);
- if( pPager->nHash==0 ){
- rc = SQLITE_NOMEM;
- goto pager_allocate_out;
- }
- }
- pagerLeave(pPager);
- nByteHdr = sizeof(*pPg) + sizeof(u32) + pPager->nExtra
- + MEMDB*sizeof(PgHistory);
- pPg = sqlite3_malloc( nByteHdr );
- if( pPg ){
- pData = sqlite3_malloc( pPager->pageSize );
- if( pData==0 ){
- sqlite3_free(pPg);
- pPg = 0;
- }
- }
- pagerEnter(pPager);
- if( pPg==0 ){
- rc = SQLITE_NOMEM;
- goto pager_allocate_out;
- }
- memset(pPg, 0, nByteHdr);
- pPg->pData = pData;
- pPg->pPager = pPager;
- pPg->pNextAll = pPager->pAll;
- pPager->pAll = pPg;
- pPager->nPage++;
- }else{
- /* Recycle an existing page with a zero ref-count. */
- rc = pager_recycle(pPager, &pPg);
- if( rc==SQLITE_BUSY ){
- rc = SQLITE_IOERR_BLOCKED;
- }
- if( rc!=SQLITE_OK ){
- goto pager_allocate_out;
- }
- assert( pPager->state>=SHARED_LOCK );
- assert(pPg);
- }
- *ppPg = pPg;
- pager_allocate_out:
- return rc;
- }
- /*
- ** Make sure we have the content for a page. If the page was
- ** previously acquired with noContent==1, then the content was
- ** just initialized to zeros instead of being read from disk.
- ** But now we need the real data off of disk. So make sure we
- ** have it. Read it in if we do not have it already.
- */
- static int pager_get_content(PgHdr *pPg){
- if( pPg->needRead ){
- int rc = readDbPage(pPg->pPager, pPg, pPg->pgno);
- if( rc==SQLITE_OK ){
- pPg->needRead = 0;
- }else{
- return rc;
- }
- }
- return SQLITE_OK;
- }
- /*
- ** Acquire a page.
- **
- ** A read lock on the disk file is obtained when the first page is acquired.
- ** This read lock is dropped when the last page is released.
- **
- ** This routine works for any page number greater than 0. If the database
- ** file is smaller than the requested page, then no actual disk
- ** read occurs and the memory image of the page is initialized to
- ** all zeros. The extra data appended to a page is always initialized
- ** to zeros the first time a page is loaded into memory.
- **
- ** The acquisition might fail for several reasons. In all cases,
- ** an appropriate error code is returned and *ppPage is set to NULL.
- **
- ** See also sqlite3PagerLookup(). Both this routine and Lookup() attempt
- ** to find a page in the in-memory cache first. If the page is not already
- ** in memory, this routine goes to disk to read it in whereas Lookup()
- ** just returns 0. This routine acquires a read-lock the first time it
- ** has to go to disk, and could also playback an old journal if necessary.
- ** Since Lookup() never goes to disk, it never has to deal with locks
- ** or journal files.
- **
- ** If noContent is false, the page contents are actually read from disk.
- ** If noContent is true, it means that we do not care about the contents
- ** of the page at this time, so do not do a disk read. Just fill in the
- ** page content with zeros. But mark the fact that we have not read the
- ** content by setting the PgHdr.needRead flag. Later on, if
- ** sqlite3PagerWrite() is called on this page or if this routine is
- ** called again with noContent==0, that means that the content is needed
- ** and the disk read should occur at that point.
- */
- static int pagerAcquire(
- Pager *pPager, /* The pager open on the database file */
- Pgno pgno, /* Page number to fetch */
- DbPage **ppPage, /* Write a pointer to the page here */
- int noContent /* Do not bother reading content from disk if true */
- ){
- PgHdr *pPg;
- int rc;
- assert( pPager->state==PAGER_UNLOCK || pPager->nRef>0 || pgno==1 );
- /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
- ** number greater than this, or zero, is requested.
- */
- if( pgno>PAGER_MAX_PGNO || pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){
- return SQLITE_CORRUPT_BKPT;
- }
- /* Make sure we have not hit any critical errors.
- */
- assert( pPager!=0 );
- *ppPage = 0;
- /* If this is the first page accessed, then get a SHARED lock
- ** on the database file. pagerSharedLock() is a no-op if
- ** a database lock is already held.
- */
- rc = pagerSharedLock(pPager);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- assert( pPager->state!=PAGER_UNLOCK );
- pPg = pager_lookup(pPager, pgno);
- if( pPg==0 ){
- /* The requested page is not in the page cache. */
- int nMax;
- int h;
- PAGER_INCR(pPager->nMiss);
- rc = pagerAllocatePage(pPager, &pPg);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- pPg->pgno = pgno;
- assert( !MEMDB || pgno>pPager->stmtSize );
- pPg->inJournal = sqlite3BitvecTest(pPager->pInJournal, pgno);
- pPg->needSync = 0;
- makeClean(pPg);
- pPg->nRef = 1;
- pPager->nRef++;
- if( pPager->nExtra>0 ){
- memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
- }
- nMax = sqlite3PagerPagecount(pPager);
- if( pPager->errCode ){
- rc = pPager->errCode;
- sqlite3PagerUnref(pPg);
- return rc;
- }
- /* Populate the page with data, either by reading from the database
- ** file, or by setting the entire page to zero.
- */
- if( nMax<(int)pgno || MEMDB || (noContent && !pPager->alwaysRollback) ){
- if( pgno>pPager->mxPgno ){
- sqlite3PagerUnref(pPg);
- return SQLITE_FULL;
- }
- memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
- pPg->needRead = noContent && !pPager->alwaysRollback;
- IOTRACE(("ZERO %p %dn", pPager, pgno));
- }else{
- rc = readDbPage(pPager, pPg, pgno);
- if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
- pPg->pgno = 0;
- sqlite3PagerUnref(pPg);
- return rc;
- }
- pPg->needRead = 0;
- }
- /* Link the page into the page hash table */
- h = pgno & (pPager->nHash-1);
- assert( pgno!=0 );
- pPg->pNextHash = pPager->aHash[h];
- pPager->aHash[h] = pPg;
- if( pPg->pNextHash ){
- assert( pPg->pNextHash->pPrevHash==0 );
- pPg->pNextHash->pPrevHash = pPg;
- }
- #ifdef SQLITE_CHECK_PAGES
- pPg->pageHash = pager_pagehash(pPg);
- #endif
- }else{
- /* The requested page is in the page cache. */
- assert(pPager->nRef>0 || pgno==1);
- PAGER_INCR(pPager->nHit);
- if( !noContent ){
- rc = pager_get_content(pPg);
- if( rc ){
- return rc;
- }
- }
- page_ref(pPg);
- }
- *ppPage = pPg;
- return SQLITE_OK;
- }
- int sqlite3PagerAcquire(
- Pager *pPager, /* The pager open on the database file */
- Pgno pgno, /* Page number to fetch */
- DbPage **ppPage, /* Write a pointer to the page here */
- int noContent /* Do not bother reading content from disk if true */
- ){
- int rc;
- pagerEnter(pPager);
- rc = pagerAcquire(pPager, pgno, ppPage, noContent);
- pagerLeave(pPager);
- return rc;
- }
- /*
- ** Acquire a page if it is already in the in-memory cache. Do
- ** not read the page from disk. Return a pointer to the page,
- ** or 0 if the page is not in cache.
- **
- ** See also sqlite3PagerGet(). The difference between this routine
- ** and sqlite3PagerGet() is that _get() will go to the disk and read
- ** in the page if the page is not already in cache. This routine
- ** returns NULL if the page is not in cache or if a disk I/O error
- ** has ever happened.
- */
- DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
- PgHdr *pPg = 0;
- assert( pPager!=0 );
- assert( pgno!=0 );
- pagerEnter(pPager);
- if( pPager->state==PAGER_UNLOCK ){
- assert( !pPager->pAll || pPager->exclusiveMode );
- }else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
- /* Do nothing */
- }else if( (pPg = pager_lookup(pPager, pgno))!=0 ){
- page_ref(pPg);
- }
- pagerLeave(pPager);
- return pPg;
- }
- /*
- ** Release a page.
- **
- ** If the number of references to the page drop to zero, then the
- ** page is added to the LRU list. When all references to all pages
- ** are released, a rollback occurs and the lock on the database is
- ** removed.
- */
- int sqlite3PagerUnref(DbPage *pPg){
- Pager *pPager = pPg->pPager;
- /* Decrement the reference count for this page
- */
- assert( pPg->nRef>0 );
- pagerEnter(pPg->pPager);
- pPg->nRef--;
- CHECK_PAGE(pPg);
- /* When the number of references to a page reach 0, call the
- ** destructor and add the page to the freelist.
- */
- if( pPg->nRef==0 ){
- lruListAdd(pPg);
- if( pPager->xDestructor ){
- pPager->xDestructor(pPg, pPager->pageSize);
- }
-
- /* When all pages reach the freelist, drop the read lock from
- ** the database file.
- */
- pPager->nRef--;
- assert( pPager->nRef>=0 );
- if( pPager->nRef==0 && (!pPager->exclusiveMode || pPager->journalOff>0) ){
- pagerUnlockAndRollback(pPager);
- }
- }
- pagerLeave(pPager);
- return SQLITE_OK;
- }
- /*
- ** Create a journal file for pPager. There should already be a RESERVED
- ** or EXCLUSIVE lock on the database file when this routine is called.
- **
- ** Return SQLITE_OK if everything. Return an error code and release the
- ** write lock if anything goes wrong.
- */
- static int pager_open_journal(Pager *pPager){
- sqlite3_vfs *pVfs = pPager->pVfs;
- int flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_CREATE);
- int rc;
- assert( !MEMDB );
- assert( pPager->state>=PAGER_RESERVED );
- assert( pPager->journalOpen==0 );
- assert( pPager->useJournal );
- assert( pPager->pInJournal==0 );
- sqlite3PagerPagecount(pPager);
- pagerLeave(pPager);
- pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize);
- pagerEnter(pPager);
- if( pPager->pInJournal==0 ){
- rc = SQLITE_NOMEM;
- goto failed_to_open_journal;
- }
- if( pPager->tempFile ){
- flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
- }else{
- flags |= (SQLITE_OPEN_MAIN_JOURNAL);
- }
- #ifdef SQLITE_ENABLE_ATOMIC_WRITE
- rc = sqlite3JournalOpen(
- pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
- );
- #else
- rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
- #endif
- assert( rc!=SQLITE_OK || pPager->jfd->pMethods );
- pPager->journalOff = 0;
- pPager->setMaster = 0;
- pPager->journalHdr = 0;
- if( rc!=SQLITE_OK ){
- if( rc==SQLITE_NOMEM ){
- sqlite3OsDelete(pVfs, pPager->zJournal, 0);
- }
- goto failed_to_open_journal;
- }
- pPager->journalOpen = 1;
- pPager->journalStarted = 0;
- pPager->needSync = 0;
- pPager->alwaysRollback = 0;
- pPager->nRec = 0;
- if( pPager->errCode ){
- rc = pPager->errCode;
- goto failed_to_open_journal;
- }
- pPager->origDbSize = pPager->dbSize;
- rc = writeJournalHdr(pPager);
- if( pPager->stmtAutoopen && rc==SQLITE_OK ){
- rc = sqlite3PagerStmtBegin(pPager);
- }
- if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && rc!=SQLITE_IOERR_NOMEM ){
- rc = pager_end_transaction(pPager);
- if( rc==SQLITE_OK ){
- rc = SQLITE_FULL;
- }
- }
- return rc;
- failed_to_open_journal:
- sqlite3BitvecDestroy(pPager->pInJournal);
- pPager->pInJournal = 0;
- return rc;
- }
- /*
- ** Acquire a write-lock on the database. The lock is removed when
- ** the any of the following happen:
- **
- ** * sqlite3PagerCommitPhaseTwo() is called.
- ** * sqlite3PagerRollback() is called.
- ** * sqlite3PagerClose() is called.
- ** * sqlite3PagerUnref() is called to on every outstanding page.
- **
- ** The first parameter to this routine is a pointer to any open page of the
- ** database file. Nothing changes about the page - it is used merely to
- ** acquire a pointer to the Pager structure and as proof that there is
- ** already a read-lock on the database.
- **
- ** The second parameter indicates how much space in bytes to reserve for a
- ** master journal file-name at the start of the journal when it is created.
- **
- ** A journal file is opened if this is not a temporary file. For temporary
- ** files, the opening of the journal file is deferred until there is an
- ** actual need to write to the journal.
- **
- ** If the database is already reserved for writing, this routine is a no-op.
- **
- ** If exFlag is true, go ahead and get an EXCLUSIVE lock on the file
- ** immediately instead of waiting until we try to flush the cache. The
- ** exFlag is ignored if a transaction is already active.
- */
- int sqlite3PagerBegin(DbPage *pPg, int exFlag){
- Pager *pPager = pPg->pPager;
- int rc = SQLITE_OK;
- pagerEnter(pPager);
- assert( pPg->nRef>0 );
- assert( pPager->state!=PAGER_UNLOCK );
- if( pPager->state==PAGER_SHARED ){
- assert( pPager->pInJournal==0 );
- if( MEMDB ){
- pPager->state = PAGER_EXCLUSIVE;
- pPager->origDbSize = pPager->dbSize;
- }else{
- rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
- if( rc==SQLITE_OK ){
- pPager->state = PAGER_RESERVED;
- if( exFlag ){
- rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
- }
- }
- if( rc!=SQLITE_OK ){
- pagerLeave(pPager);
- return rc;
- }
- pPager->dirtyCache = 0;
- PAGERTRACE2("TRANSACTION %dn", PAGERID(pPager));
- if( pPager->useJournal && !pPager->tempFile ){
- rc = pager_open_journal(pPager);
- }
- }
- }else if( pPager->journalOpen && pPager->journalOff==0 ){
- /* This happens when the pager was in exclusive-access mode last
- ** time a (read or write) transaction was successfully concluded
- ** by this connection. Instead of deleting the journal file it was
- ** kept open and truncated to 0 bytes.
- */
- assert( pPager->nRec==0 );
- assert( pPager->origDbSize==0 );
- assert( pPager->pInJournal==0 );
- sqlite3PagerPagecount(pPager);
- pagerLeave(pPager);
- pPager->pInJournal = sqlite3BitvecCreate( pPager->dbSize );
- pagerEnter(pPager);
- if( !pPager->pInJournal ){
- rc = SQLITE_NOMEM;
- }else{
- pPager->origDbSize = pPager->dbSize;
- rc = writeJournalHdr(pPager);
- }
- }
- assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK );
- pagerLeave(pPager);
- return rc;
- }
- /*
- ** Make a page dirty. Set its dirty flag and add it to the dirty
- ** page list.
- */
- static void makeDirty(PgHdr *pPg){
- if( pPg->dirty==0 ){
- Pager *pPager = pPg->pPager;
- pPg->dirty = 1;
- pPg->pDirty = pPager->pDirty;
- if( pPager->pDirty ){
- pPager->pDirty->pPrevDirty = pPg;
- }
- pPg->pPrevDirty = 0;
- pPager->pDirty = pPg;
- }
- }
- /*
- ** Make a page clean. Clear its dirty bit and remove it from the
- ** dirty page list.
- */
- static void makeClean(PgHdr *pPg){
- if( pPg->dirty ){
- pPg->dirty = 0;
- if( pPg->pDirty ){
- assert( pPg->pDirty->pPrevDirty==pPg );
- pPg->pDirty->pPrevDirty = pPg->pPrevDirty;
- }
- if( pPg->pPrevDirty ){
- assert( pPg->pPrevDirty->pDirty==pPg );
- pPg->pPrevDirty->pDirty = pPg->pDirty;
- }else{
- assert( pPg->pPager->pDirty==pPg );
- pPg->pPager->pDirty = pPg->pDirty;
- }
- }
- }
- /*
- ** Mark a data page as writeable. The page is written into the journal
- ** if it is not there already. This routine must be called before making
- ** changes to a page.
- **
- ** The first time this routine is called, the pager creates a new
- ** journal and acquires a RESERVED lock on the database. If the RESERVED
- ** lock could not be acquired, this routine returns SQLITE_BUSY. The
- ** calling routine must check for that return value and be careful not to
- ** change any page data until this routine returns SQLITE_OK.
- **
- ** If the journal file could not be written because the disk is full,
- ** then this routine returns SQLITE_FULL and does an immediate rollback.
- ** All subsequent write attempts also return SQLITE_FULL until there
- ** is a call to sqlite3PagerCommit() or sqlite3PagerRollback() to
- ** reset.
- */
- static int pager_write(PgHdr *pPg){
- void *pData = PGHDR_TO_DATA(pPg);
- Pager *pPager = pPg->pPager;
- int rc = SQLITE_OK;
- /* Check for errors
- */
- if( pPager->errCode ){
- return pPager->errCode;
- }
- if( pPager->readOnly ){
- return SQLITE_PERM;
- }
- assert( !pPager->setMaster );
- CHECK_PAGE(pPg);
- /* If this page was previously acquired with noContent==1, that means
- ** we didn't really read in the content of the page. This can happen
- ** (for example) when the page is being moved to the freelist. But
- ** now we are (perhaps) moving the page off of the freelist for
- ** reuse and we need to know its original content so that content
- ** can be stored in the rollback journal. So do the read at this
- ** time.
- */
- rc = pager_get_content(pPg);
- if( rc ){
- return rc;
- }
- /* Mark the page as dirty. If the page has already been written
- ** to the journal then we can return right away.
- */
- makeDirty(pPg);
- if( pPg->inJournal && (pageInStatement(pPg) || pPager->stmtInUse==0) ){
- pPager->dirtyCache = 1;
- }else{
- /* If we get this far, it means that the page needs to be
- ** written to the transaction journal or the ckeckpoint journal
- ** or both.
- **
- ** First check to see that the transaction journal exists and
- ** create it if it does not.
- */
- assert( pPager->state!=PAGER_UNLOCK );
- rc = sqlite3PagerBegin(pPg, 0);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- assert( pPager->state>=PAGER_RESERVED );
- if( !pPager->journalOpen && pPager->useJournal ){
- rc = pager_open_journal(pPager);
- if( rc!=SQLITE_OK ) return rc;
- }
- assert( pPager->journalOpen || !pPager->useJournal );
- pPager->dirtyCache = 1;
-
- /* The transaction journal now exists and we have a RESERVED or an
- ** EXCLUSIVE lock on the main database file. Write the current page to
- ** the transaction journal if it is not there already.
- */
- if( !pPg->inJournal && (pPager->useJournal || MEMDB) ){
- if( (int)pPg->pgno <= pPager->origDbSize ){
- if( MEMDB ){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- PAGERTRACE3("JOURNAL %d page %dn", PAGERID(pPager), pPg->pgno);
- assert( pHist->pOrig==0 );
- pHist->pOrig = sqlite3_malloc( pPager->pageSize );
- if( !pHist->pOrig ){
- return SQLITE_NOMEM;
- }
- memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize);
- }else{
- u32 cksum;
- char *pData2;
- /* We should never write to the journal file the page that
- ** contains the database locks. The following assert verifies
- ** that we do not. */
- assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
- pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
- cksum = pager_cksum(pPager, (u8*)pData2);
- rc = write32bits(pPager->jfd, pPager->journalOff, pPg->pgno);
- if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize,
- pPager->journalOff + 4);
- pPager->journalOff += pPager->pageSize+4;
- }
- if( rc==SQLITE_OK ){
- rc = write32bits(pPager->jfd, pPager->journalOff, cksum);
- pPager->journalOff += 4;
- }
- IOTRACE(("JOUT %p %d %lld %dn", pPager, pPg->pgno,
- pPager->journalOff, pPager->pageSize));
- PAGER_INCR(sqlite3_pager_writej_count);
- PAGERTRACE5("JOURNAL %d page %d needSync=%d hash(%08x)n",
- PAGERID(pPager), pPg->pgno, pPg->needSync, pager_pagehash(pPg));
- /* An error has occured writing to the journal file. The
- ** transaction will be rolled back by the layer above.
- */
- if( rc!=SQLITE_OK ){
- return rc;
- }
- pPager->nRec++;
- assert( pPager->pInJournal!=0 );
- sqlite3BitvecSet(pPager->pInJournal, pPg->pgno);
- pPg->needSync = !pPager->noSync;
- if( pPager->stmtInUse ){
- sqlite3BitvecSet(pPager->pInStmt, pPg->pgno);
- }
- }
- }else{
- pPg->needSync = !pPager->journalStarted && !pPager->noSync;
- PAGERTRACE4("APPEND %d page %d needSync=%dn",
- PAGERID(pPager), pPg->pgno, pPg->needSync);
- }
- if( pPg->needSync ){
- pPager->needSync = 1;
- }
- pPg->inJournal = 1;
- }
-
- /* If the statement journal is open and the page is not in it,
- ** then write the current page to the statement journal. Note that
- ** the statement journal format differs from the standard journal format
- ** in that it omits the checksums and the header.
- */
- if( pPager->stmtInUse
- && !pageInStatement(pPg)
- && (int)pPg->pgno<=pPager->stmtSize
- ){
- assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
- if( MEMDB ){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- assert( pHist->pStmt==0 );
- pHist->pStmt = sqlite3_malloc( pPager->pageSize );
- if( pHist->pStmt ){
- memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize);
- }
- PAGERTRACE3("STMT-JOURNAL %d page %dn", PAGERID(pPager), pPg->pgno);
- page_add_to_stmt_list(pPg);
- }else{
- i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
- char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
- rc = write32bits(pPager->stfd, offset, pPg->pgno);
- if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize, offset+4);
- }
- PAGERTRACE3("STMT-JOURNAL %d page %dn", PAGERID(pPager), pPg->pgno);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- pPager->stmtNRec++;
- assert( pPager->pInStmt!=0 );
- sqlite3BitvecSet(pPager->pInStmt, pPg->pgno);
- }
- }
- }
- /* Update the database size and return.
- */
- assert( pPager->state>=PAGER_SHARED );
- if( pPager->dbSize<(int)pPg->pgno ){
- pPager->dbSize = pPg->pgno;
- if( !MEMDB && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){
- pPager->dbSize++;
- }
- }
- return rc;
- }
- /*
- ** This function is used to mark a data-page as writable. It uses
- ** pager_write() to open a journal file (if it is not already open)
- ** and write the page *pData to the journal.
- **
- ** The difference between this function and pager_write() is that this
- ** function also deals with the special case where 2 or more pages
- ** fit on a single disk sector. In this case all co-resident pages
- ** must have been written to the journal file before returning.
- */
- int sqlite3PagerWrite(DbPage *pDbPage){
- int rc = SQLITE_OK;
- PgHdr *pPg = pDbPage;
- Pager *pPager = pPg->pPager;
- Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
- pagerEnter(pPager);
- if( !MEMDB && nPagePerSector>1 ){
- Pgno nPageCount; /* Total number of pages in database file */
- Pgno pg1; /* First page of the sector pPg is located on. */
- int nPage; /* Number of pages starting at pg1 to journal */
- int ii;
- int needSync = 0;
- /* Set the doNotSync flag to 1. This is because we cannot allow a journal
- ** header to be written between the pages journaled by this function.
- */
- assert( pPager->doNotSync==0 );
- pPager->doNotSync = 1;
- /* This trick assumes that both the page-size and sector-size are
- ** an integer power of 2. It sets variable pg1 to the identifier
- ** of the first page of the sector pPg is located on.
- */
- pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
- nPageCount = sqlite3PagerPagecount(pPager);
- if( pPg->pgno>nPageCount ){
- nPage = (pPg->pgno - pg1)+1;
- }else if( (pg1+nPagePerSector-1)>nPageCount ){
- nPage = nPageCount+1-pg1;
- }else{
- nPage = nPagePerSector;
- }
- assert(nPage>0);
- assert(pg1<=pPg->pgno);
- assert((pg1+nPage)>pPg->pgno);
- for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
- Pgno pg = pg1+ii;
- PgHdr *pPage;
- if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
- if( pg!=PAGER_MJ_PGNO(pPager) ){
- rc = sqlite3PagerGet(pPager, pg, &pPage);
- if( rc==SQLITE_OK ){
- rc = pager_write(pPage);
- if( pPage->needSync ){
- needSync = 1;
- }
- sqlite3PagerUnref(pPage);
- }
- }
- }else if( (pPage = pager_lookup(pPager, pg))!=0 ){
- if( pPage->needSync ){
- needSync = 1;
- }
- }
- }
- /* If the PgHdr.needSync flag is set for any of the nPage pages
- ** starting at pg1, then it needs to be set for all of them. Because
- ** writing to any of these nPage pages may damage the others, the
- ** journal file must contain sync()ed copies of all of them
- ** before any of them can be written out to the database file.
- */
- if( needSync ){
- for(ii=0; ii<nPage && needSync; ii++){
- PgHdr *pPage = pager_lookup(pPager, pg1+ii);
- if( pPage ) pPage->needSync = 1;
- }
- assert(pPager->needSync);
- }
- assert( pPager->doNotSync==1 );
- pPager->doNotSync = 0;
- }else{
- rc = pager_write(pDbPage);
- }
- pagerLeave(pPager);
- return rc;
- }
- /*
- ** Return TRUE if the page given in the argument was previously passed
- ** to sqlite3PagerWrite(). In other words, return TRUE if it is ok
- ** to change the content of the page.
- */
- #ifndef NDEBUG
- int sqlite3PagerIswriteable(DbPage *pPg){
- return pPg->dirty;
- }
- #endif
- #ifndef SQLITE_OMIT_VACUUM
- /*
- ** Replace the content of a single page with the information in the third
- ** argument.
- */
- int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void *pData){
- PgHdr *pPg;
- int rc;
- pagerEnter(pPager);
- rc = sqlite3PagerGet(pPager, pgno, &pPg);
- if( rc==SQLITE_OK ){
- rc = sqlite3PagerWrite(pPg);
- if( rc==SQLITE_OK ){
- memcpy(sqlite3PagerGetData(pPg), pData, pPager->pageSize);
- }
- sqlite3PagerUnref(pPg);
- }
- pagerLeave(pPager);
- return rc;
- }
- #endif
- /*
- ** A call to this routine tells the pager that it is not necessary to
- ** write the information on page pPg back to the disk, even though
- ** that page might be marked as dirty.
- **
- ** The overlying software layer calls this routine when all of the data
- ** on the given page is unused. The pager marks the page as clean so
- ** that it does not get written to disk.
- **
- ** Tests show that this optimization, together with the
- ** sqlite3PagerDontRollback() below, more than double the speed
- ** of large INSERT operations and quadruple the speed of large DELETEs.
- **
- ** When this routine is called, set the alwaysRollback flag to true.
- ** Subsequent calls to sqlite3PagerDontRollback() for the same page
- ** will thereafter be ignored. This is necessary to avoid a problem
- ** where a page with data is added to the freelist during one part of
- ** a transaction then removed from the freelist during a later part
- ** of the same transaction and reused for some other purpose. When it
- ** is first added to the freelist, this routine is called. When reused,
- ** the sqlite3PagerDontRollback() routine is called. But because the
- ** page contains critical data, we still need to be sure it gets
- ** rolled back in spite of the sqlite3PagerDontRollback() call.
- */
- void sqlite3PagerDontWrite(DbPage *pDbPage){
- PgHdr *pPg = pDbPage;
- Pager *pPager = pPg->pPager;
- if( MEMDB ) return;
- pagerEnter(pPager);
- pPg->alwaysRollback = 1;
- if( pPg->dirty && !pPager->stmtInUse ){
- assert( pPager->state>=PAGER_SHARED );
- if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){
- /* If this pages is the last page in the file and the file has grown
- ** during the current transaction, then do NOT mark the page as clean.
- ** When the database file grows, we must make sure that the last page
- ** gets written at least once so that the disk file will be the correct
- ** size. If you do not write this page and the size of the file
- ** on the disk ends up being too small, that can lead to database
- ** corruption during the next transaction.
- */
- }else{
- PAGERTRACE3("DONT_WRITE page %d of %dn", pPg->pgno, PAGERID(pPager));
- IOTRACE(("CLEAN %p %dn", pPager, pPg->pgno))
- makeClean(pPg);
- #ifdef SQLITE_CHECK_PAGES
- pPg->pageHash = pager_pagehash(pPg);
- #endif
- }
- }
- pagerLeave(pPager);
- }
- /*
- ** A call to this routine tells the pager that if a rollback occurs,
- ** it is not necessary to restore the data on the given page. This
- ** means that the pager does not have to record the given page in the
- ** rollback journal.
- **
- ** If we have not yet actually read the content of this page (if
- ** the PgHdr.needRead flag is set) then this routine acts as a promise
- ** that we will never need to read the page content in the future.
- ** so the needRead flag can be cleared at this point.
- */
- void sqlite3PagerDontRollback(DbPage *pPg){
- Pager *pPager = pPg->pPager;
- pagerEnter(pPager);
- assert( pPager->state>=PAGER_RESERVED );
- /* If the journal file is not open, or DontWrite() has been called on
- ** this page (DontWrite() sets the alwaysRollback flag), then this
- ** function is a no-op.
- */
- if( pPager->journalOpen==0 || pPg->alwaysRollback || pPager->alwaysRollback ){
- pagerLeave(pPager);
- return;
- }
- assert( !MEMDB ); /* For a memdb, pPager->journalOpen is always 0 */
- #ifdef SQLITE_SECURE_DELETE
- if( pPg->inJournal || (int)pPg->pgno > pPager->origDbSize ){
- return;
- }
- #endif
- /* If SECURE_DELETE is disabled, then there is no way that this
- ** routine can be called on a page for which sqlite3PagerDontWrite()
- ** has not been previously called during the same transaction.
- ** And if DontWrite() has previously been called, the following
- ** conditions must be met.
- */
- assert( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize );
- assert( pPager->pInJournal!=0 );
- sqlite3BitvecSet(pPager->pInJournal, pPg->pgno);
- pPg->inJournal = 1;
- pPg->needRead = 0;
- if( pPager->stmtInUse ){
- assert( pPager->stmtSize >= pPager->origDbSize );
- sqlite3BitvecSet(pPager->pInStmt, pPg->pgno);
- }
- PAGERTRACE3("DONT_ROLLBACK page %d of %dn", pPg->pgno, PAGERID(pPager));
- IOTRACE(("GARBAGE %p %dn", pPager, pPg->pgno))
- pagerLeave(pPager);
- }
- /*
- ** This routine is called to increment the database file change-counter,
- ** stored at byte 24 of the pager file.
- */
- static int pager_incr_changecounter(Pager *pPager, int isDirect){
- PgHdr *pPgHdr;
- u32 change_counter;
- int rc = SQLITE_OK;
- if( !pPager->changeCountDone ){
- /* Open page 1 of the file for writing. */
- rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
- if( rc!=SQLITE_OK ) return rc;
- if( !isDirect ){
- rc = sqlite3PagerWrite(pPgHdr);
- if( rc!=SQLITE_OK ){
- sqlite3PagerUnref(pPgHdr);
- return rc;
- }
- }
- /* Increment the value just read and write it back to byte 24. */
- change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers);
- change_counter++;
- put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
- if( isDirect && pPager->fd->pMethods ){
- const void *zBuf = PGHDR_TO_DATA(pPgHdr);
- rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
- }
- /* Release the page reference. */
- sqlite3PagerUnref(pPgHdr);
- pPager->changeCountDone = 1;
- }
- return rc;
- }
- /*
- ** Sync the pager file to disk.
- */
- int sqlite3PagerSync(Pager *pPager){
- int rc;
- pagerEnter(pPager);
- rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
- pagerLeave(pPager);
- return rc;
- }
- /*
- ** Sync the database file for the pager pPager. zMaster points to the name
- ** of a master journal file that should be written into the individual
- ** journal file. zMaster may be NULL, which is interpreted as no master
- ** journal (a single database transaction).
- **
- ** This routine ensures that the journal is synced, all dirty pages written
- ** to the database file and the database file synced. The only thing that
- ** remains to commit the transaction is to delete the journal file (or
- ** master journal file if specified).
- **
- ** Note that if zMaster==NULL, this does not overwrite a previous value
- ** passed to an sqlite3PagerCommitPhaseOne() call.
- **
- ** If parameter nTrunc is non-zero, then the pager file is truncated to
- ** nTrunc pages (this is used by auto-vacuum databases).
- **
- ** If the final parameter - noSync - is true, then the database file itself
- ** is not synced. The caller must call sqlite3PagerSync() directly to
- ** sync the database file before calling CommitPhaseTwo() to delete the
- ** journal file in this case.
- */
- int sqlite3PagerCommitPhaseOne(
- Pager *pPager,
- const char *zMaster,
- Pgno nTrunc,
- int noSync
- ){
- int rc = SQLITE_OK;
- PAGERTRACE4("DATABASE SYNC: File=%s zMaster=%s nTrunc=%dn",
- pPager->zFilename, zMaster, nTrunc);
- pagerEnter(pPager);
- /* If this is an in-memory db, or no pages have been written to, or this
- ** function has already been called, it is a no-op.
- */
- if( pPager->state!=PAGER_SYNCED && !MEMDB && pPager->dirtyCache ){
- PgHdr *pPg;
- #ifdef SQLITE_ENABLE_ATOMIC_WRITE
- /* The atomic-write optimization can be used if all of the
- ** following are true:
- **
- ** + The file-system supports the atomic-write property for
- ** blocks of size page-size, and
- ** + This commit is not part of a multi-file transaction, and
- ** + Exactly one page has been modified and store in the journal file.
- **
- ** If the optimization can be used, then the journal file will never
- ** be created for this transaction.
- */
- int useAtomicWrite = (
- !zMaster &&
- pPager->journalOff==jrnlBufferSize(pPager) &&
- nTrunc==0 &&
- (0==pPager->pDirty || 0==pPager->pDirty->pDirty)
- );
- if( useAtomicWrite ){
- /* Update the nRec field in the journal file. */
- int offset = pPager->journalHdr + sizeof(aJournalMagic);
- assert(pPager->nRec==1);
- rc = write32bits(pPager->jfd, offset, pPager->nRec);
- /* Update the db file change counter. The following call will modify
- ** the in-memory representation of page 1 to include the updated
- ** change counter and then write page 1 directly to the database
- ** file. Because of the atomic-write property of the host file-system,
- ** this is safe.
- */
- if( rc==SQLITE_OK ){
- rc = pager_incr_changecounter(pPager, 1);
- }
- }else{
- rc = sqlite3JournalCreate(pPager->jfd);
- }
- if( !useAtomicWrite && rc==SQLITE_OK )
- #endif
- /* If a master journal file name has already been written to the
- ** journal file, then no sync is required. This happens when it is
- ** written, then the process fails to upgrade from a RESERVED to an
- ** EXCLUSIVE lock. The next time the process tries to commit the
- ** transaction the m-j name will have already been written.
- */
- if( !pPager->setMaster ){
- assert( pPager->journalOpen );
- rc = pager_incr_changecounter(pPager, 0);
- if( rc!=SQLITE_OK ) goto sync_exit;
- #ifndef SQLITE_OMIT_AUTOVACUUM
- if( nTrunc!=0 ){
- /* If this transaction has made the database smaller, then all pages
- ** being discarded by the truncation must be written to the journal
- ** file.
- */
- Pgno i;
- int iSkip = PAGER_MJ_PGNO(pPager);
- for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){
- if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
- rc = sqlite3PagerGet(pPager, i, &pPg);
- if( rc!=SQLITE_OK ) goto sync_exit;
- rc = sqlite3PagerWrite(pPg);
- sqlite3PagerUnref(pPg);
- if( rc!=SQLITE_OK ) goto sync_exit;
- }
- }
- }
- #endif
- rc = writeMasterJournal(pPager, zMaster);
- if( rc!=SQLITE_OK ) goto sync_exit;
- rc = syncJournal(pPager);
- }
- if( rc!=SQLITE_OK ) goto sync_exit;
- #ifndef SQLITE_OMIT_AUTOVACUUM
- if( nTrunc!=0 ){
- rc = sqlite3PagerTruncate(pPager, nTrunc);
- if( rc!=SQLITE_OK ) goto sync_exit;
- }
- #endif
- /* Write all dirty pages to the database file */
- pPg = pager_get_all_dirty_pages(pPager);
- rc = pager_write_pagelist(pPg);
- if( rc!=SQLITE_OK ){
- assert( rc!=SQLITE_IOERR_BLOCKED );
- /* The error might have left the dirty list all fouled up here,
- ** but that does not matter because if the if the dirty list did
- ** get corrupted, then the transaction will roll back and
- ** discard the dirty list. There is an assert in
- ** pager_get_all_dirty_pages() that verifies that no attempt
- ** is made to use an invalid dirty list.
- */
- goto sync_exit;
- }
- pPager->pDirty = 0;
- /* Sync the database file. */
- if( !pPager->noSync && !noSync ){
- rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
- }
- IOTRACE(("DBSYNC %pn", pPager))
- pPager->state = PAGER_SYNCED;
- }else if( MEMDB && nTrunc!=0 ){
- rc = sqlite3PagerTruncate(pPager, nTrunc);
- }
- sync_exit:
- if( rc==SQLITE_IOERR_BLOCKED ){
- /* pager_incr_changecounter() may attempt to obtain an exclusive
- * lock to spill the cache and return IOERR_BLOCKED. But since
- * there is no chance the cache is inconsistent, it is
- * better to return SQLITE_BUSY.
- */
- rc = SQLITE_BUSY;
- }
- pagerLeave(pPager);
- return rc;
- }
- /*
- ** Commit all changes to the database and release the write lock.
- **
- ** If the commit fails for any reason, a rollback attempt is made
- ** and an error code is returned. If the commit worked, SQLITE_OK
- ** is returned.
- */
- int sqlite3PagerCommitPhaseTwo(Pager *pPager){
- int rc;
- PgHdr *pPg;
- if( pPager->errCode ){
- return pPager->errCode;
- }
- if( pPager->state<PAGER_RESERVED ){
- return SQLITE_ERROR;
- }
- pagerEnter(pPager);
- PAGERTRACE2("COMMIT %dn", PAGERID(pPager));
- if( MEMDB ){
- pPg = pager_get_all_dirty_pages(pPager);
- while( pPg ){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- clearHistory(pHist);
- pPg->dirty = 0;
- pPg->inJournal = 0;
- pHist->inStmt = 0;
- pPg->needSync = 0;
- pHist->pPrevStmt = pHist->pNextStmt = 0;
- pPg = pPg->pDirty;
- }
- pPager->pDirty = 0;
- #ifndef NDEBUG
- for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- assert( !pPg->alwaysRollback );
- assert( !pHist->pOrig );
- assert( !pHist->pStmt );
- }
- #endif
- pPager->pStmt = 0;
- pPager->state = PAGER_SHARED;
- pagerLeave(pPager);
- return SQLITE_OK;
- }
- assert( pPager->journalOpen || !pPager->dirtyCache );
- assert( pPager->state==PAGER_SYNCED || !pPager->dirtyCache );
- rc = pager_end_transaction(pPager);
- rc = pager_error(pPager, rc);
- pagerLeave(pPager);
- return rc;
- }
- /*
- ** Rollback all changes. The database falls back to PAGER_SHARED mode.
- ** All in-memory cache pages revert to their original data contents.
- ** The journal is deleted.
- **
- ** This routine cannot fail unless some other process is not following
- ** the correct locking protocol or unless some other
- ** process is writing trash into the journal file (SQLITE_CORRUPT) or
- ** unless a prior malloc() failed (SQLITE_NOMEM). Appropriate error
- ** codes are returned for all these occasions. Otherwise,
- ** SQLITE_OK is returned.
- */
- int sqlite3PagerRollback(Pager *pPager){
- int rc;
- PAGERTRACE2("ROLLBACK %dn", PAGERID(pPager));
- if( MEMDB ){
- PgHdr *p;
- for(p=pPager->pAll; p; p=p->pNextAll){
- PgHistory *pHist;
- assert( !p->alwaysRollback );
- if( !p->dirty ){
- assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pOrig );
- assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt );
- continue;
- }
- pHist = PGHDR_TO_HIST(p, pPager);
- if( pHist->pOrig ){
- memcpy(PGHDR_TO_DATA(p), pHist->pOrig, pPager->pageSize);
- PAGERTRACE3("ROLLBACK-PAGE %d of %dn", p->pgno, PAGERID(pPager));
- }else{
- PAGERTRACE3("PAGE %d is clean on %dn", p->pgno, PAGERID(pPager));
- }
- clearHistory(pHist);
- p->dirty = 0;
- p->inJournal = 0;
- pHist->inStmt = 0;
- pHist->pPrevStmt = pHist->pNextStmt = 0;
- if( pPager->xReiniter ){
- pPager->xReiniter(p, pPager->pageSize);
- }
- }
- pPager->pDirty = 0;
- pPager->pStmt = 0;
- pPager->dbSize = pPager->origDbSize;
- pager_truncate_cache(pPager);
- pPager->stmtInUse = 0;
- pPager->state = PAGER_SHARED;
- return SQLITE_OK;
- }
- pagerEnter(pPager);
- if( !pPager->dirtyCache || !pPager->journalOpen ){
- rc = pager_end_transaction(pPager);
- pagerLeave(pPager);
- return rc;
- }
- if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
- if( pPager->state>=PAGER_EXCLUSIVE ){
- pager_playback(pPager, 0);
- }
- pagerLeave(pPager);
- return pPager->errCode;
- }
- if( pPager->state==PAGER_RESERVED ){
- int rc2;
- rc = pager_playback(pPager, 0);
- rc2 = pager_end_transaction(pPager);
- if( rc==SQLITE_OK ){
- rc = rc2;
- }
- }else{
- rc = pager_playback(pPager, 0);
- }
- /* pager_reset(pPager); */
- pPager->dbSize = -1;
- /* If an error occurs during a ROLLBACK, we can no longer trust the pager
- ** cache. So call pager_error() on the way out to make any error
- ** persistent.
- */
- rc = pager_error(pPager, rc);
- pagerLeave(pPager);
- return rc;
- }
- /*
- ** Return TRUE if the database file is opened read-only. Return FALSE
- ** if the database is (in theory) writable.
- */
- int sqlite3PagerIsreadonly(Pager *pPager){
- return pPager->readOnly;
- }
- /*
- ** Return the number of references to the pager.
- */
- int sqlite3PagerRefcount(Pager *pPager){
- return pPager->nRef;
- }
- #ifdef SQLITE_TEST
- /*
- ** This routine is used for testing and analysis only.
- */
- int *sqlite3PagerStats(Pager *pPager){
- static int a[11];
- a[0] = pPager->nRef;
- a[1] = pPager->nPage;
- a[2] = pPager->mxPage;
- a[3] = pPager->dbSize;
- a[4] = pPager->state;
- a[5] = pPager->errCode;
- a[6] = pPager->nHit;
- a[7] = pPager->nMiss;
- a[8] = 0; /* Used to be pPager->nOvfl */
- a[9] = pPager->nRead;
- a[10] = pPager->nWrite;
- return a;
- }
- #endif
- /*
- ** Set the statement rollback point.
- **
- ** This routine should be called with the transaction journal already
- ** open. A new statement journal is created that can be used to rollback
- ** changes of a single SQL command within a larger transaction.
- */
- static int pagerStmtBegin(Pager *pPager){
- int rc;
- assert( !pPager->stmtInUse );
- assert( pPager->state>=PAGER_SHARED );
- assert( pPager->dbSize>=0 );
- PAGERTRACE2("STMT-BEGIN %dn", PAGERID(pPager));
- if( MEMDB ){
- pPager->stmtInUse = 1;
- pPager->stmtSize = pPager->dbSize;
- return SQLITE_OK;
- }
- if( !pPager->journalOpen ){
- pPager->stmtAutoopen = 1;
- return SQLITE_OK;
- }
- assert( pPager->journalOpen );
- pagerLeave(pPager);
- assert( pPager->pInStmt==0 );
- pPager->pInStmt = sqlite3BitvecCreate(pPager->dbSize);
- pagerEnter(pPager);
- if( pPager->pInStmt==0 ){
- /* sqlite3OsLock(pPager->fd, SHARED_LOCK); */
- return SQLITE_NOMEM;
- }
- #ifndef NDEBUG
- rc = sqlite3OsFileSize(pPager->jfd, &pPager->stmtJSize);
- if( rc ) goto stmt_begin_failed;
- assert( pPager->stmtJSize == pPager->journalOff );
- #endif
- pPager->stmtJSize = pPager->journalOff;
- pPager->stmtSize = pPager->dbSize;
- pPager->stmtHdrOff = 0;
- pPager->stmtCksum = pPager->cksumInit;
- if( !pPager->stmtOpen ){
- rc = sqlite3PagerOpentemp(pPager->pVfs, pPager->stfd, pPager->zStmtJrnl,
- SQLITE_OPEN_SUBJOURNAL);
- if( rc ){
- goto stmt_begin_failed;
- }
- pPager->stmtOpen = 1;
- pPager->stmtNRec = 0;
- }
- pPager->stmtInUse = 1;
- return SQLITE_OK;
-
- stmt_begin_failed:
- if( pPager->pInStmt ){
- sqlite3BitvecDestroy(pPager->pInStmt);
- pPager->pInStmt = 0;
- }
- return rc;
- }
- int sqlite3PagerStmtBegin(Pager *pPager){
- int rc;
- pagerEnter(pPager);
- rc = pagerStmtBegin(pPager);
- pagerLeave(pPager);
- return rc;
- }
- /*
- ** Commit a statement.
- */
- int sqlite3PagerStmtCommit(Pager *pPager){
- pagerEnter(pPager);
- if( pPager->stmtInUse ){
- PgHdr *pPg, *pNext;
- PAGERTRACE2("STMT-COMMIT %dn", PAGERID(pPager));
- if( !MEMDB ){
- /* sqlite3OsTruncate(pPager->stfd, 0); */
- sqlite3BitvecDestroy(pPager->pInStmt);
- pPager->pInStmt = 0;
- }else{
- for(pPg=pPager->pStmt; pPg; pPg=pNext){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- pNext = pHist->pNextStmt;
- assert( pHist->inStmt );
- pHist->inStmt = 0;
- pHist->pPrevStmt = pHist->pNextStmt = 0;
- sqlite3_free(pHist->pStmt);
- pHist->pStmt = 0;
- }
- }
- pPager->stmtNRec = 0;
- pPager->stmtInUse = 0;
- pPager->pStmt = 0;
- }
- pPager->stmtAutoopen = 0;
- pagerLeave(pPager);
- return SQLITE_OK;
- }
- /*
- ** Rollback a statement.
- */
- int sqlite3PagerStmtRollback(Pager *pPager){
- int rc;
- pagerEnter(pPager);
- if( pPager->stmtInUse ){
- PAGERTRACE2("STMT-ROLLBACK %dn", PAGERID(pPager));
- if( MEMDB ){
- PgHdr *pPg;
- PgHistory *pHist;
- for(pPg=pPager->pStmt; pPg; pPg=pHist->pNextStmt){
- pHist = PGHDR_TO_HIST(pPg, pPager);
- if( pHist->pStmt ){
- memcpy(PGHDR_TO_DATA(pPg), pHist->pStmt, pPager->pageSize);
- sqlite3_free(pHist->pStmt);
- pHist->pStmt = 0;
- }
- }
- pPager->dbSize = pPager->stmtSize;
- pager_truncate_cache(pPager);
- rc = SQLITE_OK;
- }else{
- rc = pager_stmt_playback(pPager);
- }
- sqlite3PagerStmtCommit(pPager);
- }else{
- rc = SQLITE_OK;
- }
- pPager->stmtAutoopen = 0;
- pagerLeave(pPager);
- return rc;
- }
- /*
- ** Return the full pathname of the database file.
- */
- const char *sqlite3PagerFilename(Pager *pPager){
- return pPager->zFilename;
- }
- /*
- ** Return the VFS structure for the pager.
- */
- const sqlite3_vfs *sqlite3PagerVfs(Pager *pPager){
- return pPager->pVfs;
- }
- /*
- ** Return the file handle for the database file associated
- ** with the pager. This might return NULL if the file has
- ** not yet been opened.
- */
- sqlite3_file *sqlite3PagerFile(Pager *pPager){
- return pPager->fd;
- }
- /*
- ** Return the directory of the database file.
- */
- const char *sqlite3PagerDirname(Pager *pPager){
- return pPager->zDirectory;
- }
- /*
- ** Return the full pathname of the journal file.
- */
- const char *sqlite3PagerJournalname(Pager *pPager){
- return pPager->zJournal;
- }
- /*
- ** Return true if fsync() calls are disabled for this pager. Return FALSE
- ** if fsync()s are executed normally.
- */
- int sqlite3PagerNosync(Pager *pPager){
- return pPager->noSync;
- }
- #ifdef SQLITE_HAS_CODEC
- /*
- ** Set the codec for this pager
- */
- void sqlite3PagerSetCodec(
- Pager *pPager,
- void *(*xCodec)(void*,void*,Pgno,int),
- void *pCodecArg
- ){
- pPager->xCodec = xCodec;
- pPager->pCodecArg = pCodecArg;
- }
- #endif
- #ifndef SQLITE_OMIT_AUTOVACUUM
- /*
- ** Move the page pPg to location pgno in the file.
- **
- ** There must be no references to the page previously located at
- ** pgno (which we call pPgOld) though that page is allowed to be
- ** in cache. If the page previous located at pgno is not already
- ** in the rollback journal, it is not put there by by this routine.
- **
- ** References to the page pPg remain valid. Updating any
- ** meta-data associated with pPg (i.e. data stored in the nExtra bytes
- ** allocated along with the page) is the responsibility of the caller.
- **
- ** A transaction must be active when this routine is called. It used to be
- ** required that a statement transaction was not active, but this restriction
- ** has been removed (CREATE INDEX needs to move a page when a statement
- ** transaction is active).
- */
- int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno){
- PgHdr *pPgOld; /* The page being overwritten. */
- int h;
- Pgno needSyncPgno = 0;
- pagerEnter(pPager);
- assert( pPg->nRef>0 );
- PAGERTRACE5("MOVE %d page %d (needSync=%d) moves to %dn",
- PAGERID(pPager), pPg->pgno, pPg->needSync, pgno);
- IOTRACE(("MOVE %p %d %dn", pPager, pPg->pgno, pgno))
- pager_get_content(pPg);
- if( pPg->needSync ){
- needSyncPgno = pPg->pgno;
- assert( pPg->inJournal || (int)pgno>pPager->origDbSize );
- assert( pPg->dirty );
- assert( pPager->needSync );
- }
- /* Unlink pPg from its hash-chain */
- unlinkHashChain(pPager, pPg);
- /* If the cache contains a page with page-number pgno, remove it
- ** from its hash chain. Also, if the PgHdr.needSync was set for
- ** page pgno before the 'move' operation, it needs to be retained
- ** for the page moved there.
- */
- pPg->needSync = 0;
- pPgOld = pager_lookup(pPager, pgno);
- if( pPgOld ){
- assert( pPgOld->nRef==0 );
- unlinkHashChain(pPager, pPgOld);
- makeClean(pPgOld);
- pPg->needSync = pPgOld->needSync;
- }else{
- pPg->needSync = 0;
- }
- pPg->inJournal = sqlite3BitvecTest(pPager->pInJournal, pgno);
- /* Change the page number for pPg and insert it into the new hash-chain. */
- assert( pgno!=0 );
- pPg->pgno = pgno;
- h = pgno & (pPager->nHash-1);
- if( pPager->aHash[h] ){
- assert( pPager->aHash[h]->pPrevHash==0 );
- pPager->aHash[h]->pPrevHash = pPg;
- }
- pPg->pNextHash = pPager->aHash[h];
- pPager->aHash[h] = pPg;
- pPg->pPrevHash = 0;
- makeDirty(pPg);
- pPager->dirtyCache = 1;
- if( needSyncPgno ){
- /* If needSyncPgno is non-zero, then the journal file needs to be
- ** sync()ed before any data is written to database file page needSyncPgno.
- ** Currently, no such page exists in the page-cache and the
- ** Pager.pInJournal bit has been set. This needs to be remedied by loading
- ** the page into the pager-cache and setting the PgHdr.needSync flag.
- **
- ** If the attempt to load the page into the page-cache fails, (due
- ** to a malloc() or IO failure), clear the bit in the pInJournal[]
- ** array. Otherwise, if the page is loaded and written again in
- ** this transaction, it may be written to the database file before
- ** it is synced into the journal file. This way, it may end up in
- ** the journal file twice, but that is not a problem.
- **
- ** The sqlite3PagerGet() call may cause the journal to sync. So make
- ** sure the Pager.needSync flag is set too.
- */
- int rc;
- PgHdr *pPgHdr;
- assert( pPager->needSync );
- rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
- if( rc!=SQLITE_OK ){
- if( pPager->pInJournal && (int)needSyncPgno<=pPager->origDbSize ){
- sqlite3BitvecClear(pPager->pInJournal, needSyncPgno);
- }
- pagerLeave(pPager);
- return rc;
- }
- pPager->needSync = 1;
- pPgHdr->needSync = 1;
- pPgHdr->inJournal = 1;
- makeDirty(pPgHdr);
- sqlite3PagerUnref(pPgHdr);
- }
- pagerLeave(pPager);
- return SQLITE_OK;
- }
- #endif
- /*
- ** Return a pointer to the data for the specified page.
- */
- void *sqlite3PagerGetData(DbPage *pPg){
- return PGHDR_TO_DATA(pPg);
- }
- /*
- ** Return a pointer to the Pager.nExtra bytes of "extra" space
- ** allocated along with the specified page.
- */
- void *sqlite3PagerGetExtra(DbPage *pPg){
- Pager *pPager = pPg->pPager;
- return (pPager?PGHDR_TO_EXTRA(pPg, pPager):0);
- }
- /*
- ** Get/set the locking-mode for this pager. Parameter eMode must be one
- ** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or
- ** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then
- ** the locking-mode is set to the value specified.
- **
- ** The returned value is either PAGER_LOCKINGMODE_NORMAL or
- ** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated)
- ** locking-mode.
- */
- int sqlite3PagerLockingMode(Pager *pPager, int eMode){
- assert( eMode==PAGER_LOCKINGMODE_QUERY
- || eMode==PAGER_LOCKINGMODE_NORMAL
- || eMode==PAGER_LOCKINGMODE_EXCLUSIVE );
- assert( PAGER_LOCKINGMODE_QUERY<0 );
- assert( PAGER_LOCKINGMODE_NORMAL>=0 && PAGER_LOCKINGMODE_EXCLUSIVE>=0 );
- if( eMode>=0 && !pPager->tempFile ){
- pPager->exclusiveMode = eMode;
- }
- return (int)pPager->exclusiveMode;
- }
- #ifdef SQLITE_TEST
- /*
- ** Print a listing of all referenced pages and their ref count.
- */
- void sqlite3PagerRefdump(Pager *pPager){
- PgHdr *pPg;
- for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
- if( pPg->nRef<=0 ) continue;
- sqlite3DebugPrintf("PAGE %3d addr=%p nRef=%dn",
- pPg->pgno, PGHDR_TO_DATA(pPg), pPg->nRef);
- }
- }
- #endif
- #endif /* SQLITE_OMIT_DISKIO */