Add some test logic to the new memory allocation subsystem. (Lots more needed.)
The test suite is currently indicating memory leaks, though it is unclear if this is a true code problem or just an instrumentation problem. (CVS 5240) FossilOrigin-Name: cb1f11cd9764cf0275e88e1f6342e366e5536bfd
This commit is contained in:
+25
-19
@@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.466 2008/06/18 17:09:10 danielk1977 Exp $
|
||||
** $Id: btree.c,v 1.467 2008/06/19 00:16:08 drh Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** See the header comment on "btreeInt.h" for additional information.
|
||||
@@ -1400,6 +1400,24 @@ static int removeFromSharingList(BtShared *pBt){
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Make sure pBt->pTmpSpace points to an allocation of
|
||||
** MX_CELL_SIZE(pBt) bytes.
|
||||
*/
|
||||
static void allocateTempSpace(BtShared *pBt){
|
||||
if( !pBt->pTmpSpace ){
|
||||
pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Free the pBt->pTmpSpace allocation
|
||||
*/
|
||||
static void freeTempSpace(BtShared *pBt){
|
||||
sqlite3PageFree( pBt->pTmpSpace);
|
||||
pBt->pTmpSpace = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close an open database and invalidate all cursors.
|
||||
*/
|
||||
@@ -1444,8 +1462,7 @@ int sqlite3BtreeClose(Btree *p){
|
||||
pBt->xFreeSchema(pBt->pSchema);
|
||||
}
|
||||
sqlite3_free(pBt->pSchema);
|
||||
sqlite3_free(pBt->pTmpSpace);
|
||||
sqlite3_free(pBt);
|
||||
freeTempSpace(pBt);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
@@ -1549,8 +1566,7 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){
|
||||
assert( (pageSize & 7)==0 );
|
||||
assert( !pBt->pPage1 && !pBt->pCursor );
|
||||
pBt->pageSize = pageSize;
|
||||
sqlite3_free(pBt->pTmpSpace);
|
||||
pBt->pTmpSpace = 0;
|
||||
freeTempSpace(pBt);
|
||||
rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize);
|
||||
}
|
||||
pBt->usableSize = pBt->pageSize - nReserve;
|
||||
@@ -1698,8 +1714,7 @@ static int lockBtree(BtShared *pBt){
|
||||
releasePage(pPage1);
|
||||
pBt->usableSize = usableSize;
|
||||
pBt->pageSize = pageSize;
|
||||
sqlite3_free(pBt->pTmpSpace);
|
||||
pBt->pTmpSpace = 0;
|
||||
freeTempSpace(pBt);
|
||||
sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -5677,16 +5692,6 @@ static int checkReadLocks(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make sure pBt->pTmpSpace points to an allocation of
|
||||
** MX_CELL_SIZE(pBt) bytes.
|
||||
*/
|
||||
static void allocateTempSpace(BtShared *pBt){
|
||||
if( !pBt->pTmpSpace ){
|
||||
pBt->pTmpSpace = sqlite3Malloc(MX_CELL_SIZE(pBt));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Insert a new record into the BTree. The key is given by (pKey,nKey)
|
||||
** and the data is given by (pData,nData). The cursor is used only to
|
||||
@@ -6643,8 +6648,9 @@ static int checkTreePage(
|
||||
*/
|
||||
data = pPage->aData;
|
||||
hdr = pPage->hdrOffset;
|
||||
hit = sqlite3MallocZero( usableSize );
|
||||
hit = sqlite3PageMalloc( pBt->pageSize );
|
||||
if( hit ){
|
||||
memset(hit, 0, usableSize );
|
||||
memset(hit, 1, get2byte(&data[hdr+5]));
|
||||
nCell = get2byte(&data[hdr+3]);
|
||||
cellStart = hdr + 12 - 4*pPage->leaf;
|
||||
@@ -6686,7 +6692,7 @@ static int checkTreePage(
|
||||
cnt, data[hdr+7], iPage);
|
||||
}
|
||||
}
|
||||
sqlite3_free(hit);
|
||||
sqlite3PageFree(hit);
|
||||
|
||||
releasePage(pPage);
|
||||
return depth+1;
|
||||
|
||||
+2
-1
@@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.450 2008/06/18 18:57:42 danielk1977 Exp $
|
||||
** $Id: main.c,v 1.451 2008/06/19 00:16:08 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -80,6 +80,7 @@ int sqlite3_initialize(void){
|
||||
sqlite3_mutex_enter(pMutex);
|
||||
if( sqlite3IsInit==0 ){
|
||||
sqlite3IsInit = 1;
|
||||
sqlite3StatusReset();
|
||||
if( rc==SQLITE_OK ) rc = sqlite3MallocInit();
|
||||
if( rc==SQLITE_OK ) rc = sqlite3_os_init();
|
||||
if( rc!=SQLITE_OK ){
|
||||
|
||||
+162
-75
@@ -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);
|
||||
|
||||
+91
-2
@@ -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.336 2008/06/18 18:57:42 danielk1977 Exp $
|
||||
** @(#) $Id: sqlite.h.in,v 1.337 2008/06/19 00:16:08 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE3_H_
|
||||
#define _SQLITE3_H_
|
||||
@@ -1057,7 +1057,7 @@ struct sqlite3_mem_methods {
|
||||
** 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 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.
|
||||
** argument should point to an allocation of at least (sz+4)*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.
|
||||
@@ -5998,6 +5998,95 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_PRNG_RESET 7
|
||||
#define SQLITE_TESTCTRL_BITVEC_TEST 8
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQLite Runtime Status {F17200}
|
||||
**
|
||||
** This interface is used to retrieve run-time status information
|
||||
** about the preformance of SQLite, and optionally to reset various
|
||||
** highwater marks. The first argument is an integer code for
|
||||
** the specific parameter to measure. Recognized integer codes
|
||||
** are of the form [SQLITE_STATUS_MEMORY_USED | SQLITE_STATUS_...].
|
||||
** The current value of the parameter is returned into *pCurrent.
|
||||
** The highest recorded value is returned in *pHighwater. If the
|
||||
** resetFlag is true, then the highest record value is reset after
|
||||
** *pHighwater is written. Some parameters do not record the highest
|
||||
** value. For those parameters
|
||||
** nothing is written into *pHighwater and the resetFlag is ignored.
|
||||
** Other parameters record only the highwater mark and not the current
|
||||
** value. For these latter parameters nothing is written into *pCurrent.
|
||||
**
|
||||
** This routine returns SQLITE_OK on success and a non-zero
|
||||
** [error code] on failure.
|
||||
**
|
||||
** This routine is threadsafe but is not atomic. This routine can
|
||||
** called while other threads are running the same or different SQLite
|
||||
** interfaces. However the values returned in *pCurrent and
|
||||
** *pHighwater reflect the status of SQLite at different points in time
|
||||
** and it is possible that another thread might change the parameter
|
||||
** in between the times when *pCurrent and *pHighwater are written.
|
||||
**
|
||||
** This interface is experimental and is subject to change or
|
||||
** removal in future releases of SQLite.
|
||||
*/
|
||||
int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Status Parameters {F17250}
|
||||
**
|
||||
** These integer constants designate various run-time status parameters
|
||||
** that can be returned by [sqlite3_status()].
|
||||
**
|
||||
** <dl>
|
||||
** <dt>SQLITE_STATUS_MEMORY_USED</dt>
|
||||
** <dd>This parameter is the current amount of memory checked out
|
||||
** using [sqlite3_malloc()], either directly or indirectly. The
|
||||
** figure includes calls made to [sqlite3_malloc()] by the application
|
||||
** and internal memory usage by the SQLite library. Scratch memory
|
||||
** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache
|
||||
** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in
|
||||
** this parameter. The amount returned is the sum of the allocation
|
||||
** sizes as are reported by the xSize method in [sqlite3_mem_methods].</dd>
|
||||
**
|
||||
** <dt>SQLITE_STATUS_PAGECACHE_USED</dt>
|
||||
** <dd>This parameter returns the number of pages used out of the
|
||||
** page cache buffer configured using [SQLITE_CONFIG_PAGECACHE]. The
|
||||
** value returned is in pages, not in bytes.</dd>
|
||||
**
|
||||
** <dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt>
|
||||
** <dd>This parameter returns the number of bytes of page cache
|
||||
** allocation which could not be statisfied by the [SQLITE_CONFIG_PAGECACHE]
|
||||
** buffer and where forced to overflow to [sqlite3_malloc()].</dd>
|
||||
**
|
||||
** <dt>SQLITE_STATUS_SCRATCH_USED</dt>
|
||||
** <dd>This parameter returns the number of allocations used out of the
|
||||
** scratch allocation lookaside buffer configured using
|
||||
** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not
|
||||
** in bytes. Since a single thread may only have one allocation
|
||||
** outstanding at time, this parameter also reports the number of threads
|
||||
** using scratch memory at the same time.</dd>
|
||||
**
|
||||
** <dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt>
|
||||
** <dd>This parameter returns the number of bytes of scratch memory
|
||||
** allocation which could not be statisfied by the [SQLITE_CONFIG_SCRATCH]
|
||||
** buffer and where forced to overflow to [sqlite3_malloc()].</dd>
|
||||
**
|
||||
** <dt>SQLITE_STATUS_MALLOC_SIZE</dt>
|
||||
** <dd>This parameter records the largest memory allocation request
|
||||
** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their
|
||||
** internal equivalents). The value of interest is return in the
|
||||
** *pHighwater parameter to [sqlite3_status()]. The value written
|
||||
** into the *pCurrent parameter is undefined.</dd>
|
||||
** </dl>
|
||||
**
|
||||
** New status parameters may be added from time to time.
|
||||
*/
|
||||
#define SQLITE_STATUS_MEMORY_USED 0
|
||||
#define SQLITE_STATUS_PAGECACHE_USED 1
|
||||
#define SQLITE_STATUS_PAGECACHE_OVERFLOW 2
|
||||
#define SQLITE_STATUS_SCRATCH_USED 3
|
||||
#define SQLITE_STATUS_SCRATCH_OVERFLOW 4
|
||||
#define SQLITE_STATUS_MALLOC_SIZE 5
|
||||
|
||||
|
||||
/*
|
||||
** Undo the hack that converts floating point types to integer for
|
||||
|
||||
+6
-1
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.715 2008/06/18 18:57:42 danielk1977 Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.716 2008/06/19 00:16:08 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
@@ -1810,6 +1810,11 @@ sqlite3_mutex *sqlite3MutexAlloc(int);
|
||||
int sqlite3MutexInit(void);
|
||||
int sqlite3MutexEnd(void);
|
||||
|
||||
void sqlite3StatusReset(void);
|
||||
int sqlite3StatusValue(int);
|
||||
void sqlite3StatusAdd(int, int);
|
||||
void sqlite3StatusSet(int, int);
|
||||
|
||||
int sqlite3IsNaN(double);
|
||||
|
||||
char *sqlite3MPrintf(sqlite3*,const char*, ...);
|
||||
|
||||
+60
-9
@@ -13,7 +13,7 @@
|
||||
** This file contains code used to implement test interfaces to the
|
||||
** memory allocation subsystem.
|
||||
**
|
||||
** $Id: test_malloc.c,v 1.24 2008/06/18 18:12:04 drh Exp $
|
||||
** $Id: test_malloc.c,v 1.25 2008/06/19 00:16:08 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "tcl.h"
|
||||
@@ -669,16 +669,16 @@ static int test_config_scratch(
|
||||
){
|
||||
int sz, N, rc;
|
||||
Tcl_Obj *pResult;
|
||||
static char buf[20000];
|
||||
static char buf[30000];
|
||||
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( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
|
||||
if( sz<0 ){
|
||||
rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0);
|
||||
}else if( sz==0 ){
|
||||
}else{
|
||||
int mx = sizeof(buf)/(sz+4);
|
||||
if( N>mx ) N = mx;
|
||||
rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
|
||||
@@ -713,11 +713,11 @@ static int test_config_pagecache(
|
||||
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( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
|
||||
if( sz<0 ){
|
||||
rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0);
|
||||
}else if( sz==0 ){
|
||||
rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0);
|
||||
}else{
|
||||
int mx = sizeof(buf)/(sz+4);
|
||||
if( N>mx ) N = mx;
|
||||
rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
|
||||
@@ -729,6 +729,56 @@ static int test_config_pagecache(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_status OPCODE RESETFLAG
|
||||
**
|
||||
** Return a list of three elements which are the sqlite3_status() return
|
||||
** code, the current value, and the high-water mark value.
|
||||
*/
|
||||
static int test_status(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int rc, iValue, mxValue;
|
||||
int i, op, resetFlag;
|
||||
const char *zOpName;
|
||||
static const struct {
|
||||
const char *zName;
|
||||
int op;
|
||||
} aOp[] = {
|
||||
{ "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED },
|
||||
{ "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED },
|
||||
{ "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW },
|
||||
{ "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED },
|
||||
{ "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW },
|
||||
{ "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE },
|
||||
};
|
||||
Tcl_Obj *pResult;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zOpName = Tcl_GetString(objv[1]);
|
||||
for(i=0; i<ArraySize(aOp); i++){
|
||||
if( strcmp(aOp[i].zName, zOpName)==0 ){
|
||||
op = aOp[i].op;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i>=ArraySize(aOp) ){
|
||||
if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
|
||||
rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
|
||||
pResult = Tcl_NewObj();
|
||||
Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
|
||||
Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
|
||||
Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
|
||||
Tcl_SetObjResult(interp, pResult);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
@@ -754,6 +804,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_memdebug_log", test_memdebug_log },
|
||||
{ "sqlite3_config_scratch", test_config_scratch },
|
||||
{ "sqlite3_config_pagecache", test_config_pagecache },
|
||||
{ "sqlite3_status", test_status },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
|
||||
|
||||
Reference in New Issue
Block a user