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, iHwtr; | |
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: { | |
223 int totalUsed = 0; | |
224 int i; | |
225 sqlite3BtreeEnterAll(db); | |
226 for(i=0; i<db->nDb; i++){ | |
227 Btree *pBt = db->aDb[i].pBt; | |
228 if( pBt ){ | |
229 Pager *pPager = sqlite3BtreePager(pBt); | |
230 totalUsed += sqlite3PagerMemUsed(pPager); | |
231 } | |
232 } | |
233 sqlite3BtreeLeaveAll(db); | |
234 *pCurrent = totalUsed; | |
235 *pHighwater = 0; | |
236 break; | |
237 } | |
238 | |
239 /* | |
240 ** *pCurrent gets an accurate estimate of the amount of memory used | |
241 ** to store the schema for all databases (main, temp, and any ATTACHed | |
242 ** databases. *pHighwater is set to zero. | |
243 */ | |
244 case SQLITE_DBSTATUS_SCHEMA_USED: { | |
245 int i; /* Used to iterate through schemas */ | |
246 int nByte = 0; /* Used to accumulate return value */ | |
247 | |
248 sqlite3BtreeEnterAll(db); | |
249 db->pnBytesFreed = &nByte; | |
250 for(i=0; i<db->nDb; i++){ | |
251 Schema *pSchema = db->aDb[i].pSchema; | |
252 if( ALWAYS(pSchema!=0) ){ | |
253 HashElem *p; | |
254 | |
255 nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * ( | |
256 pSchema->tblHash.count | |
257 + pSchema->trigHash.count | |
258 + pSchema->idxHash.count | |
259 + pSchema->fkeyHash.count | |
260 ); | |
261 nByte += sqlite3_msize(pSchema->tblHash.ht); | |
262 nByte += sqlite3_msize(pSchema->trigHash.ht); | |
263 nByte += sqlite3_msize(pSchema->idxHash.ht); | |
264 nByte += sqlite3_msize(pSchema->fkeyHash.ht); | |
265 | |
266 for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){ | |
267 sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)); | |
268 } | |
269 for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ | |
270 sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); | |
271 } | |
272 } | |
273 } | |
274 db->pnBytesFreed = 0; | |
275 sqlite3BtreeLeaveAll(db); | |
276 | |
277 *pHighwater = 0; | |
278 *pCurrent = nByte; | |
279 break; | |
280 } | |
281 | |
282 /* | |
283 ** *pCurrent gets an accurate estimate of the amount of memory used | |
284 ** to store all prepared statements. | |
285 ** *pHighwater is set to zero. | |
286 */ | |
287 case SQLITE_DBSTATUS_STMT_USED: { | |
288 struct Vdbe *pVdbe; /* Used to iterate through VMs */ | |
289 int nByte = 0; /* Used to accumulate return value */ | |
290 | |
291 db->pnBytesFreed = &nByte; | |
292 for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ | |
293 sqlite3VdbeClearObject(db, pVdbe); | |
294 sqlite3DbFree(db, pVdbe); | |
295 } | |
296 db->pnBytesFreed = 0; | |
297 | |
298 *pHighwater = 0; /* IMP: R-64479-57858 */ | |
299 *pCurrent = nByte; | |
300 | |
301 break; | |
302 } | |
303 | |
304 /* | |
305 ** Set *pCurrent to the total cache hits or misses encountered by all | |
306 ** pagers the database handle is connected to. *pHighwater is always set | |
307 ** to zero. | |
308 */ | |
309 case SQLITE_DBSTATUS_CACHE_HIT: | |
310 case SQLITE_DBSTATUS_CACHE_MISS: | |
311 case SQLITE_DBSTATUS_CACHE_WRITE:{ | |
312 int i; | |
313 int nRet = 0; | |
314 assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 ); | |
315 assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 ); | |
316 | |
317 for(i=0; i<db->nDb; i++){ | |
318 if( db->aDb[i].pBt ){ | |
319 Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt); | |
320 sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet); | |
321 } | |
322 } | |
323 *pHighwater = 0; /* IMP: R-42420-56072 */ | |
324 /* IMP: R-54100-20147 */ | |
325 /* IMP: R-29431-39229 */ | |
326 *pCurrent = nRet; | |
327 break; | |
328 } | |
329 | |
330 /* Set *pCurrent to non-zero if there are unresolved deferred foreign | |
331 ** key constraints. Set *pCurrent to zero if all foreign key constraints | |
332 ** have been satisfied. The *pHighwater is always set to zero. | |
333 */ | |
334 case SQLITE_DBSTATUS_DEFERRED_FKS: { | |
335 *pHighwater = 0; /* IMP: R-11967-56545 */ | |
336 *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0; | |
337 break; | |
338 } | |
339 | |
340 default: { | |
341 rc = SQLITE_ERROR; | |
342 } | |
343 } | |
344 sqlite3_mutex_leave(db->mutex); | |
345 return rc; | |
346 } | |
OLD | NEW |