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: int i;
229: int nRet = 0;
230: assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 );
231:
232: for(i=0; i<db->nDb; i++){
233: if( db->aDb[i].pBt ){
234: Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt);
235: sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet);
236: }
237: }
238: *pHighwater = 0;
239: *pCurrent = nRet;
240: break;
241: }
242:
243: default: {
244: rc = SQLITE_ERROR;
245: }
246: }
247: sqlite3_mutex_leave(db->mutex);
248: return rc;
249: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>