123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215 |
- /*
- ** 2008 April 10
- **
- ** The author disclaims copyright to this source code. In place of
- ** a legal notice, here is a blessing:
- **
- ** May you do good and not evil.
- ** May you find forgiveness for yourself and forgive others.
- ** May you share freely, never taking more than you give.
- **
- ******************************************************************************
- **
- ** This file contains the implementation of an SQLite vfs wrapper that
- ** adds instrumentation to all vfs and file methods. C and Tcl interfaces
- ** are provided to control the instrumentation.
- */
- /*
- ** This module contains code for a wrapper VFS that causes a log of
- ** most VFS calls to be written into a nominated file on disk. The log
- ** is stored in a compressed binary format to reduce the amount of IO
- ** overhead introduced into the application by logging.
- **
- ** All calls on sqlite3_file objects except xFileControl() are logged.
- ** Additionally, calls to the xAccess(), xOpen(), and xDelete()
- ** methods are logged. The other sqlite3_vfs object methods (xDlXXX,
- ** xRandomness, xSleep, xCurrentTime, xGetLastError and xCurrentTimeInt64)
- ** are not logged.
- **
- ** The binary log files are read using a virtual table implementation
- ** also contained in this file.
- **
- ** CREATING LOG FILES:
- **
- ** int sqlite3_vfslog_new(
- ** const char *zVfs, // Name of new VFS
- ** const char *zParentVfs, // Name of parent VFS (or NULL)
- ** const char *zLog // Name of log file to write to
- ** );
- **
- ** int sqlite3_vfslog_finalize(const char *zVfs);
- **
- ** ANNOTATING LOG FILES:
- **
- ** To write an arbitrary message into a log file:
- **
- ** int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg);
- **
- ** READING LOG FILES:
- **
- ** Log files are read using the "vfslog" virtual table implementation
- ** in this file. To register the virtual table with SQLite, use:
- **
- ** int sqlite3_vfslog_register(sqlite3 *db);
- **
- ** Then, if the log file is named "vfs.log", the following SQL command:
- **
- ** CREATE VIRTUAL TABLE v USING vfslog('vfs.log');
- **
- ** creates a virtual table with 6 columns, as follows:
- **
- ** CREATE TABLE v(
- ** event TEXT, // "xOpen", "xRead" etc.
- ** file TEXT, // Name of file this call applies to
- ** clicks INTEGER, // Time spent in call
- ** rc INTEGER, // Return value
- ** size INTEGER, // Bytes read or written
- ** offset INTEGER // File offset read or written
- ** );
- */
- #include "sqlite3.h"
- #include <string.h>
- #include <assert.h>
- /*
- ** Maximum pathname length supported by the vfslog backend.
- */
- #define INST_MAX_PATHNAME 512
- #define OS_ACCESS 1
- #define OS_CHECKRESERVEDLOCK 2
- #define OS_CLOSE 3
- #define OS_CURRENTTIME 4
- #define OS_DELETE 5
- #define OS_DEVCHAR 6
- #define OS_FILECONTROL 7
- #define OS_FILESIZE 8
- #define OS_FULLPATHNAME 9
- #define OS_LOCK 11
- #define OS_OPEN 12
- #define OS_RANDOMNESS 13
- #define OS_READ 14
- #define OS_SECTORSIZE 15
- #define OS_SLEEP 16
- #define OS_SYNC 17
- #define OS_TRUNCATE 18
- #define OS_UNLOCK 19
- #define OS_WRITE 20
- #define OS_SHMUNMAP 22
- #define OS_SHMMAP 23
- #define OS_SHMLOCK 25
- #define OS_SHMBARRIER 26
- #define OS_ANNOTATE 28
- #define OS_NUMEVENTS 29
- #define VFSLOG_BUFFERSIZE 8192
- typedef struct VfslogVfs VfslogVfs;
- typedef struct VfslogFile VfslogFile;
- struct VfslogVfs {
- sqlite3_vfs base; /* VFS methods */
- sqlite3_vfs *pVfs; /* Parent VFS */
- int iNextFileId; /* Next file id */
- sqlite3_file *pLog; /* Log file handle */
- sqlite3_int64 iOffset; /* Log file offset of start of write buffer */
- int nBuf; /* Number of valid bytes in aBuf[] */
- char aBuf[VFSLOG_BUFFERSIZE]; /* Write buffer */
- };
- struct VfslogFile {
- sqlite3_file base; /* IO methods */
- sqlite3_file *pReal; /* Underlying file handle */
- sqlite3_vfs *pVfslog; /* Associated VsflogVfs object */
- int iFileId; /* File id number */
- };
- #define REALVFS(p) (((VfslogVfs *)(p))->pVfs)
- /*
- ** Method declarations for vfslog_file.
- */
- static int vfslogClose(sqlite3_file*);
- static int vfslogRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
- static int vfslogWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
- static int vfslogTruncate(sqlite3_file*, sqlite3_int64 size);
- static int vfslogSync(sqlite3_file*, int flags);
- static int vfslogFileSize(sqlite3_file*, sqlite3_int64 *pSize);
- static int vfslogLock(sqlite3_file*, int);
- static int vfslogUnlock(sqlite3_file*, int);
- static int vfslogCheckReservedLock(sqlite3_file*, int *pResOut);
- static int vfslogFileControl(sqlite3_file*, int op, void *pArg);
- static int vfslogSectorSize(sqlite3_file*);
- static int vfslogDeviceCharacteristics(sqlite3_file*);
- static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags);
- static int vfslogShmMap(sqlite3_file *pFile,int,int,int,volatile void **);
- static void vfslogShmBarrier(sqlite3_file*);
- static int vfslogShmUnmap(sqlite3_file *pFile, int deleteFlag);
- /*
- ** Method declarations for vfslog_vfs.
- */
- static int vfslogOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
- static int vfslogDelete(sqlite3_vfs*, const char *zName, int syncDir);
- static int vfslogAccess(sqlite3_vfs*, const char *zName, int flags, int *);
- static int vfslogFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
- static void *vfslogDlOpen(sqlite3_vfs*, const char *zFilename);
- static void vfslogDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
- static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
- static void vfslogDlClose(sqlite3_vfs*, void*);
- static int vfslogRandomness(sqlite3_vfs*, int nByte, char *zOut);
- static int vfslogSleep(sqlite3_vfs*, int microseconds);
- static int vfslogCurrentTime(sqlite3_vfs*, double*);
- static int vfslogGetLastError(sqlite3_vfs*, int, char *);
- static int vfslogCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
- static sqlite3_vfs vfslog_vfs = {
- 1, /* iVersion */
- sizeof(VfslogFile), /* szOsFile */
- INST_MAX_PATHNAME, /* mxPathname */
- 0, /* pNext */
- 0, /* zName */
- 0, /* pAppData */
- vfslogOpen, /* xOpen */
- vfslogDelete, /* xDelete */
- vfslogAccess, /* xAccess */
- vfslogFullPathname, /* xFullPathname */
- vfslogDlOpen, /* xDlOpen */
- vfslogDlError, /* xDlError */
- vfslogDlSym, /* xDlSym */
- vfslogDlClose, /* xDlClose */
- vfslogRandomness, /* xRandomness */
- vfslogSleep, /* xSleep */
- vfslogCurrentTime, /* xCurrentTime */
- vfslogGetLastError, /* xGetLastError */
- vfslogCurrentTimeInt64 /* xCurrentTime */
- };
- static sqlite3_io_methods vfslog_io_methods = {
- 2, /* iVersion */
- vfslogClose, /* xClose */
- vfslogRead, /* xRead */
- vfslogWrite, /* xWrite */
- vfslogTruncate, /* xTruncate */
- vfslogSync, /* xSync */
- vfslogFileSize, /* xFileSize */
- vfslogLock, /* xLock */
- vfslogUnlock, /* xUnlock */
- vfslogCheckReservedLock, /* xCheckReservedLock */
- vfslogFileControl, /* xFileControl */
- vfslogSectorSize, /* xSectorSize */
- vfslogDeviceCharacteristics, /* xDeviceCharacteristics */
- vfslogShmMap, /* xShmMap */
- vfslogShmLock, /* xShmLock */
- vfslogShmBarrier, /* xShmBarrier */
- vfslogShmUnmap /* xShmUnmap */
- };
- #if SQLITE_OS_UNIX && !defined(NO_GETTOD)
- #include <sys/time.h>
- static sqlite3_uint64 vfslog_time(){
- struct timeval sTime;
- gettimeofday(&sTime, 0);
- return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000;
- }
- #elif SQLITE_OS_WIN
- #include <windows.h>
- #include <time.h>
- static sqlite3_uint64 vfslog_time(){
- FILETIME ft;
- sqlite3_uint64 u64time = 0;
-
- GetSystemTimeAsFileTime(&ft);
- u64time |= ft.dwHighDateTime;
- u64time <<= 32;
- u64time |= ft.dwLowDateTime;
- /* ft is 100-nanosecond intervals, we want microseconds */
- return u64time /(sqlite3_uint64)10;
- }
- #else
- static sqlite3_uint64 vfslog_time(){
- return 0;
- }
- #endif
- static void vfslog_call(sqlite3_vfs *, int, int, sqlite3_int64, int, int, int);
- static void vfslog_string(sqlite3_vfs *, const char *);
- /*
- ** Close an vfslog-file.
- */
- static int vfslogClose(sqlite3_file *pFile){
- sqlite3_uint64 t;
- int rc = SQLITE_OK;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- if( p->pReal->pMethods ){
- rc = p->pReal->pMethods->xClose(p->pReal);
- }
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_CLOSE, p->iFileId, t, rc, 0, 0);
- return rc;
- }
- /*
- ** Read data from an vfslog-file.
- */
- static int vfslogRead(
- sqlite3_file *pFile,
- void *zBuf,
- int iAmt,
- sqlite_int64 iOfst
- ){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_READ, p->iFileId, t, rc, iAmt, (int)iOfst);
- return rc;
- }
- /*
- ** Write data to an vfslog-file.
- */
- static int vfslogWrite(
- sqlite3_file *pFile,
- const void *z,
- int iAmt,
- sqlite_int64 iOfst
- ){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_WRITE, p->iFileId, t, rc, iAmt, (int)iOfst);
- return rc;
- }
- /*
- ** Truncate an vfslog-file.
- */
- static int vfslogTruncate(sqlite3_file *pFile, sqlite_int64 size){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- rc = p->pReal->pMethods->xTruncate(p->pReal, size);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_TRUNCATE, p->iFileId, t, rc, 0, (int)size);
- return rc;
- }
- /*
- ** Sync an vfslog-file.
- */
- static int vfslogSync(sqlite3_file *pFile, int flags){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- rc = p->pReal->pMethods->xSync(p->pReal, flags);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_SYNC, p->iFileId, t, rc, flags, 0);
- return rc;
- }
- /*
- ** Return the current file-size of an vfslog-file.
- */
- static int vfslogFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_FILESIZE, p->iFileId, t, rc, 0, (int)*pSize);
- return rc;
- }
- /*
- ** Lock an vfslog-file.
- */
- static int vfslogLock(sqlite3_file *pFile, int eLock){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- rc = p->pReal->pMethods->xLock(p->pReal, eLock);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_LOCK, p->iFileId, t, rc, eLock, 0);
- return rc;
- }
- /*
- ** Unlock an vfslog-file.
- */
- static int vfslogUnlock(sqlite3_file *pFile, int eLock){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_UNLOCK, p->iFileId, t, rc, eLock, 0);
- return rc;
- }
- /*
- ** Check if another file-handle holds a RESERVED lock on an vfslog-file.
- */
- static int vfslogCheckReservedLock(sqlite3_file *pFile, int *pResOut){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_CHECKRESERVEDLOCK, p->iFileId, t, rc, *pResOut, 0);
- return rc;
- }
- /*
- ** File control method. For custom operations on an vfslog-file.
- */
- static int vfslogFileControl(sqlite3_file *pFile, int op, void *pArg){
- VfslogFile *p = (VfslogFile *)pFile;
- int rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
- if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
- *(char**)pArg = sqlite3_mprintf("vfslog/%z", *(char**)pArg);
- }
- return rc;
- }
- /*
- ** Return the sector-size in bytes for an vfslog-file.
- */
- static int vfslogSectorSize(sqlite3_file *pFile){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- rc = p->pReal->pMethods->xSectorSize(p->pReal);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_SECTORSIZE, p->iFileId, t, rc, 0, 0);
- return rc;
- }
- /*
- ** Return the device characteristic flags supported by an vfslog-file.
- */
- static int vfslogDeviceCharacteristics(sqlite3_file *pFile){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_DEVCHAR, p->iFileId, t, rc, 0, 0);
- return rc;
- }
- static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_SHMLOCK, p->iFileId, t, rc, 0, 0);
- return rc;
- }
- static int vfslogShmMap(
- sqlite3_file *pFile,
- int iRegion,
- int szRegion,
- int isWrite,
- volatile void **pp
- ){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_SHMMAP, p->iFileId, t, rc, 0, 0);
- return rc;
- }
- static void vfslogShmBarrier(sqlite3_file *pFile){
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- p->pReal->pMethods->xShmBarrier(p->pReal);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_SHMBARRIER, p->iFileId, t, SQLITE_OK, 0, 0);
- }
- static int vfslogShmUnmap(sqlite3_file *pFile, int deleteFlag){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- t = vfslog_time();
- rc = p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
- t = vfslog_time() - t;
- vfslog_call(p->pVfslog, OS_SHMUNMAP, p->iFileId, t, rc, 0, 0);
- return rc;
- }
- /*
- ** Open an vfslog file handle.
- */
- static int vfslogOpen(
- sqlite3_vfs *pVfs,
- const char *zName,
- sqlite3_file *pFile,
- int flags,
- int *pOutFlags
- ){
- int rc;
- sqlite3_uint64 t;
- VfslogFile *p = (VfslogFile *)pFile;
- VfslogVfs *pLog = (VfslogVfs *)pVfs;
- pFile->pMethods = &vfslog_io_methods;
- p->pReal = (sqlite3_file *)&p[1];
- p->pVfslog = pVfs;
- p->iFileId = ++pLog->iNextFileId;
- t = vfslog_time();
- rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
- t = vfslog_time() - t;
- vfslog_call(pVfs, OS_OPEN, p->iFileId, t, rc, 0, 0);
- vfslog_string(pVfs, zName);
- return rc;
- }
- /*
- ** Delete the file located at zPath. If the dirSync argument is true,
- ** ensure the file-system modifications are synced to disk before
- ** returning.
- */
- static int vfslogDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
- int rc;
- sqlite3_uint64 t;
- t = vfslog_time();
- rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
- t = vfslog_time() - t;
- vfslog_call(pVfs, OS_DELETE, 0, t, rc, dirSync, 0);
- vfslog_string(pVfs, zPath);
- return rc;
- }
- /*
- ** Test for access permissions. Return true if the requested permission
- ** is available, or false otherwise.
- */
- static int vfslogAccess(
- sqlite3_vfs *pVfs,
- const char *zPath,
- int flags,
- int *pResOut
- ){
- int rc;
- sqlite3_uint64 t;
- t = vfslog_time();
- rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
- t = vfslog_time() - t;
- vfslog_call(pVfs, OS_ACCESS, 0, t, rc, flags, *pResOut);
- vfslog_string(pVfs, zPath);
- return rc;
- }
- /*
- ** Populate buffer zOut with the full canonical pathname corresponding
- ** to the pathname in zPath. zOut is guaranteed to point to a buffer
- ** of at least (INST_MAX_PATHNAME+1) bytes.
- */
- static int vfslogFullPathname(
- sqlite3_vfs *pVfs,
- const char *zPath,
- int nOut,
- char *zOut
- ){
- return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
- }
- /*
- ** Open the dynamic library located at zPath and return a handle.
- */
- static void *vfslogDlOpen(sqlite3_vfs *pVfs, const char *zPath){
- return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
- }
- /*
- ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
- ** utf-8 string describing the most recent error encountered associated
- ** with dynamic libraries.
- */
- static void vfslogDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
- REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
- }
- /*
- ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
- */
- static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
- return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
- }
- /*
- ** Close the dynamic library handle pHandle.
- */
- static void vfslogDlClose(sqlite3_vfs *pVfs, void *pHandle){
- REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
- }
- /*
- ** Populate the buffer pointed to by zBufOut with nByte bytes of
- ** random data.
- */
- static int vfslogRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
- return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
- }
- /*
- ** Sleep for nMicro microseconds. Return the number of microseconds
- ** actually slept.
- */
- static int vfslogSleep(sqlite3_vfs *pVfs, int nMicro){
- return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
- }
- /*
- ** Return the current time as a Julian Day number in *pTimeOut.
- */
- static int vfslogCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
- return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
- }
- static int vfslogGetLastError(sqlite3_vfs *pVfs, int a, char *b){
- return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
- }
- static int vfslogCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
- return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
- }
- static void vfslog_flush(VfslogVfs *p){
- #ifdef SQLITE_TEST
- extern int sqlite3_io_error_pending;
- extern int sqlite3_io_error_persist;
- extern int sqlite3_diskfull_pending;
- int pending = sqlite3_io_error_pending;
- int persist = sqlite3_io_error_persist;
- int diskfull = sqlite3_diskfull_pending;
- sqlite3_io_error_pending = 0;
- sqlite3_io_error_persist = 0;
- sqlite3_diskfull_pending = 0;
- #endif
- if( p->nBuf ){
- p->pLog->pMethods->xWrite(p->pLog, p->aBuf, p->nBuf, p->iOffset);
- p->iOffset += p->nBuf;
- p->nBuf = 0;
- }
- #ifdef SQLITE_TEST
- sqlite3_io_error_pending = pending;
- sqlite3_io_error_persist = persist;
- sqlite3_diskfull_pending = diskfull;
- #endif
- }
- static void put32bits(unsigned char *p, unsigned int v){
- p[0] = v>>24;
- p[1] = v>>16;
- p[2] = v>>8;
- p[3] = v;
- }
- static void vfslog_call(
- sqlite3_vfs *pVfs,
- int eEvent,
- int iFileid,
- sqlite3_int64 nClick,
- int return_code,
- int size,
- int offset
- ){
- VfslogVfs *p = (VfslogVfs *)pVfs;
- unsigned char *zRec;
- if( (24+p->nBuf)>sizeof(p->aBuf) ){
- vfslog_flush(p);
- }
- zRec = (unsigned char *)&p->aBuf[p->nBuf];
- put32bits(&zRec[0], eEvent);
- put32bits(&zRec[4], iFileid);
- put32bits(&zRec[8], (unsigned int)(nClick&0xffff));
- put32bits(&zRec[12], return_code);
- put32bits(&zRec[16], size);
- put32bits(&zRec[20], offset);
- p->nBuf += 24;
- }
- static void vfslog_string(sqlite3_vfs *pVfs, const char *zStr){
- VfslogVfs *p = (VfslogVfs *)pVfs;
- unsigned char *zRec;
- int nStr = zStr ? (int)strlen(zStr) : 0;
- if( (4+nStr+p->nBuf)>sizeof(p->aBuf) ){
- vfslog_flush(p);
- }
- zRec = (unsigned char *)&p->aBuf[p->nBuf];
- put32bits(&zRec[0], nStr);
- if( zStr ){
- memcpy(&zRec[4], zStr, nStr);
- }
- p->nBuf += (4 + nStr);
- }
- static void vfslog_finalize(VfslogVfs *p){
- if( p->pLog->pMethods ){
- vfslog_flush(p);
- p->pLog->pMethods->xClose(p->pLog);
- }
- sqlite3_free(p);
- }
- int sqlite3_vfslog_finalize(const char *zVfs){
- sqlite3_vfs *pVfs;
- pVfs = sqlite3_vfs_find(zVfs);
- if( !pVfs || pVfs->xOpen!=vfslogOpen ){
- return SQLITE_ERROR;
- }
- sqlite3_vfs_unregister(pVfs);
- vfslog_finalize((VfslogVfs *)pVfs);
- return SQLITE_OK;
- }
- int sqlite3_vfslog_new(
- const char *zVfs, /* New VFS name */
- const char *zParentVfs, /* Parent VFS name (or NULL) */
- const char *zLog /* Log file name */
- ){
- VfslogVfs *p;
- sqlite3_vfs *pParent;
- int nByte;
- int flags;
- int rc;
- char *zFile;
- int nVfs;
- pParent = sqlite3_vfs_find(zParentVfs);
- if( !pParent ){
- return SQLITE_ERROR;
- }
- nVfs = (int)strlen(zVfs);
- nByte = sizeof(VfslogVfs) + pParent->szOsFile + nVfs+1+pParent->mxPathname+1;
- p = (VfslogVfs *)sqlite3_malloc(nByte);
- memset(p, 0, nByte);
- p->pVfs = pParent;
- p->pLog = (sqlite3_file *)&p[1];
- memcpy(&p->base, &vfslog_vfs, sizeof(sqlite3_vfs));
- p->base.zName = &((char *)p->pLog)[pParent->szOsFile];
- p->base.szOsFile += pParent->szOsFile;
- memcpy((char *)p->base.zName, zVfs, nVfs);
- zFile = (char *)&p->base.zName[nVfs+1];
- pParent->xFullPathname(pParent, zLog, pParent->mxPathname, zFile);
- flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MASTER_JOURNAL;
- pParent->xDelete(pParent, zFile, 0);
- rc = pParent->xOpen(pParent, zFile, p->pLog, flags, &flags);
- if( rc==SQLITE_OK ){
- memcpy(p->aBuf, "sqlite_ostrace1.....", 20);
- p->iOffset = 0;
- p->nBuf = 20;
- rc = sqlite3_vfs_register((sqlite3_vfs *)p, 1);
- }
- if( rc ){
- vfslog_finalize(p);
- }
- return rc;
- }
- int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg){
- sqlite3_vfs *pVfs;
- pVfs = sqlite3_vfs_find(zVfs);
- if( !pVfs || pVfs->xOpen!=vfslogOpen ){
- return SQLITE_ERROR;
- }
- vfslog_call(pVfs, OS_ANNOTATE, 0, 0, 0, 0, 0);
- vfslog_string(pVfs, zMsg);
- return SQLITE_OK;
- }
- static const char *vfslog_eventname(int eEvent){
- const char *zEvent = 0;
- switch( eEvent ){
- case OS_CLOSE: zEvent = "xClose"; break;
- case OS_READ: zEvent = "xRead"; break;
- case OS_WRITE: zEvent = "xWrite"; break;
- case OS_TRUNCATE: zEvent = "xTruncate"; break;
- case OS_SYNC: zEvent = "xSync"; break;
- case OS_FILESIZE: zEvent = "xFilesize"; break;
- case OS_LOCK: zEvent = "xLock"; break;
- case OS_UNLOCK: zEvent = "xUnlock"; break;
- case OS_CHECKRESERVEDLOCK: zEvent = "xCheckResLock"; break;
- case OS_FILECONTROL: zEvent = "xFileControl"; break;
- case OS_SECTORSIZE: zEvent = "xSectorSize"; break;
- case OS_DEVCHAR: zEvent = "xDeviceChar"; break;
- case OS_OPEN: zEvent = "xOpen"; break;
- case OS_DELETE: zEvent = "xDelete"; break;
- case OS_ACCESS: zEvent = "xAccess"; break;
- case OS_FULLPATHNAME: zEvent = "xFullPathname"; break;
- case OS_RANDOMNESS: zEvent = "xRandomness"; break;
- case OS_SLEEP: zEvent = "xSleep"; break;
- case OS_CURRENTTIME: zEvent = "xCurrentTime"; break;
- case OS_SHMUNMAP: zEvent = "xShmUnmap"; break;
- case OS_SHMLOCK: zEvent = "xShmLock"; break;
- case OS_SHMBARRIER: zEvent = "xShmBarrier"; break;
- case OS_SHMMAP: zEvent = "xShmMap"; break;
- case OS_ANNOTATE: zEvent = "annotation"; break;
- }
- return zEvent;
- }
- typedef struct VfslogVtab VfslogVtab;
- typedef struct VfslogCsr VfslogCsr;
- /*
- ** Virtual table type for the vfslog reader module.
- */
- struct VfslogVtab {
- sqlite3_vtab base; /* Base class */
- sqlite3_file *pFd; /* File descriptor open on vfslog file */
- sqlite3_int64 nByte; /* Size of file in bytes */
- char *zFile; /* File name for pFd */
- };
- /*
- ** Virtual table cursor type for the vfslog reader module.
- */
- struct VfslogCsr {
- sqlite3_vtab_cursor base; /* Base class */
- sqlite3_int64 iRowid; /* Current rowid. */
- sqlite3_int64 iOffset; /* Offset of next record in file */
- char *zTransient; /* Transient 'file' string */
- int nFile; /* Size of array azFile[] */
- char **azFile; /* File strings */
- unsigned char aBuf[1024]; /* Current vfs log entry (read from file) */
- };
- static unsigned int get32bits(unsigned char *p){
- return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
- }
- /*
- ** The argument must point to a buffer containing a nul-terminated string.
- ** If the string begins with an SQL quote character it is overwritten by
- ** the dequoted version. Otherwise the buffer is left unmodified.
- */
- static void dequote(char *z){
- char quote; /* Quote character (if any ) */
- quote = z[0];
- if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){
- int iIn = 1; /* Index of next byte to read from input */
- int iOut = 0; /* Index of next byte to write to output */
- if( quote=='[' ) quote = ']';
- while( z[iIn] ){
- if( z[iIn]==quote ){
- if( z[iIn+1]!=quote ) break;
- z[iOut++] = quote;
- iIn += 2;
- }else{
- z[iOut++] = z[iIn++];
- }
- }
- z[iOut] = '\0';
- }
- }
- #ifndef SQLITE_OMIT_VIRTUALTABLE
- /*
- ** Connect to or create a vfslog virtual table.
- */
- static int vlogConnect(
- sqlite3 *db,
- void *pAux,
- int argc, const char *const*argv,
- sqlite3_vtab **ppVtab,
- char **pzErr
- ){
- sqlite3_vfs *pVfs; /* VFS used to read log file */
- int flags; /* flags passed to pVfs->xOpen() */
- VfslogVtab *p;
- int rc;
- int nByte;
- char *zFile;
- *ppVtab = 0;
- pVfs = sqlite3_vfs_find(0);
- nByte = sizeof(VfslogVtab) + pVfs->szOsFile + pVfs->mxPathname;
- p = sqlite3_malloc(nByte);
- if( p==0 ) return SQLITE_NOMEM;
- memset(p, 0, nByte);
- p->pFd = (sqlite3_file *)&p[1];
- p->zFile = &((char *)p->pFd)[pVfs->szOsFile];
- zFile = sqlite3_mprintf("%s", argv[3]);
- if( !zFile ){
- sqlite3_free(p);
- return SQLITE_NOMEM;
- }
- dequote(zFile);
- pVfs->xFullPathname(pVfs, zFile, pVfs->mxPathname, p->zFile);
- sqlite3_free(zFile);
- flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MASTER_JOURNAL;
- rc = pVfs->xOpen(pVfs, p->zFile, p->pFd, flags, &flags);
- if( rc==SQLITE_OK ){
- p->pFd->pMethods->xFileSize(p->pFd, &p->nByte);
- sqlite3_declare_vtab(db,
- "CREATE TABLE xxx(event, file, click, rc, size, offset)"
- );
- *ppVtab = &p->base;
- }else{
- sqlite3_free(p);
- }
- return rc;
- }
- /*
- ** There is no "best-index". This virtual table always does a linear
- ** scan of the binary VFS log file.
- */
- static int vlogBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
- pIdxInfo->estimatedCost = 10.0;
- return SQLITE_OK;
- }
- /*
- ** Disconnect from or destroy a vfslog virtual table.
- */
- static int vlogDisconnect(sqlite3_vtab *pVtab){
- VfslogVtab *p = (VfslogVtab *)pVtab;
- if( p->pFd->pMethods ){
- p->pFd->pMethods->xClose(p->pFd);
- p->pFd->pMethods = 0;
- }
- sqlite3_free(p);
- return SQLITE_OK;
- }
- /*
- ** Open a new vfslog cursor.
- */
- static int vlogOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
- VfslogCsr *pCsr; /* Newly allocated cursor object */
- pCsr = sqlite3_malloc(sizeof(VfslogCsr));
- if( !pCsr ) return SQLITE_NOMEM;
- memset(pCsr, 0, sizeof(VfslogCsr));
- *ppCursor = &pCsr->base;
- return SQLITE_OK;
- }
- /*
- ** Close a vfslog cursor.
- */
- static int vlogClose(sqlite3_vtab_cursor *pCursor){
- VfslogCsr *p = (VfslogCsr *)pCursor;
- int i;
- for(i=0; i<p->nFile; i++){
- sqlite3_free(p->azFile[i]);
- }
- sqlite3_free(p->azFile);
- sqlite3_free(p->zTransient);
- sqlite3_free(p);
- return SQLITE_OK;
- }
- /*
- ** Move a vfslog cursor to the next entry in the file.
- */
- static int vlogNext(sqlite3_vtab_cursor *pCursor){
- VfslogCsr *pCsr = (VfslogCsr *)pCursor;
- VfslogVtab *p = (VfslogVtab *)pCursor->pVtab;
- int rc = SQLITE_OK;
- int nRead;
- sqlite3_free(pCsr->zTransient);
- pCsr->zTransient = 0;
- nRead = 24;
- if( pCsr->iOffset+nRead<=p->nByte ){
- int eEvent;
- rc = p->pFd->pMethods->xRead(p->pFd, pCsr->aBuf, nRead, pCsr->iOffset);
- eEvent = get32bits(pCsr->aBuf);
- if( (rc==SQLITE_OK)
- && (eEvent==OS_OPEN || eEvent==OS_DELETE || eEvent==OS_ACCESS)
- ){
- char buf[4];
- rc = p->pFd->pMethods->xRead(p->pFd, buf, 4, pCsr->iOffset+nRead);
- nRead += 4;
- if( rc==SQLITE_OK ){
- int nStr = get32bits((unsigned char *)buf);
- char *zStr = sqlite3_malloc(nStr+1);
- rc = p->pFd->pMethods->xRead(p->pFd, zStr, nStr, pCsr->iOffset+nRead);
- zStr[nStr] = '\0';
- nRead += nStr;
- if( eEvent==OS_OPEN ){
- int iFileid = get32bits(&pCsr->aBuf[4]);
- if( iFileid>=pCsr->nFile ){
- int nNew = sizeof(pCsr->azFile[0])*(iFileid+1);
- pCsr->azFile = (char **)sqlite3_realloc(pCsr->azFile, nNew);
- nNew -= sizeof(pCsr->azFile[0])*pCsr->nFile;
- memset(&pCsr->azFile[pCsr->nFile], 0, nNew);
- pCsr->nFile = iFileid+1;
- }
- sqlite3_free(pCsr->azFile[iFileid]);
- pCsr->azFile[iFileid] = zStr;
- }else{
- pCsr->zTransient = zStr;
- }
- }
- }
- }
- pCsr->iRowid += 1;
- pCsr->iOffset += nRead;
- return rc;
- }
- static int vlogEof(sqlite3_vtab_cursor *pCursor){
- VfslogCsr *pCsr = (VfslogCsr *)pCursor;
- VfslogVtab *p = (VfslogVtab *)pCursor->pVtab;
- return (pCsr->iOffset>=p->nByte);
- }
- static int vlogFilter(
- sqlite3_vtab_cursor *pCursor,
- int idxNum, const char *idxStr,
- int argc, sqlite3_value **argv
- ){
- VfslogCsr *pCsr = (VfslogCsr *)pCursor;
- pCsr->iRowid = 0;
- pCsr->iOffset = 20;
- return vlogNext(pCursor);
- }
- static int vlogColumn(
- sqlite3_vtab_cursor *pCursor,
- sqlite3_context *ctx,
- int i
- ){
- unsigned int val;
- VfslogCsr *pCsr = (VfslogCsr *)pCursor;
- assert( i<7 );
- val = get32bits(&pCsr->aBuf[4*i]);
- switch( i ){
- case 0: {
- sqlite3_result_text(ctx, vfslog_eventname(val), -1, SQLITE_STATIC);
- break;
- }
- case 1: {
- char *zStr = pCsr->zTransient;
- if( val!=0 && val<(unsigned)pCsr->nFile ){
- zStr = pCsr->azFile[val];
- }
- sqlite3_result_text(ctx, zStr, -1, SQLITE_TRANSIENT);
- break;
- }
- default:
- sqlite3_result_int(ctx, val);
- break;
- }
- return SQLITE_OK;
- }
- static int vlogRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
- VfslogCsr *pCsr = (VfslogCsr *)pCursor;
- *pRowid = pCsr->iRowid;
- return SQLITE_OK;
- }
- int sqlite3_vfslog_register(sqlite3 *db){
- static sqlite3_module vfslog_module = {
- 0, /* iVersion */
- vlogConnect, /* xCreate */
- vlogConnect, /* xConnect */
- vlogBestIndex, /* xBestIndex */
- vlogDisconnect, /* xDisconnect */
- vlogDisconnect, /* xDestroy */
- vlogOpen, /* xOpen - open a cursor */
- vlogClose, /* xClose - close a cursor */
- vlogFilter, /* xFilter - configure scan constraints */
- vlogNext, /* xNext - advance a cursor */
- vlogEof, /* xEof - check for end of scan */
- vlogColumn, /* xColumn - read data */
- vlogRowid, /* xRowid - read data */
- 0, /* xUpdate */
- 0, /* xBegin */
- 0, /* xSync */
- 0, /* xCommit */
- 0, /* xRollback */
- 0, /* xFindMethod */
- 0, /* xRename */
- };
- sqlite3_create_module(db, "vfslog", &vfslog_module, 0);
- return SQLITE_OK;
- }
- #endif /* SQLITE_OMIT_VIRTUALTABLE */
- /**************************************************************************
- ***************************************************************************
- ** Tcl interface starts here.
- */
- #if defined(SQLITE_TEST) || defined(TCLSH)
- #include <tcl.h>
- static int test_vfslog(
- void *clientData,
- Tcl_Interp *interp,
- int objc,
- Tcl_Obj *CONST objv[]
- ){
- struct SqliteDb { sqlite3 *db; };
- sqlite3 *db;
- Tcl_CmdInfo cmdInfo;
- int rc = SQLITE_ERROR;
- static const char *strs[] = { "annotate", "finalize", "new", "register", 0 };
- enum VL_enum { VL_ANNOTATE, VL_FINALIZE, VL_NEW, VL_REGISTER };
- int iSub;
- if( objc<2 ){
- Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
- return TCL_ERROR;
- }
- if( Tcl_GetIndexFromObj(interp, objv[1], strs, "sub-command", 0, &iSub) ){
- return TCL_ERROR;
- }
- switch( (enum VL_enum)iSub ){
- case VL_ANNOTATE: {
- int rc;
- char *zVfs;
- char *zMsg;
- if( objc!=4 ){
- Tcl_WrongNumArgs(interp, 3, objv, "VFS");
- return TCL_ERROR;
- }
- zVfs = Tcl_GetString(objv[2]);
- zMsg = Tcl_GetString(objv[3]);
- rc = sqlite3_vfslog_annotate(zVfs, zMsg);
- if( rc!=SQLITE_OK ){
- Tcl_AppendResult(interp, "failed", 0);
- return TCL_ERROR;
- }
- break;
- }
- case VL_FINALIZE: {
- int rc;
- char *zVfs;
- if( objc!=3 ){
- Tcl_WrongNumArgs(interp, 2, objv, "VFS");
- return TCL_ERROR;
- }
- zVfs = Tcl_GetString(objv[2]);
- rc = sqlite3_vfslog_finalize(zVfs);
- if( rc!=SQLITE_OK ){
- Tcl_AppendResult(interp, "failed", 0);
- return TCL_ERROR;
- }
- break;
- };
- case VL_NEW: {
- int rc;
- char *zVfs;
- char *zParent;
- char *zLog;
- if( objc!=5 ){
- Tcl_WrongNumArgs(interp, 2, objv, "VFS PARENT LOGFILE");
- return TCL_ERROR;
- }
- zVfs = Tcl_GetString(objv[2]);
- zParent = Tcl_GetString(objv[3]);
- zLog = Tcl_GetString(objv[4]);
- if( *zParent=='\0' ) zParent = 0;
- rc = sqlite3_vfslog_new(zVfs, zParent, zLog);
- if( rc!=SQLITE_OK ){
- Tcl_AppendResult(interp, "failed", 0);
- return TCL_ERROR;
- }
- break;
- };
- case VL_REGISTER: {
- char *zDb;
- if( objc!=3 ){
- Tcl_WrongNumArgs(interp, 2, objv, "DB");
- return TCL_ERROR;
- }
- #ifdef SQLITE_OMIT_VIRTUALTABLE
- Tcl_AppendResult(interp, "vfslog not available because of "
- "SQLITE_OMIT_VIRTUALTABLE", (void*)0);
- return TCL_ERROR;
- #else
- zDb = Tcl_GetString(objv[2]);
- if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
- db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
- rc = sqlite3_vfslog_register(db);
- }
- if( rc!=SQLITE_OK ){
- Tcl_AppendResult(interp, "bad sqlite3 handle: ", zDb, (void*)0);
- return TCL_ERROR;
- }
- break;
- #endif
- }
- }
- return TCL_OK;
- }
- int SqlitetestOsinst_Init(Tcl_Interp *interp){
- Tcl_CreateObjCommand(interp, "vfslog", test_vfslog, 0, 0);
- return TCL_OK;
- }
- #endif /* SQLITE_TEST */
|