From a85f7e36e8fc5aa88625726b113be6704ce3792a Mon Sep 17 00:00:00 2001 From: drh <drh@noemail.net> Date: Thu, 28 Aug 2008 02:26:07 +0000 Subject: [PATCH] Miscellaneous cleanup in the new pcache code. (CVS 5629) FossilOrigin-Name: da1777259f53c2e20c7ced06bf6f2a550f0ea0fc --- manifest | 20 ++-- manifest.uuid | 2 +- src/pager.c | 9 +- src/pcache.c | 274 ++++++++++++++++++++++++++---------------------- src/pcache.h | 22 ++-- src/test_func.c | 7 +- 6 files changed, 183 insertions(+), 151 deletions(-) diff --git a/manifest b/manifest index 2b436e05ac..ad116edebf 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C If\sany\serror\soccurs\sduring\ssqlite3_open(),\smove\sthe\sdatabase\shandle\sinto\s"sick"\sstate.\sWhen\sin\sthe\ssick\sstate\sthe\suser\scan\suse\ssqlite3_errcode()\sand\ssqlite3_errmsg(),\sbut\snot\smuch\selse.\s(CVS\s5628) -D 2008-08-27T19:01:58 +C Miscellaneous\scleanup\sin\sthe\snew\spcache\scode.\s(CVS\s5629) +D 2008-08-28T02:26:07 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in 689e14735f862a5553bceef206d8c13e29504e44 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -134,11 +134,11 @@ F src/os_common.h 24525d8b7bce66c374dfc1810a6c9043f3359b60 F src/os_os2.c e391fc95adc744bbdcefd4d11e3066998185a0a0 F src/os_unix.c 4665cef7639dd937893c3ea076f0e8a8f215bb32 F src/os_win.c aefe9ee26430678a19a058a874e4e2bd91398142 -F src/pager.c 84f4c171a0cb4561291f212508b1a91a8a325abb +F src/pager.c 032d11049af4ec49bdbaa3584e7ce9887098b66a F src/pager.h 914103bb62dbcc3d8e9f14baec812d027264d457 F src/parse.y d0f76d2cb8d6883d5600dc20beb961a6022b94b8 -F src/pcache.c 3d9d933bb22f10956ab78d83798d88ca9a147e86 -F src/pcache.h 7a50b77f06c220ff7696be1a9f2a17c9e6ddc486 +F src/pcache.c aa609c9b1fc1a2b00f7d7bfb3d06b1e507767b93 +F src/pcache.h bd373ee3e4db310d6bbe7fa6d8d971de9678edd8 F src/pragma.c f5b271b090af7fcedd308d7c5807a5503f7a853d F src/prepare.c c197041e0c4770672cda75e6bfe10242f885e510 F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d @@ -167,7 +167,7 @@ F src/test_autoext.c f53b0cdf7bf5f08100009572a5d65cdb540bd0ad F src/test_btree.c 7170e0c922ed3979f2d38f4a3f84728e5740dfc3 F src/test_config.c 224f699a34d45eb8ac5c22a7ad6cdbb8edf0ba28 F src/test_devsym.c 6012cb8e3acf812513511025a4fa5d626e0ba19b -F src/test_func.c bc648b7747320e037d756acfa1037bd8dedf3f8b +F src/test_func.c a55c4d5479ff2eb5c0a22d4d88e9528ab59c953b F src/test_hexio.c 2f1122aa3f012fa0142ee3c36ce5c902a70cd12f F src/test_loadext.c 97dc8800e46a46ed002c2968572656f37e9c0dd9 F src/test_malloc.c 49abbf5d9c71fb06cf7a7cf96f9b9a799b77a421 @@ -624,7 +624,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P 39c34e2238c27b2a2f4f0b896126ccbd299114c5 -R 0bf03a77bd82f6ac6f412ad9339ae6a4 -U danielk1977 -Z ac6800a3d7725cc034896ca6e2243181 +P ce9c74eaab459ddde213c828e821940f5d6cb354 +R 55c280ec697a3a6039a240cf488ad9ad +U drh +Z 7df830e688305e6be422e59df78b53fe diff --git a/manifest.uuid b/manifest.uuid index 9e981efe54..609a5bfb32 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ce9c74eaab459ddde213c828e821940f5d6cb354 \ No newline at end of file +da1777259f53c2e20c7ced06bf6f2a550f0ea0fc \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index b5296fbcd6..9b063b7b2c 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.484 2008/08/27 18:03:20 drh Exp $ +** @(#) $Id: pager.c,v 1.485 2008/08/28 02:26:07 drh Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -3271,15 +3271,14 @@ static int pager_write(PgHdr *pPg){ && !pageInStatement(pPg) && (int)pPg->pgno<=pPager->stmtSize ){ - assert( - (pPg->flags&PGHDR_IN_JOURNAL) || (int)pPg->pgno>pPager->origDbSize ); + assert( (pPg->flags&PGHDR_IN_JOURNAL) + || (int)pPg->pgno>pPager->origDbSize ); if( MEMDB ){ rc = sqlite3PcachePreserve(pPg, 1); if( rc!=SQLITE_OK ){ return rc; } PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); - /* page_add_to_stmt_list(pPg); */ }else{ i64 offset = pPager->stmtNRec*(4+pPager->pageSize); char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7); @@ -3507,7 +3506,7 @@ void sqlite3PagerDontRollback(DbPage *pPg){ assert( !MEMDB ); /* For a memdb, pPager->journalOpen is always 0 */ #ifdef SQLITE_SECURE_DELETE - if( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize ){ + if( (pPg->flags & PGHDR_IN_JOURNAL)!=0 || (int)pPg->pgno>pPager->origDbSize ){ return; } #endif diff --git a/src/pcache.c b/src/pcache.c index b0127120b4..50616bf88b 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -11,30 +11,50 @@ ************************************************************************* ** This file implements that page cache. ** -** @(#) $Id: pcache.c,v 1.18 2008/08/27 16:38:57 danielk1977 Exp $ +** @(#) $Id: pcache.c,v 1.19 2008/08/28 02:26:07 drh Exp $ */ #include "sqliteInt.h" /* ** A complete page cache is an instance of this structure. +** +** A cache may only be deleted by its owner and while holding the +** SQLITE_MUTEX_STATUS_LRU mutex. */ struct PCache { - int szPage; /* Size of every page in this cache */ - int szExtra; /* Size of extra space for each page */ - int nHash; /* Number of slots in apHash[] */ - int nPage; /* Total number of pages in apHash */ - int nMax; /* Configured cache size */ - int nMin; /* Configured minimum cache size */ - PgHdr **apHash; /* Hash table for fast lookup by pgno */ - int bPurgeable; /* True if pages are on backing store */ - void (*xDestroy)(PgHdr*); /* Called when refcnt goes 1->0 */ - int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ - void *pStress; /* Argument to xStress */ - PgHdr *pClean; /* List of clean pages in use */ + /********************************************************************* + ** The first group of elements may be read or written at any time by + ** the cache owner without holding the mutex. No thread other than the + ** cache owner is permitted to access these elements at any time. + */ PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ PgHdr *pSynced; /* Last synced page in dirty page list */ int nRef; /* Number of pinned pages */ int nPinned; /* Number of pinned and/or dirty pages */ + int nMax; /* Configured cache size */ + int nMin; /* Configured minimum cache size */ + /********************************************************************** + ** The next group of elements are fixed when the cache is created and + ** may not be changed afterwards. These elements can read at any time by + ** the cache owner or by any thread holding the the mutex. Non-owner + ** threads must hold the mutex when reading these elements to prevent + ** the entire PCache object from being deleted during the read. + */ + int szPage; /* Size of every page in this cache */ + int szExtra; /* Size of extra space for each page */ + int bPurgeable; /* True if pages are on backing store */ + void (*xDestroy)(PgHdr*); /* Called when refcnt goes 1->0 */ + int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ + void *pStress; /* Argument to xStress */ + /********************************************************************** + ** The final group of elements can only be accessed while holding the + ** mutex. Both the cache owner and any other thread must hold the mutex + ** to read or write any of these elements. + */ + int nPage; /* Total number of pages in apHash */ + int nHash; /* Number of slots in apHash[] */ + PgHdr **apHash; /* Hash table for fast lookup by pgno */ + PgHdr *pClean; /* List of clean pages in use */ }; /* @@ -47,20 +67,6 @@ struct PgFreeslot { /* ** Global data for the page cache. -** -** The maximum number of cached pages stored by the system is determined -** by the pcache.mxPage and pcache.mxPagePurgeable variables. If -** mxPage is non-zero, then the system tries to limit the number of -** cached pages stored to mxPage. In this case mxPagePurgeable is not -** used. -** -** If mxPage is zero, then the system tries to limit the number of -** pages held by purgable caches to mxPagePurgeable. -** -** The doubly-linked list that runs between pcache.pLruHead and -** pcache.pLruTail contains all clean purgable pages in the system -** with a zero reference count. pcache.pLruTail is the next page to -** be recycled. */ static struct PCacheGlobal { int isInit; /* True when initialized */ @@ -78,29 +84,46 @@ static struct PCacheGlobal { } pcache = {0}; /* -** All global variables used by this module (most of which are grouped +** All global variables used by this module (all of which are grouped ** together in global structure "pcache" above) are protected by the static ** SQLITE_MUTEX_STATIC_LRU mutex. A pointer to this mutex is stored in ** variable "pcache.mutex". ** -** Access to the contents of the individual PCache structures is not -** protected. It is the job of the caller to ensure that these structures -** are accessed in a thread-safe manner. +** Some elements of the PCache and PgHdr structures are protected by the +** SQLITE_MUTEX_STATUS_LRU mutex and other are not. The protected +** elements are grouped at the end of the structures and are clearly +** marked. +** +** Use the following macros must surround all access (read or write) +** of protected elements. The mutex is not recursive and may not be +** entered more than once. The pcacheMutexHeld() macro should only be +** used within an assert() to verify that the mutex is being held. */ +#define pcacheEnterMutex() sqlite3_mutex_enter(pcache.mutex) +#define pcacheExitMutex() sqlite3_mutex_leave(pcache.mutex) +#define pcacheMutexHeld() sqlite3_mutex_held(pcache.mutex) -#define pcacheEnterGlobal() sqlite3_mutex_enter(pcache.mutex) -#define pcacheExitGlobal() sqlite3_mutex_leave(pcache.mutex) +/* +** Some of the assert() macros in this code are too expensive to run +** even during normal debugging. Use them only rarely on long-running +** tests. Enable the expensive asserts using the +** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option. +*/ +#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT +# define expensive_assert(X) assert(X) +#else +# define expensive_assert(X) +#endif /********************************** Linked List Management ********************/ -#ifndef NDEBUG +#if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT) /* ** This routine verifies that the number of entries in the hash table ** is pCache->nPage. This routine is used within assert() statements ** only and is therefore disabled during production builds. */ static int pcacheCheckHashCount(PCache *pCache){ -#if 0 int i; int nPage = 0; for(i=0; i<pCache->nHash; i++){ @@ -110,19 +133,20 @@ static int pcacheCheckHashCount(PCache *pCache){ } } assert( nPage==pCache->nPage ); -#endif return 1; } +#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */ + +#if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT) /* ** Based on the current value of PCache.nRef and the contents of the ** PCache.pDirty list, return the expected value of the PCache.nPinned ** counter. This is only used in debugging builds, as follows: ** -** assert( pCache->nPinned==pcachePinnedCount(pCache) ); +** expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); */ static int pcachePinnedCount(PCache *pCache){ -#if 0 PgHdr *p; int nPinned = pCache->nRef; for(p=pCache->pDirty; p; p=p->pNext){ @@ -131,34 +155,35 @@ static int pcachePinnedCount(PCache *pCache){ } } return nPinned; -#endif - return pCache->nPinned; } +#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */ + +#if !defined(NDEBUG) && defined(SQLITE_ENABLE_EXPENSIVE_ASSERT) /* ** Check that the pCache->pSynced variable is set correctly. If it ** is not, either fail an assert or return zero. Otherwise, return ** non-zero. This is only used in debugging builds, as follows: ** -** assert( pcacheCheckSynced(pCache) ); +** expensive_assert( pcacheCheckSynced(pCache) ); */ static int pcacheCheckSynced(PCache *pCache){ -#if 0 PgHdr *p = pCache->pDirtyTail; for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pPrev){ assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) ); } return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0); -#endif return 1; } +#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */ + -#endif /* ** Remove a page from its hash table (PCache.apHash[]). */ static void pcacheRemoveFromHash(PgHdr *pPage){ + /* assert( pcacheMutexHeld() ); *** FIXME ****/ if( pPage->pPrevHash ){ pPage->pPrevHash->pNextHash = pPage->pNextHash; }else{ @@ -171,15 +196,18 @@ static void pcacheRemoveFromHash(PgHdr *pPage){ pPage->pNextHash->pPrevHash = pPage->pPrevHash; } pPage->pCache->nPage--; - assert( pcacheCheckHashCount(pPage->pCache) ); + expensive_assert( pcacheCheckHashCount(pPage->pCache) ); } /* ** Insert a page into the hash table +** +** The mutex must be held by the caller. */ static void pcacheAddToHash(PgHdr *pPage){ PCache *pCache = pPage->pCache; u32 h = pPage->pgno % pCache->nHash; + /* assert( pcacheMutexHeld() ); *** FIXME *****/ pPage->pNextHash = pCache->apHash[h]; pPage->pPrevHash = 0; if( pCache->apHash[h] ){ @@ -187,7 +215,7 @@ static void pcacheAddToHash(PgHdr *pPage){ } pCache->apHash[h] = pPage; pCache->nPage++; - assert( pcacheCheckHashCount(pCache) ); + expensive_assert( pcacheCheckHashCount(pCache) ); } /* @@ -195,29 +223,29 @@ static void pcacheAddToHash(PgHdr *pPage){ ** at least nHash buckets. */ static int pcacheResizeHash(PCache *pCache, int nHash){ + PgHdr *p; + PgHdr **pNew; + /* assert( pcacheMutexHeld() ); **** FIXME *****/ #ifdef SQLITE_MALLOC_SOFT_LIMIT if( nHash*sizeof(PgHdr*)>SQLITE_MALLOC_SOFT_LIMIT ){ nHash = SQLITE_MALLOC_SOFT_LIMIT/sizeof(PgHdr *); } #endif - if( nHash>pCache->nHash ){ - PgHdr *p; - PgHdr **pNew = (PgHdr **)sqlite3_malloc(sizeof(PgHdr*)*nHash); - if( !pNew ){ - return SQLITE_NOMEM; - } - memset(pNew, 0, sizeof(PgHdr *)*nHash); - sqlite3_free(pCache->apHash); - pCache->apHash = pNew; - pCache->nHash = nHash; - pCache->nPage = 0; - - for(p=pCache->pClean; p; p=p->pNext){ - pcacheAddToHash(p); - } - for(p=pCache->pDirty; p; p=p->pNext){ - pcacheAddToHash(p); - } + pNew = (PgHdr **)sqlite3_malloc(sizeof(PgHdr*)*nHash); + if( !pNew ){ + return SQLITE_NOMEM; + } + memset(pNew, 0, sizeof(PgHdr *)*nHash); + sqlite3_free(pCache->apHash); + pCache->apHash = pNew; + pCache->nHash = nHash; + pCache->nPage = 0; + + for(p=pCache->pClean; p; p=p->pNext){ + pcacheAddToHash(p); + } + for(p=pCache->pDirty; p; p=p->pNext){ + pcacheAddToHash(p); } return SQLITE_OK; } @@ -229,6 +257,7 @@ static int pcacheResizeHash(PCache *pCache, int nHash){ static void pcacheRemoveFromList(PgHdr **ppHead, PgHdr *pPage){ int isDirtyList = (ppHead==&pPage->pCache->pDirty); assert( ppHead==&pPage->pCache->pClean || ppHead==&pPage->pCache->pDirty ); + /* assert( pcacheMutexHeld() || ppHead!=&pPage->pCache->pClean ); *** FIXME */ if( pPage->pPrev ){ pPage->pPrev->pNext = pPage->pNext; @@ -384,13 +413,11 @@ void *pcacheMalloc(int sz, PCache *pCache){ ** global pcache mutex and unlock the pager-cache object pCache. This is ** so that if the attempt to allocate a new buffer causes the the ** configured soft-heap-limit to be breached, it will be possible to - ** reclaim memory from this pager-cache. Because sqlite3PcacheLock() - ** might block on the MEM2 mutex, it has to be called before re-entering - ** the global LRU mutex. + ** reclaim memory from this pager-cache. */ - pcacheExitGlobal(); + pcacheExitMutex(); p = sqlite3Malloc(sz); - pcacheEnterGlobal(); + pcacheEnterMutex(); if( p ){ sz = sqlite3MallocSize(p); @@ -401,9 +428,9 @@ void *pcacheMalloc(int sz, PCache *pCache){ } void *sqlite3PageMalloc(sz){ void *p; - pcacheEnterGlobal(); + pcacheEnterMutex(); p = pcacheMalloc(sz, 0); - pcacheExitGlobal(); + pcacheExitMutex(); return p; } @@ -426,9 +453,9 @@ void pcacheFree(void *p){ } } void sqlite3PageFree(void *p){ - pcacheEnterGlobal(); + pcacheEnterMutex(); pcacheFree(p); - pcacheExitGlobal(); + pcacheExitMutex(); } /* @@ -519,14 +546,14 @@ static int pcacheRecycleOrAlloc(PCache *pCache, PgHdr **ppPage){ assert( sqlite3_mutex_notheld(pcache.mutex) ); *ppPage = 0; - pcacheEnterGlobal(); + pcacheEnterMutex(); /* 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. */ - assert( pCache->nPinned==pcachePinnedCount(pCache) ); - assert( pcacheCheckSynced(pCache) ); + expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); + expensive_assert( pcacheCheckSynced(pCache) ); if( pCache->xStress && pCache->pDirty && pCache->nPinned>=(pcache.nMaxPage+pCache->nMin-pcache.nMinPage) @@ -543,12 +570,12 @@ static int pcacheRecycleOrAlloc(PCache *pCache, PgHdr **ppPage){ } if( pPg ){ int rc; - pcacheExitGlobal(); + pcacheExitMutex(); rc = pCache->xStress(pCache->pStress, pPg); if( rc!=SQLITE_OK ){ return rc; } - pcacheEnterGlobal(); + pcacheEnterMutex(); } } @@ -558,7 +585,7 @@ static int pcacheRecycleOrAlloc(PCache *pCache, PgHdr **ppPage){ } /* If a page has been recycled but it is the wrong size, free it. */ - if( p && (p->pCache->szPage!=szPage || p->pCache->szExtra!=szExtra) ){ + if( p && (p->pCache->szPage!=szPage || p->pCache->szPage!=szExtra) ){ pcachePageFree(p); p = 0; } @@ -567,7 +594,7 @@ static int pcacheRecycleOrAlloc(PCache *pCache, PgHdr **ppPage){ p = pcachePageAlloc(pCache); } - pcacheExitGlobal(); + pcacheExitMutex(); *ppPage = p; return (p?SQLITE_OK:SQLITE_NOMEM); } @@ -622,13 +649,13 @@ void sqlite3PcacheOpen( p->nMax = 100; p->nMin = 10; - pcacheEnterGlobal(); + pcacheEnterMutex(); if( bPurgeable ){ pcache.nMaxPage += p->nMax; pcache.nMinPage += p->nMin; } - pcacheExitGlobal(); + pcacheExitMutex(); } /* @@ -653,7 +680,7 @@ int sqlite3PcacheFetch( assert( pcache.isInit ); assert( pCache!=0 ); assert( pgno>0 ); - assert( pCache->nPinned==pcachePinnedCount(pCache) ); + expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); /* Search the hash table for the requested page. Exit early if it is found. */ if( pCache->apHash ){ @@ -662,9 +689,9 @@ int sqlite3PcacheFetch( if( pPage->pgno==pgno ){ if( pPage->nRef==0 ){ if( 0==(pPage->flags&PGHDR_DIRTY) ){ - pcacheEnterGlobal(); + pcacheEnterMutex(); pcacheRemoveFromLruList(pPage); - pcacheExitGlobal(); + pcacheExitMutex(); pCache->nPinned++; } pCache->nRef++; @@ -679,7 +706,7 @@ int sqlite3PcacheFetch( if( createFlag ){ int rc = SQLITE_OK; if( pCache->nHash<=pCache->nPage ){ - rc = pcacheResizeHash(pCache, pCache->nHash<256?256:pCache->nHash*2); + rc = pcacheResizeHash(pCache, pCache->nHash<256 ? 256 : pCache->nHash*2); if( rc!=SQLITE_OK ){ return rc; } @@ -704,7 +731,7 @@ int sqlite3PcacheFetch( *ppPage = 0; } - assert( pCache->nPinned==pcachePinnedCount(pCache) ); + expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); return SQLITE_OK; } @@ -723,9 +750,9 @@ void sqlite3PcacheRelease(PgHdr *p){ pCache->nRef--; if( (p->flags&PGHDR_DIRTY)==0 ){ pCache->nPinned--; - pcacheEnterGlobal(); + pcacheEnterMutex(); pcacheAddToLruList(p); - pcacheExitGlobal(); + pcacheExitMutex(); }else{ /* Move the page to the head of the caches dirty list. */ pcacheRemoveFromList(&pCache->pDirty, p); @@ -753,9 +780,9 @@ void sqlite3PcacheDrop(PgHdr *p){ pCache->nPinned--; pcacheRemoveFromList(&pCache->pClean, p); pcacheRemoveFromHash(p); - pcacheEnterGlobal(); + pcacheEnterMutex(); pcachePageFree(p); - pcacheExitGlobal(); + pcacheExitMutex(); } /* @@ -785,15 +812,15 @@ void sqlite3PcacheMakeClean(PgHdr *p){ assert( p->flags & PGHDR_DIRTY ); pCache = p->pCache; pcacheRemoveFromList(&pCache->pDirty, p); - pcacheEnterGlobal(); + pcacheEnterMutex(); pcacheAddToList(&pCache->pClean, p); p->flags &= ~PGHDR_DIRTY; if( p->nRef==0 ){ pcacheAddToLruList(p); pCache->nPinned--; } - assert( pCache->nPinned==pcachePinnedCount(pCache) ); - pcacheExitGlobal(); + expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); + pcacheExitMutex(); } /* @@ -801,7 +828,7 @@ void sqlite3PcacheMakeClean(PgHdr *p){ */ void sqlite3PcacheCleanAll(PCache *pCache){ PgHdr *p; - pcacheEnterGlobal(); + pcacheEnterMutex(); while( (p = pCache->pDirty)!=0 ){ assert( p->apSave[0]==0 && p->apSave[1]==0 ); pcacheRemoveFromList(&pCache->pDirty, p); @@ -813,8 +840,8 @@ void sqlite3PcacheCleanAll(PCache *pCache){ } } sqlite3PcacheAssertFlags(pCache, 0, PGHDR_DIRTY); - assert( pCache->nPinned==pcachePinnedCount(pCache) ); - pcacheExitGlobal(); + expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) ); + pcacheExitMutex(); } /* @@ -828,10 +855,10 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ p->pgno = newPgno; if( newPgno==0 ){ p->flags |= PGHDR_REUSE_UNLIKELY; - pcacheEnterGlobal(); + pcacheEnterMutex(); pcacheFree(p->apSave[0]); pcacheFree(p->apSave[1]); - pcacheExitGlobal(); + pcacheExitMutex(); p->apSave[0] = 0; p->apSave[1] = 0; sqlite3PcacheMakeClean(p); @@ -869,7 +896,7 @@ void pcacheClear(PCache *pCache){ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ PgHdr *p, *pNext; PgHdr *pDirty = pCache->pDirty; - pcacheEnterGlobal(); + pcacheEnterMutex(); for(p=pCache->pClean; p||pDirty; p=pNext){ if( !p ){ p = pDirty; @@ -895,7 +922,7 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ } } } - pcacheExitGlobal(); + pcacheExitMutex(); } @@ -903,7 +930,7 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ ** Close a cache. */ void sqlite3PcacheClose(PCache *pCache){ - pcacheEnterGlobal(); + pcacheEnterMutex(); /* Free all the pages used by this pager and remove them from the LRU list. */ pcacheClear(pCache); @@ -913,12 +940,14 @@ void sqlite3PcacheClose(PCache *pCache){ } sqlite3_free(pCache->apHash); - pcacheExitGlobal(); + pcacheExitMutex(); } /* -** Preserve the content of the page, if it has not been preserved -** already. If idJournal==0 then this is for the overall transaction. +** Preserve the content of the page. It is assumed that the content +** has not been preserved already. +** +** If idJournal==0 then this is for the overall transaction. ** If idJournal==1 then this is for the statement journal. ** ** This routine is used for in-memory databases only. @@ -929,12 +958,11 @@ int sqlite3PcachePreserve(PgHdr *p, int idJournal){ void *x; int sz; assert( p->pCache->bPurgeable==0 ); - if( !p->apSave[idJournal] ){ - sz = p->pCache->szPage; - p->apSave[idJournal] = x = sqlite3PageMalloc( sz ); - if( x==0 ) return SQLITE_NOMEM; - memcpy(x, p->pData, sz); - } + assert( p->apSave[idJournal]==0 ); + sz = p->pCache->szPage; + p->apSave[idJournal] = x = sqlite3PageMalloc( sz ); + if( x==0 ) return SQLITE_NOMEM; + memcpy(x, p->pData, sz); return SQLITE_OK; } @@ -943,14 +971,14 @@ int sqlite3PcachePreserve(PgHdr *p, int idJournal){ */ void sqlite3PcacheCommit(PCache *pCache, int idJournal){ PgHdr *p; - pcacheEnterGlobal(); /* Mutex is required to call pcacheFree() */ + pcacheEnterMutex(); /* Mutex is required to call pcacheFree() */ for(p=pCache->pDirty; p; p=p->pNext){ if( p->apSave[idJournal] ){ pcacheFree(p->apSave[idJournal]); p->apSave[idJournal] = 0; } } - pcacheExitGlobal(); + pcacheExitMutex(); } /* @@ -959,7 +987,7 @@ void sqlite3PcacheCommit(PCache *pCache, int idJournal){ void sqlite3PcacheRollback(PCache *pCache, int idJournal){ PgHdr *p; int sz; - pcacheEnterGlobal(); /* Mutex is required to call pcacheFree() */ + pcacheEnterMutex(); /* Mutex is required to call pcacheFree() */ sz = pCache->szPage; for(p=pCache->pDirty; p; p=p->pNext){ if( p->apSave[idJournal] ){ @@ -968,7 +996,7 @@ void sqlite3PcacheRollback(PCache *pCache, int idJournal){ p->apSave[idJournal] = 0; } } - pcacheExitGlobal(); + pcacheExitMutex(); } /* @@ -991,9 +1019,9 @@ void sqlite3PcacheAssertFlags(PCache *pCache, int trueMask, int falseMask){ */ int sqlite3PcacheClear(PCache *pCache){ assert(pCache->nRef==0); - pcacheEnterGlobal(); + pcacheEnterMutex(); pcacheClear(pCache); - pcacheExitGlobal(); + pcacheExitMutex(); return SQLITE_OK; } @@ -1125,7 +1153,7 @@ void sqlite3PcacheSetFlags(PCache *pCache, int andMask, int orMask){ /* Obtain the global mutex before modifying any PgHdr.flags variables ** or traversing the LRU list. */ - pcacheEnterGlobal(); + pcacheEnterMutex(); for(p=pCache->pDirty; p; p=p->pNext){ p->flags = (p->flags&andMask)|orMask; @@ -1139,7 +1167,7 @@ void sqlite3PcacheSetFlags(PCache *pCache, int andMask, int orMask){ assert( !pCache->pSynced || (pCache->pSynced->flags&PGHDR_NEED_SYNC)==0 ); } - pcacheExitGlobal(); + pcacheExitMutex(); } /* @@ -1157,10 +1185,10 @@ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ mxPage = 10; } if( pCache->bPurgeable ){ - pcacheEnterGlobal(); + pcacheEnterMutex(); pcache.nMaxPage -= pCache->nMax; pcache.nMaxPage += mxPage; - pcacheExitGlobal(); + pcacheExitMutex(); } pCache->nMax = mxPage; } @@ -1179,12 +1207,12 @@ int sqlite3PcacheReleaseMemory(int nReq){ int nFree = 0; if( pcache.pStart==0 ){ PgHdr *p; - pcacheEnterGlobal(); + pcacheEnterMutex(); while( (nReq<0 || nFree<nReq) && (p=pcacheRecyclePage()) ){ nFree += pcachePageSize(p); pcachePageFree(p); } - pcacheExitGlobal(); + pcacheExitMutex(); } return nFree; } diff --git a/src/pcache.h b/src/pcache.h index 8dcc3655aa..d3fd7a9331 100644 --- a/src/pcache.h +++ b/src/pcache.h @@ -12,7 +12,7 @@ ** This header file defines the interface that the sqlite page cache ** subsystem. ** -** @(#) $Id: pcache.h,v 1.7 2008/08/27 15:16:34 danielk1977 Exp $ +** @(#) $Id: pcache.h,v 1.8 2008/08/28 02:26:07 drh Exp $ */ #ifndef _PCACHE_H_ @@ -25,22 +25,30 @@ typedef struct PCache PCache; ** structure. */ struct PgHdr { - u32 flags; /* PGHDR flags defined below */ void *pData; /* Content of this page */ void *pExtra; /* Extra content */ PgHdr *pDirty; /* Transient list of dirty pages */ Pgno pgno; /* Page number for this page */ - Pager *pPager; + Pager *pPager; /* The pager this page is part of */ #ifdef SQLITE_CHECK_PAGES - u32 pageHash; + u32 pageHash; /* Hash of page content */ #endif - /*** Public data is above. All that follows is private to pcache.c ***/ + u16 flags; /* PGHDR flags defined below */ + /********************************************************************** + ** Elements above are public. All that follows is private to pcache.c + ** and should not be accessed by other modules. + */ + i16 nRef; /* Number of users of this page */ PCache *pCache; /* Cache that owns this page */ + void *apSave[2]; /* Journal entries for in-memory databases */ + /********************************************************************** + ** Elements above are accessible at any time by the owner of the cache + ** without the need for a mutex. The elements that follow can only be + ** accessed while holding the SQLITE_MUTEX_STATIC_LRU mutex. + */ PgHdr *pNextHash, *pPrevHash; /* Hash collision chain for PgHdr.pgno */ PgHdr *pNext, *pPrev; /* List of clean or dirty pages */ PgHdr *pNextLru, *pPrevLru; /* Part of global LRU list */ - int nRef; /* Number of users of this page */ - void *apSave[2]; /* Journal entries for in-memory databases */ }; /* Bit values for PgHdr.flags */ diff --git a/src/test_func.c b/src/test_func.c index 2812382816..20f3307185 100644 --- a/src/test_func.c +++ b/src/test_func.c @@ -12,7 +12,7 @@ ** Code for testing all sorts of SQLite interfaces. This code ** implements new SQL functions used by the test scripts. ** -** $Id: test_func.c,v 1.12 2008/08/27 15:21:35 drh Exp $ +** $Id: test_func.c,v 1.13 2008/08/28 02:26:07 drh Exp $ */ #include "sqlite3.h" #include "tcl.h" @@ -217,10 +217,7 @@ static void counterFunc( int nArg, /* Number of function arguments */ sqlite3_value **argv /* Values for all function arguments */ ){ - int i; - int *pCounter; - - pCounter = (int*)sqlite3_get_auxdata(pCtx, 0); + int *pCounter = (int*)sqlite3_get_auxdata(pCtx, 0); if( pCounter==0 ){ pCounter = sqlite3_malloc( sizeof(*pCounter) ); if( pCounter==0 ){