Miscellaneous cleanup in the new pcache code. (CVS 5629)
FossilOrigin-Name: da1777259f53c2e20c7ced06bf6f2a550f0ea0fc
This commit is contained in:
parent
59633aeec2
commit
a85f7e36e8
20
manifest
20
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)
|
C Miscellaneous\scleanup\sin\sthe\snew\spcache\scode.\s(CVS\s5629)
|
||||||
D 2008-08-27T19:01:58
|
D 2008-08-28T02:26:07
|
||||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||||
F Makefile.in 689e14735f862a5553bceef206d8c13e29504e44
|
F Makefile.in 689e14735f862a5553bceef206d8c13e29504e44
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@ -134,11 +134,11 @@ F src/os_common.h 24525d8b7bce66c374dfc1810a6c9043f3359b60
|
|||||||
F src/os_os2.c e391fc95adc744bbdcefd4d11e3066998185a0a0
|
F src/os_os2.c e391fc95adc744bbdcefd4d11e3066998185a0a0
|
||||||
F src/os_unix.c 4665cef7639dd937893c3ea076f0e8a8f215bb32
|
F src/os_unix.c 4665cef7639dd937893c3ea076f0e8a8f215bb32
|
||||||
F src/os_win.c aefe9ee26430678a19a058a874e4e2bd91398142
|
F src/os_win.c aefe9ee26430678a19a058a874e4e2bd91398142
|
||||||
F src/pager.c 84f4c171a0cb4561291f212508b1a91a8a325abb
|
F src/pager.c 032d11049af4ec49bdbaa3584e7ce9887098b66a
|
||||||
F src/pager.h 914103bb62dbcc3d8e9f14baec812d027264d457
|
F src/pager.h 914103bb62dbcc3d8e9f14baec812d027264d457
|
||||||
F src/parse.y d0f76d2cb8d6883d5600dc20beb961a6022b94b8
|
F src/parse.y d0f76d2cb8d6883d5600dc20beb961a6022b94b8
|
||||||
F src/pcache.c 3d9d933bb22f10956ab78d83798d88ca9a147e86
|
F src/pcache.c aa609c9b1fc1a2b00f7d7bfb3d06b1e507767b93
|
||||||
F src/pcache.h 7a50b77f06c220ff7696be1a9f2a17c9e6ddc486
|
F src/pcache.h bd373ee3e4db310d6bbe7fa6d8d971de9678edd8
|
||||||
F src/pragma.c f5b271b090af7fcedd308d7c5807a5503f7a853d
|
F src/pragma.c f5b271b090af7fcedd308d7c5807a5503f7a853d
|
||||||
F src/prepare.c c197041e0c4770672cda75e6bfe10242f885e510
|
F src/prepare.c c197041e0c4770672cda75e6bfe10242f885e510
|
||||||
F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d
|
F src/printf.c 785f87120589c1db672e37c6eb1087c456e6f84d
|
||||||
@ -167,7 +167,7 @@ F src/test_autoext.c f53b0cdf7bf5f08100009572a5d65cdb540bd0ad
|
|||||||
F src/test_btree.c 7170e0c922ed3979f2d38f4a3f84728e5740dfc3
|
F src/test_btree.c 7170e0c922ed3979f2d38f4a3f84728e5740dfc3
|
||||||
F src/test_config.c 224f699a34d45eb8ac5c22a7ad6cdbb8edf0ba28
|
F src/test_config.c 224f699a34d45eb8ac5c22a7ad6cdbb8edf0ba28
|
||||||
F src/test_devsym.c 6012cb8e3acf812513511025a4fa5d626e0ba19b
|
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_hexio.c 2f1122aa3f012fa0142ee3c36ce5c902a70cd12f
|
||||||
F src/test_loadext.c 97dc8800e46a46ed002c2968572656f37e9c0dd9
|
F src/test_loadext.c 97dc8800e46a46ed002c2968572656f37e9c0dd9
|
||||||
F src/test_malloc.c 49abbf5d9c71fb06cf7a7cf96f9b9a799b77a421
|
F src/test_malloc.c 49abbf5d9c71fb06cf7a7cf96f9b9a799b77a421
|
||||||
@ -624,7 +624,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
|
|||||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||||
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
|
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
P 39c34e2238c27b2a2f4f0b896126ccbd299114c5
|
P ce9c74eaab459ddde213c828e821940f5d6cb354
|
||||||
R 0bf03a77bd82f6ac6f412ad9339ae6a4
|
R 55c280ec697a3a6039a240cf488ad9ad
|
||||||
U danielk1977
|
U drh
|
||||||
Z ac6800a3d7725cc034896ca6e2243181
|
Z 7df830e688305e6be422e59df78b53fe
|
||||||
|
@ -1 +1 @@
|
|||||||
ce9c74eaab459ddde213c828e821940f5d6cb354
|
da1777259f53c2e20c7ced06bf6f2a550f0ea0fc
|
@ -18,7 +18,7 @@
|
|||||||
** file simultaneously, or one process from reading the database while
|
** file simultaneously, or one process from reading the database while
|
||||||
** another is writing.
|
** 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
|
#ifndef SQLITE_OMIT_DISKIO
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
@ -3271,15 +3271,14 @@ static int pager_write(PgHdr *pPg){
|
|||||||
&& !pageInStatement(pPg)
|
&& !pageInStatement(pPg)
|
||||||
&& (int)pPg->pgno<=pPager->stmtSize
|
&& (int)pPg->pgno<=pPager->stmtSize
|
||||||
){
|
){
|
||||||
assert(
|
assert( (pPg->flags&PGHDR_IN_JOURNAL)
|
||||||
(pPg->flags&PGHDR_IN_JOURNAL) || (int)pPg->pgno>pPager->origDbSize );
|
|| (int)pPg->pgno>pPager->origDbSize );
|
||||||
if( MEMDB ){
|
if( MEMDB ){
|
||||||
rc = sqlite3PcachePreserve(pPg, 1);
|
rc = sqlite3PcachePreserve(pPg, 1);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
|
PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
|
||||||
/* page_add_to_stmt_list(pPg); */
|
|
||||||
}else{
|
}else{
|
||||||
i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
|
i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
|
||||||
char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
|
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 */
|
assert( !MEMDB ); /* For a memdb, pPager->journalOpen is always 0 */
|
||||||
|
|
||||||
#ifdef SQLITE_SECURE_DELETE
|
#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;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
274
src/pcache.c
274
src/pcache.c
@ -11,30 +11,50 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file implements that page cache.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A complete page cache is an instance of this structure.
|
** 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 {
|
struct PCache {
|
||||||
int szPage; /* Size of every page in this cache */
|
/*********************************************************************
|
||||||
int szExtra; /* Size of extra space for each page */
|
** The first group of elements may be read or written at any time by
|
||||||
int nHash; /* Number of slots in apHash[] */
|
** the cache owner without holding the mutex. No thread other than the
|
||||||
int nPage; /* Total number of pages in apHash */
|
** cache owner is permitted to access these elements at any time.
|
||||||
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 */
|
|
||||||
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
|
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
|
||||||
PgHdr *pSynced; /* Last synced page in dirty page list */
|
PgHdr *pSynced; /* Last synced page in dirty page list */
|
||||||
int nRef; /* Number of pinned pages */
|
int nRef; /* Number of pinned pages */
|
||||||
int nPinned; /* Number of pinned and/or dirty 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.
|
** 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 {
|
static struct PCacheGlobal {
|
||||||
int isInit; /* True when initialized */
|
int isInit; /* True when initialized */
|
||||||
@ -78,29 +84,46 @@ static struct PCacheGlobal {
|
|||||||
} pcache = {0};
|
} 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
|
** together in global structure "pcache" above) are protected by the static
|
||||||
** SQLITE_MUTEX_STATIC_LRU mutex. A pointer to this mutex is stored in
|
** SQLITE_MUTEX_STATIC_LRU mutex. A pointer to this mutex is stored in
|
||||||
** variable "pcache.mutex".
|
** variable "pcache.mutex".
|
||||||
**
|
**
|
||||||
** Access to the contents of the individual PCache structures is not
|
** Some elements of the PCache and PgHdr structures are protected by the
|
||||||
** protected. It is the job of the caller to ensure that these structures
|
** SQLITE_MUTEX_STATUS_LRU mutex and other are not. The protected
|
||||||
** are accessed in a thread-safe manner.
|
** 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 ********************/
|
/********************************** 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
|
** This routine verifies that the number of entries in the hash table
|
||||||
** is pCache->nPage. This routine is used within assert() statements
|
** is pCache->nPage. This routine is used within assert() statements
|
||||||
** only and is therefore disabled during production builds.
|
** only and is therefore disabled during production builds.
|
||||||
*/
|
*/
|
||||||
static int pcacheCheckHashCount(PCache *pCache){
|
static int pcacheCheckHashCount(PCache *pCache){
|
||||||
#if 0
|
|
||||||
int i;
|
int i;
|
||||||
int nPage = 0;
|
int nPage = 0;
|
||||||
for(i=0; i<pCache->nHash; i++){
|
for(i=0; i<pCache->nHash; i++){
|
||||||
@ -110,19 +133,20 @@ static int pcacheCheckHashCount(PCache *pCache){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert( nPage==pCache->nPage );
|
assert( nPage==pCache->nPage );
|
||||||
#endif
|
|
||||||
return 1;
|
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
|
** Based on the current value of PCache.nRef and the contents of the
|
||||||
** PCache.pDirty list, return the expected value of the PCache.nPinned
|
** PCache.pDirty list, return the expected value of the PCache.nPinned
|
||||||
** counter. This is only used in debugging builds, as follows:
|
** 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){
|
static int pcachePinnedCount(PCache *pCache){
|
||||||
#if 0
|
|
||||||
PgHdr *p;
|
PgHdr *p;
|
||||||
int nPinned = pCache->nRef;
|
int nPinned = pCache->nRef;
|
||||||
for(p=pCache->pDirty; p; p=p->pNext){
|
for(p=pCache->pDirty; p; p=p->pNext){
|
||||||
@ -131,34 +155,35 @@ static int pcachePinnedCount(PCache *pCache){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nPinned;
|
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
|
** Check that the pCache->pSynced variable is set correctly. If it
|
||||||
** is not, either fail an assert or return zero. Otherwise, return
|
** is not, either fail an assert or return zero. Otherwise, return
|
||||||
** non-zero. This is only used in debugging builds, as follows:
|
** non-zero. This is only used in debugging builds, as follows:
|
||||||
**
|
**
|
||||||
** assert( pcacheCheckSynced(pCache) );
|
** expensive_assert( pcacheCheckSynced(pCache) );
|
||||||
*/
|
*/
|
||||||
static int pcacheCheckSynced(PCache *pCache){
|
static int pcacheCheckSynced(PCache *pCache){
|
||||||
#if 0
|
|
||||||
PgHdr *p = pCache->pDirtyTail;
|
PgHdr *p = pCache->pDirtyTail;
|
||||||
for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pPrev){
|
for(p=pCache->pDirtyTail; p!=pCache->pSynced; p=p->pPrev){
|
||||||
assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) );
|
assert( p->nRef || (p->flags&PGHDR_NEED_SYNC) );
|
||||||
}
|
}
|
||||||
return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0);
|
return (p==0 || p->nRef || (p->flags&PGHDR_NEED_SYNC)==0);
|
||||||
#endif
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif /* !NDEBUG && SQLITE_ENABLE_EXPENSIVE_ASSERT */
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Remove a page from its hash table (PCache.apHash[]).
|
** Remove a page from its hash table (PCache.apHash[]).
|
||||||
*/
|
*/
|
||||||
static void pcacheRemoveFromHash(PgHdr *pPage){
|
static void pcacheRemoveFromHash(PgHdr *pPage){
|
||||||
|
/* assert( pcacheMutexHeld() ); *** FIXME ****/
|
||||||
if( pPage->pPrevHash ){
|
if( pPage->pPrevHash ){
|
||||||
pPage->pPrevHash->pNextHash = pPage->pNextHash;
|
pPage->pPrevHash->pNextHash = pPage->pNextHash;
|
||||||
}else{
|
}else{
|
||||||
@ -171,15 +196,18 @@ static void pcacheRemoveFromHash(PgHdr *pPage){
|
|||||||
pPage->pNextHash->pPrevHash = pPage->pPrevHash;
|
pPage->pNextHash->pPrevHash = pPage->pPrevHash;
|
||||||
}
|
}
|
||||||
pPage->pCache->nPage--;
|
pPage->pCache->nPage--;
|
||||||
assert( pcacheCheckHashCount(pPage->pCache) );
|
expensive_assert( pcacheCheckHashCount(pPage->pCache) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Insert a page into the hash table
|
** Insert a page into the hash table
|
||||||
|
**
|
||||||
|
** The mutex must be held by the caller.
|
||||||
*/
|
*/
|
||||||
static void pcacheAddToHash(PgHdr *pPage){
|
static void pcacheAddToHash(PgHdr *pPage){
|
||||||
PCache *pCache = pPage->pCache;
|
PCache *pCache = pPage->pCache;
|
||||||
u32 h = pPage->pgno % pCache->nHash;
|
u32 h = pPage->pgno % pCache->nHash;
|
||||||
|
/* assert( pcacheMutexHeld() ); *** FIXME *****/
|
||||||
pPage->pNextHash = pCache->apHash[h];
|
pPage->pNextHash = pCache->apHash[h];
|
||||||
pPage->pPrevHash = 0;
|
pPage->pPrevHash = 0;
|
||||||
if( pCache->apHash[h] ){
|
if( pCache->apHash[h] ){
|
||||||
@ -187,7 +215,7 @@ static void pcacheAddToHash(PgHdr *pPage){
|
|||||||
}
|
}
|
||||||
pCache->apHash[h] = pPage;
|
pCache->apHash[h] = pPage;
|
||||||
pCache->nPage++;
|
pCache->nPage++;
|
||||||
assert( pcacheCheckHashCount(pCache) );
|
expensive_assert( pcacheCheckHashCount(pCache) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -195,29 +223,29 @@ static void pcacheAddToHash(PgHdr *pPage){
|
|||||||
** at least nHash buckets.
|
** at least nHash buckets.
|
||||||
*/
|
*/
|
||||||
static int pcacheResizeHash(PCache *pCache, int nHash){
|
static int pcacheResizeHash(PCache *pCache, int nHash){
|
||||||
|
PgHdr *p;
|
||||||
|
PgHdr **pNew;
|
||||||
|
/* assert( pcacheMutexHeld() ); **** FIXME *****/
|
||||||
#ifdef SQLITE_MALLOC_SOFT_LIMIT
|
#ifdef SQLITE_MALLOC_SOFT_LIMIT
|
||||||
if( nHash*sizeof(PgHdr*)>SQLITE_MALLOC_SOFT_LIMIT ){
|
if( nHash*sizeof(PgHdr*)>SQLITE_MALLOC_SOFT_LIMIT ){
|
||||||
nHash = SQLITE_MALLOC_SOFT_LIMIT/sizeof(PgHdr *);
|
nHash = SQLITE_MALLOC_SOFT_LIMIT/sizeof(PgHdr *);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if( nHash>pCache->nHash ){
|
pNew = (PgHdr **)sqlite3_malloc(sizeof(PgHdr*)*nHash);
|
||||||
PgHdr *p;
|
if( !pNew ){
|
||||||
PgHdr **pNew = (PgHdr **)sqlite3_malloc(sizeof(PgHdr*)*nHash);
|
return SQLITE_NOMEM;
|
||||||
if( !pNew ){
|
}
|
||||||
return SQLITE_NOMEM;
|
memset(pNew, 0, sizeof(PgHdr *)*nHash);
|
||||||
}
|
sqlite3_free(pCache->apHash);
|
||||||
memset(pNew, 0, sizeof(PgHdr *)*nHash);
|
pCache->apHash = pNew;
|
||||||
sqlite3_free(pCache->apHash);
|
pCache->nHash = nHash;
|
||||||
pCache->apHash = pNew;
|
pCache->nPage = 0;
|
||||||
pCache->nHash = nHash;
|
|
||||||
pCache->nPage = 0;
|
for(p=pCache->pClean; p; p=p->pNext){
|
||||||
|
pcacheAddToHash(p);
|
||||||
for(p=pCache->pClean; p; p=p->pNext){
|
}
|
||||||
pcacheAddToHash(p);
|
for(p=pCache->pDirty; p; p=p->pNext){
|
||||||
}
|
pcacheAddToHash(p);
|
||||||
for(p=pCache->pDirty; p; p=p->pNext){
|
|
||||||
pcacheAddToHash(p);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
@ -229,6 +257,7 @@ static int pcacheResizeHash(PCache *pCache, int nHash){
|
|||||||
static void pcacheRemoveFromList(PgHdr **ppHead, PgHdr *pPage){
|
static void pcacheRemoveFromList(PgHdr **ppHead, PgHdr *pPage){
|
||||||
int isDirtyList = (ppHead==&pPage->pCache->pDirty);
|
int isDirtyList = (ppHead==&pPage->pCache->pDirty);
|
||||||
assert( ppHead==&pPage->pCache->pClean || ppHead==&pPage->pCache->pDirty );
|
assert( ppHead==&pPage->pCache->pClean || ppHead==&pPage->pCache->pDirty );
|
||||||
|
/* assert( pcacheMutexHeld() || ppHead!=&pPage->pCache->pClean ); *** FIXME */
|
||||||
|
|
||||||
if( pPage->pPrev ){
|
if( pPage->pPrev ){
|
||||||
pPage->pPrev->pNext = pPage->pNext;
|
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
|
** 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
|
** 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
|
** configured soft-heap-limit to be breached, it will be possible to
|
||||||
** reclaim memory from this pager-cache. Because sqlite3PcacheLock()
|
** reclaim memory from this pager-cache.
|
||||||
** might block on the MEM2 mutex, it has to be called before re-entering
|
|
||||||
** the global LRU mutex.
|
|
||||||
*/
|
*/
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
p = sqlite3Malloc(sz);
|
p = sqlite3Malloc(sz);
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
|
|
||||||
if( p ){
|
if( p ){
|
||||||
sz = sqlite3MallocSize(p);
|
sz = sqlite3MallocSize(p);
|
||||||
@ -401,9 +428,9 @@ void *pcacheMalloc(int sz, PCache *pCache){
|
|||||||
}
|
}
|
||||||
void *sqlite3PageMalloc(sz){
|
void *sqlite3PageMalloc(sz){
|
||||||
void *p;
|
void *p;
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
p = pcacheMalloc(sz, 0);
|
p = pcacheMalloc(sz, 0);
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,9 +453,9 @@ void pcacheFree(void *p){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void sqlite3PageFree(void *p){
|
void sqlite3PageFree(void *p){
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
pcacheFree(p);
|
pcacheFree(p);
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -519,14 +546,14 @@ static int pcacheRecycleOrAlloc(PCache *pCache, PgHdr **ppPage){
|
|||||||
assert( sqlite3_mutex_notheld(pcache.mutex) );
|
assert( sqlite3_mutex_notheld(pcache.mutex) );
|
||||||
|
|
||||||
*ppPage = 0;
|
*ppPage = 0;
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
|
|
||||||
/* If we have reached the limit for pinned/dirty pages, and there is at
|
/* 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
|
** least one dirty page, invoke the xStress callback to cause a page to
|
||||||
** become clean.
|
** become clean.
|
||||||
*/
|
*/
|
||||||
assert( pCache->nPinned==pcachePinnedCount(pCache) );
|
expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
|
||||||
assert( pcacheCheckSynced(pCache) );
|
expensive_assert( pcacheCheckSynced(pCache) );
|
||||||
if( pCache->xStress
|
if( pCache->xStress
|
||||||
&& pCache->pDirty
|
&& pCache->pDirty
|
||||||
&& pCache->nPinned>=(pcache.nMaxPage+pCache->nMin-pcache.nMinPage)
|
&& pCache->nPinned>=(pcache.nMaxPage+pCache->nMin-pcache.nMinPage)
|
||||||
@ -543,12 +570,12 @@ static int pcacheRecycleOrAlloc(PCache *pCache, PgHdr **ppPage){
|
|||||||
}
|
}
|
||||||
if( pPg ){
|
if( pPg ){
|
||||||
int rc;
|
int rc;
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
rc = pCache->xStress(pCache->pStress, pPg);
|
rc = pCache->xStress(pCache->pStress, pPg);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
return rc;
|
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 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);
|
pcachePageFree(p);
|
||||||
p = 0;
|
p = 0;
|
||||||
}
|
}
|
||||||
@ -567,7 +594,7 @@ static int pcacheRecycleOrAlloc(PCache *pCache, PgHdr **ppPage){
|
|||||||
p = pcachePageAlloc(pCache);
|
p = pcachePageAlloc(pCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
*ppPage = p;
|
*ppPage = p;
|
||||||
return (p?SQLITE_OK:SQLITE_NOMEM);
|
return (p?SQLITE_OK:SQLITE_NOMEM);
|
||||||
}
|
}
|
||||||
@ -622,13 +649,13 @@ void sqlite3PcacheOpen(
|
|||||||
p->nMax = 100;
|
p->nMax = 100;
|
||||||
p->nMin = 10;
|
p->nMin = 10;
|
||||||
|
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
if( bPurgeable ){
|
if( bPurgeable ){
|
||||||
pcache.nMaxPage += p->nMax;
|
pcache.nMaxPage += p->nMax;
|
||||||
pcache.nMinPage += p->nMin;
|
pcache.nMinPage += p->nMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -653,7 +680,7 @@ int sqlite3PcacheFetch(
|
|||||||
assert( pcache.isInit );
|
assert( pcache.isInit );
|
||||||
assert( pCache!=0 );
|
assert( pCache!=0 );
|
||||||
assert( pgno>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. */
|
/* Search the hash table for the requested page. Exit early if it is found. */
|
||||||
if( pCache->apHash ){
|
if( pCache->apHash ){
|
||||||
@ -662,9 +689,9 @@ int sqlite3PcacheFetch(
|
|||||||
if( pPage->pgno==pgno ){
|
if( pPage->pgno==pgno ){
|
||||||
if( pPage->nRef==0 ){
|
if( pPage->nRef==0 ){
|
||||||
if( 0==(pPage->flags&PGHDR_DIRTY) ){
|
if( 0==(pPage->flags&PGHDR_DIRTY) ){
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
pcacheRemoveFromLruList(pPage);
|
pcacheRemoveFromLruList(pPage);
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
pCache->nPinned++;
|
pCache->nPinned++;
|
||||||
}
|
}
|
||||||
pCache->nRef++;
|
pCache->nRef++;
|
||||||
@ -679,7 +706,7 @@ int sqlite3PcacheFetch(
|
|||||||
if( createFlag ){
|
if( createFlag ){
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
if( pCache->nHash<=pCache->nPage ){
|
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 ){
|
if( rc!=SQLITE_OK ){
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -704,7 +731,7 @@ int sqlite3PcacheFetch(
|
|||||||
*ppPage = 0;
|
*ppPage = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert( pCache->nPinned==pcachePinnedCount(pCache) );
|
expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -723,9 +750,9 @@ void sqlite3PcacheRelease(PgHdr *p){
|
|||||||
pCache->nRef--;
|
pCache->nRef--;
|
||||||
if( (p->flags&PGHDR_DIRTY)==0 ){
|
if( (p->flags&PGHDR_DIRTY)==0 ){
|
||||||
pCache->nPinned--;
|
pCache->nPinned--;
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
pcacheAddToLruList(p);
|
pcacheAddToLruList(p);
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
}else{
|
}else{
|
||||||
/* Move the page to the head of the caches dirty list. */
|
/* Move the page to the head of the caches dirty list. */
|
||||||
pcacheRemoveFromList(&pCache->pDirty, p);
|
pcacheRemoveFromList(&pCache->pDirty, p);
|
||||||
@ -753,9 +780,9 @@ void sqlite3PcacheDrop(PgHdr *p){
|
|||||||
pCache->nPinned--;
|
pCache->nPinned--;
|
||||||
pcacheRemoveFromList(&pCache->pClean, p);
|
pcacheRemoveFromList(&pCache->pClean, p);
|
||||||
pcacheRemoveFromHash(p);
|
pcacheRemoveFromHash(p);
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
pcachePageFree(p);
|
pcachePageFree(p);
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -785,15 +812,15 @@ void sqlite3PcacheMakeClean(PgHdr *p){
|
|||||||
assert( p->flags & PGHDR_DIRTY );
|
assert( p->flags & PGHDR_DIRTY );
|
||||||
pCache = p->pCache;
|
pCache = p->pCache;
|
||||||
pcacheRemoveFromList(&pCache->pDirty, p);
|
pcacheRemoveFromList(&pCache->pDirty, p);
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
pcacheAddToList(&pCache->pClean, p);
|
pcacheAddToList(&pCache->pClean, p);
|
||||||
p->flags &= ~PGHDR_DIRTY;
|
p->flags &= ~PGHDR_DIRTY;
|
||||||
if( p->nRef==0 ){
|
if( p->nRef==0 ){
|
||||||
pcacheAddToLruList(p);
|
pcacheAddToLruList(p);
|
||||||
pCache->nPinned--;
|
pCache->nPinned--;
|
||||||
}
|
}
|
||||||
assert( pCache->nPinned==pcachePinnedCount(pCache) );
|
expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -801,7 +828,7 @@ void sqlite3PcacheMakeClean(PgHdr *p){
|
|||||||
*/
|
*/
|
||||||
void sqlite3PcacheCleanAll(PCache *pCache){
|
void sqlite3PcacheCleanAll(PCache *pCache){
|
||||||
PgHdr *p;
|
PgHdr *p;
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
while( (p = pCache->pDirty)!=0 ){
|
while( (p = pCache->pDirty)!=0 ){
|
||||||
assert( p->apSave[0]==0 && p->apSave[1]==0 );
|
assert( p->apSave[0]==0 && p->apSave[1]==0 );
|
||||||
pcacheRemoveFromList(&pCache->pDirty, p);
|
pcacheRemoveFromList(&pCache->pDirty, p);
|
||||||
@ -813,8 +840,8 @@ void sqlite3PcacheCleanAll(PCache *pCache){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sqlite3PcacheAssertFlags(pCache, 0, PGHDR_DIRTY);
|
sqlite3PcacheAssertFlags(pCache, 0, PGHDR_DIRTY);
|
||||||
assert( pCache->nPinned==pcachePinnedCount(pCache) );
|
expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -828,10 +855,10 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
|
|||||||
p->pgno = newPgno;
|
p->pgno = newPgno;
|
||||||
if( newPgno==0 ){
|
if( newPgno==0 ){
|
||||||
p->flags |= PGHDR_REUSE_UNLIKELY;
|
p->flags |= PGHDR_REUSE_UNLIKELY;
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
pcacheFree(p->apSave[0]);
|
pcacheFree(p->apSave[0]);
|
||||||
pcacheFree(p->apSave[1]);
|
pcacheFree(p->apSave[1]);
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
p->apSave[0] = 0;
|
p->apSave[0] = 0;
|
||||||
p->apSave[1] = 0;
|
p->apSave[1] = 0;
|
||||||
sqlite3PcacheMakeClean(p);
|
sqlite3PcacheMakeClean(p);
|
||||||
@ -869,7 +896,7 @@ void pcacheClear(PCache *pCache){
|
|||||||
void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
|
void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
|
||||||
PgHdr *p, *pNext;
|
PgHdr *p, *pNext;
|
||||||
PgHdr *pDirty = pCache->pDirty;
|
PgHdr *pDirty = pCache->pDirty;
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
for(p=pCache->pClean; p||pDirty; p=pNext){
|
for(p=pCache->pClean; p||pDirty; p=pNext){
|
||||||
if( !p ){
|
if( !p ){
|
||||||
p = pDirty;
|
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.
|
** Close a cache.
|
||||||
*/
|
*/
|
||||||
void sqlite3PcacheClose(PCache *pCache){
|
void sqlite3PcacheClose(PCache *pCache){
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
|
|
||||||
/* Free all the pages used by this pager and remove them from the LRU list. */
|
/* Free all the pages used by this pager and remove them from the LRU list. */
|
||||||
pcacheClear(pCache);
|
pcacheClear(pCache);
|
||||||
@ -913,12 +940,14 @@ void sqlite3PcacheClose(PCache *pCache){
|
|||||||
}
|
}
|
||||||
sqlite3_free(pCache->apHash);
|
sqlite3_free(pCache->apHash);
|
||||||
|
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Preserve the content of the page, if it has not been preserved
|
** Preserve the content of the page. It is assumed that the content
|
||||||
** already. If idJournal==0 then this is for the overall transaction.
|
** 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.
|
** If idJournal==1 then this is for the statement journal.
|
||||||
**
|
**
|
||||||
** This routine is used for in-memory databases only.
|
** This routine is used for in-memory databases only.
|
||||||
@ -929,12 +958,11 @@ int sqlite3PcachePreserve(PgHdr *p, int idJournal){
|
|||||||
void *x;
|
void *x;
|
||||||
int sz;
|
int sz;
|
||||||
assert( p->pCache->bPurgeable==0 );
|
assert( p->pCache->bPurgeable==0 );
|
||||||
if( !p->apSave[idJournal] ){
|
assert( p->apSave[idJournal]==0 );
|
||||||
sz = p->pCache->szPage;
|
sz = p->pCache->szPage;
|
||||||
p->apSave[idJournal] = x = sqlite3PageMalloc( sz );
|
p->apSave[idJournal] = x = sqlite3PageMalloc( sz );
|
||||||
if( x==0 ) return SQLITE_NOMEM;
|
if( x==0 ) return SQLITE_NOMEM;
|
||||||
memcpy(x, p->pData, sz);
|
memcpy(x, p->pData, sz);
|
||||||
}
|
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -943,14 +971,14 @@ int sqlite3PcachePreserve(PgHdr *p, int idJournal){
|
|||||||
*/
|
*/
|
||||||
void sqlite3PcacheCommit(PCache *pCache, int idJournal){
|
void sqlite3PcacheCommit(PCache *pCache, int idJournal){
|
||||||
PgHdr *p;
|
PgHdr *p;
|
||||||
pcacheEnterGlobal(); /* Mutex is required to call pcacheFree() */
|
pcacheEnterMutex(); /* Mutex is required to call pcacheFree() */
|
||||||
for(p=pCache->pDirty; p; p=p->pNext){
|
for(p=pCache->pDirty; p; p=p->pNext){
|
||||||
if( p->apSave[idJournal] ){
|
if( p->apSave[idJournal] ){
|
||||||
pcacheFree(p->apSave[idJournal]);
|
pcacheFree(p->apSave[idJournal]);
|
||||||
p->apSave[idJournal] = 0;
|
p->apSave[idJournal] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -959,7 +987,7 @@ void sqlite3PcacheCommit(PCache *pCache, int idJournal){
|
|||||||
void sqlite3PcacheRollback(PCache *pCache, int idJournal){
|
void sqlite3PcacheRollback(PCache *pCache, int idJournal){
|
||||||
PgHdr *p;
|
PgHdr *p;
|
||||||
int sz;
|
int sz;
|
||||||
pcacheEnterGlobal(); /* Mutex is required to call pcacheFree() */
|
pcacheEnterMutex(); /* Mutex is required to call pcacheFree() */
|
||||||
sz = pCache->szPage;
|
sz = pCache->szPage;
|
||||||
for(p=pCache->pDirty; p; p=p->pNext){
|
for(p=pCache->pDirty; p; p=p->pNext){
|
||||||
if( p->apSave[idJournal] ){
|
if( p->apSave[idJournal] ){
|
||||||
@ -968,7 +996,7 @@ void sqlite3PcacheRollback(PCache *pCache, int idJournal){
|
|||||||
p->apSave[idJournal] = 0;
|
p->apSave[idJournal] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -991,9 +1019,9 @@ void sqlite3PcacheAssertFlags(PCache *pCache, int trueMask, int falseMask){
|
|||||||
*/
|
*/
|
||||||
int sqlite3PcacheClear(PCache *pCache){
|
int sqlite3PcacheClear(PCache *pCache){
|
||||||
assert(pCache->nRef==0);
|
assert(pCache->nRef==0);
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
pcacheClear(pCache);
|
pcacheClear(pCache);
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
return SQLITE_OK;
|
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
|
/* Obtain the global mutex before modifying any PgHdr.flags variables
|
||||||
** or traversing the LRU list.
|
** or traversing the LRU list.
|
||||||
*/
|
*/
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
|
|
||||||
for(p=pCache->pDirty; p; p=p->pNext){
|
for(p=pCache->pDirty; p; p=p->pNext){
|
||||||
p->flags = (p->flags&andMask)|orMask;
|
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 );
|
assert( !pCache->pSynced || (pCache->pSynced->flags&PGHDR_NEED_SYNC)==0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1157,10 +1185,10 @@ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
|
|||||||
mxPage = 10;
|
mxPage = 10;
|
||||||
}
|
}
|
||||||
if( pCache->bPurgeable ){
|
if( pCache->bPurgeable ){
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
pcache.nMaxPage -= pCache->nMax;
|
pcache.nMaxPage -= pCache->nMax;
|
||||||
pcache.nMaxPage += mxPage;
|
pcache.nMaxPage += mxPage;
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
}
|
}
|
||||||
pCache->nMax = mxPage;
|
pCache->nMax = mxPage;
|
||||||
}
|
}
|
||||||
@ -1179,12 +1207,12 @@ int sqlite3PcacheReleaseMemory(int nReq){
|
|||||||
int nFree = 0;
|
int nFree = 0;
|
||||||
if( pcache.pStart==0 ){
|
if( pcache.pStart==0 ){
|
||||||
PgHdr *p;
|
PgHdr *p;
|
||||||
pcacheEnterGlobal();
|
pcacheEnterMutex();
|
||||||
while( (nReq<0 || nFree<nReq) && (p=pcacheRecyclePage()) ){
|
while( (nReq<0 || nFree<nReq) && (p=pcacheRecyclePage()) ){
|
||||||
nFree += pcachePageSize(p);
|
nFree += pcachePageSize(p);
|
||||||
pcachePageFree(p);
|
pcachePageFree(p);
|
||||||
}
|
}
|
||||||
pcacheExitGlobal();
|
pcacheExitMutex();
|
||||||
}
|
}
|
||||||
return nFree;
|
return nFree;
|
||||||
}
|
}
|
||||||
|
22
src/pcache.h
22
src/pcache.h
@ -12,7 +12,7 @@
|
|||||||
** This header file defines the interface that the sqlite page cache
|
** This header file defines the interface that the sqlite page cache
|
||||||
** subsystem.
|
** 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_
|
#ifndef _PCACHE_H_
|
||||||
@ -25,22 +25,30 @@ typedef struct PCache PCache;
|
|||||||
** structure.
|
** structure.
|
||||||
*/
|
*/
|
||||||
struct PgHdr {
|
struct PgHdr {
|
||||||
u32 flags; /* PGHDR flags defined below */
|
|
||||||
void *pData; /* Content of this page */
|
void *pData; /* Content of this page */
|
||||||
void *pExtra; /* Extra content */
|
void *pExtra; /* Extra content */
|
||||||
PgHdr *pDirty; /* Transient list of dirty pages */
|
PgHdr *pDirty; /* Transient list of dirty pages */
|
||||||
Pgno pgno; /* Page number for this page */
|
Pgno pgno; /* Page number for this page */
|
||||||
Pager *pPager;
|
Pager *pPager; /* The pager this page is part of */
|
||||||
#ifdef SQLITE_CHECK_PAGES
|
#ifdef SQLITE_CHECK_PAGES
|
||||||
u32 pageHash;
|
u32 pageHash; /* Hash of page content */
|
||||||
#endif
|
#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 */
|
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 *pNextHash, *pPrevHash; /* Hash collision chain for PgHdr.pgno */
|
||||||
PgHdr *pNext, *pPrev; /* List of clean or dirty pages */
|
PgHdr *pNext, *pPrev; /* List of clean or dirty pages */
|
||||||
PgHdr *pNextLru, *pPrevLru; /* Part of global LRU list */
|
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 */
|
/* Bit values for PgHdr.flags */
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
** Code for testing all sorts of SQLite interfaces. This code
|
** Code for testing all sorts of SQLite interfaces. This code
|
||||||
** implements new SQL functions used by the test scripts.
|
** 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 "sqlite3.h"
|
||||||
#include "tcl.h"
|
#include "tcl.h"
|
||||||
@ -217,10 +217,7 @@ static void counterFunc(
|
|||||||
int nArg, /* Number of function arguments */
|
int nArg, /* Number of function arguments */
|
||||||
sqlite3_value **argv /* Values for all function arguments */
|
sqlite3_value **argv /* Values for all function arguments */
|
||||||
){
|
){
|
||||||
int i;
|
int *pCounter = (int*)sqlite3_get_auxdata(pCtx, 0);
|
||||||
int *pCounter;
|
|
||||||
|
|
||||||
pCounter = (int*)sqlite3_get_auxdata(pCtx, 0);
|
|
||||||
if( pCounter==0 ){
|
if( pCounter==0 ){
|
||||||
pCounter = sqlite3_malloc( sizeof(*pCounter) );
|
pCounter = sqlite3_malloc( sizeof(*pCounter) );
|
||||||
if( pCounter==0 ){
|
if( pCounter==0 ){
|
||||||
|
Loading…
x
Reference in New Issue
Block a user