mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Automatically increase the size of the pager hash table as the number
of in-memory pages increases. Tickets #1790 and #1799. (CVS 3180) FossilOrigin-Name: ef8e9886f40c8528604264308f5e4734ae6706c5
This commit is contained in:
75
src/pager.c
75
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.267 2006/05/03 23:34:06 drh Exp $
|
||||
** @(#) $Id: pager.c,v 1.268 2006/05/07 17:49:39 drh Exp $
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_DISKIO
|
||||
#include "sqliteInt.h"
|
||||
@@ -208,24 +208,6 @@ struct PgHistory {
|
||||
#define PGHDR_TO_HIST(P,PGR) \
|
||||
((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra])
|
||||
|
||||
/*
|
||||
** How big to make the hash table used for locating in-memory pages
|
||||
** by page number. This macro looks a little silly, but is evaluated
|
||||
** at compile-time, not run-time (at least for gcc this is true).
|
||||
*/
|
||||
#define N_PG_HASH (\
|
||||
(MAX_PAGES>1024)?2048: \
|
||||
(MAX_PAGES>512)?1024: \
|
||||
(MAX_PAGES>256)?512: \
|
||||
(MAX_PAGES>128)?256: \
|
||||
(MAX_PAGES>64)?128:64 \
|
||||
)
|
||||
|
||||
/*
|
||||
** Hash a page number
|
||||
*/
|
||||
#define pager_hash(PN) ((PN)&(N_PG_HASH-1))
|
||||
|
||||
/*
|
||||
** A open page cache is an instance of the following structure.
|
||||
**
|
||||
@@ -296,7 +278,8 @@ struct Pager {
|
||||
void (*xReiniter)(void*,int); /* Call this routine when reloading pages */
|
||||
void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
|
||||
void *pCodecArg; /* First argument to xCodec() */
|
||||
PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */
|
||||
int nHash; /* Size of the pager hash table */
|
||||
PgHdr **aHash; /* Hash table to map page number to PgHdr */
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
Pager *pNext; /* Linked list of pagers in this thread */
|
||||
#endif
|
||||
@@ -403,6 +386,33 @@ static const unsigned char aJournalMagic[] = {
|
||||
# define REFINFO(X)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Change the size of the pager hash table to N. N must be a power
|
||||
** of two.
|
||||
*/
|
||||
static void pager_resize_hash_table(Pager *pPager, int N){
|
||||
PgHdr **aHash, *pPg;
|
||||
assert( N>0 && (N&(N-1))==0 );
|
||||
aHash = sqliteMalloc( sizeof(aHash[0])*N );
|
||||
if( aHash==0 ){
|
||||
/* Failure to rehash is not an error. It is only a performance hit. */
|
||||
return;
|
||||
}
|
||||
sqliteFree(pPager->aHash);
|
||||
pPager->nHash = N;
|
||||
pPager->aHash = aHash;
|
||||
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
|
||||
int h = pPg->pgno & (N-1);
|
||||
pPg->pNextHash = aHash[h];
|
||||
if( aHash[h] ){
|
||||
aHash[h]->pPrevHash = pPg;
|
||||
}
|
||||
aHash[h] = pPg;
|
||||
pPg->pPrevHash = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Read a 32-bit integer from the given file descriptor. Store the integer
|
||||
** that is read in *pRes. Return SQLITE_OK if everything worked, or an
|
||||
@@ -822,7 +832,9 @@ static void page_remove_from_stmt_list(PgHdr *pPg){
|
||||
** a pointer to the page or NULL if not found.
|
||||
*/
|
||||
static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
|
||||
PgHdr *p = pPager->aHash[pager_hash(pgno)];
|
||||
PgHdr *p;
|
||||
if( pPager->aHash==0 ) return 0;
|
||||
p = pPager->aHash[pgno & (pPager->nHash-1)];
|
||||
while( p && p->pgno!=pgno ){
|
||||
p = p->pNextHash;
|
||||
}
|
||||
@@ -846,8 +858,10 @@ static void pager_reset(Pager *pPager){
|
||||
pPager->pFirstSynced = 0;
|
||||
pPager->pLast = 0;
|
||||
pPager->pAll = 0;
|
||||
memset(pPager->aHash, 0, sizeof(pPager->aHash));
|
||||
pPager->nHash = 0;
|
||||
sqliteFree(pPager->aHash);
|
||||
pPager->nPage = 0;
|
||||
pPager->aHash = 0;
|
||||
if( pPager->state>=PAGER_RESERVED ){
|
||||
sqlite3pager_rollback(pPager);
|
||||
}
|
||||
@@ -1849,10 +1863,10 @@ static void unlinkHashChain(Pager *pPager, PgHdr *pPg){
|
||||
pPg->pNextHash->pPrevHash = pPg->pPrevHash;
|
||||
}
|
||||
if( pPg->pPrevHash ){
|
||||
assert( pPager->aHash[pager_hash(pPg->pgno)]!=pPg );
|
||||
assert( pPager->aHash[pPg->pgno & (pPager->nHash-1)]!=pPg );
|
||||
pPg->pPrevHash->pNextHash = pPg->pNextHash;
|
||||
}else{
|
||||
int h = pager_hash(pPg->pgno);
|
||||
int h = pPg->pgno & (pPager->nHash-1);
|
||||
assert( pPager->aHash[h]==pPg );
|
||||
pPager->aHash[h] = pPg->pNextHash;
|
||||
}
|
||||
@@ -2084,7 +2098,7 @@ int sqlite3pager_close(Pager *pPager){
|
||||
pTmp->pNext = pPager->pNext;
|
||||
}
|
||||
#endif
|
||||
|
||||
sqliteFree(pPager->aHash);
|
||||
sqliteFree(pPager);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -2622,6 +2636,13 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
TEST_INCR(pPager->nMiss);
|
||||
if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 || MEMDB ){
|
||||
/* Create a new page */
|
||||
if( pPager->nPage>=pPager->nHash ){
|
||||
pager_resize_hash_table(pPager,
|
||||
pPager->nHash<256 ? 256 : pPager->nHash*2);
|
||||
if( pPager->nHash==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize
|
||||
+ sizeof(u32) + pPager->nExtra
|
||||
+ MEMDB*sizeof(PgHistory) );
|
||||
@@ -2710,7 +2731,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
}
|
||||
|
||||
/* Link the page into the page hash table */
|
||||
h = pager_hash(pgno);
|
||||
h = pgno & (pPager->nHash-1);
|
||||
pPg->pNextHash = pPager->aHash[h];
|
||||
pPager->aHash[h] = pPg;
|
||||
if( pPg->pNextHash ){
|
||||
@@ -3766,7 +3787,7 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
|
||||
|
||||
/* Change the page number for pPg and insert it into the new hash-chain. */
|
||||
pPg->pgno = pgno;
|
||||
h = pager_hash(pgno);
|
||||
h = pgno & (pPager->nHash-1);
|
||||
if( pPager->aHash[h] ){
|
||||
assert( pPager->aHash[h]->pPrevHash==0 );
|
||||
pPager->aHash[h]->pPrevHash = pPg;
|
||||
|
Reference in New Issue
Block a user