Exemple #1
0
/*
** If there are currently more than pcache.nMaxPage pages allocated, try
** to recycle pages to reduce the number allocated to pcache.nMaxPage.
*/
static void pcacheEnforceMaxPage() {
    PgHdr *p;
    assert( sqlite3_mutex_held(pcache.mutex) );
    while( pcache.nCurrentPage>pcache.nMaxPage && (p = pcacheRecyclePage()) ) {
        pcachePageFree(p);
    }
}
/*
** Drop every cache entry whose page number is greater than "pgno".
*/
void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
  PgHdr *p, *pNext;
  PgHdr *pDirty = pCache->pDirty;
  pcacheEnterMutex();
  for(p=pCache->pClean; p||pDirty; p=pNext){
    if( !p ){
      p = pDirty;
      pDirty = 0;
    }
    pNext = p->pNext;
    if( p->pgno>pgno ){
      if( p->nRef==0 ){
        pcacheRemoveFromHash(p);
        if( p->flags&PGHDR_DIRTY ){
          pcacheRemoveFromList(&pCache->pDirty, p);
          pCache->nPinned--;
        }else{
          pcacheRemoveFromList(&pCache->pClean, p);
          pcacheRemoveFromLruList(p);
        }
        pcachePageFree(p);
      }else{
        /* If there are references to the page, it cannot be freed. In this
        ** case, zero the page content instead.
        */
        memset(p->pData, 0, pCache->szPage);
      }
    }
  }
  pcacheExitMutex();
}
Exemple #3
0
/*
** Dereference a page.  When the reference count reaches zero,
** move the page to the LRU list if it is clean.
*/
void sqlite3PcacheRelease(PgHdr *p) {
    assert( p->nRef>0 );
    p->nRef--;
    if( p->nRef==0 ) {
        PCache *pCache = p->pCache;
        if( p->pCache->xDestroy ) {
            p->pCache->xDestroy(p);
        }
        pCache->nRef--;
        if( (p->flags&PGHDR_DIRTY)==0 ) {
            pCache->nPinned--;
            pcacheEnterMutex();
            if( pcache.nCurrentPage>pcache.nMaxPage ) {
                pcacheRemoveFromList(&pCache->pClean, p);
                pcacheRemoveFromHash(p);
                pcachePageFree(p);
            } else {
                pcacheAddToLruList(p);
            }
            pcacheExitMutex();
        } else {
            /* Move the page to the head of the caches dirty list. */
            pcacheRemoveFromList(&pCache->pDirty, p);
            pcacheAddToList(&pCache->pDirty, p);
        }
    }
}
Exemple #4
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);
}
/*
** Remove all content from a page cache
*/
static void pcacheClear(PCache *pCache){
  PgHdr *p, *pNext;
  assert( sqlite3_mutex_held(pcache_g.mutex) );
  for(p=pCache->pClean; p; p=pNext){
    pNext = p->pNext;
    pcacheRemoveFromLruList(p);
    pcachePageFree(p);
  }
  for(p=pCache->pDirty; p; p=pNext){
    pNext = p->pNext;
    pcachePageFree(p);
  }
  pCache->pClean = 0;
  pCache->pDirty = 0;
  pCache->pDirtyTail = 0;
  pCache->nPage = 0;
  pCache->nPinned = 0;
  memset(pCache->apHash, 0, pCache->nHash*sizeof(pCache->apHash[0]));
}
/*
** Drop a page from the cache. There must be exactly one reference to the
** page. This function deletes that reference, so after it returns the
** page pointed to by p is invalid.
*/
void sqlite3PcacheDrop(PgHdr *p){
  PCache *pCache;
  assert( p->nRef==1 );
  assert( 0==(p->flags&PGHDR_DIRTY) );
  pCache = p->pCache;
  pCache->nRef--;
  pCache->nPinned--;
  pcacheEnterMutex();
  pcacheRemoveFromList(&pCache->pClean, p);
  pcacheRemoveFromHash(p);
  pcachePageFree(p);
  pcacheExitMutex();
}
/*
** 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 sqlite3PcacheReleaseMemory(int nReq){
  int nFree = 0;
  if( pcache_g.pStart==0 ){
    PgHdr *p;
    pcacheEnterMutex();
    while( (nReq<0 || nFree<nReq) && (p=pcacheRecyclePage()) ){
      nFree += pcachePageSize(p);
      pcachePageFree(p);
    }
    pcacheExitMutex();
  }
  return nFree;
}