Annotation of embedaddon/sqlite3/src/test_osinst.c, revision 1.1.1.1
1.1 misho 1: /*
2: ** 2008 April 10
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 file contains the implementation of an SQLite vfs wrapper that
14: ** adds instrumentation to all vfs and file methods. C and Tcl interfaces
15: ** are provided to control the instrumentation.
16: */
17:
18: /*
19: ** This module contains code for a wrapper VFS that causes a log of
20: ** most VFS calls to be written into a nominated file on disk. The log
21: ** is stored in a compressed binary format to reduce the amount of IO
22: ** overhead introduced into the application by logging.
23: **
24: ** All calls on sqlite3_file objects except xFileControl() are logged.
25: ** Additionally, calls to the xAccess(), xOpen(), and xDelete()
26: ** methods are logged. The other sqlite3_vfs object methods (xDlXXX,
27: ** xRandomness, xSleep, xCurrentTime, xGetLastError and xCurrentTimeInt64)
28: ** are not logged.
29: **
30: ** The binary log files are read using a virtual table implementation
31: ** also contained in this file.
32: **
33: ** CREATING LOG FILES:
34: **
35: ** int sqlite3_vfslog_new(
36: ** const char *zVfs, // Name of new VFS
37: ** const char *zParentVfs, // Name of parent VFS (or NULL)
38: ** const char *zLog // Name of log file to write to
39: ** );
40: **
41: ** int sqlite3_vfslog_finalize(const char *zVfs);
42: **
43: ** ANNOTATING LOG FILES:
44: **
45: ** To write an arbitrary message into a log file:
46: **
47: ** int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg);
48: **
49: ** READING LOG FILES:
50: **
51: ** Log files are read using the "vfslog" virtual table implementation
52: ** in this file. To register the virtual table with SQLite, use:
53: **
54: ** int sqlite3_vfslog_register(sqlite3 *db);
55: **
56: ** Then, if the log file is named "vfs.log", the following SQL command:
57: **
58: ** CREATE VIRTUAL TABLE v USING vfslog('vfs.log');
59: **
60: ** creates a virtual table with 6 columns, as follows:
61: **
62: ** CREATE TABLE v(
63: ** event TEXT, // "xOpen", "xRead" etc.
64: ** file TEXT, // Name of file this call applies to
65: ** clicks INTEGER, // Time spent in call
66: ** rc INTEGER, // Return value
67: ** size INTEGER, // Bytes read or written
68: ** offset INTEGER // File offset read or written
69: ** );
70: */
71:
72: #include "sqlite3.h"
73: #include <string.h>
74: #include <assert.h>
75:
76:
77: /*
78: ** Maximum pathname length supported by the vfslog backend.
79: */
80: #define INST_MAX_PATHNAME 512
81:
82: #define OS_ACCESS 1
83: #define OS_CHECKRESERVEDLOCK 2
84: #define OS_CLOSE 3
85: #define OS_CURRENTTIME 4
86: #define OS_DELETE 5
87: #define OS_DEVCHAR 6
88: #define OS_FILECONTROL 7
89: #define OS_FILESIZE 8
90: #define OS_FULLPATHNAME 9
91: #define OS_LOCK 11
92: #define OS_OPEN 12
93: #define OS_RANDOMNESS 13
94: #define OS_READ 14
95: #define OS_SECTORSIZE 15
96: #define OS_SLEEP 16
97: #define OS_SYNC 17
98: #define OS_TRUNCATE 18
99: #define OS_UNLOCK 19
100: #define OS_WRITE 20
101: #define OS_SHMUNMAP 22
102: #define OS_SHMMAP 23
103: #define OS_SHMLOCK 25
104: #define OS_SHMBARRIER 26
105: #define OS_ANNOTATE 28
106:
107: #define OS_NUMEVENTS 29
108:
109: #define VFSLOG_BUFFERSIZE 8192
110:
111: typedef struct VfslogVfs VfslogVfs;
112: typedef struct VfslogFile VfslogFile;
113:
114: struct VfslogVfs {
115: sqlite3_vfs base; /* VFS methods */
116: sqlite3_vfs *pVfs; /* Parent VFS */
117: int iNextFileId; /* Next file id */
118: sqlite3_file *pLog; /* Log file handle */
119: sqlite3_int64 iOffset; /* Log file offset of start of write buffer */
120: int nBuf; /* Number of valid bytes in aBuf[] */
121: char aBuf[VFSLOG_BUFFERSIZE]; /* Write buffer */
122: };
123:
124: struct VfslogFile {
125: sqlite3_file base; /* IO methods */
126: sqlite3_file *pReal; /* Underlying file handle */
127: sqlite3_vfs *pVfslog; /* Associated VsflogVfs object */
128: int iFileId; /* File id number */
129: };
130:
131: #define REALVFS(p) (((VfslogVfs *)(p))->pVfs)
132:
133:
134:
135: /*
136: ** Method declarations for vfslog_file.
137: */
138: static int vfslogClose(sqlite3_file*);
139: static int vfslogRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
140: static int vfslogWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
141: static int vfslogTruncate(sqlite3_file*, sqlite3_int64 size);
142: static int vfslogSync(sqlite3_file*, int flags);
143: static int vfslogFileSize(sqlite3_file*, sqlite3_int64 *pSize);
144: static int vfslogLock(sqlite3_file*, int);
145: static int vfslogUnlock(sqlite3_file*, int);
146: static int vfslogCheckReservedLock(sqlite3_file*, int *pResOut);
147: static int vfslogFileControl(sqlite3_file*, int op, void *pArg);
148: static int vfslogSectorSize(sqlite3_file*);
149: static int vfslogDeviceCharacteristics(sqlite3_file*);
150:
151: static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags);
152: static int vfslogShmMap(sqlite3_file *pFile,int,int,int,volatile void **);
153: static void vfslogShmBarrier(sqlite3_file*);
154: static int vfslogShmUnmap(sqlite3_file *pFile, int deleteFlag);
155:
156: /*
157: ** Method declarations for vfslog_vfs.
158: */
159: static int vfslogOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
160: static int vfslogDelete(sqlite3_vfs*, const char *zName, int syncDir);
161: static int vfslogAccess(sqlite3_vfs*, const char *zName, int flags, int *);
162: static int vfslogFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
163: static void *vfslogDlOpen(sqlite3_vfs*, const char *zFilename);
164: static void vfslogDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
165: static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
166: static void vfslogDlClose(sqlite3_vfs*, void*);
167: static int vfslogRandomness(sqlite3_vfs*, int nByte, char *zOut);
168: static int vfslogSleep(sqlite3_vfs*, int microseconds);
169: static int vfslogCurrentTime(sqlite3_vfs*, double*);
170:
171: static int vfslogGetLastError(sqlite3_vfs*, int, char *);
172: static int vfslogCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
173:
174: static sqlite3_vfs vfslog_vfs = {
175: 1, /* iVersion */
176: sizeof(VfslogFile), /* szOsFile */
177: INST_MAX_PATHNAME, /* mxPathname */
178: 0, /* pNext */
179: 0, /* zName */
180: 0, /* pAppData */
181: vfslogOpen, /* xOpen */
182: vfslogDelete, /* xDelete */
183: vfslogAccess, /* xAccess */
184: vfslogFullPathname, /* xFullPathname */
185: vfslogDlOpen, /* xDlOpen */
186: vfslogDlError, /* xDlError */
187: vfslogDlSym, /* xDlSym */
188: vfslogDlClose, /* xDlClose */
189: vfslogRandomness, /* xRandomness */
190: vfslogSleep, /* xSleep */
191: vfslogCurrentTime, /* xCurrentTime */
192: vfslogGetLastError, /* xGetLastError */
193: vfslogCurrentTimeInt64 /* xCurrentTime */
194: };
195:
196: static sqlite3_io_methods vfslog_io_methods = {
197: 2, /* iVersion */
198: vfslogClose, /* xClose */
199: vfslogRead, /* xRead */
200: vfslogWrite, /* xWrite */
201: vfslogTruncate, /* xTruncate */
202: vfslogSync, /* xSync */
203: vfslogFileSize, /* xFileSize */
204: vfslogLock, /* xLock */
205: vfslogUnlock, /* xUnlock */
206: vfslogCheckReservedLock, /* xCheckReservedLock */
207: vfslogFileControl, /* xFileControl */
208: vfslogSectorSize, /* xSectorSize */
209: vfslogDeviceCharacteristics, /* xDeviceCharacteristics */
210: vfslogShmMap, /* xShmMap */
211: vfslogShmLock, /* xShmLock */
212: vfslogShmBarrier, /* xShmBarrier */
213: vfslogShmUnmap /* xShmUnmap */
214: };
215:
216: #if SQLITE_OS_UNIX && !defined(NO_GETTOD)
217: #include <sys/time.h>
218: static sqlite3_uint64 vfslog_time(){
219: struct timeval sTime;
220: gettimeofday(&sTime, 0);
221: return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000;
222: }
223: #elif SQLITE_OS_WIN
224: #include <windows.h>
225: #include <time.h>
226: static sqlite3_uint64 vfslog_time(){
227: FILETIME ft;
228: sqlite3_uint64 u64time = 0;
229:
230: GetSystemTimeAsFileTime(&ft);
231:
232: u64time |= ft.dwHighDateTime;
233: u64time <<= 32;
234: u64time |= ft.dwLowDateTime;
235:
236: /* ft is 100-nanosecond intervals, we want microseconds */
237: return u64time /(sqlite3_uint64)10;
238: }
239: #else
240: static sqlite3_uint64 vfslog_time(){
241: return 0;
242: }
243: #endif
244:
245: static void vfslog_call(sqlite3_vfs *, int, int, int, int, int, int);
246: static void vfslog_string(sqlite3_vfs *, const char *);
247:
248: /*
249: ** Close an vfslog-file.
250: */
251: static int vfslogClose(sqlite3_file *pFile){
252: sqlite3_uint64 t;
253: int rc = SQLITE_OK;
254: VfslogFile *p = (VfslogFile *)pFile;
255:
256: t = vfslog_time();
257: if( p->pReal->pMethods ){
258: rc = p->pReal->pMethods->xClose(p->pReal);
259: }
260: t = vfslog_time() - t;
261: vfslog_call(p->pVfslog, OS_CLOSE, p->iFileId, t, rc, 0, 0);
262: return rc;
263: }
264:
265: /*
266: ** Read data from an vfslog-file.
267: */
268: static int vfslogRead(
269: sqlite3_file *pFile,
270: void *zBuf,
271: int iAmt,
272: sqlite_int64 iOfst
273: ){
274: int rc;
275: sqlite3_uint64 t;
276: VfslogFile *p = (VfslogFile *)pFile;
277: t = vfslog_time();
278: rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
279: t = vfslog_time() - t;
280: vfslog_call(p->pVfslog, OS_READ, p->iFileId, t, rc, iAmt, (int)iOfst);
281: return rc;
282: }
283:
284: /*
285: ** Write data to an vfslog-file.
286: */
287: static int vfslogWrite(
288: sqlite3_file *pFile,
289: const void *z,
290: int iAmt,
291: sqlite_int64 iOfst
292: ){
293: int rc;
294: sqlite3_uint64 t;
295: VfslogFile *p = (VfslogFile *)pFile;
296: t = vfslog_time();
297: rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
298: t = vfslog_time() - t;
299: vfslog_call(p->pVfslog, OS_WRITE, p->iFileId, t, rc, iAmt, (int)iOfst);
300: return rc;
301: }
302:
303: /*
304: ** Truncate an vfslog-file.
305: */
306: static int vfslogTruncate(sqlite3_file *pFile, sqlite_int64 size){
307: int rc;
308: sqlite3_uint64 t;
309: VfslogFile *p = (VfslogFile *)pFile;
310: t = vfslog_time();
311: rc = p->pReal->pMethods->xTruncate(p->pReal, size);
312: t = vfslog_time() - t;
313: vfslog_call(p->pVfslog, OS_TRUNCATE, p->iFileId, t, rc, 0, (int)size);
314: return rc;
315: }
316:
317: /*
318: ** Sync an vfslog-file.
319: */
320: static int vfslogSync(sqlite3_file *pFile, int flags){
321: int rc;
322: sqlite3_uint64 t;
323: VfslogFile *p = (VfslogFile *)pFile;
324: t = vfslog_time();
325: rc = p->pReal->pMethods->xSync(p->pReal, flags);
326: t = vfslog_time() - t;
327: vfslog_call(p->pVfslog, OS_SYNC, p->iFileId, t, rc, flags, 0);
328: return rc;
329: }
330:
331: /*
332: ** Return the current file-size of an vfslog-file.
333: */
334: static int vfslogFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
335: int rc;
336: sqlite3_uint64 t;
337: VfslogFile *p = (VfslogFile *)pFile;
338: t = vfslog_time();
339: rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
340: t = vfslog_time() - t;
341: vfslog_call(p->pVfslog, OS_FILESIZE, p->iFileId, t, rc, 0, (int)*pSize);
342: return rc;
343: }
344:
345: /*
346: ** Lock an vfslog-file.
347: */
348: static int vfslogLock(sqlite3_file *pFile, int eLock){
349: int rc;
350: sqlite3_uint64 t;
351: VfslogFile *p = (VfslogFile *)pFile;
352: t = vfslog_time();
353: rc = p->pReal->pMethods->xLock(p->pReal, eLock);
354: t = vfslog_time() - t;
355: vfslog_call(p->pVfslog, OS_LOCK, p->iFileId, t, rc, eLock, 0);
356: return rc;
357: }
358:
359: /*
360: ** Unlock an vfslog-file.
361: */
362: static int vfslogUnlock(sqlite3_file *pFile, int eLock){
363: int rc;
364: sqlite3_uint64 t;
365: VfslogFile *p = (VfslogFile *)pFile;
366: t = vfslog_time();
367: rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
368: t = vfslog_time() - t;
369: vfslog_call(p->pVfslog, OS_UNLOCK, p->iFileId, t, rc, eLock, 0);
370: return rc;
371: }
372:
373: /*
374: ** Check if another file-handle holds a RESERVED lock on an vfslog-file.
375: */
376: static int vfslogCheckReservedLock(sqlite3_file *pFile, int *pResOut){
377: int rc;
378: sqlite3_uint64 t;
379: VfslogFile *p = (VfslogFile *)pFile;
380: t = vfslog_time();
381: rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
382: t = vfslog_time() - t;
383: vfslog_call(p->pVfslog, OS_CHECKRESERVEDLOCK, p->iFileId, t, rc, *pResOut, 0);
384: return rc;
385: }
386:
387: /*
388: ** File control method. For custom operations on an vfslog-file.
389: */
390: static int vfslogFileControl(sqlite3_file *pFile, int op, void *pArg){
391: VfslogFile *p = (VfslogFile *)pFile;
392: int rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
393: if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
394: *(char**)pArg = sqlite3_mprintf("vfslog/%z", *(char**)pArg);
395: }
396: return rc;
397: }
398:
399: /*
400: ** Return the sector-size in bytes for an vfslog-file.
401: */
402: static int vfslogSectorSize(sqlite3_file *pFile){
403: int rc;
404: sqlite3_uint64 t;
405: VfslogFile *p = (VfslogFile *)pFile;
406: t = vfslog_time();
407: rc = p->pReal->pMethods->xSectorSize(p->pReal);
408: t = vfslog_time() - t;
409: vfslog_call(p->pVfslog, OS_SECTORSIZE, p->iFileId, t, rc, 0, 0);
410: return rc;
411: }
412:
413: /*
414: ** Return the device characteristic flags supported by an vfslog-file.
415: */
416: static int vfslogDeviceCharacteristics(sqlite3_file *pFile){
417: int rc;
418: sqlite3_uint64 t;
419: VfslogFile *p = (VfslogFile *)pFile;
420: t = vfslog_time();
421: rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
422: t = vfslog_time() - t;
423: vfslog_call(p->pVfslog, OS_DEVCHAR, p->iFileId, t, rc, 0, 0);
424: return rc;
425: }
426:
427: static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
428: int rc;
429: sqlite3_uint64 t;
430: VfslogFile *p = (VfslogFile *)pFile;
431: t = vfslog_time();
432: rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
433: t = vfslog_time() - t;
434: vfslog_call(p->pVfslog, OS_SHMLOCK, p->iFileId, t, rc, 0, 0);
435: return rc;
436: }
437: static int vfslogShmMap(
438: sqlite3_file *pFile,
439: int iRegion,
440: int szRegion,
441: int isWrite,
442: volatile void **pp
443: ){
444: int rc;
445: sqlite3_uint64 t;
446: VfslogFile *p = (VfslogFile *)pFile;
447: t = vfslog_time();
448: rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
449: t = vfslog_time() - t;
450: vfslog_call(p->pVfslog, OS_SHMMAP, p->iFileId, t, rc, 0, 0);
451: return rc;
452: }
453: static void vfslogShmBarrier(sqlite3_file *pFile){
454: sqlite3_uint64 t;
455: VfslogFile *p = (VfslogFile *)pFile;
456: t = vfslog_time();
457: p->pReal->pMethods->xShmBarrier(p->pReal);
458: t = vfslog_time() - t;
459: vfslog_call(p->pVfslog, OS_SHMBARRIER, p->iFileId, t, SQLITE_OK, 0, 0);
460: }
461: static int vfslogShmUnmap(sqlite3_file *pFile, int deleteFlag){
462: int rc;
463: sqlite3_uint64 t;
464: VfslogFile *p = (VfslogFile *)pFile;
465: t = vfslog_time();
466: rc = p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
467: t = vfslog_time() - t;
468: vfslog_call(p->pVfslog, OS_SHMUNMAP, p->iFileId, t, rc, 0, 0);
469: return rc;
470: }
471:
472:
473: /*
474: ** Open an vfslog file handle.
475: */
476: static int vfslogOpen(
477: sqlite3_vfs *pVfs,
478: const char *zName,
479: sqlite3_file *pFile,
480: int flags,
481: int *pOutFlags
482: ){
483: int rc;
484: sqlite3_uint64 t;
485: VfslogFile *p = (VfslogFile *)pFile;
486: VfslogVfs *pLog = (VfslogVfs *)pVfs;
487:
488: pFile->pMethods = &vfslog_io_methods;
489: p->pReal = (sqlite3_file *)&p[1];
490: p->pVfslog = pVfs;
491: p->iFileId = ++pLog->iNextFileId;
492:
493: t = vfslog_time();
494: rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
495: t = vfslog_time() - t;
496:
497: vfslog_call(pVfs, OS_OPEN, p->iFileId, t, rc, 0, 0);
498: vfslog_string(pVfs, zName);
499: return rc;
500: }
501:
502: /*
503: ** Delete the file located at zPath. If the dirSync argument is true,
504: ** ensure the file-system modifications are synced to disk before
505: ** returning.
506: */
507: static int vfslogDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
508: int rc;
509: sqlite3_uint64 t;
510: t = vfslog_time();
511: rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
512: t = vfslog_time() - t;
513: vfslog_call(pVfs, OS_DELETE, 0, t, rc, dirSync, 0);
514: vfslog_string(pVfs, zPath);
515: return rc;
516: }
517:
518: /*
519: ** Test for access permissions. Return true if the requested permission
520: ** is available, or false otherwise.
521: */
522: static int vfslogAccess(
523: sqlite3_vfs *pVfs,
524: const char *zPath,
525: int flags,
526: int *pResOut
527: ){
528: int rc;
529: sqlite3_uint64 t;
530: t = vfslog_time();
531: rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
532: t = vfslog_time() - t;
533: vfslog_call(pVfs, OS_ACCESS, 0, t, rc, flags, *pResOut);
534: vfslog_string(pVfs, zPath);
535: return rc;
536: }
537:
538: /*
539: ** Populate buffer zOut with the full canonical pathname corresponding
540: ** to the pathname in zPath. zOut is guaranteed to point to a buffer
541: ** of at least (INST_MAX_PATHNAME+1) bytes.
542: */
543: static int vfslogFullPathname(
544: sqlite3_vfs *pVfs,
545: const char *zPath,
546: int nOut,
547: char *zOut
548: ){
549: return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
550: }
551:
552: /*
553: ** Open the dynamic library located at zPath and return a handle.
554: */
555: static void *vfslogDlOpen(sqlite3_vfs *pVfs, const char *zPath){
556: return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
557: }
558:
559: /*
560: ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
561: ** utf-8 string describing the most recent error encountered associated
562: ** with dynamic libraries.
563: */
564: static void vfslogDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
565: REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
566: }
567:
568: /*
569: ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
570: */
571: static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
572: return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
573: }
574:
575: /*
576: ** Close the dynamic library handle pHandle.
577: */
578: static void vfslogDlClose(sqlite3_vfs *pVfs, void *pHandle){
579: REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
580: }
581:
582: /*
583: ** Populate the buffer pointed to by zBufOut with nByte bytes of
584: ** random data.
585: */
586: static int vfslogRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
587: return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
588: }
589:
590: /*
591: ** Sleep for nMicro microseconds. Return the number of microseconds
592: ** actually slept.
593: */
594: static int vfslogSleep(sqlite3_vfs *pVfs, int nMicro){
595: return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
596: }
597:
598: /*
599: ** Return the current time as a Julian Day number in *pTimeOut.
600: */
601: static int vfslogCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
602: return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
603: }
604:
605: static int vfslogGetLastError(sqlite3_vfs *pVfs, int a, char *b){
606: return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
607: }
608: static int vfslogCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
609: return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
610: }
611:
612: static void vfslog_flush(VfslogVfs *p){
613: #ifdef SQLITE_TEST
614: extern int sqlite3_io_error_pending;
615: extern int sqlite3_io_error_persist;
616: extern int sqlite3_diskfull_pending;
617:
618: int pending = sqlite3_io_error_pending;
619: int persist = sqlite3_io_error_persist;
620: int diskfull = sqlite3_diskfull_pending;
621:
622: sqlite3_io_error_pending = 0;
623: sqlite3_io_error_persist = 0;
624: sqlite3_diskfull_pending = 0;
625: #endif
626:
627: if( p->nBuf ){
628: p->pLog->pMethods->xWrite(p->pLog, p->aBuf, p->nBuf, p->iOffset);
629: p->iOffset += p->nBuf;
630: p->nBuf = 0;
631: }
632:
633: #ifdef SQLITE_TEST
634: sqlite3_io_error_pending = pending;
635: sqlite3_io_error_persist = persist;
636: sqlite3_diskfull_pending = diskfull;
637: #endif
638: }
639:
640: static void put32bits(unsigned char *p, unsigned int v){
641: p[0] = v>>24;
642: p[1] = v>>16;
643: p[2] = v>>8;
644: p[3] = v;
645: }
646:
647: static void vfslog_call(
648: sqlite3_vfs *pVfs,
649: int eEvent,
650: int iFileid,
651: int nClick,
652: int return_code,
653: int size,
654: int offset
655: ){
656: VfslogVfs *p = (VfslogVfs *)pVfs;
657: unsigned char *zRec;
658: if( (24+p->nBuf)>sizeof(p->aBuf) ){
659: vfslog_flush(p);
660: }
661: zRec = (unsigned char *)&p->aBuf[p->nBuf];
662: put32bits(&zRec[0], eEvent);
663: put32bits(&zRec[4], iFileid);
664: put32bits(&zRec[8], nClick);
665: put32bits(&zRec[12], return_code);
666: put32bits(&zRec[16], size);
667: put32bits(&zRec[20], offset);
668: p->nBuf += 24;
669: }
670:
671: static void vfslog_string(sqlite3_vfs *pVfs, const char *zStr){
672: VfslogVfs *p = (VfslogVfs *)pVfs;
673: unsigned char *zRec;
674: int nStr = zStr ? strlen(zStr) : 0;
675: if( (4+nStr+p->nBuf)>sizeof(p->aBuf) ){
676: vfslog_flush(p);
677: }
678: zRec = (unsigned char *)&p->aBuf[p->nBuf];
679: put32bits(&zRec[0], nStr);
680: if( zStr ){
681: memcpy(&zRec[4], zStr, nStr);
682: }
683: p->nBuf += (4 + nStr);
684: }
685:
686: static void vfslog_finalize(VfslogVfs *p){
687: if( p->pLog->pMethods ){
688: vfslog_flush(p);
689: p->pLog->pMethods->xClose(p->pLog);
690: }
691: sqlite3_free(p);
692: }
693:
694: int sqlite3_vfslog_finalize(const char *zVfs){
695: sqlite3_vfs *pVfs;
696: pVfs = sqlite3_vfs_find(zVfs);
697: if( !pVfs || pVfs->xOpen!=vfslogOpen ){
698: return SQLITE_ERROR;
699: }
700: sqlite3_vfs_unregister(pVfs);
701: vfslog_finalize((VfslogVfs *)pVfs);
702: return SQLITE_OK;
703: }
704:
705: int sqlite3_vfslog_new(
706: const char *zVfs, /* New VFS name */
707: const char *zParentVfs, /* Parent VFS name (or NULL) */
708: const char *zLog /* Log file name */
709: ){
710: VfslogVfs *p;
711: sqlite3_vfs *pParent;
712: int nByte;
713: int flags;
714: int rc;
715: char *zFile;
716: int nVfs;
717:
718: pParent = sqlite3_vfs_find(zParentVfs);
719: if( !pParent ){
720: return SQLITE_ERROR;
721: }
722:
723: nVfs = strlen(zVfs);
724: nByte = sizeof(VfslogVfs) + pParent->szOsFile + nVfs+1+pParent->mxPathname+1;
725: p = (VfslogVfs *)sqlite3_malloc(nByte);
726: memset(p, 0, nByte);
727:
728: p->pVfs = pParent;
729: p->pLog = (sqlite3_file *)&p[1];
730: memcpy(&p->base, &vfslog_vfs, sizeof(sqlite3_vfs));
731: p->base.zName = &((char *)p->pLog)[pParent->szOsFile];
732: p->base.szOsFile += pParent->szOsFile;
733: memcpy((char *)p->base.zName, zVfs, nVfs);
734:
735: zFile = (char *)&p->base.zName[nVfs+1];
736: pParent->xFullPathname(pParent, zLog, pParent->mxPathname, zFile);
737:
738: flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MASTER_JOURNAL;
739: pParent->xDelete(pParent, zFile, 0);
740: rc = pParent->xOpen(pParent, zFile, p->pLog, flags, &flags);
741: if( rc==SQLITE_OK ){
742: memcpy(p->aBuf, "sqlite_ostrace1.....", 20);
743: p->iOffset = 0;
744: p->nBuf = 20;
745: rc = sqlite3_vfs_register((sqlite3_vfs *)p, 1);
746: }
747: if( rc ){
748: vfslog_finalize(p);
749: }
750: return rc;
751: }
752:
753: int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg){
754: sqlite3_vfs *pVfs;
755: pVfs = sqlite3_vfs_find(zVfs);
756: if( !pVfs || pVfs->xOpen!=vfslogOpen ){
757: return SQLITE_ERROR;
758: }
759: vfslog_call(pVfs, OS_ANNOTATE, 0, 0, 0, 0, 0);
760: vfslog_string(pVfs, zMsg);
761: return SQLITE_OK;
762: }
763:
764: static const char *vfslog_eventname(int eEvent){
765: const char *zEvent = 0;
766:
767: switch( eEvent ){
768: case OS_CLOSE: zEvent = "xClose"; break;
769: case OS_READ: zEvent = "xRead"; break;
770: case OS_WRITE: zEvent = "xWrite"; break;
771: case OS_TRUNCATE: zEvent = "xTruncate"; break;
772: case OS_SYNC: zEvent = "xSync"; break;
773: case OS_FILESIZE: zEvent = "xFilesize"; break;
774: case OS_LOCK: zEvent = "xLock"; break;
775: case OS_UNLOCK: zEvent = "xUnlock"; break;
776: case OS_CHECKRESERVEDLOCK: zEvent = "xCheckResLock"; break;
777: case OS_FILECONTROL: zEvent = "xFileControl"; break;
778: case OS_SECTORSIZE: zEvent = "xSectorSize"; break;
779: case OS_DEVCHAR: zEvent = "xDeviceChar"; break;
780: case OS_OPEN: zEvent = "xOpen"; break;
781: case OS_DELETE: zEvent = "xDelete"; break;
782: case OS_ACCESS: zEvent = "xAccess"; break;
783: case OS_FULLPATHNAME: zEvent = "xFullPathname"; break;
784: case OS_RANDOMNESS: zEvent = "xRandomness"; break;
785: case OS_SLEEP: zEvent = "xSleep"; break;
786: case OS_CURRENTTIME: zEvent = "xCurrentTime"; break;
787:
788: case OS_SHMUNMAP: zEvent = "xShmUnmap"; break;
789: case OS_SHMLOCK: zEvent = "xShmLock"; break;
790: case OS_SHMBARRIER: zEvent = "xShmBarrier"; break;
791: case OS_SHMMAP: zEvent = "xShmMap"; break;
792:
793: case OS_ANNOTATE: zEvent = "annotation"; break;
794: }
795:
796: return zEvent;
797: }
798:
799: typedef struct VfslogVtab VfslogVtab;
800: typedef struct VfslogCsr VfslogCsr;
801:
802: /*
803: ** Virtual table type for the vfslog reader module.
804: */
805: struct VfslogVtab {
806: sqlite3_vtab base; /* Base class */
807: sqlite3_file *pFd; /* File descriptor open on vfslog file */
808: sqlite3_int64 nByte; /* Size of file in bytes */
809: char *zFile; /* File name for pFd */
810: };
811:
812: /*
813: ** Virtual table cursor type for the vfslog reader module.
814: */
815: struct VfslogCsr {
816: sqlite3_vtab_cursor base; /* Base class */
817: sqlite3_int64 iRowid; /* Current rowid. */
818: sqlite3_int64 iOffset; /* Offset of next record in file */
819: char *zTransient; /* Transient 'file' string */
820: int nFile; /* Size of array azFile[] */
821: char **azFile; /* File strings */
822: unsigned char aBuf[1024]; /* Current vfs log entry (read from file) */
823: };
824:
825: static unsigned int get32bits(unsigned char *p){
826: return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
827: }
828:
829: /*
830: ** The argument must point to a buffer containing a nul-terminated string.
831: ** If the string begins with an SQL quote character it is overwritten by
832: ** the dequoted version. Otherwise the buffer is left unmodified.
833: */
834: static void dequote(char *z){
835: char quote; /* Quote character (if any ) */
836: quote = z[0];
837: if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){
838: int iIn = 1; /* Index of next byte to read from input */
839: int iOut = 0; /* Index of next byte to write to output */
840: if( quote=='[' ) quote = ']';
841: while( z[iIn] ){
842: if( z[iIn]==quote ){
843: if( z[iIn+1]!=quote ) break;
844: z[iOut++] = quote;
845: iIn += 2;
846: }else{
847: z[iOut++] = z[iIn++];
848: }
849: }
850: z[iOut] = '\0';
851: }
852: }
853:
854: #ifndef SQLITE_OMIT_VIRTUALTABLE
855: /*
856: ** Connect to or create a vfslog virtual table.
857: */
858: static int vlogConnect(
859: sqlite3 *db,
860: void *pAux,
861: int argc, const char *const*argv,
862: sqlite3_vtab **ppVtab,
863: char **pzErr
864: ){
865: sqlite3_vfs *pVfs; /* VFS used to read log file */
866: int flags; /* flags passed to pVfs->xOpen() */
867: VfslogVtab *p;
868: int rc;
869: int nByte;
870: char *zFile;
871:
872: *ppVtab = 0;
873: pVfs = sqlite3_vfs_find(0);
874: nByte = sizeof(VfslogVtab) + pVfs->szOsFile + pVfs->mxPathname;
875: p = sqlite3_malloc(nByte);
876: if( p==0 ) return SQLITE_NOMEM;
877: memset(p, 0, nByte);
878:
879: p->pFd = (sqlite3_file *)&p[1];
880: p->zFile = &((char *)p->pFd)[pVfs->szOsFile];
881:
882: zFile = sqlite3_mprintf("%s", argv[3]);
883: if( !zFile ){
884: sqlite3_free(p);
885: return SQLITE_NOMEM;
886: }
887: dequote(zFile);
888: pVfs->xFullPathname(pVfs, zFile, pVfs->mxPathname, p->zFile);
889: sqlite3_free(zFile);
890:
891: flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MASTER_JOURNAL;
892: rc = pVfs->xOpen(pVfs, p->zFile, p->pFd, flags, &flags);
893:
894: if( rc==SQLITE_OK ){
895: p->pFd->pMethods->xFileSize(p->pFd, &p->nByte);
896: sqlite3_declare_vtab(db,
897: "CREATE TABLE xxx(event, file, click, rc, size, offset)"
898: );
899: *ppVtab = &p->base;
900: }else{
901: sqlite3_free(p);
902: }
903:
904: return rc;
905: }
906:
907: /*
908: ** There is no "best-index". This virtual table always does a linear
909: ** scan of the binary VFS log file.
910: */
911: static int vlogBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
912: pIdxInfo->estimatedCost = 10.0;
913: return SQLITE_OK;
914: }
915:
916: /*
917: ** Disconnect from or destroy a vfslog virtual table.
918: */
919: static int vlogDisconnect(sqlite3_vtab *pVtab){
920: VfslogVtab *p = (VfslogVtab *)pVtab;
921: if( p->pFd->pMethods ){
922: p->pFd->pMethods->xClose(p->pFd);
923: p->pFd->pMethods = 0;
924: }
925: sqlite3_free(p);
926: return SQLITE_OK;
927: }
928:
929: /*
930: ** Open a new vfslog cursor.
931: */
932: static int vlogOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
933: VfslogCsr *pCsr; /* Newly allocated cursor object */
934:
935: pCsr = sqlite3_malloc(sizeof(VfslogCsr));
936: if( !pCsr ) return SQLITE_NOMEM;
937: memset(pCsr, 0, sizeof(VfslogCsr));
938: *ppCursor = &pCsr->base;
939: return SQLITE_OK;
940: }
941:
942: /*
943: ** Close a vfslog cursor.
944: */
945: static int vlogClose(sqlite3_vtab_cursor *pCursor){
946: VfslogCsr *p = (VfslogCsr *)pCursor;
947: int i;
948: for(i=0; i<p->nFile; i++){
949: sqlite3_free(p->azFile[i]);
950: }
951: sqlite3_free(p->azFile);
952: sqlite3_free(p->zTransient);
953: sqlite3_free(p);
954: return SQLITE_OK;
955: }
956:
957: /*
958: ** Move a vfslog cursor to the next entry in the file.
959: */
960: static int vlogNext(sqlite3_vtab_cursor *pCursor){
961: VfslogCsr *pCsr = (VfslogCsr *)pCursor;
962: VfslogVtab *p = (VfslogVtab *)pCursor->pVtab;
963: int rc = SQLITE_OK;
964: int nRead;
965:
966: sqlite3_free(pCsr->zTransient);
967: pCsr->zTransient = 0;
968:
969: nRead = 24;
970: if( pCsr->iOffset+nRead<=p->nByte ){
971: int eEvent;
972: rc = p->pFd->pMethods->xRead(p->pFd, pCsr->aBuf, nRead, pCsr->iOffset);
973:
974: eEvent = get32bits(pCsr->aBuf);
975: if( (rc==SQLITE_OK)
976: && (eEvent==OS_OPEN || eEvent==OS_DELETE || eEvent==OS_ACCESS)
977: ){
978: char buf[4];
979: rc = p->pFd->pMethods->xRead(p->pFd, buf, 4, pCsr->iOffset+nRead);
980: nRead += 4;
981: if( rc==SQLITE_OK ){
982: int nStr = get32bits((unsigned char *)buf);
983: char *zStr = sqlite3_malloc(nStr+1);
984: rc = p->pFd->pMethods->xRead(p->pFd, zStr, nStr, pCsr->iOffset+nRead);
985: zStr[nStr] = '\0';
986: nRead += nStr;
987:
988: if( eEvent==OS_OPEN ){
989: int iFileid = get32bits(&pCsr->aBuf[4]);
990: if( iFileid>=pCsr->nFile ){
991: int nNew = sizeof(pCsr->azFile[0])*(iFileid+1);
992: pCsr->azFile = (char **)sqlite3_realloc(pCsr->azFile, nNew);
993: nNew -= sizeof(pCsr->azFile[0])*pCsr->nFile;
994: memset(&pCsr->azFile[pCsr->nFile], 0, nNew);
995: pCsr->nFile = iFileid+1;
996: }
997: sqlite3_free(pCsr->azFile[iFileid]);
998: pCsr->azFile[iFileid] = zStr;
999: }else{
1000: pCsr->zTransient = zStr;
1001: }
1002: }
1003: }
1004: }
1005:
1006: pCsr->iRowid += 1;
1007: pCsr->iOffset += nRead;
1008: return rc;
1009: }
1010:
1011: static int vlogEof(sqlite3_vtab_cursor *pCursor){
1012: VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1013: VfslogVtab *p = (VfslogVtab *)pCursor->pVtab;
1014: return (pCsr->iOffset>=p->nByte);
1015: }
1016:
1017: static int vlogFilter(
1018: sqlite3_vtab_cursor *pCursor,
1019: int idxNum, const char *idxStr,
1020: int argc, sqlite3_value **argv
1021: ){
1022: VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1023: pCsr->iRowid = 0;
1024: pCsr->iOffset = 20;
1025: return vlogNext(pCursor);
1026: }
1027:
1028: static int vlogColumn(
1029: sqlite3_vtab_cursor *pCursor,
1030: sqlite3_context *ctx,
1031: int i
1032: ){
1033: unsigned int val;
1034: VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1035:
1036: assert( i<7 );
1037: val = get32bits(&pCsr->aBuf[4*i]);
1038:
1039: switch( i ){
1040: case 0: {
1041: sqlite3_result_text(ctx, vfslog_eventname(val), -1, SQLITE_STATIC);
1042: break;
1043: }
1044: case 1: {
1045: char *zStr = pCsr->zTransient;
1046: if( val!=0 && val<pCsr->nFile ){
1047: zStr = pCsr->azFile[val];
1048: }
1049: sqlite3_result_text(ctx, zStr, -1, SQLITE_TRANSIENT);
1050: break;
1051: }
1052: default:
1053: sqlite3_result_int(ctx, val);
1054: break;
1055: }
1056:
1057: return SQLITE_OK;
1058: }
1059:
1060: static int vlogRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
1061: VfslogCsr *pCsr = (VfslogCsr *)pCursor;
1062: *pRowid = pCsr->iRowid;
1063: return SQLITE_OK;
1064: }
1065:
1066: int sqlite3_vfslog_register(sqlite3 *db){
1067: static sqlite3_module vfslog_module = {
1068: 0, /* iVersion */
1069: vlogConnect, /* xCreate */
1070: vlogConnect, /* xConnect */
1071: vlogBestIndex, /* xBestIndex */
1072: vlogDisconnect, /* xDisconnect */
1073: vlogDisconnect, /* xDestroy */
1074: vlogOpen, /* xOpen - open a cursor */
1075: vlogClose, /* xClose - close a cursor */
1076: vlogFilter, /* xFilter - configure scan constraints */
1077: vlogNext, /* xNext - advance a cursor */
1078: vlogEof, /* xEof - check for end of scan */
1079: vlogColumn, /* xColumn - read data */
1080: vlogRowid, /* xRowid - read data */
1081: 0, /* xUpdate */
1082: 0, /* xBegin */
1083: 0, /* xSync */
1084: 0, /* xCommit */
1085: 0, /* xRollback */
1086: 0, /* xFindMethod */
1087: 0, /* xRename */
1088: };
1089:
1090: sqlite3_create_module(db, "vfslog", &vfslog_module, 0);
1091: return SQLITE_OK;
1092: }
1093: #endif /* SQLITE_OMIT_VIRTUALTABLE */
1094:
1095: /**************************************************************************
1096: ***************************************************************************
1097: ** Tcl interface starts here.
1098: */
1099:
1100: #if defined(SQLITE_TEST) || defined(TCLSH)
1101:
1102: #include <tcl.h>
1103:
1104: static int test_vfslog(
1105: void *clientData,
1106: Tcl_Interp *interp,
1107: int objc,
1108: Tcl_Obj *CONST objv[]
1109: ){
1110: struct SqliteDb { sqlite3 *db; };
1111: sqlite3 *db;
1112: Tcl_CmdInfo cmdInfo;
1113: int rc = SQLITE_ERROR;
1114:
1115: static const char *strs[] = { "annotate", "finalize", "new", "register", 0 };
1116: enum VL_enum { VL_ANNOTATE, VL_FINALIZE, VL_NEW, VL_REGISTER };
1117: int iSub;
1118:
1119: if( objc<2 ){
1120: Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
1121: return TCL_ERROR;
1122: }
1123: if( Tcl_GetIndexFromObj(interp, objv[1], strs, "sub-command", 0, &iSub) ){
1124: return TCL_ERROR;
1125: }
1126:
1127: switch( (enum VL_enum)iSub ){
1128: case VL_ANNOTATE: {
1129: int rc;
1130: char *zVfs;
1131: char *zMsg;
1132: if( objc!=4 ){
1133: Tcl_WrongNumArgs(interp, 3, objv, "VFS");
1134: return TCL_ERROR;
1135: }
1136: zVfs = Tcl_GetString(objv[2]);
1137: zMsg = Tcl_GetString(objv[3]);
1138: rc = sqlite3_vfslog_annotate(zVfs, zMsg);
1139: if( rc!=SQLITE_OK ){
1140: Tcl_AppendResult(interp, "failed", 0);
1141: return TCL_ERROR;
1142: }
1143: break;
1144: }
1145: case VL_FINALIZE: {
1146: int rc;
1147: char *zVfs;
1148: if( objc!=3 ){
1149: Tcl_WrongNumArgs(interp, 2, objv, "VFS");
1150: return TCL_ERROR;
1151: }
1152: zVfs = Tcl_GetString(objv[2]);
1153: rc = sqlite3_vfslog_finalize(zVfs);
1154: if( rc!=SQLITE_OK ){
1155: Tcl_AppendResult(interp, "failed", 0);
1156: return TCL_ERROR;
1157: }
1158: break;
1159: };
1160:
1161: case VL_NEW: {
1162: int rc;
1163: char *zVfs;
1164: char *zParent;
1165: char *zLog;
1166: if( objc!=5 ){
1167: Tcl_WrongNumArgs(interp, 2, objv, "VFS PARENT LOGFILE");
1168: return TCL_ERROR;
1169: }
1170: zVfs = Tcl_GetString(objv[2]);
1171: zParent = Tcl_GetString(objv[3]);
1172: zLog = Tcl_GetString(objv[4]);
1173: if( *zParent=='\0' ) zParent = 0;
1174: rc = sqlite3_vfslog_new(zVfs, zParent, zLog);
1175: if( rc!=SQLITE_OK ){
1176: Tcl_AppendResult(interp, "failed", 0);
1177: return TCL_ERROR;
1178: }
1179: break;
1180: };
1181:
1182: case VL_REGISTER: {
1183: char *zDb;
1184: if( objc!=3 ){
1185: Tcl_WrongNumArgs(interp, 2, objv, "DB");
1186: return TCL_ERROR;
1187: }
1188: #ifdef SQLITE_OMIT_VIRTUALTABLE
1189: Tcl_AppendResult(interp, "vfslog not available because of "
1190: "SQLITE_OMIT_VIRTUALTABLE", (void*)0);
1191: return TCL_ERROR;
1192: #else
1193: zDb = Tcl_GetString(objv[2]);
1194: if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
1195: db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
1196: rc = sqlite3_vfslog_register(db);
1197: }
1198: if( rc!=SQLITE_OK ){
1199: Tcl_AppendResult(interp, "bad sqlite3 handle: ", zDb, (void*)0);
1200: return TCL_ERROR;
1201: }
1202: break;
1203: #endif
1204: }
1205: }
1206:
1207: return TCL_OK;
1208: }
1209:
1210: int SqlitetestOsinst_Init(Tcl_Interp *interp){
1211: Tcl_CreateObjCommand(interp, "vfslog", test_vfslog, 0, 0);
1212: return TCL_OK;
1213: }
1214:
1215: #endif /* SQLITE_TEST */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>