OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ** 2008 June 18 |
| 3 ** |
| 4 ** The author disclaims copyright to this source code. In place of |
| 5 ** a legal notice, here is a blessing: |
| 6 ** |
| 7 ** May you do good and not evil. |
| 8 ** May you find forgiveness for yourself and forgive others. |
| 9 ** May you share freely, never taking more than you give. |
| 10 ** |
| 11 ************************************************************************* |
| 12 ** |
| 13 ** This module implements the sqlite3_status() interface and related |
| 14 ** functionality. |
| 15 */ |
| 16 #include "sqliteInt.h" |
| 17 #include "vdbeInt.h" |
| 18 |
| 19 /* |
| 20 ** Variables in which to record status information. |
| 21 */ |
| 22 #if SQLITE_PTRSIZE>4 |
| 23 typedef sqlite3_int64 sqlite3StatValueType; |
| 24 #else |
| 25 typedef u32 sqlite3StatValueType; |
| 26 #endif |
| 27 typedef struct sqlite3StatType sqlite3StatType; |
| 28 static SQLITE_WSD struct sqlite3StatType { |
| 29 sqlite3StatValueType nowValue[10]; /* Current value */ |
| 30 sqlite3StatValueType mxValue[10]; /* Maximum value */ |
| 31 } sqlite3Stat = { {0,}, {0,} }; |
| 32 |
| 33 /* |
| 34 ** Elements of sqlite3Stat[] are protected by either the memory allocator |
| 35 ** mutex, or by the pcache1 mutex. The following array determines which. |
| 36 */ |
| 37 static const char statMutex[] = { |
| 38 0, /* SQLITE_STATUS_MEMORY_USED */ |
| 39 1, /* SQLITE_STATUS_PAGECACHE_USED */ |
| 40 1, /* SQLITE_STATUS_PAGECACHE_OVERFLOW */ |
| 41 0, /* SQLITE_STATUS_SCRATCH_USED */ |
| 42 0, /* SQLITE_STATUS_SCRATCH_OVERFLOW */ |
| 43 0, /* SQLITE_STATUS_MALLOC_SIZE */ |
| 44 0, /* SQLITE_STATUS_PARSER_STACK */ |
| 45 1, /* SQLITE_STATUS_PAGECACHE_SIZE */ |
| 46 0, /* SQLITE_STATUS_SCRATCH_SIZE */ |
| 47 0, /* SQLITE_STATUS_MALLOC_COUNT */ |
| 48 }; |
| 49 |
| 50 |
| 51 /* The "wsdStat" macro will resolve to the status information |
| 52 ** state vector. If writable static data is unsupported on the target, |
| 53 ** we have to locate the state vector at run-time. In the more common |
| 54 ** case where writable static data is supported, wsdStat can refer directly |
| 55 ** to the "sqlite3Stat" state vector declared above. |
| 56 */ |
| 57 #ifdef SQLITE_OMIT_WSD |
| 58 # define wsdStatInit sqlite3StatType *x = &GLOBAL(sqlite3StatType,sqlite3Stat) |
| 59 # define wsdStat x[0] |
| 60 #else |
| 61 # define wsdStatInit |
| 62 # define wsdStat sqlite3Stat |
| 63 #endif |
| 64 |
| 65 /* |
| 66 ** Return the current value of a status parameter. The caller must |
| 67 ** be holding the appropriate mutex. |
| 68 */ |
| 69 sqlite3_int64 sqlite3StatusValue(int op){ |
| 70 wsdStatInit; |
| 71 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); |
| 72 assert( op>=0 && op<ArraySize(statMutex) ); |
| 73 assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex() |
| 74 : sqlite3MallocMutex()) ); |
| 75 return wsdStat.nowValue[op]; |
| 76 } |
| 77 |
| 78 /* |
| 79 ** Add N to the value of a status record. The caller must hold the |
| 80 ** appropriate mutex. (Locking is checked by assert()). |
| 81 ** |
| 82 ** The StatusUp() routine can accept positive or negative values for N. |
| 83 ** The value of N is added to the current status value and the high-water |
| 84 ** mark is adjusted if necessary. |
| 85 ** |
| 86 ** The StatusDown() routine lowers the current value by N. The highwater |
| 87 ** mark is unchanged. N must be non-negative for StatusDown(). |
| 88 */ |
| 89 void sqlite3StatusUp(int op, int N){ |
| 90 wsdStatInit; |
| 91 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); |
| 92 assert( op>=0 && op<ArraySize(statMutex) ); |
| 93 assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex() |
| 94 : sqlite3MallocMutex()) ); |
| 95 wsdStat.nowValue[op] += N; |
| 96 if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){ |
| 97 wsdStat.mxValue[op] = wsdStat.nowValue[op]; |
| 98 } |
| 99 } |
| 100 void sqlite3StatusDown(int op, int N){ |
| 101 wsdStatInit; |
| 102 assert( N>=0 ); |
| 103 assert( op>=0 && op<ArraySize(statMutex) ); |
| 104 assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex() |
| 105 : sqlite3MallocMutex()) ); |
| 106 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); |
| 107 wsdStat.nowValue[op] -= N; |
| 108 } |
| 109 |
| 110 /* |
| 111 ** Adjust the highwater mark if necessary. |
| 112 ** The caller must hold the appropriate mutex. |
| 113 */ |
| 114 void sqlite3StatusHighwater(int op, int X){ |
| 115 sqlite3StatValueType newValue; |
| 116 wsdStatInit; |
| 117 assert( X>=0 ); |
| 118 newValue = (sqlite3StatValueType)X; |
| 119 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); |
| 120 assert( op>=0 && op<ArraySize(statMutex) ); |
| 121 assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex() |
| 122 : sqlite3MallocMutex()) ); |
| 123 assert( op==SQLITE_STATUS_MALLOC_SIZE |
| 124 || op==SQLITE_STATUS_PAGECACHE_SIZE |
| 125 || op==SQLITE_STATUS_SCRATCH_SIZE |
| 126 || op==SQLITE_STATUS_PARSER_STACK ); |
| 127 if( newValue>wsdStat.mxValue[op] ){ |
| 128 wsdStat.mxValue[op] = newValue; |
| 129 } |
| 130 } |
| 131 |
| 132 /* |
| 133 ** Query status information. |
| 134 */ |
| 135 int sqlite3_status64( |
| 136 int op, |
| 137 sqlite3_int64 *pCurrent, |
| 138 sqlite3_int64 *pHighwater, |
| 139 int resetFlag |
| 140 ){ |
| 141 sqlite3_mutex *pMutex; |
| 142 wsdStatInit; |
| 143 if( op<0 || op>=ArraySize(wsdStat.nowValue) ){ |
| 144 return SQLITE_MISUSE_BKPT; |
| 145 } |
| 146 #ifdef SQLITE_ENABLE_API_ARMOR |
| 147 if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; |
| 148 #endif |
| 149 pMutex = statMutex[op] ? sqlite3Pcache1Mutex() : sqlite3MallocMutex(); |
| 150 sqlite3_mutex_enter(pMutex); |
| 151 *pCurrent = wsdStat.nowValue[op]; |
| 152 *pHighwater = wsdStat.mxValue[op]; |
| 153 if( resetFlag ){ |
| 154 wsdStat.mxValue[op] = wsdStat.nowValue[op]; |
| 155 } |
| 156 sqlite3_mutex_leave(pMutex); |
| 157 (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */ |
| 158 return SQLITE_OK; |
| 159 } |
| 160 int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ |
| 161 sqlite3_int64 iCur = 0, iHwtr = 0; |
| 162 int rc; |
| 163 #ifdef SQLITE_ENABLE_API_ARMOR |
| 164 if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; |
| 165 #endif |
| 166 rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag); |
| 167 if( rc==0 ){ |
| 168 *pCurrent = (int)iCur; |
| 169 *pHighwater = (int)iHwtr; |
| 170 } |
| 171 return rc; |
| 172 } |
| 173 |
| 174 /* |
| 175 ** Query status information for a single database connection |
| 176 */ |
| 177 int sqlite3_db_status( |
| 178 sqlite3 *db, /* The database connection whose status is desired */ |
| 179 int op, /* Status verb */ |
| 180 int *pCurrent, /* Write current value here */ |
| 181 int *pHighwater, /* Write high-water mark here */ |
| 182 int resetFlag /* Reset high-water mark if true */ |
| 183 ){ |
| 184 int rc = SQLITE_OK; /* Return code */ |
| 185 #ifdef SQLITE_ENABLE_API_ARMOR |
| 186 if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){ |
| 187 return SQLITE_MISUSE_BKPT; |
| 188 } |
| 189 #endif |
| 190 sqlite3_mutex_enter(db->mutex); |
| 191 switch( op ){ |
| 192 case SQLITE_DBSTATUS_LOOKASIDE_USED: { |
| 193 *pCurrent = db->lookaside.nOut; |
| 194 *pHighwater = db->lookaside.mxOut; |
| 195 if( resetFlag ){ |
| 196 db->lookaside.mxOut = db->lookaside.nOut; |
| 197 } |
| 198 break; |
| 199 } |
| 200 |
| 201 case SQLITE_DBSTATUS_LOOKASIDE_HIT: |
| 202 case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE: |
| 203 case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: { |
| 204 testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT ); |
| 205 testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE ); |
| 206 testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL ); |
| 207 assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 ); |
| 208 assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 ); |
| 209 *pCurrent = 0; |
| 210 *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT]; |
| 211 if( resetFlag ){ |
| 212 db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0; |
| 213 } |
| 214 break; |
| 215 } |
| 216 |
| 217 /* |
| 218 ** Return an approximation for the amount of memory currently used |
| 219 ** by all pagers associated with the given database connection. The |
| 220 ** highwater mark is meaningless and is returned as zero. |
| 221 */ |
| 222 case SQLITE_DBSTATUS_CACHE_USED_SHARED: |
| 223 case SQLITE_DBSTATUS_CACHE_USED: { |
| 224 int totalUsed = 0; |
| 225 int i; |
| 226 sqlite3BtreeEnterAll(db); |
| 227 for(i=0; i<db->nDb; i++){ |
| 228 Btree *pBt = db->aDb[i].pBt; |
| 229 if( pBt ){ |
| 230 Pager *pPager = sqlite3BtreePager(pBt); |
| 231 int nByte = sqlite3PagerMemUsed(pPager); |
| 232 if( op==SQLITE_DBSTATUS_CACHE_USED_SHARED ){ |
| 233 nByte = nByte / sqlite3BtreeConnectionCount(pBt); |
| 234 } |
| 235 totalUsed += nByte; |
| 236 } |
| 237 } |
| 238 sqlite3BtreeLeaveAll(db); |
| 239 *pCurrent = totalUsed; |
| 240 *pHighwater = 0; |
| 241 break; |
| 242 } |
| 243 |
| 244 /* |
| 245 ** *pCurrent gets an accurate estimate of the amount of memory used |
| 246 ** to store the schema for all databases (main, temp, and any ATTACHed |
| 247 ** databases. *pHighwater is set to zero. |
| 248 */ |
| 249 case SQLITE_DBSTATUS_SCHEMA_USED: { |
| 250 int i; /* Used to iterate through schemas */ |
| 251 int nByte = 0; /* Used to accumulate return value */ |
| 252 |
| 253 sqlite3BtreeEnterAll(db); |
| 254 db->pnBytesFreed = &nByte; |
| 255 for(i=0; i<db->nDb; i++){ |
| 256 Schema *pSchema = db->aDb[i].pSchema; |
| 257 if( ALWAYS(pSchema!=0) ){ |
| 258 HashElem *p; |
| 259 |
| 260 nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * ( |
| 261 pSchema->tblHash.count |
| 262 + pSchema->trigHash.count |
| 263 + pSchema->idxHash.count |
| 264 + pSchema->fkeyHash.count |
| 265 ); |
| 266 nByte += sqlite3_msize(pSchema->tblHash.ht); |
| 267 nByte += sqlite3_msize(pSchema->trigHash.ht); |
| 268 nByte += sqlite3_msize(pSchema->idxHash.ht); |
| 269 nByte += sqlite3_msize(pSchema->fkeyHash.ht); |
| 270 |
| 271 for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){ |
| 272 sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)); |
| 273 } |
| 274 for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ |
| 275 sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); |
| 276 } |
| 277 } |
| 278 } |
| 279 db->pnBytesFreed = 0; |
| 280 sqlite3BtreeLeaveAll(db); |
| 281 |
| 282 *pHighwater = 0; |
| 283 *pCurrent = nByte; |
| 284 break; |
| 285 } |
| 286 |
| 287 /* |
| 288 ** *pCurrent gets an accurate estimate of the amount of memory used |
| 289 ** to store all prepared statements. |
| 290 ** *pHighwater is set to zero. |
| 291 */ |
| 292 case SQLITE_DBSTATUS_STMT_USED: { |
| 293 struct Vdbe *pVdbe; /* Used to iterate through VMs */ |
| 294 int nByte = 0; /* Used to accumulate return value */ |
| 295 |
| 296 db->pnBytesFreed = &nByte; |
| 297 for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ |
| 298 sqlite3VdbeClearObject(db, pVdbe); |
| 299 sqlite3DbFree(db, pVdbe); |
| 300 } |
| 301 db->pnBytesFreed = 0; |
| 302 |
| 303 *pHighwater = 0; /* IMP: R-64479-57858 */ |
| 304 *pCurrent = nByte; |
| 305 |
| 306 break; |
| 307 } |
| 308 |
| 309 /* |
| 310 ** Set *pCurrent to the total cache hits or misses encountered by all |
| 311 ** pagers the database handle is connected to. *pHighwater is always set |
| 312 ** to zero. |
| 313 */ |
| 314 case SQLITE_DBSTATUS_CACHE_HIT: |
| 315 case SQLITE_DBSTATUS_CACHE_MISS: |
| 316 case SQLITE_DBSTATUS_CACHE_WRITE:{ |
| 317 int i; |
| 318 int nRet = 0; |
| 319 assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 ); |
| 320 assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 ); |
| 321 |
| 322 for(i=0; i<db->nDb; i++){ |
| 323 if( db->aDb[i].pBt ){ |
| 324 Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt); |
| 325 sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet); |
| 326 } |
| 327 } |
| 328 *pHighwater = 0; /* IMP: R-42420-56072 */ |
| 329 /* IMP: R-54100-20147 */ |
| 330 /* IMP: R-29431-39229 */ |
| 331 *pCurrent = nRet; |
| 332 break; |
| 333 } |
| 334 |
| 335 /* Set *pCurrent to non-zero if there are unresolved deferred foreign |
| 336 ** key constraints. Set *pCurrent to zero if all foreign key constraints |
| 337 ** have been satisfied. The *pHighwater is always set to zero. |
| 338 */ |
| 339 case SQLITE_DBSTATUS_DEFERRED_FKS: { |
| 340 *pHighwater = 0; /* IMP: R-11967-56545 */ |
| 341 *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0; |
| 342 break; |
| 343 } |
| 344 |
| 345 default: { |
| 346 rc = SQLITE_ERROR; |
| 347 } |
| 348 } |
| 349 sqlite3_mutex_leave(db->mutex); |
| 350 return rc; |
| 351 } |
OLD | NEW |