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 sqlite3VdbeClearObject(db, pVdbe); | |
212 sqlite3DbFree(db, pVdbe); | |
213 } | |
214 db->pnBytesFreed = 0; | |
215 | |
216 *pHighwater = 0; /* IMP: R-64479-57858 */ | |
217 *pCurrent = nByte; | |
218 | |
219 break; | |
220 } | |
221 | |
222 /* | |
223 ** Set *pCurrent to the total cache hits or misses encountered by all | |
224 ** pagers the database handle is connected to. *pHighwater is always set | |
225 ** to zero. | |
226 */ | |
227 case SQLITE_DBSTATUS_CACHE_HIT: | |
228 case SQLITE_DBSTATUS_CACHE_MISS: | |
229 case SQLITE_DBSTATUS_CACHE_WRITE:{ | |
230 int i; | |
231 int nRet = 0; | |
232 assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 ); | |
233 assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 ); | |
234 | |
235 for(i=0; i<db->nDb; i++){ | |
236 if( db->aDb[i].pBt ){ | |
237 Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt); | |
238 sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet); | |
239 } | |
240 } | |
241 *pHighwater = 0; /* IMP: R-42420-56072 */ | |
242 /* IMP: R-54100-20147 */ | |
243 /* IMP: R-29431-39229 */ | |
244 *pCurrent = nRet; | |
245 break; | |
246 } | |
247 | |
248 /* Set *pCurrent to non-zero if there are unresolved deferred foreign | |
249 ** key constraints. Set *pCurrent to zero if all foreign key constraints | |
250 ** have been satisfied. The *pHighwater is always set to zero. | |
251 */ | |
252 case SQLITE_DBSTATUS_DEFERRED_FKS: { | |
253 *pHighwater = 0; /* IMP: R-11967-56545 */ | |
254 *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0; | |
255 break; | |
256 } | |
257 | |
258 default: { | |
259 rc = SQLITE_ERROR; | |
260 } | |
261 } | |
262 sqlite3_mutex_leave(db->mutex); | |
263 return rc; | |
264 } | |
OLD | NEW |