diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/malloc.c | 82 | ||||
-rw-r--r-- | src/sqlite.h.in | 12 | ||||
-rw-r--r-- | src/test_malloc.c | 85 |
3 files changed, 163 insertions, 16 deletions
diff --git a/src/malloc.c b/src/malloc.c index cdfd6a9ea..a278e4816 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -12,7 +12,7 @@ ** ** Memory allocation functions used throughout sqlite. ** -** $Id: malloc.c,v 1.19 2008/06/18 17:09:10 danielk1977 Exp $ +** $Id: malloc.c,v 1.20 2008/06/18 18:12:04 drh Exp $ */ #include "sqliteInt.h" #include <stdarg.h> @@ -43,6 +43,7 @@ void sqlite3_soft_heap_limit(int n){ }else{ iLimit = n; } + sqlite3_initialize(); if( iLimit>0 ){ sqlite3_memory_alarm(softHeapLimitEnforcer, 0, iLimit); }else{ @@ -86,6 +87,18 @@ static struct { int alarmBusy; /* + ** Pointers to the end of sqlite3Config.pScratch and + ** sqlite3Config.pPage to a block of memory that records + ** which pages are available. + */ + u32 *aScratchFree; + u32 *aPageFree; + + /* Number of free pages for scratch and page-cache memory */ + u32 nScratchFree; + u32 nPageFree; + + /* ** Performance statistics */ sqlite3_int64 nowUsed; /* Main memory currently in use */ @@ -102,9 +115,29 @@ int sqlite3MallocInit(void){ sqlite3MemSetDefault(); } memset(&mem0, 0, sizeof(mem0)); - if( sqlite3Config.bMemstat ){ + if( sqlite3Config.bCoreMutex ){ mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); } + if( sqlite3Config.pScratch && sqlite3Config.szScratch>=3000 + && sqlite3Config.nScratch>0 ){ + int i; + mem0.aScratchFree = (u32*)&((char*)sqlite3Config.pScratch) + [sqlite3Config.szScratch*sqlite3Config.nScratch]; + for(i=0; i<sqlite3Config.nScratch; i++){ mem0.aScratchFree[i] = i; } + mem0.nScratchFree = sqlite3Config.nScratch; + }else{ + sqlite3Config.pScratch = 0; + } + if( sqlite3Config.pPage && sqlite3Config.szPage>=512 + && sqlite3Config.nPage>0 ){ + int i; + mem0.aPageFree = (u32*)&((char*)sqlite3Config.pPage) + [sqlite3Config.szPage*sqlite3Config.nPage]; + for(i=0; i<sqlite3Config.nPage; i++){ mem0.aPageFree[i] = i; } + mem0.nPageFree = sqlite3Config.nPage; + }else{ + sqlite3Config.pPage = 0; + } return sqlite3Config.m.xInit(sqlite3Config.m.pAppData); } @@ -112,7 +145,8 @@ int sqlite3MallocInit(void){ ** Deinitialize the memory allocation subsystem. */ void sqlite3MallocEnd(void){ - sqlite3Config.m.xShutdown(sqlite3Config.m.pAppData); + sqlite3Config.m.xShutdown(sqlite3Config.m.pAppData); + memset(&mem0, 0, sizeof(mem0)); } /* @@ -120,6 +154,7 @@ void sqlite3MallocEnd(void){ */ sqlite3_int64 sqlite3_memory_used(void){ sqlite3_int64 n; + sqlite3_initialize(); sqlite3_mutex_enter(mem0.mutex); n = mem0.nowUsed; sqlite3_mutex_leave(mem0.mutex); @@ -133,6 +168,7 @@ sqlite3_int64 sqlite3_memory_used(void){ */ sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ sqlite3_int64 n; + sqlite3_initialize(); sqlite3_mutex_enter(mem0.mutex); n = mem0.mxUsed; if( resetFlag ){ @@ -252,27 +288,55 @@ void *sqlite3ScratchMalloc(int n){ if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){ return 0; } + #if SQLITE_THREADSAFE==0 && !defined(NDEBUG) + /* Verify that no more than one scratch allocation per thread + ** is outstanding at one time. (This is only checked in the + ** single-threaded case since checking in the multi-threaded case + ** would be much more complicated.) */ assert( scratchAllocOut==0 ); scratchAllocOut = 1; #endif - if( sqlite3Config.bMemstat ){ - sqlite3_mutex_enter(mem0.mutex); - if( n>mem0.mxScratchReq ) mem0.mxScratchReq = n; + + sqlite3_mutex_enter(mem0.mutex); + if( n>mem0.mxScratchReq ) mem0.mxScratchReq = n; + if( mem0.nScratchFree==0 || sqlite3Config.szScratch>=n ){ p = sqlite3Config.m.xMalloc(n); - sqlite3_mutex_leave(mem0.mutex); }else{ - p = sqlite3Config.m.xMalloc(n); + int i; + i = mem0.aScratchFree[--mem0.nScratchFree]; + i *= sqlite3Config.szScratch; + p = (void*)&((char*)sqlite3Config.pScratch)[i]; } + sqlite3_mutex_leave(mem0.mutex); return p; } void sqlite3ScratchFree(void *p){ if( p ){ + #if SQLITE_THREADSAFE==0 && !defined(NDEBUG) + /* Verify that no more than one scratch allocation per thread + ** is outstanding at one time. (This is only checked in the + ** single-threaded case since checking in the multi-threaded case + ** would be much more complicated.) */ assert( scratchAllocOut==1 ); scratchAllocOut = 0; #endif - sqlite3Config.m.xFree(p); + + if( sqlite3Config.pScratch==0 + || p<sqlite3Config.pScratch + || p>=(void*)mem0.aScratchFree ){ + 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 ); + mem0.aScratchFree[mem0.nScratchFree++] = i; + sqlite3_mutex_leave(mem0.mutex); + } } } diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 737904db9..b14d32bfb 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -30,7 +30,7 @@ ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** -** @(#) $Id: sqlite.h.in,v 1.334 2008/06/18 13:47:04 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.335 2008/06/18 18:12:04 drh Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -1055,8 +1055,9 @@ struct sqlite3_mem_methods { ** <dt>SQLITE_CONFIG_SCRATCH</dt> ** <dd>This option specifies a static memory buffer that SQLite can use for ** scratch memory. There are three arguments: A pointer to the memory, the -** size of each scratch buffer (sz), and the number of buffers (N). The first -** argument should point to an allocation of at least sz*N bytes of memory. +** size of each scratch buffer (sz), and the number of buffers (N). The sz +** argument must be a multiple of 16. The first +** argument should point to an allocation of at least (sz+1)*N bytes of memory. ** SQLite will use no more than one scratch buffer at once per thread, so ** N should be set to the expected maximum number of threads. The sz ** parameter should be 6 times the size of the largest database page size. @@ -1070,8 +1071,9 @@ struct sqlite3_mem_methods { ** <dd>This option specifies a static memory buffer that SQLite can use for ** the database page cache. There are three arguments: ** A pointer to the memory, the -** size of each page buffer (sz), and the number of pages (N). The first -** argument should point to an allocation of at least sz*N bytes of memory. +** size of each page buffer (sz), and the number of pages (N). The sz +** argument must be a power of two between 512 and 32768. The first +** argument should point to an allocation of at least (sz+4)*N bytes of memory. ** SQLite will use the memory provided by the first argument to satisfy ** its memory needs for the first N pages that it adds to cache. If ** additional page cache memory is needed beyond what is provided by diff --git a/src/test_malloc.c b/src/test_malloc.c index da2a7b5f9..95ee36561 100644 --- a/src/test_malloc.c +++ b/src/test_malloc.c @@ -13,7 +13,7 @@ ** This file contains code used to implement test interfaces to the ** memory allocation subsystem. ** -** $Id: test_malloc.c,v 1.23 2008/05/29 02:57:48 shane Exp $ +** $Id: test_malloc.c,v 1.24 2008/06/18 18:12:04 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -652,6 +652,85 @@ static int test_memdebug_log( } /* +** Usage: sqlite3_config_scratch SIZE N +** +** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH. +** The buffer is static and is of limited size. N might be +** adjusted downward as needed to accomodate the requested size. +** The revised value of N is returned. +** +** A negative SIZE causes the buffer pointer to be NULL. +*/ +static int test_config_scratch( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int sz, N, rc; + Tcl_Obj *pResult; + static char buf[20000]; + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[2], &sz) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[3], &N) ) return TCL_ERROR; + if( sz<0 ){ + rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0); + }else if( sz==0 ){ + int mx = sizeof(buf)/(sz+4); + if( N>mx ) N = mx; + rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N); + } + pResult = Tcl_NewObj(); + Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); + Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); + Tcl_SetObjResult(interp, pResult); + return TCL_OK; +} + +/* +** Usage: sqlite3_config_pagecache SIZE N +** +** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE. +** The buffer is static and is of limited size. N might be +** adjusted downward as needed to accomodate the requested size. +** The revised value of N is returned. +** +** A negative SIZE causes the buffer pointer to be NULL. +*/ +static int test_config_pagecache( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int sz, N, rc; + Tcl_Obj *pResult; + static char buf[100000]; + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[2], &sz) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[3], &N) ) return TCL_ERROR; + if( sz<0 ){ + rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0); + }else if( sz==0 ){ + int mx = sizeof(buf)/(sz+4); + if( N>mx ) N = mx; + rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N); + } + pResult = Tcl_NewObj(); + Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); + Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); + Tcl_SetObjResult(interp, pResult); + return TCL_OK; +} + + +/* ** Register commands with the TCL interpreter. */ int Sqlitetest_malloc_Init(Tcl_Interp *interp){ @@ -672,7 +751,9 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){ { "sqlite3_memdebug_pending", test_memdebug_pending }, { "sqlite3_memdebug_settitle", test_memdebug_settitle }, { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count }, - { "sqlite3_memdebug_log", test_memdebug_log }, + { "sqlite3_memdebug_log", test_memdebug_log }, + { "sqlite3_config_scratch", test_config_scratch }, + { "sqlite3_config_pagecache", test_config_pagecache }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ |