示例#1
0
        /*
        ** Implementation of the sqlite3_pcache.xPagecount method.
        */
        static int pcache1Pagecount(sqlite3_pcache p)
        {
            int n;

            pcache1EnterMutex();
            n = (int)((PCache1)p).nPage;
            pcache1LeaveMutex();
            return(n);
        }
示例#2
0
 private void SetPageSize(int value)
 {
     if (Cache != null)
     {
         //sqlite3GlobalConfig_pcache.xDestroy(Cache);
         Cache = null;
         Page1 = null;
     }
     PageSize = value;
 }
示例#3
0
        /*
        ** Implementation of the sqlite3_pcache.xPagecount method.
        */
        static int pcache1Pagecount(sqlite3_pcache p)
        {
            int     n;
            PCache1 pCache = (PCache1)p;

            pcache1EnterMutex(pCache.pGroup);
            n = (int)pCache.nPage;
            pcache1LeaveMutex(pCache.pGroup);
            return(n);
        }
示例#4
0
        /*
        ** Implementation of the sqlite3_pcache.xTruncate method.
        **
        ** Discard all unpinned pages in the cache with a page number equal to
        ** or greater than parameter iLimit. Any pinned pages with a page number
        ** equal to or greater than iLimit are implicitly unpinned.
        */
        static void pcache1Truncate(sqlite3_pcache p, Pgno iLimit)
        {
            PCache1 pCache = (PCache1)p;

            pcache1EnterMutex(pCache.pGroup);
            if (iLimit <= pCache.iMaxKey)
            {
                pcache1TruncateUnsafe(pCache, iLimit);
                pCache.iMaxKey = iLimit - 1;
            }
            pcache1LeaveMutex(pCache.pGroup);
        }
示例#5
0
        /*
        ** Implementation of the sqlite3_pcache.xCachesize method.
        **
        ** Configure the cache_size limit for a cache.
        */
        private static void pcache1Cachesize(sqlite3_pcache p, int nMax)
        {
            var pCache = p;

            if (pCache.bPurgeable)
            {
                pcache1EnterMutex();
                pcache1.nMaxPage += (int)(nMax - pCache.nMax);
                pCache.nMax       = (uint)nMax;
                pcache1EnforceMaxPage();
                pcache1LeaveMutex();
            }
        }
示例#6
0
        /*
        ** Implementation of the sqlite3_pcache.xDestroy method.
        **
        ** Destroy a cache allocated using pcache1Create().
        */
        static void pcache1Destroy(ref sqlite3_pcache p)
        {
            PCache1 pCache = p;

            pcache1EnterMutex();
            pcache1TruncateUnsafe(pCache, 0);
            pcache1.nMaxPage -= (int)pCache.nMax;
            pcache1.nMinPage -= (int)pCache.nMin;
            pcache1EnforceMaxPage();
            pcache1LeaveMutex();
            //sqlite3_free( ref pCache.apHash );
            //sqlite3_free( ref pCache );
        }
示例#7
0
        /*
        ** Implementation of the sqlite3_pcache.xTruncate method.
        **
        ** Discard all unpinned pages in the cache with a page number equal to
        ** or greater than parameter iLimit. Any pinned pages with a page number
        ** equal to or greater than iLimit are implicitly unpinned.
        */
        private static void pcache1Truncate(sqlite3_pcache p, uint iLimit)
        {
            var pCache = p;

            pcache1EnterMutex();
            if (iLimit <= pCache.iMaxKey)
            {
                pcache1TruncateUnsafe(pCache, iLimit);
                pCache.iMaxKey = iLimit - 1;
            }

            pcache1LeaveMutex();
        }
示例#8
0
        /*
        ** Implementation of the sqlite3_pcache.xCachesize method.
        **
        ** Configure the cache_size limit for a cache.
        */
        static void pcache1Cachesize(sqlite3_pcache p, int nMax)
        {
            PCache1 pCache = (PCache1)p;

            if (pCache.bPurgeable)
            {
                pcache1EnterMutex();
                pcache1.nMaxPage += (int)(nMax - pCache.nMax);
                pCache.nMax       = (u32)nMax;
                pcache1EnforceMaxPage();
                pcache1LeaveMutex();
            }
        }
示例#9
0
        /*
        ** Implementation of the sqlite3_pcache.xRekey method.
        */
        static void pcache1Rekey(
            sqlite3_pcache p,
            PgHdr pPg,
            u32 iOld,
            u32 iNew
            )
        {
            PCache1 pCache = p;
            PgHdr1  pPage  = PAGE_TO_PGHDR1(pCache, pPg);
            PgHdr1  pp;
            u32     h;

            Debug.Assert(pPage.iKey == iOld);
            Debug.Assert(pPage.pCache == pCache);

            pcache1EnterMutex();

            h  = iOld % pCache.nHash;
            pp = pCache.apHash[h];
            while (pp != pPage)
            {
                pp = pp.pNext;
            }
            if (pp == pCache.apHash[h])
            {
                pCache.apHash[h] = pp.pNext;
            }
            else
            {
                pp.pNext = pPage.pNext;
            }

            h                = iNew % pCache.nHash;
            pPage.iKey       = iNew;
            pPage.pNext      = pCache.apHash[h];
            pCache.apHash[h] = pPage;

            /* The xRekey() interface is only used to move pages earlier in the
            ** database file (in order to move all free pages to the end of the
            ** file where they can be truncated off.)  Hence, it is not possible
            ** for the new page number to be greater than the largest previously
            ** fetched page.  But we retain the following test in case xRekey()
            ** begins to be used in different ways in the future.
            */
            if (NEVER(iNew > pCache.iMaxKey))
            {
                pCache.iMaxKey = iNew;
            }

            pcache1LeaveMutex();
        }
示例#10
0
        /*
        ** Implementation of the sqlite3_pcache.xCachesize method.
        **
        ** Configure the cache_size limit for a cache.
        */
        static void pcache1Cachesize(sqlite3_pcache p, int nMax)
        {
            PCache1 pCache = (PCache1)p;

            if (pCache.bPurgeable)
            {
                PGroup pGroup = pCache.pGroup;
                pcache1EnterMutex(pGroup);
                pGroup.nMaxPage += nMax - pCache.nMax;
                pGroup.mxPinned  = pGroup.nMaxPage + 10 - pGroup.nMinPage;
                pCache.nMax      = nMax;
                pCache.n90pct    = pCache.nMax * 9 / 10;
                pcache1EnforceMaxPage(pGroup);
                pcache1LeaveMutex(pGroup);
            }
        }
示例#11
0
        /*
        ** Implementation of the sqlite3_pcache.xDestroy method.
        **
        ** Destroy a cache allocated using pcache1Create().
        */
        static void pcache1Destroy(ref sqlite3_pcache p)
        {
            PCache1 pCache = (PCache1)p;
            PGroup  pGroup = pCache.pGroup;

            Debug.Assert(pCache.bPurgeable || (pCache.nMax == 0 && pCache.nMin == 0));
            pcache1EnterMutex(pGroup);
            pcache1TruncateUnsafe(pCache, 0);
            pGroup.nMaxPage -= pCache.nMax;
            pGroup.nMinPage -= pCache.nMin;
            pGroup.mxPinned  = pGroup.nMaxPage + 10 - pGroup.nMinPage;
            pcache1EnforceMaxPage(pGroup);
            pcache1LeaveMutex(pGroup);
            //sqlite3_free(  pCache.apHash );
            //sqlite3_free( pCache );
            p = null;
        }
示例#12
0
        /*
        ** Implementation of the sqlite3_pcache.xRekey method.
        */
        static void pcache1Rekey(
            sqlite3_pcache p,
            PgHdr pPg,
            u32 iOld,
            u32 iNew
            )
        {
            PCache1 pCache = p;
            PgHdr1  pPage  = PAGE_TO_PGHDR1(pCache, pPg);
            PgHdr1  pp;
            u32     h;

            Debug.Assert(pPage.iKey == iOld);
            Debug.Assert(pPage.pCache == pCache);

            pcache1EnterMutex();

            h  = iOld % pCache.nHash;
            pp = pCache.apHash[h];
            while (pp != pPage)
            {
                pp = pp.pNext;
            }
            if (pp == pCache.apHash[h])
            {
                pCache.apHash[h] = pp.pNext;
            }
            else
            {
                pp.pNext = pPage.pNext;
            }

            h                = iNew % pCache.nHash;
            pPage.iKey       = iNew;
            pPage.pNext      = pCache.apHash[h];
            pCache.apHash[h] = pPage;
            if (iNew > pCache.iMaxKey)
            {
                pCache.iMaxKey = iNew;
            }

            pcache1LeaveMutex();
        }
示例#13
0
        /*
        ** Implementation of the sqlite3_pcache.xRekey method.
        */
        static void pcache1Rekey(
            sqlite3_pcache p,
            PgHdr pPg,
            Pgno iOld,
            Pgno iNew
            )
        {
            PCache1 pCache = (PCache1)p;
            PgHdr1  pPage  = PAGE_TO_PGHDR1(pCache, pPg);
            PgHdr1  pp;
            int     h;

            Debug.Assert(pPage.iKey == iOld);
            Debug.Assert(pPage.pCache == pCache);

            pcache1EnterMutex(pCache.pGroup);

            h  = (int)(iOld % pCache.nHash);
            pp = pCache.apHash[h];
            while ((pp) != pPage)
            {
                pp = (pp).pNext;
            }
            if (pp == pCache.apHash[h])
            {
                pCache.apHash[h] = pp.pNext;
            }
            else
            {
                pp.pNext = pPage.pNext;
            }

            h                = (int)(iNew % pCache.nHash);
            pPage.iKey       = iNew;
            pPage.pNext      = pCache.apHash[h];
            pCache.apHash[h] = pPage;
            if (iNew > pCache.iMaxKey)
            {
                pCache.iMaxKey = iNew;
            }

            pcache1LeaveMutex(pCache.pGroup);
        }
示例#14
0
        /*
        ** Implementation of the sqlite3_pcache.xUnpin method.
        **
        ** Mark a page as unpinned (eligible for asynchronous recycling).
        */
        private static void pcache1Unpin(sqlite3_pcache p, PgHdr pPg, int reuseUnlikely)
        {
            var pCache = p;
            var pPage  = PAGE_TO_PGHDR1(pCache, pPg);

            Debug.Assert(pPage.pCache == pCache);
            pcache1EnterMutex();

            /* It is an error to call this function if the page is already
            ** part of the global LRU list.
            */
            Debug.Assert(pPage.pLruPrev == null && pPage.pLruNext == null);
            Debug.Assert(pcache1.pLruHead != pPage && pcache1.pLruTail != pPage);

            if (reuseUnlikely != 0 || pcache1.nCurrentPage > pcache1.nMaxPage)
            {
                pcache1RemoveFromHash(pPage);
                pcache1FreePage(ref pPage);
            }
            else
            {
                /* Add the page to the global LRU list. Normally, the page is added to
                ** the head of the list (last page to be recycled). However, if the
                ** reuseUnlikely flag passed to this function is true, the page is added
                ** to the tail of the list (first page to be recycled).
                */
                if (pcache1.pLruHead != null)
                {
                    pcache1.pLruHead.pLruPrev = pPage;
                    pPage.pLruNext            = pcache1.pLruHead;
                    pcache1.pLruHead          = pPage;
                }
                else
                {
                    pcache1.pLruTail = pPage;
                    pcache1.pLruHead = pPage;
                }

                pCache.nRecyclable++;
            }

            pcache1LeaveMutex();
        }
示例#15
0
        /*
        ** Implementation of the sqlite3_pcache.xUnpin method.
        **
        ** Mark a page as unpinned (eligible for asynchronous recycling).
        */
        static void pcache1Unpin(sqlite3_pcache p, PgHdr pPg, bool reuseUnlikely)
        {
            PCache1 pCache = (PCache1)p;
            PgHdr1  pPage  = PAGE_TO_PGHDR1(pCache, pPg);
            PGroup  pGroup = pCache.pGroup;

            Debug.Assert(pPage.pCache == pCache);
            pcache1EnterMutex(pGroup);

            /* It is an error to call this function if the page is already
            ** part of the PGroup LRU list.
            */
            Debug.Assert(pPage.pLruPrev == null && pPage.pLruNext == null);
            Debug.Assert(pGroup.pLruHead != pPage && pGroup.pLruTail != pPage);

            if (reuseUnlikely || pGroup.nCurrentPage > pGroup.nMaxPage)
            {
                pcache1RemoveFromHash(pPage);
                pcache1FreePage(ref pPage);
            }
            else
            {
                /* Add the page to the PGroup LRU list. */
                if (pGroup.pLruHead != null)
                {
                    pGroup.pLruHead.pLruPrev = pPage;
                    pPage.pLruNext           = pGroup.pLruHead;
                    pGroup.pLruHead          = pPage;
                }
                else
                {
                    pGroup.pLruTail = pPage;
                    pGroup.pLruHead = pPage;
                }
                pCache.nRecyclable++;
            }

            pcache1LeaveMutex(pCache.pGroup);
        }
示例#16
0
 /*
 ** Implementation of the sqlite3_pcache.xTruncate method.
 **
 ** Discard all unpinned pages in the cache with a page number equal to
 ** or greater than parameter iLimit. Any pinned pages with a page number
 ** equal to or greater than iLimit are implicitly unpinned.
 */
 static void pcache1Truncate( sqlite3_pcache p, u32 iLimit )
 {
   PCache1 pCache = (PCache1)p;
   pcache1EnterMutex();
   if ( iLimit <= pCache.iMaxKey )
   {
     pcache1TruncateUnsafe( pCache, iLimit );
     pCache.iMaxKey = iLimit - 1;
   }
   pcache1LeaveMutex();
 }
示例#17
0
    /*
    ** Implementation of the sqlite3_pcache.xRekey method.
    */
    static void pcache1Rekey(
    sqlite3_pcache p,
    PgHdr pPg,
    u32 iOld,
    u32 iNew
    )
    {
      PCache1 pCache = p;
      PgHdr1 pPage = PAGE_TO_PGHDR1( pCache, pPg );
      PgHdr1 pp;
      u32 h;
      Debug.Assert( pPage.iKey == iOld );
      Debug.Assert( pPage.pCache == pCache );

      pcache1EnterMutex();

      h = iOld % pCache.nHash;
      pp = pCache.apHash[h];
      while ( pp != pPage )
      {
        pp = pp.pNext;
      }
      if ( pp == pCache.apHash[h] ) pCache.apHash[h] = pp.pNext;
      else pp.pNext = pPage.pNext;

      h = iNew % pCache.nHash;
      pPage.iKey = iNew;
      pPage.pNext = pCache.apHash[h];
      pCache.apHash[h] = pPage;

      /* The xRekey() interface is only used to move pages earlier in the
      ** database file (in order to move all free pages to the end of the
      ** file where they can be truncated off.)  Hence, it is not possible
      ** for the new page number to be greater than the largest previously
      ** fetched page.  But we retain the following test in case xRekey()
      ** begins to be used in different ways in the future.
      */
      if ( NEVER( iNew > pCache.iMaxKey ) )
      {
        pCache.iMaxKey = iNew;
      }

      pcache1LeaveMutex();
    }
示例#18
0
        /*
        ** Implementation of the sqlite3_pcache.xFetch method.
        **
        ** Fetch a page by key value.
        **
        ** Whether or not a new page may be allocated by this function depends on
        ** the value of the createFlag argument.  0 means do not allocate a new
        ** page.  1 means allocate a new page if space is easily available.  2
        ** means to try really hard to allocate a new page.
        **
        ** For a non-purgeable cache (a cache used as the storage for an in-memory
        ** database) there is really no difference between createFlag 1 and 2.  So
        ** the calling function (pcache.c) will never have a createFlag of 1 on
        ** a non-purgable cache.
        **
        ** There are three different approaches to obtaining space for a page,
        ** depending on the value of parameter createFlag (which may be 0, 1 or 2).
        **
        **   1. Regardless of the value of createFlag, the cache is searched for a
        **      copy of the requested page. If one is found, it is returned.
        **
        **   2. If createFlag==0 and the page is not already in the cache, NULL is
        **      returned.
        **
        **   3. If createFlag is 1, and the page is not already in the cache, then
        **      return NULL (do not allocate a new page) if any of the following
        **      conditions are true:
        **
        **       (a) the number of pages pinned by the cache is greater than
        **           PCache1.nMax, or
        **
        **       (b) the number of pages pinned by the cache is greater than
        **           the sum of nMax for all purgeable caches, less the sum of
        **           nMin for all other purgeable caches, or
        **
        **   4. If none of the first three conditions apply and the cache is marked
        **      as purgeable, and if one of the following is true:
        **
        **       (a) The number of pages allocated for the cache is already
        **           PCache1.nMax, or
        **
        **       (b) The number of pages allocated for all purgeable caches is
        **           already equal to or greater than the sum of nMax for all
        **           purgeable caches,
        **
        **       (c) The system is under memory pressure and wants to avoid
        **           unnecessary pages cache entry allocations
        **
        **      then attempt to recycle a page from the LRU list. If it is the right
        **      size, return the recycled buffer. Otherwise, free the buffer and
        **      proceed to step 5.
        **
        **   5. Otherwise, allocate and return a new page buffer.
        */
        static PgHdr pcache1Fetch(sqlite3_pcache p, Pgno iKey, int createFlag)
        {
            int     nPinned;
            PCache1 pCache = (PCache1)p;
            PGroup  pGroup;
            PgHdr1  pPage = null;

            Debug.Assert(pCache.bPurgeable || createFlag != 1);
            Debug.Assert(pCache.bPurgeable || pCache.nMin == 0);
            Debug.Assert(pCache.bPurgeable == false || pCache.nMin == 10);
            Debug.Assert(pCache.nMin == 0 || pCache.bPurgeable);
            pcache1EnterMutex(pGroup = pCache.pGroup);

            /* Step 1: Search the hash table for an existing entry. */
            if (pCache.nHash > 0)
            {
                int h = (int)(iKey % pCache.nHash);
                for (pPage = pCache.apHash[h]; pPage != null && pPage.iKey != iKey; pPage = pPage.pNext)
                {
                    ;
                }
            }

            /* Step 2: Abort if no existing page is found and createFlag is 0 */
            if (pPage != null || createFlag == 0)
            {
                pcache1PinPage(pPage);
                goto fetch_out;
            }

            /* The pGroup local variable will normally be initialized by the
            ** pcache1EnterMutex() macro above.  But if SQLITE_MUTEX_OMIT is defined,
            ** then pcache1EnterMutex() is a no-op, so we have to initialize the
            ** local variable here.  Delaying the initialization of pGroup is an
            ** optimization:  The common case is to exit the module before reaching
            ** this point.
            */
#if  SQLITE_MUTEX_OMIT
            pGroup = pCache.pGroup;
#endif


            /* Step 3: Abort if createFlag is 1 but the cache is nearly full */
            nPinned = pCache.nPage - pCache.nRecyclable;
            Debug.Assert(nPinned >= 0);
            Debug.Assert(pGroup.mxPinned == pGroup.nMaxPage + 10 - pGroup.nMinPage);
            Debug.Assert(pCache.n90pct == pCache.nMax * 9 / 10);
            if (createFlag == 1 && (
                    nPinned >= pGroup.mxPinned ||
                    nPinned >= (int)pCache.n90pct ||
                    pcache1UnderMemoryPressure(pCache)
                    ))
            {
                goto fetch_out;
            }

            if (pCache.nPage >= pCache.nHash && pcache1ResizeHash(pCache) != 0)
            {
                goto fetch_out;
            }

            /* Step 4. Try to recycle a page. */
            if (pCache.bPurgeable && pGroup.pLruTail != null && (
                    (pCache.nPage + 1 >= pCache.nMax) ||
                    pGroup.nCurrentPage >= pGroup.nMaxPage ||
                    pcache1UnderMemoryPressure(pCache)
                    ))
            {
                PCache1 pOtherCache;
                pPage = pGroup.pLruTail;
                pcache1RemoveFromHash(pPage);
                pcache1PinPage(pPage);
                if ((pOtherCache = pPage.pCache).szPage != pCache.szPage)
                {
                    pcache1FreePage(ref pPage);
                    pPage = null;
                }
                else
                {
                    pGroup.nCurrentPage -=
                        (pOtherCache.bPurgeable ? 1 : 0) - (pCache.bPurgeable ? 1 : 0);
                }
            }

            /* Step 5. If a usable page buffer has still not been found,
            ** attempt to allocate a new one.
            */
            if (null == pPage)
            {
                if (createFlag == 1)
                {
                    sqlite3BeginBenignMalloc();
                }
                pcache1LeaveMutex(pGroup);
                pPage = pcache1AllocPage(pCache);
                pcache1EnterMutex(pGroup);
                if (createFlag == 1)
                {
                    sqlite3EndBenignMalloc();
                }
            }

            if (pPage != null)
            {
                int h = (int)(iKey % pCache.nHash);
                pCache.nPage++;
                pPage.iKey     = iKey;
                pPage.pNext    = pCache.apHash[h];
                pPage.pCache   = pCache;
                pPage.pLruPrev = null;
                pPage.pLruNext = null;
                PGHDR1_TO_PAGE(pPage).Clear();// *(void **)(PGHDR1_TO_PAGE(pPage)) = 0;
                pPage.pPgHdr.pPgHdr1 = pPage;
                pCache.apHash[h]     = pPage;
            }

fetch_out:
            if (pPage != null && iKey > pCache.iMaxKey)
            {
                pCache.iMaxKey = iKey;
            }
            pcache1LeaveMutex(pGroup);
            return(pPage != null ? PGHDR1_TO_PAGE(pPage) : null);
        }
示例#19
0
 /*
 ** Implementation of the sqlite3_pcache.xPagecount method.
 */
 static int pcache1Pagecount( sqlite3_pcache p )
 {
   int n;
   pcache1EnterMutex();
   n = (int)( (PCache1)p ).nPage;
   pcache1LeaveMutex();
   return n;
 }
示例#20
0
 /*
 ** Implementation of the sqlite3_pcache.xCachesize method.
 **
 ** Configure the cache_size limit for a cache.
 */
 static void pcache1Cachesize( sqlite3_pcache p, int nMax )
 {
   PCache1 pCache = (PCache1)p;
   if ( pCache.bPurgeable )
   {
     pcache1EnterMutex();
     pcache1.nMaxPage += (int)( nMax - pCache.nMax );
     pCache.nMax = (u32)nMax;
     pcache1EnforceMaxPage();
     pcache1LeaveMutex();
   }
 }
示例#21
0
    /*
    ** Implementation of the sqlite3_pcache.xFetch method. 
    **
    ** Fetch a page by key value.
    **
    ** Whether or not a new page may be allocated by this function depends on
    ** the value of the createFlag argument.  0 means do not allocate a new
    ** page.  1 means allocate a new page if space is easily available.  2 
    ** means to try really hard to allocate a new page.
    **
    ** For a non-purgeable cache (a cache used as the storage for an in-memory
    ** database) there is really no difference between createFlag 1 and 2.  So
    ** the calling function (pcache.c) will never have a createFlag of 1 on
    ** a non-purgable cache.
    **
    ** There are three different approaches to obtaining space for a page,
    ** depending on the value of parameter createFlag (which may be 0, 1 or 2).
    **
    **   1. Regardless of the value of createFlag, the cache is searched for a 
    **      copy of the requested page. If one is found, it is returned.
    **
    **   2. If createFlag==0 and the page is not already in the cache, NULL is
    **      returned.
    **
    **   3. If createFlag is 1, and the page is not already in the cache,
    **      and if either of the following are true, return NULL:
    **
    **       (a) the number of pages pinned by the cache is greater than
    **           PCache1.nMax, or
    **       (b) the number of pages pinned by the cache is greater than
    **           the sum of nMax for all purgeable caches, less the sum of 
    **           nMin for all other purgeable caches. 
    **
    **   4. If none of the first three conditions apply and the cache is marked
    **      as purgeable, and if one of the following is true:
    **
    **       (a) The number of pages allocated for the cache is already 
    **           PCache1.nMax, or
    **
    **       (b) The number of pages allocated for all purgeable caches is
    **           already equal to or greater than the sum of nMax for all
    **           purgeable caches,
    **
    **      then attempt to recycle a page from the LRU list. If it is the right
    **      size, return the recycled buffer. Otherwise, free the buffer and
    **      proceed to step 5. 
    **
    **   5. Otherwise, allocate and return a new page buffer.
    */
    static PgHdr pcache1Fetch( sqlite3_pcache p, u32 iKey, int createFlag )
    {
      u32 nPinned;
      PCache1 pCache = p;
      PgHdr1 pPage = null;

      Debug.Assert( pCache.bPurgeable || createFlag != 1 );
      pcache1EnterMutex();
      if ( createFlag == 1 ) sqlite3BeginBenignMalloc();

      /* Search the hash table for an existing entry. */
      if ( pCache.nHash > 0 )
      {
        u32 h = iKey % pCache.nHash;
        for ( pPage = pCache.apHash[h]; pPage != null && pPage.iKey != iKey; pPage = pPage.pNext ) ;
      }

      if ( pPage != null || createFlag == 0 )
      {
        pcache1PinPage( pPage );
        goto fetch_out;
      }

      /* Step 3 of header comment. */
      nPinned = pCache.nPage - pCache.nRecyclable;
      if ( createFlag == 1 && (
      nPinned >= ( pcache1.nMaxPage + pCache.nMin - pcache1.nMinPage )
      || nPinned >= ( pCache.nMax * 9 / 10 )
      ) )
      {
        goto fetch_out;
      }

      if ( pCache.nPage >= pCache.nHash && pcache1ResizeHash( pCache ) != 0 )
      {
        goto fetch_out;
      }

      /* Step 4. Try to recycle a page buffer if appropriate. */
      if ( pCache.bPurgeable && pcache1.pLruTail != null && (
      pCache.nPage + 1 >= pCache.nMax || pcache1.nCurrentPage >= pcache1.nMaxPage
      ) )
      {
        pPage = pcache1.pLruTail;
        pcache1RemoveFromHash( pPage );
        pcache1PinPage( pPage );
        if ( pPage.pCache.szPage != pCache.szPage )
        {
          pcache1FreePage( ref pPage );
          pPage = null;
        }
        else
        {
          pcache1.nCurrentPage -= ( ( pPage.pCache.bPurgeable ? 1 : 0 ) - ( pCache.bPurgeable ? 1 : 0 ) );
        }
      }

      /* Step 5. If a usable page buffer has still not been found,
      ** attempt to allocate a new one.
      */
      if ( null == pPage )
      {
        pPage = pcache1AllocPage( pCache );
      }

      if ( pPage != null )
      {
        u32 h = iKey % pCache.nHash;
        pCache.nPage++;
        pPage.iKey = iKey;
        pPage.pNext = pCache.apHash[h];
        pPage.pCache = pCache;
        pPage.pLruPrev = null;
        pPage.pLruNext = null;
        PGHDR1_TO_PAGE( pPage ).Clear();// *(void **)(PGHDR1_TO_PAGE(pPage)) = 0;
        pPage.pPgHdr.pPgHdr1 = pPage;
        pCache.apHash[h] = pPage;
#if FALSE
        Debug.Assert( pcache1CountHash( pCache ) == pCache.nPage );
#endif
      }

    fetch_out:
      if ( pPage != null && iKey > pCache.iMaxKey )
      {
        pCache.iMaxKey = iKey;
      }
      if ( createFlag == 1 ) sqlite3EndBenignMalloc();
      pcache1LeaveMutex();
      return ( pPage != null ? PGHDR1_TO_PAGE( pPage ) : null );
    }
示例#22
0
    /*
    ** Implementation of the sqlite3_pcache.xUnpin method.
    **
    ** Mark a page as unpinned (eligible for asynchronous recycling).
    */
    static void pcache1Unpin( sqlite3_pcache p, PgHdr pPg, int reuseUnlikely )
    {
      PCache1 pCache = (PCache1)p;
      PgHdr1 pPage = PAGE_TO_PGHDR1( pCache, pPg );

      Debug.Assert( pPage.pCache == pCache );
      pcache1EnterMutex();

      /* It is an error to call this function if the page is already
      ** part of the global LRU list.
      */
      Debug.Assert( pPage.pLruPrev == null && pPage.pLruNext == null );
      Debug.Assert( pcache1.pLruHead != pPage && pcache1.pLruTail != pPage );

      if ( reuseUnlikely != 0 || pcache1.nCurrentPage > pcache1.nMaxPage )
      {
        pcache1RemoveFromHash( pPage );
        pcache1FreePage( ref pPage );
      }
      else
      {
        /* Add the page to the global LRU list. Normally, the page is added to
        ** the head of the list (last page to be recycled). However, if the
        ** reuseUnlikely flag passed to this function is true, the page is added
        ** to the tail of the list (first page to be recycled).
        */
        if ( pcache1.pLruHead != null )
        {
          pcache1.pLruHead.pLruPrev = pPage;
          pPage.pLruNext = pcache1.pLruHead;
          pcache1.pLruHead = pPage;
        }
        else
        {
          pcache1.pLruTail = pPage;
          pcache1.pLruHead = pPage;
        }
        pCache.nRecyclable++;
      }

      pcache1LeaveMutex();
    }
示例#23
0
    /*
    ** Implementation of the sqlite3_pcache.xRekey method.
    */
    static void pcache1Rekey(
    sqlite3_pcache p,
    PgHdr pPg,
    u32 iOld,
    u32 iNew
    )
    {
      PCache1 pCache = p;
      PgHdr1 pPage = PAGE_TO_PGHDR1( pCache, pPg );
      PgHdr1 pp;
      u32 h;
      Debug.Assert( pPage.iKey == iOld );
      Debug.Assert( pPage.pCache == pCache );

      pcache1EnterMutex();

      h = iOld % pCache.nHash;
      pp = pCache.apHash[h];
      while ( pp != pPage )
      {
        pp = pp.pNext;
      }
      if ( pp == pCache.apHash[h] ) pCache.apHash[h] = pp.pNext;
      else pp.pNext = pPage.pNext;

      h = iNew % pCache.nHash;
      pPage.iKey = iNew;
      pPage.pNext = pCache.apHash[h];
      pCache.apHash[h] = pPage;
      if ( iNew > pCache.iMaxKey )
      {
        pCache.iMaxKey = iNew;
      }

      pcache1LeaveMutex();
    }
示例#24
0
        /*
        ** Implementation of the sqlite3_pcache.xFetch method.
        **
        ** Fetch a page by key value.
        **
        ** Whether or not a new page may be allocated by this function depends on
        ** the value of the createFlag argument.  0 means do not allocate a new
        ** page.  1 means allocate a new page if space is easily available.  2
        ** means to try really hard to allocate a new page.
        **
        ** For a non-purgeable cache (a cache used as the storage for an in-memory
        ** database) there is really no difference between createFlag 1 and 2.  So
        ** the calling function (pcache.c) will never have a createFlag of 1 on
        ** a non-purgable cache.
        **
        ** There are three different approaches to obtaining space for a page,
        ** depending on the value of parameter createFlag (which may be 0, 1 or 2).
        **
        **   1. Regardless of the value of createFlag, the cache is searched for a
        **      copy of the requested page. If one is found, it is returned.
        **
        **   2. If createFlag==0 and the page is not already in the cache, NULL is
        **      returned.
        **
        **   3. If createFlag is 1, and the page is not already in the cache,
        **      and if either of the following are true, return NULL:
        **
        **       (a) the number of pages pinned by the cache is greater than
        **           PCache1.nMax, or
        **       (b) the number of pages pinned by the cache is greater than
        **           the sum of nMax for all purgeable caches, less the sum of
        **           nMin for all other purgeable caches.
        **
        **   4. If none of the first three conditions apply and the cache is marked
        **      as purgeable, and if one of the following is true:
        **
        **       (a) The number of pages allocated for the cache is already
        **           PCache1.nMax, or
        **
        **       (b) The number of pages allocated for all purgeable caches is
        **           already equal to or greater than the sum of nMax for all
        **           purgeable caches,
        **
        **      then attempt to recycle a page from the LRU list. If it is the right
        **      size, return the recycled buffer. Otherwise, free the buffer and
        **      proceed to step 5.
        **
        **   5. Otherwise, allocate and return a new page buffer.
        */
        static PgHdr pcache1Fetch(sqlite3_pcache p, u32 iKey, int createFlag)
        {
            u32     nPinned;
            PCache1 pCache = p;
            PgHdr1  pPage  = null;

            Debug.Assert(pCache.bPurgeable || createFlag != 1);
            pcache1EnterMutex();
            if (createFlag == 1)
            {
                sqlite3BeginBenignMalloc();
            }

            /* Search the hash table for an existing entry. */
            if (pCache.nHash > 0)
            {
                u32 h = iKey % pCache.nHash;
                for (pPage = pCache.apHash[h]; pPage != null && pPage.iKey != iKey; pPage = pPage.pNext)
                {
                    ;
                }
            }

            if (pPage != null || createFlag == 0)
            {
                pcache1PinPage(pPage);
                goto fetch_out;
            }

            /* Step 3 of header comment. */
            nPinned = pCache.nPage - pCache.nRecyclable;
            if (createFlag == 1 && (
                    nPinned >= (pcache1.nMaxPage + pCache.nMin - pcache1.nMinPage) ||
                    nPinned >= (pCache.nMax * 9 / 10)
                    ))
            {
                goto fetch_out;
            }

            if (pCache.nPage >= pCache.nHash && pcache1ResizeHash(pCache) != 0)
            {
                goto fetch_out;
            }

            /* Step 4. Try to recycle a page buffer if appropriate. */
            if (pCache.bPurgeable && pcache1.pLruTail != null && (
                    pCache.nPage + 1 >= pCache.nMax || pcache1.nCurrentPage >= pcache1.nMaxPage
                    ))
            {
                pPage = pcache1.pLruTail;
                pcache1RemoveFromHash(pPage);
                pcache1PinPage(pPage);
                if (pPage.pCache.szPage != pCache.szPage)
                {
                    pcache1FreePage(ref pPage);
                    pPage = null;
                }
                else
                {
                    pcache1.nCurrentPage -= ((pPage.pCache.bPurgeable ? 1 : 0) - (pCache.bPurgeable ? 1 : 0));
                }
            }

            /* Step 5. If a usable page buffer has still not been found,
            ** attempt to allocate a new one.
            */
            if (null == pPage)
            {
                pPage = pcache1AllocPage(pCache);
            }

            if (pPage != null)
            {
                u32 h = iKey % pCache.nHash;
                pCache.nPage++;
                pPage.iKey     = iKey;
                pPage.pNext    = pCache.apHash[h];
                pPage.pCache   = pCache;
                pPage.pLruPrev = null;
                pPage.pLruNext = null;
                PGHDR1_TO_PAGE(pPage).Clear();// *(void **)(PGHDR1_TO_PAGE(pPage)) = 0;
                pPage.pPgHdr.pPgHdr1 = pPage;
                pCache.apHash[h]     = pPage;
#if FALSE
                Debug.Assert(pcache1CountHash(pCache) == pCache.nPage);
#endif
            }

fetch_out:
            if (pPage != null && iKey > pCache.iMaxKey)
            {
                pCache.iMaxKey = iKey;
            }
            if (createFlag == 1)
            {
                sqlite3EndBenignMalloc();
            }
            pcache1LeaveMutex();
            return(pPage != null ? PGHDR1_TO_PAGE(pPage) : null);
        }
示例#25
0
 /*
 ** Implementation of the sqlite3_pcache.xDestroy method.
 **
 ** Destroy a cache allocated using pcache1Create().
 */
 static void pcache1Destroy( ref sqlite3_pcache p )
 {
   PCache1 pCache = p;
   pcache1EnterMutex();
   pcache1TruncateUnsafe( pCache, 0 );
   pcache1.nMaxPage -= (int)pCache.nMax;
   pcache1.nMinPage -= (int)pCache.nMin;
   pcache1EnforceMaxPage();
   pcache1LeaveMutex();
   //sqlite3_free( ref pCache.apHash );
   //sqlite3_free( ref pCache );
   p = null;
 }