4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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.
11 ******************************************************************************
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.
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.
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)
30 ** The binary log files are read using a virtual table implementation
31 ** also contained in this file.
33 ** CREATING LOG FILES:
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
41 ** int sqlite3_vfslog_finalize(const char *zVfs);
43 ** ANNOTATING LOG FILES:
45 ** To write an arbitrary message into a log file:
47 ** int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg);
51 ** Log files are read using the "vfslog" virtual table implementation
52 ** in this file. To register the virtual table with SQLite, use:
54 ** int sqlite3_vfslog_register(sqlite3 *db);
56 ** Then, if the log file is named "vfs.log", the following SQL command:
58 ** CREATE VIRTUAL TABLE v USING vfslog('vfs.log');
60 ** creates a virtual table with 6 columns, as follows:
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
78 ** Maximum pathname length supported by the vfslog backend.
80 #define INST_MAX_PATHNAME 512
83 #define OS_CHECKRESERVEDLOCK 2
85 #define OS_CURRENTTIME 4
88 #define OS_FILECONTROL 7
90 #define OS_FULLPATHNAME 9
93 #define OS_RANDOMNESS 13
95 #define OS_SECTORSIZE 15
98 #define OS_TRUNCATE 18
101 #define OS_SHMUNMAP 22
103 #define OS_SHMLOCK 25
104 #define OS_SHMBARRIER 26
105 #define OS_ANNOTATE 28
107 #define OS_NUMEVENTS 29
109 #define VFSLOG_BUFFERSIZE 8192
111 typedef struct VfslogVfs VfslogVfs
;
112 typedef struct VfslogFile VfslogFile
;
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 */
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 */
131 #define REALVFS(p) (((VfslogVfs *)(p))->pVfs)
136 ** Method declarations for vfslog_file.
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
*);
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
);
157 ** Method declarations for vfslog_vfs.
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*);
171 static int vfslogGetLastError(sqlite3_vfs
*, int, char *);
172 static int vfslogCurrentTimeInt64(sqlite3_vfs
*, sqlite3_int64
*);
174 static sqlite3_vfs vfslog_vfs
= {
176 sizeof(VfslogFile
), /* szOsFile */
177 INST_MAX_PATHNAME
, /* mxPathname */
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 */
196 static sqlite3_io_methods vfslog_io_methods
= {
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 */
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;
226 static sqlite3_uint64
vfslog_time(){
228 sqlite3_uint64 u64time
= 0;
230 GetSystemTimeAsFileTime(&ft
);
232 u64time
|= ft
.dwHighDateTime
;
234 u64time
|= ft
.dwLowDateTime
;
236 /* ft is 100-nanosecond intervals, we want microseconds */
237 return u64time
/(sqlite3_uint64
)10;
240 static sqlite3_uint64
vfslog_time(){
245 static void vfslog_call(sqlite3_vfs
*, int, int, sqlite3_int64
, int, int, int);
246 static void vfslog_string(sqlite3_vfs
*, const char *);
249 ** Close an vfslog-file.
251 static int vfslogClose(sqlite3_file
*pFile
){
254 VfslogFile
*p
= (VfslogFile
*)pFile
;
257 if( p
->pReal
->pMethods
){
258 rc
= p
->pReal
->pMethods
->xClose(p
->pReal
);
260 t
= vfslog_time() - t
;
261 vfslog_call(p
->pVfslog
, OS_CLOSE
, p
->iFileId
, t
, rc
, 0, 0);
266 ** Read data from an vfslog-file.
268 static int vfslogRead(
276 VfslogFile
*p
= (VfslogFile
*)pFile
;
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
);
285 ** Write data to an vfslog-file.
287 static int vfslogWrite(
295 VfslogFile
*p
= (VfslogFile
*)pFile
;
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
);
304 ** Truncate an vfslog-file.
306 static int vfslogTruncate(sqlite3_file
*pFile
, sqlite_int64 size
){
309 VfslogFile
*p
= (VfslogFile
*)pFile
;
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
);
318 ** Sync an vfslog-file.
320 static int vfslogSync(sqlite3_file
*pFile
, int flags
){
323 VfslogFile
*p
= (VfslogFile
*)pFile
;
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);
332 ** Return the current file-size of an vfslog-file.
334 static int vfslogFileSize(sqlite3_file
*pFile
, sqlite_int64
*pSize
){
337 VfslogFile
*p
= (VfslogFile
*)pFile
;
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
);
346 ** Lock an vfslog-file.
348 static int vfslogLock(sqlite3_file
*pFile
, int eLock
){
351 VfslogFile
*p
= (VfslogFile
*)pFile
;
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);
360 ** Unlock an vfslog-file.
362 static int vfslogUnlock(sqlite3_file
*pFile
, int eLock
){
365 VfslogFile
*p
= (VfslogFile
*)pFile
;
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);
374 ** Check if another file-handle holds a RESERVED lock on an vfslog-file.
376 static int vfslogCheckReservedLock(sqlite3_file
*pFile
, int *pResOut
){
379 VfslogFile
*p
= (VfslogFile
*)pFile
;
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);
388 ** File control method. For custom operations on an vfslog-file.
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
);
400 ** Return the sector-size in bytes for an vfslog-file.
402 static int vfslogSectorSize(sqlite3_file
*pFile
){
405 VfslogFile
*p
= (VfslogFile
*)pFile
;
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);
414 ** Return the device characteristic flags supported by an vfslog-file.
416 static int vfslogDeviceCharacteristics(sqlite3_file
*pFile
){
419 VfslogFile
*p
= (VfslogFile
*)pFile
;
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);
427 static int vfslogShmLock(sqlite3_file
*pFile
, int ofst
, int n
, int flags
){
430 VfslogFile
*p
= (VfslogFile
*)pFile
;
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);
437 static int vfslogShmMap(
446 VfslogFile
*p
= (VfslogFile
*)pFile
;
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);
453 static void vfslogShmBarrier(sqlite3_file
*pFile
){
455 VfslogFile
*p
= (VfslogFile
*)pFile
;
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);
461 static int vfslogShmUnmap(sqlite3_file
*pFile
, int deleteFlag
){
464 VfslogFile
*p
= (VfslogFile
*)pFile
;
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);
474 ** Open an vfslog file handle.
476 static int vfslogOpen(
485 VfslogFile
*p
= (VfslogFile
*)pFile
;
486 VfslogVfs
*pLog
= (VfslogVfs
*)pVfs
;
488 pFile
->pMethods
= &vfslog_io_methods
;
489 p
->pReal
= (sqlite3_file
*)&p
[1];
491 p
->iFileId
= ++pLog
->iNextFileId
;
494 rc
= REALVFS(pVfs
)->xOpen(REALVFS(pVfs
), zName
, p
->pReal
, flags
, pOutFlags
);
495 t
= vfslog_time() - t
;
497 vfslog_call(pVfs
, OS_OPEN
, p
->iFileId
, t
, rc
, 0, 0);
498 vfslog_string(pVfs
, zName
);
503 ** Delete the file located at zPath. If the dirSync argument is true,
504 ** ensure the file-system modifications are synced to disk before
507 static int vfslogDelete(sqlite3_vfs
*pVfs
, const char *zPath
, int dirSync
){
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
);
519 ** Test for access permissions. Return true if the requested permission
520 ** is available, or false otherwise.
522 static int vfslogAccess(
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
);
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.
543 static int vfslogFullPathname(
549 return REALVFS(pVfs
)->xFullPathname(REALVFS(pVfs
), zPath
, nOut
, zOut
);
553 ** Open the dynamic library located at zPath and return a handle.
555 static void *vfslogDlOpen(sqlite3_vfs
*pVfs
, const char *zPath
){
556 return REALVFS(pVfs
)->xDlOpen(REALVFS(pVfs
), zPath
);
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.
564 static void vfslogDlError(sqlite3_vfs
*pVfs
, int nByte
, char *zErrMsg
){
565 REALVFS(pVfs
)->xDlError(REALVFS(pVfs
), nByte
, zErrMsg
);
569 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
571 static void (*vfslogDlSym(sqlite3_vfs
*pVfs
, void *p
, const char *zSym
))(void){
572 return REALVFS(pVfs
)->xDlSym(REALVFS(pVfs
), p
, zSym
);
576 ** Close the dynamic library handle pHandle.
578 static void vfslogDlClose(sqlite3_vfs
*pVfs
, void *pHandle
){
579 REALVFS(pVfs
)->xDlClose(REALVFS(pVfs
), pHandle
);
583 ** Populate the buffer pointed to by zBufOut with nByte bytes of
586 static int vfslogRandomness(sqlite3_vfs
*pVfs
, int nByte
, char *zBufOut
){
587 return REALVFS(pVfs
)->xRandomness(REALVFS(pVfs
), nByte
, zBufOut
);
591 ** Sleep for nMicro microseconds. Return the number of microseconds
594 static int vfslogSleep(sqlite3_vfs
*pVfs
, int nMicro
){
595 return REALVFS(pVfs
)->xSleep(REALVFS(pVfs
), nMicro
);
599 ** Return the current time as a Julian Day number in *pTimeOut.
601 static int vfslogCurrentTime(sqlite3_vfs
*pVfs
, double *pTimeOut
){
602 return REALVFS(pVfs
)->xCurrentTime(REALVFS(pVfs
), pTimeOut
);
605 static int vfslogGetLastError(sqlite3_vfs
*pVfs
, int a
, char *b
){
606 return REALVFS(pVfs
)->xGetLastError(REALVFS(pVfs
), a
, b
);
608 static int vfslogCurrentTimeInt64(sqlite3_vfs
*pVfs
, sqlite3_int64
*p
){
609 return REALVFS(pVfs
)->xCurrentTimeInt64(REALVFS(pVfs
), p
);
612 static void vfslog_flush(VfslogVfs
*p
){
614 extern int sqlite3_io_error_pending
;
615 extern int sqlite3_io_error_persist
;
616 extern int sqlite3_diskfull_pending
;
618 int pending
= sqlite3_io_error_pending
;
619 int persist
= sqlite3_io_error_persist
;
620 int diskfull
= sqlite3_diskfull_pending
;
622 sqlite3_io_error_pending
= 0;
623 sqlite3_io_error_persist
= 0;
624 sqlite3_diskfull_pending
= 0;
628 p
->pLog
->pMethods
->xWrite(p
->pLog
, p
->aBuf
, p
->nBuf
, p
->iOffset
);
629 p
->iOffset
+= p
->nBuf
;
634 sqlite3_io_error_pending
= pending
;
635 sqlite3_io_error_persist
= persist
;
636 sqlite3_diskfull_pending
= diskfull
;
640 static void put32bits(unsigned char *p
, unsigned int v
){
647 static void vfslog_call(
651 sqlite3_int64 nClick
,
656 VfslogVfs
*p
= (VfslogVfs
*)pVfs
;
658 if( (24+p
->nBuf
)>sizeof(p
->aBuf
) ){
661 zRec
= (unsigned char *)&p
->aBuf
[p
->nBuf
];
662 put32bits(&zRec
[0], eEvent
);
663 put32bits(&zRec
[4], iFileid
);
664 put32bits(&zRec
[8], (unsigned int)(nClick
&0xffff));
665 put32bits(&zRec
[12], return_code
);
666 put32bits(&zRec
[16], size
);
667 put32bits(&zRec
[20], offset
);
671 static void vfslog_string(sqlite3_vfs
*pVfs
, const char *zStr
){
672 VfslogVfs
*p
= (VfslogVfs
*)pVfs
;
674 int nStr
= zStr
? (int)strlen(zStr
) : 0;
675 if( (4+nStr
+p
->nBuf
)>sizeof(p
->aBuf
) ){
678 zRec
= (unsigned char *)&p
->aBuf
[p
->nBuf
];
679 put32bits(&zRec
[0], nStr
);
681 memcpy(&zRec
[4], zStr
, nStr
);
683 p
->nBuf
+= (4 + nStr
);
686 static void vfslog_finalize(VfslogVfs
*p
){
687 if( p
->pLog
->pMethods
){
689 p
->pLog
->pMethods
->xClose(p
->pLog
);
694 int sqlite3_vfslog_finalize(const char *zVfs
){
696 pVfs
= sqlite3_vfs_find(zVfs
);
697 if( !pVfs
|| pVfs
->xOpen
!=vfslogOpen
){
700 sqlite3_vfs_unregister(pVfs
);
701 vfslog_finalize((VfslogVfs
*)pVfs
);
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 */
711 sqlite3_vfs
*pParent
;
718 pParent
= sqlite3_vfs_find(zParentVfs
);
723 nVfs
= (int)strlen(zVfs
);
724 nByte
= sizeof(VfslogVfs
) + pParent
->szOsFile
+ nVfs
+1+pParent
->mxPathname
+1;
725 p
= (VfslogVfs
*)sqlite3_malloc(nByte
);
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
);
735 zFile
= (char *)&p
->base
.zName
[nVfs
+1];
736 pParent
->xFullPathname(pParent
, zLog
, pParent
->mxPathname
, zFile
);
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
);
742 memcpy(p
->aBuf
, "sqlite_ostrace1.....", 20);
745 rc
= sqlite3_vfs_register((sqlite3_vfs
*)p
, 1);
753 int sqlite3_vfslog_annotate(const char *zVfs
, const char *zMsg
){
755 pVfs
= sqlite3_vfs_find(zVfs
);
756 if( !pVfs
|| pVfs
->xOpen
!=vfslogOpen
){
759 vfslog_call(pVfs
, OS_ANNOTATE
, 0, 0, 0, 0, 0);
760 vfslog_string(pVfs
, zMsg
);
764 static const char *vfslog_eventname(int eEvent
){
765 const char *zEvent
= 0;
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;
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;
793 case OS_ANNOTATE
: zEvent
= "annotation"; break;
799 typedef struct VfslogVtab VfslogVtab
;
800 typedef struct VfslogCsr VfslogCsr
;
803 ** Virtual table type for the vfslog reader module.
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 */
813 ** Virtual table cursor type for the vfslog reader module.
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) */
825 static unsigned int get32bits(unsigned char *p
){
826 return (p
[0]<<24) + (p
[1]<<16) + (p
[2]<<8) + p
[3];
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.
834 static void dequote(char *z
){
835 char quote
; /* Quote character (if any ) */
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
= ']';
843 if( z
[iIn
+1]!=quote
) break;
847 z
[iOut
++] = z
[iIn
++];
854 #ifndef SQLITE_OMIT_VIRTUALTABLE
856 ** Connect to or create a vfslog virtual table.
858 static int vlogConnect(
861 int argc
, const char *const*argv
,
862 sqlite3_vtab
**ppVtab
,
865 sqlite3_vfs
*pVfs
; /* VFS used to read log file */
866 int flags
; /* flags passed to pVfs->xOpen() */
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
;
879 p
->pFd
= (sqlite3_file
*)&p
[1];
880 p
->zFile
= &((char *)p
->pFd
)[pVfs
->szOsFile
];
882 zFile
= sqlite3_mprintf("%s", argv
[3]);
888 pVfs
->xFullPathname(pVfs
, zFile
, pVfs
->mxPathname
, p
->zFile
);
891 flags
= SQLITE_OPEN_READWRITE
|SQLITE_OPEN_MASTER_JOURNAL
;
892 rc
= pVfs
->xOpen(pVfs
, p
->zFile
, p
->pFd
, flags
, &flags
);
895 p
->pFd
->pMethods
->xFileSize(p
->pFd
, &p
->nByte
);
896 sqlite3_declare_vtab(db
,
897 "CREATE TABLE xxx(event, file, click, rc, size, offset)"
908 ** There is no "best-index". This virtual table always does a linear
909 ** scan of the binary VFS log file.
911 static int vlogBestIndex(sqlite3_vtab
*tab
, sqlite3_index_info
*pIdxInfo
){
912 pIdxInfo
->estimatedCost
= 10.0;
917 ** Disconnect from or destroy a vfslog virtual table.
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;
930 ** Open a new vfslog cursor.
932 static int vlogOpen(sqlite3_vtab
*pVTab
, sqlite3_vtab_cursor
**ppCursor
){
933 VfslogCsr
*pCsr
; /* Newly allocated cursor object */
935 pCsr
= sqlite3_malloc(sizeof(VfslogCsr
));
936 if( !pCsr
) return SQLITE_NOMEM
;
937 memset(pCsr
, 0, sizeof(VfslogCsr
));
938 *ppCursor
= &pCsr
->base
;
943 ** Close a vfslog cursor.
945 static int vlogClose(sqlite3_vtab_cursor
*pCursor
){
946 VfslogCsr
*p
= (VfslogCsr
*)pCursor
;
948 for(i
=0; i
<p
->nFile
; i
++){
949 sqlite3_free(p
->azFile
[i
]);
951 sqlite3_free(p
->azFile
);
952 sqlite3_free(p
->zTransient
);
958 ** Move a vfslog cursor to the next entry in the file.
960 static int vlogNext(sqlite3_vtab_cursor
*pCursor
){
961 VfslogCsr
*pCsr
= (VfslogCsr
*)pCursor
;
962 VfslogVtab
*p
= (VfslogVtab
*)pCursor
->pVtab
;
966 sqlite3_free(pCsr
->zTransient
);
967 pCsr
->zTransient
= 0;
970 if( pCsr
->iOffset
+nRead
<=p
->nByte
){
972 rc
= p
->pFd
->pMethods
->xRead(p
->pFd
, pCsr
->aBuf
, nRead
, pCsr
->iOffset
);
974 eEvent
= get32bits(pCsr
->aBuf
);
976 && (eEvent
==OS_OPEN
|| eEvent
==OS_DELETE
|| eEvent
==OS_ACCESS
)
979 rc
= p
->pFd
->pMethods
->xRead(p
->pFd
, buf
, 4, pCsr
->iOffset
+nRead
);
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
);
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;
997 sqlite3_free(pCsr
->azFile
[iFileid
]);
998 pCsr
->azFile
[iFileid
] = zStr
;
1000 pCsr
->zTransient
= zStr
;
1007 pCsr
->iOffset
+= nRead
;
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
);
1017 static int vlogFilter(
1018 sqlite3_vtab_cursor
*pCursor
,
1019 int idxNum
, const char *idxStr
,
1020 int argc
, sqlite3_value
**argv
1022 VfslogCsr
*pCsr
= (VfslogCsr
*)pCursor
;
1025 return vlogNext(pCursor
);
1028 static int vlogColumn(
1029 sqlite3_vtab_cursor
*pCursor
,
1030 sqlite3_context
*ctx
,
1034 VfslogCsr
*pCsr
= (VfslogCsr
*)pCursor
;
1037 val
= get32bits(&pCsr
->aBuf
[4*i
]);
1041 sqlite3_result_text(ctx
, vfslog_eventname(val
), -1, SQLITE_STATIC
);
1045 char *zStr
= pCsr
->zTransient
;
1046 if( val
!=0 && val
<(unsigned)pCsr
->nFile
){
1047 zStr
= pCsr
->azFile
[val
];
1049 sqlite3_result_text(ctx
, zStr
, -1, SQLITE_TRANSIENT
);
1053 sqlite3_result_int(ctx
, val
);
1060 static int vlogRowid(sqlite3_vtab_cursor
*pCursor
, sqlite_int64
*pRowid
){
1061 VfslogCsr
*pCsr
= (VfslogCsr
*)pCursor
;
1062 *pRowid
= pCsr
->iRowid
;
1066 int sqlite3_vfslog_register(sqlite3
*db
){
1067 static sqlite3_module vfslog_module
= {
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 */
1086 0, /* xFindMethod */
1090 sqlite3_create_module(db
, "vfslog", &vfslog_module
, 0);
1093 #endif /* SQLITE_OMIT_VIRTUALTABLE */
1095 /**************************************************************************
1096 ***************************************************************************
1097 ** Tcl interface starts here.
1100 #if defined(SQLITE_TEST) || defined(TCLSH)
1104 static int test_vfslog(
1108 Tcl_Obj
*CONST objv
[]
1110 struct SqliteDb
{ sqlite3
*db
; };
1112 Tcl_CmdInfo cmdInfo
;
1113 int rc
= SQLITE_ERROR
;
1115 static const char *strs
[] = { "annotate", "finalize", "new", "register", 0 };
1116 enum VL_enum
{ VL_ANNOTATE
, VL_FINALIZE
, VL_NEW
, VL_REGISTER
};
1120 Tcl_WrongNumArgs(interp
, 1, objv
, "SUB-COMMAND ...");
1123 if( Tcl_GetIndexFromObj(interp
, objv
[1], strs
, "sub-command", 0, &iSub
) ){
1127 switch( (enum VL_enum
)iSub
){
1133 Tcl_WrongNumArgs(interp
, 3, objv
, "VFS");
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);
1149 Tcl_WrongNumArgs(interp
, 2, objv
, "VFS");
1152 zVfs
= Tcl_GetString(objv
[2]);
1153 rc
= sqlite3_vfslog_finalize(zVfs
);
1154 if( rc
!=SQLITE_OK
){
1155 Tcl_AppendResult(interp
, "failed", 0);
1167 Tcl_WrongNumArgs(interp
, 2, objv
, "VFS PARENT LOGFILE");
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);
1185 Tcl_WrongNumArgs(interp
, 2, objv
, "DB");
1188 #ifdef SQLITE_OMIT_VIRTUALTABLE
1189 Tcl_AppendResult(interp
, "vfslog not available because of "
1190 "SQLITE_OMIT_VIRTUALTABLE", (void*)0);
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
);
1198 if( rc
!=SQLITE_OK
){
1199 Tcl_AppendResult(interp
, "bad sqlite3 handle: ", zDb
, (void*)0);
1210 int SqlitetestOsinst_Init(Tcl_Interp
*interp
){
1211 Tcl_CreateObjCommand(interp
, "vfslog", test_vfslog
, 0, 0);
1215 #endif /* SQLITE_TEST */