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

📄 pager.c

📁 sqlite-source-2_8_16.zip 轻量级嵌入式数据库源码
💻 C
📖 第 1 页 / 共 5 页
字号:
** 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 sync occurs.**** 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 ){      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.        */        off_t hdrSz, pgSz, jSz;        hdrSz = JOURNAL_HDR_SZ(journal_format);        pgSz = JOURNAL_PG_SZ(journal_format);        rc = sqliteOsFileSize(&pPager->jfd, &jSz);        if( rc!=0 ) return rc;        assert( pPager->nRec*pgSz+hdrSz==jSz );      }#endif      if( journal_format>=3 ){        /* Write the nRec value into the journal file header */        off_t szJ;        if( pPager->fullSync ){          TRACE1("SYNC\n");          rc = sqliteOsSync(&pPager->jfd);          if( rc!=0 ) return rc;        }        sqliteOsSeek(&pPager->jfd, sizeof(aJournalMagic1));        rc = write32bits(&pPager->jfd, pPager->nRec);        if( rc ) return rc;        szJ = JOURNAL_HDR_SZ(journal_format) +                 pPager->nRec*JOURNAL_PG_SZ(journal_format);        sqliteOsSeek(&pPager->jfd, szJ);      }      TRACE1("SYNC\n");      rc = sqliteOsSync(&pPager->jfd);      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;    }    pPager->pFirstSynced = pPager->pFirst;  }#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->pFirstSynced==pPager->pFirst );  }#endif  return rc;}/*** 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;  int rc;  if( pList==0 ) return SQLITE_OK;  pPager = pList->pPager;  while( pList ){    assert( pList->dirty );    sqliteOsSeek(&pPager->fd, (pList->pgno-1)*(off_t)SQLITE_PAGE_SIZE);    CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);    TRACE2("STORE %d\n", pList->pgno);    rc = sqliteOsWrite(&pPager->fd, PGHDR_TO_DATA(pList), SQLITE_PAGE_SIZE);    CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);    if( rc ) return rc;    pList->dirty = 0;    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){  PgHdr *p, *pList;  pList = 0;  for(p=pPager->pAll; p; p=p->pNextAll){    if( p->dirty ){      p->pDirty = pList;      pList = p;    }  }  return pList;}/*** 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.**** A _get 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 sqlitepager_lookup().  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.*/int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){  PgHdr *pPg;  int rc;  /* Make sure we have not hit any critical errors.  */   assert( pPager!=0 );  assert( pgno!=0 );  *ppPage = 0;  if( pPager->errMask & ~(PAGER_ERR_FULL) ){    return pager_errcode(pPager);  }  /* If this is the first page accessed, then get a read lock  ** on the database file.  */  if( pPager->nRef==0 ){    rc = sqliteOsReadLock(&pPager->fd);    if( rc!=SQLITE_OK ){      return rc;    }    pPager->state = SQLITE_READLOCK;    /* If a journal file exists, try to play it back.    */    if( pPager->useJournal && sqliteOsFileExists(pPager->zJournal) ){       int rc;       /* Get a write lock on the database       */       rc = sqliteOsWriteLock(&pPager->fd);       if( rc!=SQLITE_OK ){         if( sqliteOsUnlock(&pPager->fd)!=SQLITE_OK ){           /* This should never happen! */           rc = SQLITE_INTERNAL;         }         return rc;       }       pPager->state = SQLITE_WRITELOCK;       /* 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.       */       rc = sqliteOsOpenReadOnly(pPager->zJournal, &pPager->jfd);       if( rc!=SQLITE_OK ){         rc = sqliteOsUnlock(&pPager->fd);         assert( rc==SQLITE_OK );         return SQLITE_BUSY;       }       pPager->journalOpen = 1;       pPager->journalStarted = 0;       /* Playback and delete the journal.  Drop the database write       ** lock and reacquire the read lock.       */       rc = pager_playback(pPager, 0);       if( rc!=SQLITE_OK ){         return rc;       }    }    pPg = 0;  }else{    /* Search for page in cache */    pPg = pager_lookup(pPager, pgno);  }  if( pPg==0 ){    /* The requested page is not in the page cache. */    int h;    pPager->nMiss++;    if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 ){      /* Create a new page */      pPg = sqliteMallocRaw( sizeof(*pPg) + SQLITE_PAGE_SIZE                               + sizeof(u32) + pPager->nExtra );      if( pPg==0 ){        pager_unwritelock(pPager);        pPager->errMask |= PAGER_ERR_MEM;        return SQLITE_NOMEM;      }      memset(pPg, 0, sizeof(*pPg));      pPg->pPager = pPager;      pPg->pNextAll = pPager->pAll;      if( pPager->pAll ){        pPager->pAll->pPrevAll = pPg;      }      pPg->pPrevAll = 0;      pPager->pAll = pPg;      pPager->nPage++;    }else{      /* Find a page to recycle.  Try to locate a page that does not      ** require us to do an fsync() on the journal.      */      pPg = pPager->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 ){        int rc = syncJournal(pPager);        if( rc!=0 ){          sqlitepager_rollback(pPager);          return SQLITE_IOERR;        }        pPg = pPager->pFirst;      }      assert( pPg->nRef==0 );      /* Write the page to the database file if it is dirty.      */      if( pPg->dirty ){        assert( pPg->needSync==0 );        pPg->pDirty = 0;        rc = pager_write_pagelist( pPg );        if( rc!=SQLITE_OK ){          sqlitepager_rollback(pPager);          return SQLITE_IOERR;        }      }      assert( pPg->dirty==0 );      /* If the page we are recycling is marked as alwaysRollback, then      ** set the global alwaysRollback flag, thus disabling the      ** sqlite_dont_rollback() 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 ){        pPager->alwaysRollback = 1;      }      /* Unlink the old page from the free list and the hash table      */      if( pPg==pPager->pFirstSynced ){        PgHdr *p = pPg->pNextFree;        while( p && p->needSync ){ p = p->pNextFree; }        pPager->pFirstSynced = p;      }      if( pPg->pPrevFree ){        pPg->pPrevFree->pNextFree = pPg->pNextFree;      }else{        assert( pPager->pFirst==pPg );        pPager->pFirst = pPg->pNextFree;      }      if( pPg->pNextFree ){        pPg->pNextFree->pPrevFree = pPg->pPrevFree;      }else{        assert( pPager->pLast==pPg );        pPager->pLast = pPg->pPrevFree;      }      pPg->pNextFree = pPg->pPrevFree = 0;      if( pPg->pNextHash ){        pPg->pNextHash->pPrevHash = pPg->pPrevHash;      }      if( pPg->pPrevHash ){        pPg->pPrevHash->pNextHash = pPg->pNextHash;      }else{        h = pager_hash(pPg->pgno);        assert( pPager->aHash[h]==pPg );        pPager->aHash[h] = pPg->pNextHash;      }      pPg->pNextHash = pPg->pPrevHash = 0;      pPager->nOvfl++;    }    pPg->pgno = pgno;    if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){      sqliteCheckMemory(pPager->aInJournal, pgno/8);      assert( pPager->journalOpen );      pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0;      pPg->needSync = 0;    }else{      pPg->inJournal = 0;      pPg->needSync = 0;    }    if( pPager->aInCkpt && (int)pgno<=pPager->ckptSize             && (pPager->aInCkpt[pgno/8] & (1<<(pgno&7)))!=0 ){      page_add_to_ckpt_list(pPg);    }else{      page_remove_from_ckpt_list(pPg);    }    pPg->dirty = 0;    pPg->nRef = 1;    REFINFO(pPg);    pPager->nRef++;    h = pager_hash(pgno);    pPg->pNextHash = pPager->aHash[h];    pPager->aHash[h] = pPg;    if( pPg->pNextHash ){      assert( pPg->pNextHash->pPrevHash==0 );      pPg->pNextHash->pPrevHash = pPg;    }    if( pPager->nExtra>0 ){      memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);    }    if( pPager->dbSize<0 ) sqlitepager_pagecount(pPager);    if( pPager->errMask!=0 ){      sqlitepager_unref(PGHDR_TO_DATA(pPg));      rc = pager_errcode(pPager);      return rc;    }    if( pPager->dbSize<(int)pgno ){      memset(PGHDR_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE);    }else{      int rc;      sqliteOsSeek(&pPager->fd, (pgno-1)*(off_t)SQLITE_PAGE_SIZE);      rc = sqliteOsRead(&pPager->fd, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE);      TRACE2("FETCH %d\n", pPg->pgno);      CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);      if( rc!=SQLITE_OK ){        off_t fileSize;        if( sqliteOsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK               || fileSize>=pgno*SQLITE_PAGE_SIZE ){          sqlitepager_unref(PGHDR_TO_DATA(pPg));          return rc;        }else{          memset(PGHDR_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE);        }      }    }  }else{    /* The requested page is in the page cache. */    pPager->nHit++;    page_ref(pPg);  }  *ppPage = PGHDR_TO_DATA(pPg);  return SQLITE_OK;}/*** 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,

⌨️ 快捷键说明

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