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

📄 pager.c

📁 sqlite-source-2_8_16.zip 轻量级嵌入式数据库源码
💻 C
📖 第 1 页 / 共 5 页
字号:
** or 0 if the page is not in cache.**** See also sqlitepager_get().  The difference between this routine** and sqlitepager_get() 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.*/void *sqlitepager_lookup(Pager *pPager, Pgno pgno){  PgHdr *pPg;  assert( pPager!=0 );  assert( pgno!=0 );  if( pPager->errMask & ~(PAGER_ERR_FULL) ){    return 0;  }  /* if( pPager->nRef==0 ){  **  return 0;  ** }  */  pPg = pager_lookup(pPager, pgno);  if( pPg==0 ) return 0;  page_ref(pPg);  return PGHDR_TO_DATA(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 sqlitepager_unref(void *pData){  PgHdr *pPg;  /* Decrement the reference count for this page  */  pPg = DATA_TO_PGHDR(pData);  assert( pPg->nRef>0 );  pPg->nRef--;  REFINFO(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 ){    Pager *pPager;    pPager = pPg->pPager;    pPg->pNextFree = 0;    pPg->pPrevFree = pPager->pLast;    pPager->pLast = pPg;    if( pPg->pPrevFree ){      pPg->pPrevFree->pNextFree = pPg;    }else{      pPager->pFirst = pPg;    }    if( pPg->needSync==0 && pPager->pFirstSynced==0 ){      pPager->pFirstSynced = pPg;    }    if( pPager->xDestructor ){      pPager->xDestructor(pData);    }      /* When all pages reach the freelist, drop the read lock from    ** the database file.    */    pPager->nRef--;    assert( pPager->nRef>=0 );    if( pPager->nRef==0 ){      pager_reset(pPager);    }  }  return SQLITE_OK;}/*** Create a journal file for pPager.  There should already be a write** 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){  int rc;  assert( pPager->state==SQLITE_WRITELOCK );  assert( pPager->journalOpen==0 );  assert( pPager->useJournal );  sqlitepager_pagecount(pPager);  pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );  if( pPager->aInJournal==0 ){    sqliteOsReadLock(&pPager->fd);    pPager->state = SQLITE_READLOCK;    return SQLITE_NOMEM;  }  rc = sqliteOsOpenExclusive(pPager->zJournal, &pPager->jfd,pPager->tempFile);  if( rc!=SQLITE_OK ){    sqliteFree(pPager->aInJournal);    pPager->aInJournal = 0;    sqliteOsReadLock(&pPager->fd);    pPager->state = SQLITE_READLOCK;    return SQLITE_CANTOPEN;  }  sqliteOsOpenDirectory(pPager->zDirectory, &pPager->jfd);  pPager->journalOpen = 1;  pPager->journalStarted = 0;  pPager->needSync = 0;  pPager->alwaysRollback = 0;  pPager->nRec = 0;  if( pPager->errMask!=0 ){    rc = pager_errcode(pPager);    return rc;  }  pPager->origDbSize = pPager->dbSize;  if( journal_format==JOURNAL_FORMAT_3 ){    rc = sqliteOsWrite(&pPager->jfd, aJournalMagic3, sizeof(aJournalMagic3));    if( rc==SQLITE_OK ){      rc = write32bits(&pPager->jfd, pPager->noSync ? 0xffffffff : 0);    }    if( rc==SQLITE_OK ){      sqliteRandomness(sizeof(pPager->cksumInit), &pPager->cksumInit);      rc = write32bits(&pPager->jfd, pPager->cksumInit);    }  }else if( journal_format==JOURNAL_FORMAT_2 ){    rc = sqliteOsWrite(&pPager->jfd, aJournalMagic2, sizeof(aJournalMagic2));  }else{    assert( journal_format==JOURNAL_FORMAT_1 );    rc = sqliteOsWrite(&pPager->jfd, aJournalMagic1, sizeof(aJournalMagic1));  }  if( rc==SQLITE_OK ){    rc = write32bits(&pPager->jfd, pPager->dbSize);  }  if( pPager->ckptAutoopen && rc==SQLITE_OK ){    rc = sqlitepager_ckpt_begin(pPager);  }  if( rc!=SQLITE_OK ){    rc = pager_unwritelock(pPager);    if( rc==SQLITE_OK ){      rc = SQLITE_FULL;    }  }  return rc;  }/*** Acquire a write-lock on the database.  The lock is removed when** the any of the following happen:****   *  sqlitepager_commit() is called.**   *  sqlitepager_rollback() is called.**   *  sqlitepager_close() is called.**   *  sqlitepager_unref() is called to on every outstanding page.**** The 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.**** 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 write-locked, this routine is a no-op.*/int sqlitepager_begin(void *pData){  PgHdr *pPg = DATA_TO_PGHDR(pData);  Pager *pPager = pPg->pPager;  int rc = SQLITE_OK;  assert( pPg->nRef>0 );  assert( pPager->state!=SQLITE_UNLOCK );  if( pPager->state==SQLITE_READLOCK ){    assert( pPager->aInJournal==0 );    rc = sqliteOsWriteLock(&pPager->fd);    if( rc!=SQLITE_OK ){      return rc;    }    pPager->state = SQLITE_WRITELOCK;    pPager->dirtyFile = 0;    TRACE1("TRANSACTION\n");    if( pPager->useJournal && !pPager->tempFile ){      rc = pager_open_journal(pPager);    }  }  return rc;}/*** 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 write lock on the database.  If the write** 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 sqlitepager_commit() or sqlitepager_rollback() to** reset.*/int sqlitepager_write(void *pData){  PgHdr *pPg = DATA_TO_PGHDR(pData);  Pager *pPager = pPg->pPager;  int rc = SQLITE_OK;  /* Check for errors  */  if( pPager->errMask ){     return pager_errcode(pPager);  }  if( pPager->readOnly ){    return SQLITE_PERM;  }  /* Mark the page as dirty.  If the page has already been written  ** to the journal then we can return right away.  */  pPg->dirty = 1;  if( pPg->inJournal && (pPg->inCkpt || pPager->ckptInUse==0) ){    pPager->dirtyFile = 1;    return SQLITE_OK;  }  /* 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!=SQLITE_UNLOCK );  rc = sqlitepager_begin(pData);  if( rc!=SQLITE_OK ){    return rc;  }  assert( pPager->state==SQLITE_WRITELOCK );  if( !pPager->journalOpen && pPager->useJournal ){    rc = pager_open_journal(pPager);    if( rc!=SQLITE_OK ) return rc;  }  assert( pPager->journalOpen || !pPager->useJournal );  pPager->dirtyFile = 1;  /* The transaction journal now exists and we have a write 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 ){    if( (int)pPg->pgno <= pPager->origDbSize ){      int szPg;      u32 saved;      if( journal_format>=JOURNAL_FORMAT_3 ){        u32 cksum = pager_cksum(pPager, pPg->pgno, pData);        saved = *(u32*)PGHDR_TO_EXTRA(pPg);        store32bits(cksum, pPg, SQLITE_PAGE_SIZE);        szPg = SQLITE_PAGE_SIZE+8;      }else{        szPg = SQLITE_PAGE_SIZE+4;      }      store32bits(pPg->pgno, pPg, -4);      CODEC(pPager, pData, pPg->pgno, 7);      rc = sqliteOsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);      TRACE3("JOURNAL %d %d\n", pPg->pgno, pPg->needSync);      CODEC(pPager, pData, pPg->pgno, 0);      if( journal_format>=JOURNAL_FORMAT_3 ){        *(u32*)PGHDR_TO_EXTRA(pPg) = saved;      }      if( rc!=SQLITE_OK ){        sqlitepager_rollback(pPager);        pPager->errMask |= PAGER_ERR_FULL;        return rc;      }      pPager->nRec++;      assert( pPager->aInJournal!=0 );      pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);      pPg->needSync = !pPager->noSync;      pPg->inJournal = 1;      if( pPager->ckptInUse ){        pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7);        page_add_to_ckpt_list(pPg);      }    }else{      pPg->needSync = !pPager->journalStarted && !pPager->noSync;      TRACE3("APPEND %d %d\n", pPg->pgno, pPg->needSync);    }    if( pPg->needSync ){      pPager->needSync = 1;    }  }  /* If the checkpoint journal is open and the page is not in it,  ** then write the current page to the checkpoint journal.  Note that  ** the checkpoint journal always uses the simplier format 2 that lacks  ** checksums.  The header is also omitted from the checkpoint journal.  */  if( pPager->ckptInUse && !pPg->inCkpt && (int)pPg->pgno<=pPager->ckptSize ){    assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );    store32bits(pPg->pgno, pPg, -4);    CODEC(pPager, pData, pPg->pgno, 7);    rc = sqliteOsWrite(&pPager->cpfd, &((char*)pData)[-4], SQLITE_PAGE_SIZE+4);    TRACE2("CKPT-JOURNAL %d\n", pPg->pgno);    CODEC(pPager, pData, pPg->pgno, 0);    if( rc!=SQLITE_OK ){      sqlitepager_rollback(pPager);      pPager->errMask |= PAGER_ERR_FULL;      return rc;    }    pPager->ckptNRec++;    assert( pPager->aInCkpt!=0 );    pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7);    page_add_to_ckpt_list(pPg);  }  /* Update the database size and return.  */  if( pPager->dbSize<(int)pPg->pgno ){    pPager->dbSize = pPg->pgno;  }  return rc;}/*** Return TRUE if the page given in the argument was previously passed** to sqlitepager_write().  In other words, return TRUE if it is ok** to change the content of the page.*/int sqlitepager_iswriteable(void *pData){  PgHdr *pPg = DATA_TO_PGHDR(pData);  return pPg->dirty;}/*** Replace the content of a single page with the information in the third** argument.*/int sqlitepager_overwrite(Pager *pPager, Pgno pgno, void *pData){  void *pPage;  int rc;  rc = sqlitepager_get(pPager, pgno, &pPage);  if( rc==SQLITE_OK ){    rc = sqlitepager_write(pPage);    if( rc==SQLITE_OK ){      memcpy(pPage, pData, SQLITE_PAGE_SIZE);    }    sqlitepager_unref(pPage);  }  return rc;}/*** A call to this routine tells the pager that it is not necessary to** write the information on page "pgno" 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** sqlitepager_dont_rollback() 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 sqlitepager_dont_rollback() 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 dont_rollback() routine is called.  But because the page contains** critical data, we still need to be sure it gets rolled back in spite** of the dont_rollback() call.*/void sqlitepager_dont_write(Pager *pPager, Pgno pgno){  PgHdr *pPg;  pPg = pager_lookup(pPager, pgno);  pPg->alwaysRollback = 1;  if( pPg && pPg->dirty ){    if( pPage

⌨️ 快捷键说明

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