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 typedef struct sqlite3StatType sqlite3StatType; 23 static SQLITE_WSD struct sqlite3StatType { 24 int nowValue[10]; /* Current value */ 25 int mxValue[10]; /* Maximum value */ 26 } sqlite3Stat = { {0,}, {0,} }; 27 28 29 /* The "wsdStat" macro will resolve to the status information 30 ** state vector. If writable static data is unsupported on the target, 31 ** we have to locate the state vector at run-time. In the more common 32 ** case where writable static data is supported, wsdStat can refer directly 33 ** to the "sqlite3Stat" state vector declared above. 34 */ 35 #ifdef SQLITE_OMIT_WSD 36 # define wsdStatInit sqlite3StatType *x = &GLOBAL(sqlite3StatType,sqlite3Stat) 37 # define wsdStat x[0] 38 #else 39 # define wsdStatInit 40 # define wsdStat sqlite3Stat 41 #endif 42 43 /* 44 ** Return the current value of a status parameter. 45 */ 46 int sqlite3StatusValue(int op){ 47 wsdStatInit; 48 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); 49 return wsdStat.nowValue[op]; 50 } 51 52 /* 53 ** Add N to the value of a status record. It is assumed that the 54 ** caller holds appropriate locks. 55 */ 56 void sqlite3StatusAdd(int op, int N){ 57 wsdStatInit; 58 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); 59 wsdStat.nowValue[op] += N; 60 if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){ 61 wsdStat.mxValue[op] = wsdStat.nowValue[op]; 62 } 63 } 64 65 /* 66 ** Set the value of a status to X. 67 */ 68 void sqlite3StatusSet(int op, int X){ 69 wsdStatInit; 70 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); 71 wsdStat.nowValue[op] = X; 72 if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){ 73 wsdStat.mxValue[op] = wsdStat.nowValue[op]; 74 } 75 } 76 77 /* 78 ** Query status information. 79 ** 80 ** This implementation assumes that reading or writing an aligned 81 ** 32-bit integer is an atomic operation. If that assumption is not true, 82 ** then this routine is not threadsafe. 83 */ 84 int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ 85 wsdStatInit; 86 if( op<0 || op>=ArraySize(wsdStat.nowValue) ){ 87 return SQLITE_MISUSE_BKPT; 88 } 89 *pCurrent = wsdStat.nowValue[op]; 90 *pHighwater = wsdStat.mxValue[op]; 91 if( resetFlag ){ 92 wsdStat.mxValue[op] = wsdStat.nowValue[op]; 93 } 94 return SQLITE_OK; 95 } 96 97 /* 98 ** Query status information for a single database connection 99 */ 100 int sqlite3_db_status( 101 sqlite3 *db, /* The database connection whose status is desired */ 102 int op, /* Status verb */ 103 int *pCurrent, /* Write current value here */ 104 int *pHighwater, /* Write high-water mark here */ 105 int resetFlag /* Reset high-water mark if true */ 106 ){ 107 int rc = SQLITE_OK; /* Return code */ 108 sqlite3_mutex_enter(db->mutex); 109 switch( op ){ 110 case SQLITE_DBSTATUS_LOOKASIDE_USED: { 111 *pCurrent = db->lookaside.nOut; 112 *pHighwater = db->lookaside.mxOut; 113 if( resetFlag ){ 114 db->lookaside.mxOut = db->lookaside.nOut; 115 } 116 break; 117 } 118 119 case SQLITE_DBSTATUS_LOOKASIDE_HIT: 120 case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE: 121 case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: { 122 testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT ); 123 testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE ); 124 testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL ); 125 assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 ); 126 assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 ); 127 *pCurrent = 0; 128 *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT]; 129 if( resetFlag ){ 130 db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0; 131 } 132 break; 133 } 134 135 /* 136 ** Return an approximation for the amount of memory currently used 137 ** by all pagers associated with the given database connection. The 138 ** highwater mark is meaningless and is returned as zero. 139 */ 140 case SQLITE_DBSTATUS_CACHE_USED: { 141 int totalUsed = 0; 142 int i; 143 sqlite3BtreeEnterAll(db); 144 for(i=0; i<db->nDb; i++){ 145 Btree *pBt = db->aDb[i].pBt; 146 if( pBt ){ 147 Pager *pPager = sqlite3BtreePager(pBt); 148 totalUsed += sqlite3PagerMemUsed(pPager); 149 } 150 } 151 sqlite3BtreeLeaveAll(db); 152 *pCurrent = totalUsed; 153 *pHighwater = 0; 154 break; 155 } 156 157 /* 158 ** *pCurrent gets an accurate estimate of the amount of memory used 159 ** to store the schema for all databases (main, temp, and any ATTACHed 160 ** databases. *pHighwater is set to zero. 161 */ 162 case SQLITE_DBSTATUS_SCHEMA_USED: { 163 int i; /* Used to iterate through schemas */ 164 int nByte = 0; /* Used to accumulate return value */ 165 166 sqlite3BtreeEnterAll(db); 167 db->pnBytesFreed = &nByte; 168 for(i=0; i<db->nDb; i++){ 169 Schema *pSchema = db->aDb[i].pSchema; 170 if( ALWAYS(pSchema!=0) ){ 171 HashElem *p; 172 173 nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * ( 174 pSchema->tblHash.count 175 + pSchema->trigHash.count 176 + pSchema->idxHash.count 177 + pSchema->fkeyHash.count 178 ); 179 nByte += sqlite3MallocSize(pSchema->tblHash.ht); 180 nByte += sqlite3MallocSize(pSchema->trigHash.ht); 181 nByte += sqlite3MallocSize(pSchema->idxHash.ht); 182 nByte += sqlite3MallocSize(pSchema->fkeyHash.ht); 183 184 for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){ 185 sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)); 186 } 187 for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ 188 sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); 189 } 190 } 191 } 192 db->pnBytesFreed = 0; 193 sqlite3BtreeLeaveAll(db); 194 195 *pHighwater = 0; 196 *pCurrent = nByte; 197 break; 198 } 199 200 /* 201 ** *pCurrent gets an accurate estimate of the amount of memory used 202 ** to store all prepared statements. 203 ** *pHighwater is set to zero. 204 */ 205 case SQLITE_DBSTATUS_STMT_USED: { 206 struct Vdbe *pVdbe; /* Used to iterate through VMs */ 207 int nByte = 0; /* Used to accumulate return value */ 208 209 db->pnBytesFreed = &nByte; 210 for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ 211 sqlite3VdbeDeleteObject(db, pVdbe); 212 } 213 db->pnBytesFreed = 0; 214 215 *pHighwater = 0; 216 *pCurrent = nByte; 217 218 break; 219 } 220 221 /* 222 ** Set *pCurrent to the total cache hits or misses encountered by all 223 ** pagers the database handle is connected to. *pHighwater is always set 224 ** to zero. 225 */ 226 case SQLITE_DBSTATUS_CACHE_HIT: 227 case SQLITE_DBSTATUS_CACHE_MISS: 228 case SQLITE_DBSTATUS_CACHE_WRITE:{ 229 int i; 230 int nRet = 0; 231 assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 ); 232 assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 ); 233 234 for(i=0; i<db->nDb; i++){ 235 if( db->aDb[i].pBt ){ 236 Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt); 237 sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet); 238 } 239 } 240 *pHighwater = 0; 241 *pCurrent = nRet; 242 break; 243 } 244 245 default: { 246 rc = SQLITE_ERROR; 247 } 248 } 249 sqlite3_mutex_leave(db->mutex); 250 return rc; 251 } 252