000001 /* 000002 ** 2008 June 18 000003 ** 000004 ** The author disclaims copyright to this source code. In place of 000005 ** a legal notice, here is a blessing: 000006 ** 000007 ** May you do good and not evil. 000008 ** May you find forgiveness for yourself and forgive others. 000009 ** May you share freely, never taking more than you give. 000010 ** 000011 ************************************************************************* 000012 ** 000013 ** This module implements the sqlite3_status() interface and related 000014 ** functionality. 000015 */ 000016 #include "sqliteInt.h" 000017 #include "vdbeInt.h" 000018 000019 /* 000020 ** Variables in which to record status information. 000021 */ 000022 #if SQLITE_PTRSIZE>4 000023 typedef sqlite3_int64 sqlite3StatValueType; 000024 #else 000025 typedef u32 sqlite3StatValueType; 000026 #endif 000027 typedef struct sqlite3StatType sqlite3StatType; 000028 static SQLITE_WSD struct sqlite3StatType { 000029 sqlite3StatValueType nowValue[10]; /* Current value */ 000030 sqlite3StatValueType mxValue[10]; /* Maximum value */ 000031 } sqlite3Stat = { {0,}, {0,} }; 000032 000033 /* 000034 ** Elements of sqlite3Stat[] are protected by either the memory allocator 000035 ** mutex, or by the pcache1 mutex. The following array determines which. 000036 */ 000037 static const char statMutex[] = { 000038 0, /* SQLITE_STATUS_MEMORY_USED */ 000039 1, /* SQLITE_STATUS_PAGECACHE_USED */ 000040 1, /* SQLITE_STATUS_PAGECACHE_OVERFLOW */ 000041 0, /* SQLITE_STATUS_SCRATCH_USED */ 000042 0, /* SQLITE_STATUS_SCRATCH_OVERFLOW */ 000043 0, /* SQLITE_STATUS_MALLOC_SIZE */ 000044 0, /* SQLITE_STATUS_PARSER_STACK */ 000045 1, /* SQLITE_STATUS_PAGECACHE_SIZE */ 000046 0, /* SQLITE_STATUS_SCRATCH_SIZE */ 000047 0, /* SQLITE_STATUS_MALLOC_COUNT */ 000048 }; 000049 000050 000051 /* The "wsdStat" macro will resolve to the status information 000052 ** state vector. If writable static data is unsupported on the target, 000053 ** we have to locate the state vector at run-time. In the more common 000054 ** case where writable static data is supported, wsdStat can refer directly 000055 ** to the "sqlite3Stat" state vector declared above. 000056 */ 000057 #ifdef SQLITE_OMIT_WSD 000058 # define wsdStatInit sqlite3StatType *x = &GLOBAL(sqlite3StatType,sqlite3Stat) 000059 # define wsdStat x[0] 000060 #else 000061 # define wsdStatInit 000062 # define wsdStat sqlite3Stat 000063 #endif 000064 000065 /* 000066 ** Return the current value of a status parameter. The caller must 000067 ** be holding the appropriate mutex. 000068 */ 000069 sqlite3_int64 sqlite3StatusValue(int op){ 000070 wsdStatInit; 000071 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); 000072 assert( op>=0 && op<ArraySize(statMutex) ); 000073 assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex() 000074 : sqlite3MallocMutex()) ); 000075 return wsdStat.nowValue[op]; 000076 } 000077 000078 /* 000079 ** Add N to the value of a status record. The caller must hold the 000080 ** appropriate mutex. (Locking is checked by assert()). 000081 ** 000082 ** The StatusUp() routine can accept positive or negative values for N. 000083 ** The value of N is added to the current status value and the high-water 000084 ** mark is adjusted if necessary. 000085 ** 000086 ** The StatusDown() routine lowers the current value by N. The highwater 000087 ** mark is unchanged. N must be non-negative for StatusDown(). 000088 */ 000089 void sqlite3StatusUp(int op, int N){ 000090 wsdStatInit; 000091 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); 000092 assert( op>=0 && op<ArraySize(statMutex) ); 000093 assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex() 000094 : sqlite3MallocMutex()) ); 000095 wsdStat.nowValue[op] += N; 000096 if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){ 000097 wsdStat.mxValue[op] = wsdStat.nowValue[op]; 000098 } 000099 } 000100 void sqlite3StatusDown(int op, int N){ 000101 wsdStatInit; 000102 assert( N>=0 ); 000103 assert( op>=0 && op<ArraySize(statMutex) ); 000104 assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex() 000105 : sqlite3MallocMutex()) ); 000106 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); 000107 wsdStat.nowValue[op] -= N; 000108 } 000109 000110 /* 000111 ** Adjust the highwater mark if necessary. 000112 ** The caller must hold the appropriate mutex. 000113 */ 000114 void sqlite3StatusHighwater(int op, int X){ 000115 sqlite3StatValueType newValue; 000116 wsdStatInit; 000117 assert( X>=0 ); 000118 newValue = (sqlite3StatValueType)X; 000119 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); 000120 assert( op>=0 && op<ArraySize(statMutex) ); 000121 assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex() 000122 : sqlite3MallocMutex()) ); 000123 assert( op==SQLITE_STATUS_MALLOC_SIZE 000124 || op==SQLITE_STATUS_PAGECACHE_SIZE 000125 || op==SQLITE_STATUS_SCRATCH_SIZE 000126 || op==SQLITE_STATUS_PARSER_STACK ); 000127 if( newValue>wsdStat.mxValue[op] ){ 000128 wsdStat.mxValue[op] = newValue; 000129 } 000130 } 000131 000132 /* 000133 ** Query status information. 000134 */ 000135 int sqlite3_status64( 000136 int op, 000137 sqlite3_int64 *pCurrent, 000138 sqlite3_int64 *pHighwater, 000139 int resetFlag 000140 ){ 000141 sqlite3_mutex *pMutex; 000142 wsdStatInit; 000143 if( op<0 || op>=ArraySize(wsdStat.nowValue) ){ 000144 return SQLITE_MISUSE_BKPT; 000145 } 000146 #ifdef SQLITE_ENABLE_API_ARMOR 000147 if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; 000148 #endif 000149 pMutex = statMutex[op] ? sqlite3Pcache1Mutex() : sqlite3MallocMutex(); 000150 sqlite3_mutex_enter(pMutex); 000151 *pCurrent = wsdStat.nowValue[op]; 000152 *pHighwater = wsdStat.mxValue[op]; 000153 if( resetFlag ){ 000154 wsdStat.mxValue[op] = wsdStat.nowValue[op]; 000155 } 000156 sqlite3_mutex_leave(pMutex); 000157 (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */ 000158 return SQLITE_OK; 000159 } 000160 int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ 000161 sqlite3_int64 iCur = 0, iHwtr = 0; 000162 int rc; 000163 #ifdef SQLITE_ENABLE_API_ARMOR 000164 if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; 000165 #endif 000166 rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag); 000167 if( rc==0 ){ 000168 *pCurrent = (int)iCur; 000169 *pHighwater = (int)iHwtr; 000170 } 000171 return rc; 000172 } 000173 000174 /* 000175 ** Query status information for a single database connection 000176 */ 000177 int sqlite3_db_status( 000178 sqlite3 *db, /* The database connection whose status is desired */ 000179 int op, /* Status verb */ 000180 int *pCurrent, /* Write current value here */ 000181 int *pHighwater, /* Write high-water mark here */ 000182 int resetFlag /* Reset high-water mark if true */ 000183 ){ 000184 int rc = SQLITE_OK; /* Return code */ 000185 #ifdef SQLITE_ENABLE_API_ARMOR 000186 if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){ 000187 return SQLITE_MISUSE_BKPT; 000188 } 000189 #endif 000190 sqlite3_mutex_enter(db->mutex); 000191 switch( op ){ 000192 case SQLITE_DBSTATUS_LOOKASIDE_USED: { 000193 *pCurrent = db->lookaside.nOut; 000194 *pHighwater = db->lookaside.mxOut; 000195 if( resetFlag ){ 000196 db->lookaside.mxOut = db->lookaside.nOut; 000197 } 000198 break; 000199 } 000200 000201 case SQLITE_DBSTATUS_LOOKASIDE_HIT: 000202 case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE: 000203 case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: { 000204 testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT ); 000205 testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE ); 000206 testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL ); 000207 assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 ); 000208 assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 ); 000209 *pCurrent = 0; 000210 *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT]; 000211 if( resetFlag ){ 000212 db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0; 000213 } 000214 break; 000215 } 000216 000217 /* 000218 ** Return an approximation for the amount of memory currently used 000219 ** by all pagers associated with the given database connection. The 000220 ** highwater mark is meaningless and is returned as zero. 000221 */ 000222 case SQLITE_DBSTATUS_CACHE_USED_SHARED: 000223 case SQLITE_DBSTATUS_CACHE_USED: { 000224 int totalUsed = 0; 000225 int i; 000226 sqlite3BtreeEnterAll(db); 000227 for(i=0; i<db->nDb; i++){ 000228 Btree *pBt = db->aDb[i].pBt; 000229 if( pBt ){ 000230 Pager *pPager = sqlite3BtreePager(pBt); 000231 int nByte = sqlite3PagerMemUsed(pPager); 000232 if( op==SQLITE_DBSTATUS_CACHE_USED_SHARED ){ 000233 nByte = nByte / sqlite3BtreeConnectionCount(pBt); 000234 } 000235 totalUsed += nByte; 000236 } 000237 } 000238 sqlite3BtreeLeaveAll(db); 000239 *pCurrent = totalUsed; 000240 *pHighwater = 0; 000241 break; 000242 } 000243 000244 /* 000245 ** *pCurrent gets an accurate estimate of the amount of memory used 000246 ** to store the schema for all databases (main, temp, and any ATTACHed 000247 ** databases. *pHighwater is set to zero. 000248 */ 000249 case SQLITE_DBSTATUS_SCHEMA_USED: { 000250 int i; /* Used to iterate through schemas */ 000251 int nByte = 0; /* Used to accumulate return value */ 000252 000253 sqlite3BtreeEnterAll(db); 000254 db->pnBytesFreed = &nByte; 000255 for(i=0; i<db->nDb; i++){ 000256 Schema *pSchema = db->aDb[i].pSchema; 000257 if( ALWAYS(pSchema!=0) ){ 000258 HashElem *p; 000259 000260 nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * ( 000261 pSchema->tblHash.count 000262 + pSchema->trigHash.count 000263 + pSchema->idxHash.count 000264 + pSchema->fkeyHash.count 000265 ); 000266 nByte += sqlite3_msize(pSchema->tblHash.ht); 000267 nByte += sqlite3_msize(pSchema->trigHash.ht); 000268 nByte += sqlite3_msize(pSchema->idxHash.ht); 000269 nByte += sqlite3_msize(pSchema->fkeyHash.ht); 000270 000271 for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){ 000272 sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)); 000273 } 000274 for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ 000275 sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); 000276 } 000277 } 000278 } 000279 db->pnBytesFreed = 0; 000280 sqlite3BtreeLeaveAll(db); 000281 000282 *pHighwater = 0; 000283 *pCurrent = nByte; 000284 break; 000285 } 000286 000287 /* 000288 ** *pCurrent gets an accurate estimate of the amount of memory used 000289 ** to store all prepared statements. 000290 ** *pHighwater is set to zero. 000291 */ 000292 case SQLITE_DBSTATUS_STMT_USED: { 000293 struct Vdbe *pVdbe; /* Used to iterate through VMs */ 000294 int nByte = 0; /* Used to accumulate return value */ 000295 000296 db->pnBytesFreed = &nByte; 000297 for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ 000298 sqlite3VdbeClearObject(db, pVdbe); 000299 sqlite3DbFree(db, pVdbe); 000300 } 000301 db->pnBytesFreed = 0; 000302 000303 *pHighwater = 0; /* IMP: R-64479-57858 */ 000304 *pCurrent = nByte; 000305 000306 break; 000307 } 000308 000309 /* 000310 ** Set *pCurrent to the total cache hits or misses encountered by all 000311 ** pagers the database handle is connected to. *pHighwater is always set 000312 ** to zero. 000313 */ 000314 case SQLITE_DBSTATUS_CACHE_HIT: 000315 case SQLITE_DBSTATUS_CACHE_MISS: 000316 case SQLITE_DBSTATUS_CACHE_WRITE:{ 000317 int i; 000318 int nRet = 0; 000319 assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 ); 000320 assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 ); 000321 000322 for(i=0; i<db->nDb; i++){ 000323 if( db->aDb[i].pBt ){ 000324 Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt); 000325 sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet); 000326 } 000327 } 000328 *pHighwater = 0; /* IMP: R-42420-56072 */ 000329 /* IMP: R-54100-20147 */ 000330 /* IMP: R-29431-39229 */ 000331 *pCurrent = nRet; 000332 break; 000333 } 000334 000335 /* Set *pCurrent to non-zero if there are unresolved deferred foreign 000336 ** key constraints. Set *pCurrent to zero if all foreign key constraints 000337 ** have been satisfied. The *pHighwater is always set to zero. 000338 */ 000339 case SQLITE_DBSTATUS_DEFERRED_FKS: { 000340 *pHighwater = 0; /* IMP: R-11967-56545 */ 000341 *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0; 000342 break; 000343 } 000344 000345 default: { 000346 rc = SQLITE_ERROR; 000347 } 000348 } 000349 sqlite3_mutex_leave(db->mutex); 000350 return rc; 000351 }