diff options
Diffstat (limited to 'src/malloc.c')
-rw-r--r-- | src/malloc.c | 237 |
1 files changed, 162 insertions, 75 deletions
diff --git a/src/malloc.c b/src/malloc.c index a278e4816..3441123c6 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -12,7 +12,7 @@ ** ** Memory allocation functions used throughout sqlite. ** -** $Id: malloc.c,v 1.20 2008/06/18 18:12:04 drh Exp $ +** $Id: malloc.c,v 1.21 2008/06/19 00:16:08 drh Exp $ */ #include "sqliteInt.h" #include <stdarg.h> @@ -97,14 +97,6 @@ static struct { /* Number of free pages for scratch and page-cache memory */ u32 nScratchFree; u32 nPageFree; - - /* - ** Performance statistics - */ - sqlite3_int64 nowUsed; /* Main memory currently in use */ - sqlite3_int64 mxUsed; /* Highwater mark for nowUsed */ - int mxReq; /* Max request size for ordinary mallocs */ - int mxScratchReq; /* Max request size for xTemp mallocs */ } mem0; /* @@ -127,6 +119,7 @@ int sqlite3MallocInit(void){ mem0.nScratchFree = sqlite3Config.nScratch; }else{ sqlite3Config.pScratch = 0; + sqlite3Config.szScratch = 0; } if( sqlite3Config.pPage && sqlite3Config.szPage>=512 && sqlite3Config.nPage>0 ){ @@ -137,6 +130,7 @@ int sqlite3MallocInit(void){ mem0.nPageFree = sqlite3Config.nPage; }else{ sqlite3Config.pPage = 0; + sqlite3Config.szPage = 0; } return sqlite3Config.m.xInit(sqlite3Config.m.pAppData); } @@ -153,12 +147,9 @@ void sqlite3MallocEnd(void){ ** Return the amount of memory currently checked out. */ sqlite3_int64 sqlite3_memory_used(void){ - sqlite3_int64 n; - sqlite3_initialize(); - sqlite3_mutex_enter(mem0.mutex); - n = mem0.nowUsed; - sqlite3_mutex_leave(mem0.mutex); - return n; + int n, mx; + sqlite3_status(SQLITE_STATUS_MEMORY_USED, &n, &mx, 0); + return (sqlite3_int64)n; } /* @@ -167,15 +158,9 @@ sqlite3_int64 sqlite3_memory_used(void){ ** or since the most recent reset. */ sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ - sqlite3_int64 n; - sqlite3_initialize(); - sqlite3_mutex_enter(mem0.mutex); - n = mem0.mxUsed; - if( resetFlag ){ - mem0.mxUsed = mem0.nowUsed; - } - sqlite3_mutex_leave(mem0.mutex); - return n; + int n, mx; + sqlite3_status(SQLITE_STATUS_MEMORY_USED, &n, &mx, resetFlag); + return (sqlite3_int64)mx; } /* @@ -204,7 +189,7 @@ static void sqlite3MallocAlarm(int nByte){ if( mem0.alarmCallback==0 || mem0.alarmBusy ) return; mem0.alarmBusy = 1; xCallback = mem0.alarmCallback; - nowUsed = mem0.nowUsed; + nowUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); pArg = mem0.alarmArg; sqlite3_mutex_leave(mem0.mutex); xCallback(pArg, nowUsed, nByte); @@ -212,6 +197,35 @@ static void sqlite3MallocAlarm(int nByte){ mem0.alarmBusy = 0; } +/* +** Do a memory allocation with statistics and alarms. Assume the +** lock is already held. +*/ +static int mallocWithAlarm(int n, void **pp){ + int nFull; + void *p; + assert( sqlite3_mutex_held(mem0.mutex) ); + nFull = sqlite3Config.m.xRoundup(n); + sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n); + if( mem0.alarmCallback!=0 ){ + int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); + if( nUsed+nFull >= mem0.alarmThreshold ){ + sqlite3MallocAlarm(nFull); + } + } + if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){ + p = 0; + }else{ + p = sqlite3Config.m.xMalloc(nFull); + if( p==0 ){ + sqlite3MallocAlarm(nFull); + p = malloc(nFull); + } + } + if( p ) sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull); + *pp = p; + return nFull; +} /* ** Allocate memory. This routine is like sqlite3_malloc() except that it @@ -219,31 +233,11 @@ static void sqlite3MallocAlarm(int nByte){ */ void *sqlite3Malloc(int n){ void *p; - int nFull; if( n<=0 ){ - return 0; + p = 0; }else if( sqlite3Config.bMemstat ){ - nFull = sqlite3Config.m.xRoundup(n); sqlite3_mutex_enter(mem0.mutex); - if( n>mem0.mxReq ) mem0.mxReq = n; - if( mem0.alarmCallback!=0 && mem0.nowUsed+nFull>=mem0.alarmThreshold ){ - sqlite3MallocAlarm(nFull); - } - if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){ - p = 0; - }else{ - p = sqlite3Config.m.xMalloc(nFull); - if( p==0 ){ - sqlite3MallocAlarm(nFull); - p = malloc(nFull); - } - } - if( p ){ - mem0.nowUsed += nFull; - if( mem0.nowUsed>mem0.mxUsed ){ - mem0.mxUsed = mem0.nowUsed; - } - } + mallocWithAlarm(n, &p); sqlite3_mutex_leave(mem0.mutex); }else{ p = sqlite3Config.m.xMalloc(n); @@ -295,21 +289,43 @@ void *sqlite3ScratchMalloc(int n){ ** single-threaded case since checking in the multi-threaded case ** would be much more complicated.) */ assert( scratchAllocOut==0 ); - scratchAllocOut = 1; #endif - sqlite3_mutex_enter(mem0.mutex); - if( n>mem0.mxScratchReq ) mem0.mxScratchReq = n; - if( mem0.nScratchFree==0 || sqlite3Config.szScratch>=n ){ - p = sqlite3Config.m.xMalloc(n); - }else{ - int i; - i = mem0.aScratchFree[--mem0.nScratchFree]; - i *= sqlite3Config.szScratch; - p = (void*)&((char*)sqlite3Config.pScratch)[i]; + if( sqlite3Config.szScratch<n ){ + goto scratch_overflow; + }else{ + sqlite3_mutex_enter(mem0.mutex); + if( mem0.nScratchFree==0 ){ + sqlite3_mutex_leave(mem0.mutex); + goto scratch_overflow; + }else{ + int i; + i = mem0.aScratchFree[--mem0.nScratchFree]; + sqlite3_mutex_leave(mem0.mutex); + i *= sqlite3Config.szScratch; + sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1); + p = (void*)&((char*)sqlite3Config.pScratch)[i]; + } } - sqlite3_mutex_leave(mem0.mutex); +#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) + scratchAllocOut = p!=0; +#endif + return p; + +scratch_overflow: + if( sqlite3Config.bMemstat ){ + sqlite3_mutex_enter(mem0.mutex); + n = mallocWithAlarm(n, &p); + if( p ) sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, n); + sqlite3_mutex_leave(mem0.mutex); + }else{ + p = sqlite3Config.m.xMalloc(n); + } +#if SQLITE_THREADSAFE==0 && !defined(NDEBUG) + scratchAllocOut = p!=0; +#endif + return p; } void sqlite3ScratchFree(void *p){ if( p ){ @@ -324,30 +340,103 @@ void sqlite3ScratchFree(void *p){ #endif if( sqlite3Config.pScratch==0 - || p<sqlite3Config.pScratch - || p>=(void*)mem0.aScratchFree ){ - sqlite3Config.m.xFree(p); + || p<sqlite3Config.pScratch + || p>=(void*)mem0.aScratchFree ){ + if( sqlite3Config.bMemstat ){ + int iSize = sqlite3MallocSize(p); + sqlite3_mutex_enter(mem0.mutex); + sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, -iSize); + sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -iSize); + sqlite3Config.m.xFree(p); + sqlite3_mutex_leave(mem0.mutex); + }else{ + sqlite3Config.m.xFree(p); + } }else{ int i; - sqlite3_mutex_enter(mem0.mutex); - assert( mem0.nScratchFree<sqlite3Config.nScratch ); i = p - sqlite3Config.pScratch; i /= sqlite3Config.szScratch; assert( i>=0 && i<sqlite3Config.nScratch ); + sqlite3_mutex_enter(mem0.mutex); + assert( mem0.nScratchFree<sqlite3Config.nScratch ); mem0.aScratchFree[mem0.nScratchFree++] = i; + sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, -1); sqlite3_mutex_leave(mem0.mutex); } } } /* -** Place holders for the page-cache memory allocator. +** Allocate memory to be used by the page cache. Make use of the +** memory buffer provided by SQLITE_CONFIG_PAGECACHE if there is one +** and that memory is of the right size and is not completely +** consumed. Otherwise, failover to sqlite3Malloc(). */ -void *sqlite3PageMalloc(int iSize){ - return sqlite3Malloc(iSize); +void *sqlite3PageMalloc(int n){ + void *p; + assert( n>0 ); + assert( (n & (n-1))==0 ); + assert( n>=512 && n<=32768 ); + if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){ + return 0; + } + + if( sqlite3Config.szPage<n ){ + goto page_overflow; + }else{ + sqlite3_mutex_enter(mem0.mutex); + if( mem0.nPageFree==0 ){ + sqlite3_mutex_leave(mem0.mutex); + goto page_overflow; + }else{ + int i; + i = mem0.aPageFree[--mem0.nPageFree]; + sqlite3_mutex_leave(mem0.mutex); + i *= sqlite3Config.szPage; + sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1); + p = (void*)&((char*)sqlite3Config.pPage)[i]; + } + } + return p; + +page_overflow: + if( sqlite3Config.bMemstat ){ + sqlite3_mutex_enter(mem0.mutex); + n = mallocWithAlarm(n, &p); + if( p ) sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, n); + sqlite3_mutex_leave(mem0.mutex); + }else{ + p = sqlite3Config.m.xMalloc(n); + } + return p; } -void sqlite3PageFree(void *pOld){ - sqlite3_free(pOld); +void sqlite3PageFree(void *p){ + if( p ){ + if( sqlite3Config.pPage==0 + || p<sqlite3Config.pPage + || p>=(void*)mem0.aPageFree ){ + if( sqlite3Config.bMemstat ){ + int iSize = sqlite3MallocSize(p); + sqlite3_mutex_enter(mem0.mutex); + sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize); + sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -iSize); + sqlite3Config.m.xFree(p); + sqlite3_mutex_leave(mem0.mutex); + }else{ + sqlite3Config.m.xFree(p); + } + }else{ + int i; + i = p - sqlite3Config.pPage; + i /= sqlite3Config.szPage; + assert( i>=0 && i<sqlite3Config.nPage ); + sqlite3_mutex_enter(mem0.mutex); + assert( mem0.nPageFree<sqlite3Config.nPage ); + mem0.aPageFree[mem0.nPageFree++] = i; + sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1); + sqlite3_mutex_leave(mem0.mutex); + } + } } /* @@ -365,7 +454,7 @@ void sqlite3_free(void *p){ if( p==0 ) return; if( sqlite3Config.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); - mem0.nowUsed -= sqlite3MallocSize(p); + sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p)); sqlite3Config.m.xFree(p); sqlite3_mutex_leave(mem0.mutex); }else{ @@ -389,12 +478,13 @@ void *sqlite3Realloc(void *pOld, int nBytes){ nOld = sqlite3MallocSize(pOld); if( sqlite3Config.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); - if( nBytes>mem0.mxReq ) mem0.mxReq = nBytes; + sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes); nNew = sqlite3Config.m.xRoundup(nBytes); if( nOld==nNew ){ pNew = pOld; }else{ - if( mem0.nowUsed+nNew-nOld>=mem0.alarmThreshold ){ + if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nNew-nOld >= + mem0.alarmThreshold ){ sqlite3MallocAlarm(nNew-nOld); } if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){ @@ -407,10 +497,7 @@ void *sqlite3Realloc(void *pOld, int nBytes){ } } if( pNew ){ - mem0.nowUsed += nNew-nOld; - if( mem0.nowUsed>mem0.mxUsed ){ - mem0.mxUsed = mem0.nowUsed; - } + sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld); } } sqlite3_mutex_leave(mem0.mutex); |