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

📄 pcache.c

📁 最新的sqlite3.6.2源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
    if( p ){      sz = sqlite3MallocSize(p);      sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);    }    return p;  }}void *sqlite3PageMalloc(sz){  void *p;  pcacheEnterMutex();  p = pcacheMalloc(sz, 0);  pcacheExitMutex();  return p;}/*** Release a pager memory allocation*/void pcacheFree(void *p){  assert( sqlite3_mutex_held(pcache.mutex) );  if( p==0 ) return;  if( p>=pcache.pStart && p<pcache.pEnd ){    PgFreeslot *pSlot;    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);    pSlot = (PgFreeslot*)p;    pSlot->pNext = pcache.pFree;    pcache.pFree = pSlot;  }else{    int iSize = sqlite3MallocSize(p);    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);    sqlite3_free(p);  }}void sqlite3PageFree(void *p){  pcacheEnterMutex();  pcacheFree(p);  pcacheExitMutex();}/*** Allocate a new page.*/static PgHdr *pcachePageAlloc(PCache *pCache){  PgHdr *p;  int sz = sizeof(*p) + pCache->szPage + pCache->szExtra;  assert( sqlite3_mutex_held(pcache.mutex) );  p = pcacheMalloc(sz, pCache);  if( p==0 ) return 0;  memset(p, 0, sizeof(PgHdr));  p->pData = (void*)&p[1];  p->pExtra = (void*)&((char*)p->pData)[pCache->szPage];  if( pCache->bPurgeable ){    pcache.nCurrentPage++;  }  return p;}/*** Deallocate a page*/static void pcachePageFree(PgHdr *p){  assert( sqlite3_mutex_held(pcache.mutex) );  if( p->pCache->bPurgeable ){    pcache.nCurrentPage--;  }  pcacheFree(p->apSave[0]);  pcacheFree(p->apSave[1]);  pcacheFree(p);}#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT/*** Return the number of bytes that will be returned to the heap when** the argument is passed to pcachePageFree().*/static int pcachePageSize(PgHdr *p){  assert( sqlite3_mutex_held(pcache.mutex) );  assert( !pcache.pStart );  assert( p->apSave[0]==0 );  assert( p->apSave[1]==0 );  assert( p && p->pCache );  return sqlite3MallocSize(p);}#endif/*** Attempt to 'recycle' a page from the global LRU list. Only clean,** unreferenced pages from purgeable caches are eligible for recycling.**** This function removes page pcache.pLruTail from the global LRU list,** and from the hash-table and PCache.pClean list of the owner pcache.** There should be no other references to the page.**** A pointer to the recycled page is returned, or NULL if no page is** eligible for recycling.*/static PgHdr *pcacheRecyclePage(){  PgHdr *p = 0;  assert( sqlite3_mutex_held(pcache.mutex) );  if( (p=pcache.pLruTail) ){    assert( (p->flags&PGHDR_DIRTY)==0 );    pcacheRemoveFromLruList(p);    pcacheRemoveFromHash(p);    pcacheRemoveFromList(&p->pCache->pClean, p);  }  return p;}/*** 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);}/*************************************************** General Interfaces ********** Initialize and shutdown the page cache subsystem. Neither of these ** functions are threadsafe.*/int sqlite3PcacheInitialize(void){  assert( pcache.isInit==0 );  memset(&pcache, 0, sizeof(pcache));  if( sqlite3Config.bCoreMutex ){    /* No need to check the return value of sqlite3_mutex_alloc().     ** Allocating a static mutex cannot fail.    */    pcache.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);  }  pcache.isInit = 1;  return SQLITE_OK;}void sqlite3PcacheShutdown(void){  memset(&pcache, 0, sizeof(pcache));}/*** Return the size in bytes of a PCache object.*/int sqlite3PcacheSize(void){ return sizeof(PCache); }/*** Create a new PCache object.  Storage space to hold the object** has already been allocated and is passed in as the p pointer.*/void sqlite3PcacheOpen(  int szPage,                  /* Size of every page */  int szExtra,                 /* Extra space associated with each page */  int bPurgeable,              /* True if pages are on backing store */  void (*xDestroy)(PgHdr*),    /* Called to destroy a page */  int (*xStress)(void*,PgHdr*),/* Call to try to make pages clean */  void *pStress,               /* Argument to xStress */  PCache *p                    /* Preallocated space for the PCache */){  assert( pcache.isInit );  memset(p, 0, sizeof(PCache));  p->szPage = szPage;  p->szExtra = szExtra;  p->bPurgeable = bPurgeable;  p->xDestroy = xDestroy;  p->xStress = xStress;  p->pStress = pStress;  p->nMax = 100;  p->nMin = 10;  pcacheEnterMutex();  if( bPurgeable ){    pcache.nMaxPage += p->nMax;    pcache.nMinPage += p->nMin;  }  pcacheExitMutex();}/*** Change the page size for PCache object.  This can only happen** when the cache is empty.*/void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){  assert(pCache->nPage==0);  pCache->szPage = szPage;}/*** 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.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;}/*** 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);    }  }}void sqlite3PcacheRef(PgHdr *p){  assert(p->nRef>0);  p->nRef++;}/*** 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();}/*** Make sure the page is marked as dirty.  If it isn't dirty already,** make it so.*/void sqlite3PcacheMakeDirty(PgHdr *p){  PCache *pCache;  p->flags &= ~PGHDR_DONT_WRITE;  if( p->flags & PGHDR_DIRTY ) return;  assert( (p->flags & PGHDR_DIRTY)==0 );  assert( p->nRef>0 );  pCache = p->pCache;  pcacheEnterMutex();  pcacheRemoveFromList(&pCache->pClean, p);  pcacheAddToList(&pCache->pDirty, p);  pcacheExitMutex();  p->flags |= PGHDR_DIRTY;}void pcacheMakeClean(PgHdr *p){  PCache *pCache = p->pCache;  assert( p->apSave[0]==0 && p->apSave[1]==0 );  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) );}/*** Make sure the page is marked as clean.  If it isn't clean already,** make it so.*/void sqlite3PcacheMakeClean(PgHdr *p){  if( (p->flags & PGHDR_DIRTY) ){    pcacheEnterMutex();    pcacheMakeClean(p);    pcacheExitMutex();  }}/*** Make every page in the cache clean.*/void sqlite3PcacheCleanAll(PCache *pCache){  PgHdr *p;  pcacheEnterMutex();  while( (p = pCache->pDirty)!=0 ){    assert( p->apSave[0]==0 && p->apSave[1]==0 );    pcacheRemoveFromList(&pCache->pDirty, p);    p->flags &= ~PGHDR_DIRTY;

⌨️ 快捷键说明

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