Esempio n. 1
0
/*
** Obtain space for a page. Try to recycle an old page if the limit on the
** number of pages has been reached. If the limit has not been reached or
** there are no pages eligible for recycling, allocate a new page.
**
** Return a pointer to the new page, or NULL if an OOM condition occurs.
*/
static int pcacheRecycleOrAlloc(PCache *pCache, PgHdr **ppPage) {
    PgHdr *p = 0;

    int szPage = pCache->szPage;
    int szExtra = pCache->szExtra;

    assert( pcache.isInit );
    assert( sqlite3_mutex_held(pcache.mutex) );

    *ppPage = 0;

    /* If we have reached the limit for pinned/dirty pages, and there is at
    ** least one dirty page, invoke the xStress callback to cause a page to
    ** become clean.
    */
    expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
    expensive_assert( pcacheCheckSynced(pCache) );
    if( pCache->xStress
            && pCache->pDirty
            && pCache->nPinned>=(pcache.nMaxPage+pCache->nMin-pcache.nMinPage)
      ) {
        PgHdr *pPg;
        assert(pCache->pDirtyTail);

        for(pPg=pCache->pSynced;
                pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
                pPg=pPg->pPrev
           );
        if( !pPg ) {
            for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pPrev);
        }
        if( pPg ) {
            int rc;
            pcacheExitMutex();
            rc = pCache->xStress(pCache->pStress, pPg);
            pcacheEnterMutex();
            if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ) {
                return rc;
            }
        }
    }

    /* If the global page limit has been reached, try to recycle a page. */
    if( pCache->bPurgeable && pcache.nCurrentPage>=pcache.nMaxPage ) {
        p = pcacheRecyclePage();
    }

    /* If a page has been recycled but it is the wrong size, free it. */
    if( p && (p->pCache->szPage!=szPage || p->pCache->szPage!=szExtra) ) {
        pcachePageFree(p);
        p = 0;
    }

    if( !p ) {
        p = pcachePageAlloc(pCache);
    }

    *ppPage = p;
    return (p?SQLITE_OK:SQLITE_NOMEM);
}
Esempio n. 2
0
static void pcacheMakeClean(PgHdr *p){
  PCache *pCache = p->pCache;
  assert( p->flags & PGHDR_DIRTY );
  pcacheRemoveFromList(&pCache->pDirty, p);
  pcacheAddToList(&pCache->pClean, p);
  p->flags &= ~PGHDR_DIRTY;
  if( p->nRef==0 ){
    pcacheAddToLruList(p);
    pCache->nPinned--;
  }
  expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
}
Esempio n. 3
0
/*
** Make every page in the cache clean.
*/
void sqlite3PcacheCleanAll(PCache *pCache){
  PgHdr *p;
  pcacheEnterMutex();
  while( (p = pCache->pDirty)!=0 ){
    pcacheRemoveFromList(&pCache->pDirty, p);
    p->flags &= ~PGHDR_DIRTY;
    pcacheAddToList(&pCache->pClean, p);
    if( p->nRef==0 ){
      pcacheAddToLruList(p);
      pCache->nPinned--;
    }
  }
  sqlite3PcacheAssertFlags(pCache, 0, PGHDR_DIRTY);
  expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
  pcacheExitMutex();
}
Esempio n. 4
0
/*
** Try to obtain a page from the cache.
*/
int sqlite3PcacheFetch(
  PCache *pCache,       /* Obtain the page from this cache */
  Pgno pgno,            /* Page number to obtain */
  int createFlag,       /* If true, create page if it does not exist already */
  PgHdr **ppPage        /* Write the page here */
){
  int rc = SQLITE_OK;
  PgHdr *pPage = 0;

  assert( pcache_g.isInit );
  assert( pCache!=0 );
  assert( pgno>0 );
  expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );

  pcacheEnterMutex();

  /* Search the hash table for the requested page. Exit early if it is found. */
  if( pCache->apHash ){
    u32 h = pgno % pCache->nHash;
    for(pPage=pCache->apHash[h]; pPage; pPage=pPage->pNextHash){
      if( pPage->pgno==pgno ){
        if( pPage->nRef==0 ){
          if( 0==(pPage->flags&PGHDR_DIRTY) ){
            pcacheRemoveFromLruList(pPage);
            pCache->nPinned++;
          }
          pCache->nRef++;
        }
        pPage->nRef++;
        break;
      }
    }
  }

  if( !pPage && createFlag ){
    if( pCache->nHash<=pCache->nPage ){
      rc = pcacheResizeHash(pCache, pCache->nHash<256 ? 256 : pCache->nHash*2);
    }
    if( rc==SQLITE_OK ){
      rc = pcacheRecycleOrAlloc(pCache, &pPage);
    }
    if( rc==SQLITE_OK ){
      pPage->pPager = 0;
      pPage->flags = 0;
      pPage->pDirty = 0;
      pPage->pgno = pgno;
      pPage->pCache = pCache;
      pPage->nRef = 1;
      pCache->nRef++;
      pCache->nPinned++;
      pcacheAddToList(&pCache->pClean, pPage);
      pcacheAddToHash(pPage);
    }
  }

  pcacheExitMutex();

  *ppPage = pPage;
  expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
  assert( pPage || !createFlag || rc!=SQLITE_OK );
  return rc;
}