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 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 default: { |
| 222 rc = SQLITE_ERROR; |
| 223 } |
| 224 } |
| 225 sqlite3_mutex_leave(db->mutex); |
| 226 return rc; |
| 227 } |
OLD | NEW |