aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/malloc.c33
-rw-r--r--src/pcache1.c19
-rw-r--r--src/sqlite.h.in23
-rw-r--r--src/sqliteInt.h9
-rw-r--r--src/status.c86
-rw-r--r--src/tokenize.c2
6 files changed, 129 insertions, 43 deletions
diff --git a/src/malloc.c b/src/malloc.c
index 8046fb208..264d046ec 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -76,6 +76,13 @@ static SQLITE_WSD struct Mem0Global {
#define mem0 GLOBAL(struct Mem0Global, mem0)
/*
+** Return the memory allocator mutex. sqlite3_status() needs it.
+*/
+sqlite3_mutex *sqlite3MallocMutex(void){
+ return mem0.mutex;
+}
+
+/*
** This routine runs when the memory allocator sees that the
** total memory allocation is about to exceed the soft heap
** limit.
@@ -97,7 +104,7 @@ static int sqlite3MemoryAlarm(
void *pArg,
sqlite3_int64 iThreshold
){
- int nUsed;
+ sqlite3_int64 nUsed;
sqlite3_mutex_enter(mem0.mutex);
mem0.alarmCallback = xCallback;
mem0.alarmArg = pArg;
@@ -266,7 +273,7 @@ static int mallocWithAlarm(int n, void **pp){
nFull = sqlite3GlobalConfig.m.xRoundup(n);
sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
if( mem0.alarmCallback!=0 ){
- int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+ sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
if( nUsed >= mem0.alarmThreshold - nFull ){
mem0.nearlyFull = 1;
sqlite3MallocAlarm(nFull);
@@ -283,8 +290,8 @@ static int mallocWithAlarm(int n, void **pp){
#endif
if( p ){
nFull = sqlite3MallocSize(p);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull);
- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, 1);
+ sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nFull);
+ sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1);
}
*pp = p;
return nFull;
@@ -361,14 +368,14 @@ void *sqlite3ScratchMalloc(int n){
p = mem0.pScratchFree;
mem0.pScratchFree = mem0.pScratchFree->pNext;
mem0.nScratchFree--;
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, 1);
+ sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1);
sqlite3_mutex_leave(mem0.mutex);
}else{
sqlite3_mutex_leave(mem0.mutex);
p = sqlite3Malloc(n);
if( sqlite3GlobalConfig.bMemstat && p ){
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
+ sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
sqlite3_mutex_leave(mem0.mutex);
}
sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
@@ -409,7 +416,7 @@ void sqlite3ScratchFree(void *p){
mem0.pScratchFree = pSlot;
mem0.nScratchFree++;
assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch );
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, -1);
+ sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1);
sqlite3_mutex_leave(mem0.mutex);
}else{
/* Release memory back to the heap */
@@ -419,9 +426,9 @@ void sqlite3ScratchFree(void *p){
if( sqlite3GlobalConfig.bMemstat ){
int iSize = sqlite3MallocSize(p);
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, -iSize);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -iSize);
- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
+ sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize);
+ sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize);
+ sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
sqlite3GlobalConfig.m.xFree(p);
sqlite3_mutex_leave(mem0.mutex);
}else{
@@ -481,8 +488,8 @@ void sqlite3_free(void *p){
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p));
- sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
+ sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, sqlite3MallocSize(p));
+ sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
sqlite3GlobalConfig.m.xFree(p);
sqlite3_mutex_leave(mem0.mutex);
}else{
@@ -570,7 +577,7 @@ void *sqlite3Realloc(void *pOld, u64 nBytes){
}
if( pNew ){
nNew = sqlite3MallocSize(pNew);
- sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
+ sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
}
sqlite3_mutex_leave(mem0.mutex);
}else{
diff --git a/src/pcache1.c b/src/pcache1.c
index f5f789371..a8755a314 100644
--- a/src/pcache1.c
+++ b/src/pcache1.c
@@ -195,7 +195,6 @@ void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
static void *pcache1Alloc(int nByte){
void *p = 0;
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
- sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
if( nByte<=pcache1.szSlot ){
sqlite3_mutex_enter(pcache1.mutex);
p = (PgHdr1 *)pcache1.pFree;
@@ -204,7 +203,8 @@ static void *pcache1Alloc(int nByte){
pcache1.nFreeSlot--;
pcache1.bUnderPressure = pcache1.nFreeSlot<pcache1.nReserve;
assert( pcache1.nFreeSlot>=0 );
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
+ sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
+ sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1);
}
sqlite3_mutex_leave(pcache1.mutex);
}
@@ -217,7 +217,8 @@ static void *pcache1Alloc(int nByte){
if( p ){
int sz = sqlite3MallocSize(p);
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
+ sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
+ sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
sqlite3_mutex_leave(pcache1.mutex);
}
#endif
@@ -235,7 +236,7 @@ static int pcache1Free(void *p){
if( p>=pcache1.pStart && p<pcache1.pEnd ){
PgFreeslot *pSlot;
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, -1);
+ sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
pSlot = (PgFreeslot*)p;
pSlot->pNext = pcache1.pFree;
pcache1.pFree = pSlot;
@@ -249,7 +250,7 @@ static int pcache1Free(void *p){
nFreed = sqlite3MallocSize(p);
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -nFreed);
+ sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
sqlite3_mutex_leave(pcache1.mutex);
#endif
sqlite3_free(p);
@@ -986,6 +987,14 @@ void sqlite3PCacheSetDefault(void){
*/
int sqlite3HeaderSizePcache1(void){ return ROUND8(sizeof(PgHdr1)); }
+/*
+** Return the global mutex used by this PCACHE implementation. The
+** sqlite3_status() routine needs access to this mutex.
+*/
+sqlite3_mutex *sqlite3Pcache1Mutex(void){
+ return pcache1.mutex;
+}
+
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/*
** This function is called to free superfluous dynamically allocated memory
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 9e48620c6..8419392cf 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -1550,7 +1550,7 @@ struct sqlite3_mem_methods {
** <li> [sqlite3_memory_used()]
** <li> [sqlite3_memory_highwater()]
** <li> [sqlite3_soft_heap_limit64()]
-** <li> [sqlite3_status()]
+** <li> [sqlite3_status64()]
** </ul>)^
** ^Memory allocation statistics are enabled by default unless SQLite is
** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory
@@ -6305,7 +6305,7 @@ int sqlite3_test_control(int op, ...);
/*
** CAPI3REF: SQLite Runtime Status
**
-** ^This interface is used to retrieve runtime status information
+** ^These interfaces are used to retrieve runtime status information
** about the performance 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
@@ -6319,19 +6319,22 @@ int sqlite3_test_control(int op, ...);
** ^(Other parameters record only the highwater mark and not the current
** value. For these latter parameters nothing is written into *pCurrent.)^
**
-** ^The sqlite3_status() routine returns SQLITE_OK on success and a
-** non-zero [error code] on failure.
+** ^The sqlite3_status() and sqlite3_status64() routines return
+** SQLITE_OK on success and a non-zero [error code] on failure.
**
-** This routine is threadsafe but is not atomic. This routine can be
-** 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.
+** If either the current value or the highwater mark is too large to
+** be represented by a 32-bit integer, then the values returned by
+** sqlite3_status() are undefined.
**
** See also: [sqlite3_db_status()]
*/
int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+int sqlite3_status64(
+ int op,
+ sqlite3_int64 *pCurrent,
+ sqlite3_int64 *pHighwater,
+ int resetFlag
+);
/*
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 9e174d6f4..78945c1dd 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3097,10 +3097,15 @@ const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
int sqlite3MutexEnd(void);
#endif
-int sqlite3StatusValue(int);
-void sqlite3StatusAdd(int, int);
+sqlite3_int64 sqlite3StatusValue(int);
+void sqlite3StatusUp(int, int);
+void sqlite3StatusDown(int, int);
void sqlite3StatusSet(int, int);
+/* Access to mutexes used by sqlite3_status() */
+sqlite3_mutex *sqlite3Pcache1Mutex(void);
+sqlite3_mutex *sqlite3MallocMutex(void);
+
#ifndef SQLITE_OMIT_FLOATING_POINT
int sqlite3IsNaN(double);
#else
diff --git a/src/status.c b/src/status.c
index 4c2eabb66..0f6328318 100644
--- a/src/status.c
+++ b/src/status.c
@@ -21,10 +21,27 @@
*/
typedef struct sqlite3StatType sqlite3StatType;
static SQLITE_WSD struct sqlite3StatType {
- int nowValue[10]; /* Current value */
- int mxValue[10]; /* Maximum value */
+ sqlite3_int64 nowValue[10]; /* Current value */
+ sqlite3_int64 mxValue[10]; /* Maximum value */
} sqlite3Stat = { {0,}, {0,} };
+/*
+** Elements of sqlite3Stat[] are protected by either the memory allocator
+** mutex, or by the pcache1 mutex. The following array determines which.
+*/
+static const char statMutex[] = {
+ 0, /* SQLITE_STATUS_MEMORY_USED */
+ 1, /* SQLITE_STATUS_PAGECACHE_USED */
+ 1, /* SQLITE_STATUS_PAGECACHE_OVERFLOW */
+ 0, /* SQLITE_STATUS_SCRATCH_USED */
+ 0, /* SQLITE_STATUS_SCRATCH_OVERFLOW */
+ 0, /* SQLITE_STATUS_MALLOC_SIZE */
+ 0, /* SQLITE_STATUS_PARSER_STACK */
+ 1, /* SQLITE_STATUS_PAGECACHE_SIZE */
+ 0, /* SQLITE_STATUS_SCRATCH_SIZE */
+ 0, /* SQLITE_STATUS_MALLOC_COUNT */
+};
+
/* The "wsdStat" macro will resolve to the status information
** state vector. If writable static data is unsupported on the target,
@@ -41,33 +58,60 @@ static SQLITE_WSD struct sqlite3StatType {
#endif
/*
-** Return the current value of a status parameter.
+** Return the current value of a status parameter. The caller must
+** be holding the appropriate mutex.
*/
-int sqlite3StatusValue(int op){
+sqlite3_int64 sqlite3StatusValue(int op){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
return wsdStat.nowValue[op];
}
/*
-** Add N to the value of a status record. It is assumed that the
-** caller holds appropriate locks.
+** Add N to the value of a status record. The caller must hold the
+** appropriate mutex. (Locking is checked by assert()).
+**
+** The StatusUp() routine can accept positive or negative values for N.
+** The value of N is added to the current status value and the high-water
+** mark is adjusted if necessary.
+**
+** The StatusDown() routine lowers the current value by N. The highwater
+** mark is unchanged. N must be non-negative for StatusDown().
*/
-void sqlite3StatusAdd(int op, int N){
+void sqlite3StatusUp(int op, int N){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
wsdStat.nowValue[op] += N;
if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
}
}
+void sqlite3StatusDown(int op, int N){
+ wsdStatInit;
+ assert( N>=0 );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
+ assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ wsdStat.nowValue[op] -= N;
+}
/*
-** Set the value of a status to X.
+** Set the value of a status to X. The highwater mark is adjusted if
+** necessary. The caller must hold the appropriate mutex.
*/
void sqlite3StatusSet(int op, int X){
wsdStatInit;
assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
+ assert( op>=0 && op<ArraySize(statMutex) );
+ assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
+ : sqlite3MallocMutex()) );
wsdStat.nowValue[op] = X;
if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
@@ -76,26 +120,42 @@ void sqlite3StatusSet(int op, int X){
/*
** Query status information.
-**
-** This implementation assumes that reading or writing an aligned
-** 32-bit integer is an atomic operation. If that assumption is not true,
-** then this routine is not threadsafe.
*/
-int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
+int sqlite3_status64(
+ int op,
+ sqlite3_int64 *pCurrent,
+ sqlite3_int64 *pHighwater,
+ int resetFlag
+){
wsdStatInit;
+ sqlite3_mutex *pMutex;
if( op<0 || op>=ArraySize(wsdStat.nowValue) ){
return SQLITE_MISUSE_BKPT;
}
#ifdef SQLITE_ENABLE_API_ARMOR
if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
#endif
+ pMutex = statMutex[op] ? sqlite3Pcache1Mutex() : sqlite3MallocMutex();
+ sqlite3_mutex_enter(pMutex);
*pCurrent = wsdStat.nowValue[op];
*pHighwater = wsdStat.mxValue[op];
if( resetFlag ){
wsdStat.mxValue[op] = wsdStat.nowValue[op];
}
+ sqlite3_mutex_leave(pMutex);
return SQLITE_OK;
}
+int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
+ sqlite3_int64 iCur, iHwtr;
+ int rc;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag);
+ *pCurrent = (int)iCur;
+ *pHighwater = (int)iHwtr;
+ return rc;
+}
/*
** Query status information for a single database connection
diff --git a/src/tokenize.c b/src/tokenize.c
index 6fb5a35c3..5068742f3 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -459,9 +459,11 @@ abort_parse:
sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
}
#ifdef YYTRACKMAXSTACKDEPTH
+ sqlite3_mutex_enter(sqlite3MallocMutex());
sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK,
sqlite3ParserStackPeak(pEngine)
);
+ sqlite3_mutex_leave(sqlite3MallocMutex());
#endif /* YYDEBUG */
sqlite3ParserFree(pEngine, sqlite3_free);
db->lookaside.bEnabled = enableLookaside;