diff options
author | drh <drh@noemail.net> | 2010-08-27 12:21:06 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2010-08-27 12:21:06 +0000 |
commit | 50d1b5f363ffde5be8ade2b0e774fe75f7c9359c (patch) | |
tree | b98bee603d778d608663cb8cd51251b6a7fb6506 /src | |
parent | 48d9e01e36e7d6f0ad8451b981e5a8345ca18782 (diff) | |
download | sqlite-50d1b5f363ffde5be8ade2b0e774fe75f7c9359c.tar.gz sqlite-50d1b5f363ffde5be8ade2b0e774fe75f7c9359c.zip |
Remove unnecessary code from malloc.c. Enhance pcache1.c so that is tries
to reuse existing pages, rather than create new pages, when SQLite is under
memory pressure. "Memory pressure" means that SQLITE_CONFIG_PAGECACHE memory
is nearly exhausted or sqlite3_soft_heap_limit() has been reached.
FossilOrigin-Name: 51049479a8577e03cc353f71f6e13a10c8323d91
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 4 | ||||
-rw-r--r-- | src/malloc.c | 40 | ||||
-rw-r--r-- | src/pcache1.c | 51 | ||||
-rw-r--r-- | src/sqliteInt.h | 1 |
4 files changed, 75 insertions, 21 deletions
diff --git a/src/build.c b/src/build.c index 636b8a694..5d3af6c38 100644 --- a/src/build.c +++ b/src/build.c @@ -1648,12 +1648,10 @@ void sqlite3CreateView( } sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr); p = pParse->pNewTable; - if( p==0 ){ + if( p==0 || pParse->nErr ){ sqlite3SelectDelete(db, pSelect); return; } - assert( pParse->nErr==0 ); /* If sqlite3StartTable return non-NULL then - ** there could not have been an error */ sqlite3TwoPartName(pParse, pName1, pName2, &pName); iDb = sqlite3SchemaToIndex(db, p->pSchema); if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName) diff --git a/src/malloc.c b/src/malloc.c index b36b44f7f..751d9b174 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -97,7 +97,12 @@ static SQLITE_WSD struct Mem0Global { ** which pages are available. */ u32 *aScratchFree; - u32 *aPageFree; + + /* + ** True if heap is nearly "full" where "full" is defined by the + ** sqlite3_soft_heap_limit() setting. + */ + int nearlyFull; } mem0 = { 0, 0, 0, 0, 0, 0, 0, 0 }; #define mem0 GLOBAL(struct Mem0Global, mem0) @@ -125,26 +130,25 @@ int sqlite3MallocInit(void){ sqlite3GlobalConfig.pScratch = 0; sqlite3GlobalConfig.szScratch = 0; } - if( sqlite3GlobalConfig.pPage && sqlite3GlobalConfig.szPage>=512 - && sqlite3GlobalConfig.nPage>=1 ){ - int i; - int overhead; - int sz = ROUNDDOWN8(sqlite3GlobalConfig.szPage); - int n = sqlite3GlobalConfig.nPage; - overhead = (4*n + sz - 1)/sz; - sqlite3GlobalConfig.nPage -= overhead; - mem0.aPageFree = (u32*)&((char*)sqlite3GlobalConfig.pPage) - [sqlite3GlobalConfig.szPage*sqlite3GlobalConfig.nPage]; - for(i=0; i<sqlite3GlobalConfig.nPage; i++){ mem0.aPageFree[i] = i; } - mem0.nPageFree = sqlite3GlobalConfig.nPage; - }else{ + if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512 + || sqlite3GlobalConfig.nPage<1 ){ sqlite3GlobalConfig.pPage = 0; sqlite3GlobalConfig.szPage = 0; + sqlite3GlobalConfig.nPage = 0; } return sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData); } /* +** Return true if the heap is currently under memory pressure - in other +** words if the amount of heap used is close to the limit set by +** sqlite3_soft_heap_limit(). +*/ +int sqlite3HeapNearlyFull(void){ + return mem0.nearlyFull; +} + +/* ** Deinitialize the memory allocation subsystem. */ void sqlite3MallocEnd(void){ @@ -186,10 +190,13 @@ int sqlite3MemoryAlarm( void *pArg, sqlite3_int64 iThreshold ){ + int nUsed; sqlite3_mutex_enter(mem0.mutex); mem0.alarmCallback = xCallback; mem0.alarmArg = pArg; mem0.alarmThreshold = iThreshold; + nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); + mem0.nearlyFull = (iThreshold>0 && iThreshold<=nUsed); sqlite3_mutex_leave(mem0.mutex); return SQLITE_OK; } @@ -240,14 +247,19 @@ static int mallocWithAlarm(int n, void **pp){ if( mem0.alarmCallback!=0 ){ int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); if( nUsed+nFull >= mem0.alarmThreshold ){ + mem0.nearlyFull = 1; sqlite3MallocAlarm(nFull); + }else{ + mem0.nearlyFull = 0; } } p = sqlite3GlobalConfig.m.xMalloc(nFull); +#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT if( p==0 && mem0.alarmCallback ){ sqlite3MallocAlarm(nFull); p = sqlite3GlobalConfig.m.xMalloc(nFull); } +#endif if( p ){ nFull = sqlite3MallocSize(p); sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull); diff --git a/src/pcache1.c b/src/pcache1.c index 75c9be72c..eb2e2982d 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -89,6 +89,9 @@ static SQLITE_WSD struct PCacheGlobal { /* Variables related to SQLITE_CONFIG_PAGECACHE settings. */ int szSlot; /* Size of each free slot */ + int nSlot; /* The number of pcache slots */ + int nFreeSlot; /* Number of unused pcache slots */ + int nReserve; /* Try to keep nFreeSlot above this */ void *pStart, *pEnd; /* Bounds of pagecache malloc range */ PgFreeslot *pFree; /* Free page blocks */ int isInit; /* True if initialized */ @@ -136,6 +139,8 @@ void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){ PgFreeslot *p; sz = ROUNDDOWN8(sz); pcache1.szSlot = sz; + pcache1.nSlot = pcache1.nFreeSlot = n; + pcache1.nReserve = n>90 ? 10 : (n/10 + 1); pcache1.pStart = pBuf; pcache1.pFree = 0; while( n-- ){ @@ -162,6 +167,8 @@ static void *pcache1Alloc(int nByte){ assert( pcache1.isInit ); p = (PgHdr1 *)pcache1.pFree; pcache1.pFree = pcache1.pFree->pNext; + pcache1.nFreeSlot--; + assert( pcache1.nFreeSlot>=0 ); sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1); }else{ @@ -195,6 +202,8 @@ static void pcache1Free(void *p){ pSlot = (PgFreeslot*)p; pSlot->pNext = pcache1.pFree; pcache1.pFree = pSlot; + pcache1.nFreeSlot++; + assert( pcache1.nFreeSlot<=pcache1.nSlot ); }else{ int iSize; assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) ); @@ -280,6 +289,32 @@ void sqlite3PageFree(void *p){ pcache1LeaveMutex(); } + +/* +** Return true if it desirable to avoid allocating a new page cache +** entry. +** +** If memory was allocated specifically to the page cache using +** SQLITE_CONFIG_PAGECACHE but that memory has all been used, then +** it is desirable to avoid allocating a new page cache entry because +** presumably SQLITE_CONFIG_PAGECACHE was suppose to be sufficient +** for all page cache needs and we should not need to spill the +** allocation onto the heap. +** +** Or, the heap is used for all page cache memory put the heap is +** under memory pressure, then again it is desirable to avoid +** allocating a new page cache entry in order to avoid stressing +** the heap even further. +*/ +static int pcache1UnderMemoryPressure(PCache1 *pCache){ + assert( sqlite3_mutex_held(pcache1.mutex) ); + if( pcache1.nSlot && pCache->szPage<=pcache1.szSlot ){ + return pcache1.nFreeSlot<pcache1.nReserve; + }else{ + return sqlite3HeapNearlyFull(); + } +} + /******************************************************************************/ /******** General Implementation Functions ************************************/ @@ -521,14 +556,16 @@ static int pcache1Pagecount(sqlite3_pcache *p){ ** 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: +** 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. +** 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: @@ -540,6 +577,9 @@ static int pcache1Pagecount(sqlite3_pcache *p){ ** 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. @@ -571,6 +611,7 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){ if( createFlag==1 && ( nPinned>=(pcache1.nMaxPage+pCache->nMin-pcache1.nMinPage) || nPinned>=(pCache->nMax * 9 / 10) + || pcache1UnderMemoryPressure(pCache) )){ goto fetch_out; } @@ -581,7 +622,9 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){ /* Step 4. Try to recycle a page buffer if appropriate. */ if( pCache->bPurgeable && pcache1.pLruTail && ( - (pCache->nPage+1>=pCache->nMax) || pcache1.nCurrentPage>=pcache1.nMaxPage + (pCache->nPage+1>=pCache->nMax) + || pcache1.nCurrentPage>=pcache1.nMaxPage + || pcache1UnderMemoryPressure(pCache) )){ pPage = pcache1.pLruTail; pcache1RemoveFromHash(pPage); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c44c25fa5..6c41315f8 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2503,6 +2503,7 @@ void sqlite3PageFree(void*); void sqlite3MemSetDefault(void); void sqlite3BenignMallocHooks(void (*)(void), void (*)(void)); int sqlite3MemoryAlarm(void (*)(void*, sqlite3_int64, int), void*, sqlite3_int64); +int sqlite3HeapNearlyFull(void); /* ** On systems with ample stack space and that support alloca(), make |