From: danielk1977 Date: Thu, 10 Apr 2008 14:51:00 +0000 (+0000) Subject: Add source file test_osinst.c. A wrapper vfs with instrumentation capabilities. ... X-Git-Tag: version-3.6.10~1200 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5d1f5aa6ef6c3a9ea9e6e2e0becee2b134213944;p=thirdparty%2Fsqlite.git Add source file test_osinst.c. A wrapper vfs with instrumentation capabilities. (CVS 4977) FossilOrigin-Name: d9a6b653d3cb608610f13d2492fe9b3887acb3b9 --- diff --git a/main.mk b/main.mk index ea68311a30..4dc86a4894 100644 --- a/main.mk +++ b/main.mk @@ -222,6 +222,7 @@ TESTSRC = \ $(TOP)/src/test_malloc.c \ $(TOP)/src/test_md5.c \ $(TOP)/src/test_onefile.c \ + $(TOP)/src/test_osinst.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_tclvar.c \ diff --git a/manifest b/manifest index 5e05359d6e..f7a7d73508 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\ssure\schanges\sto\svirtual\stables\sare\scounted\sthe\ssame\sas\sreal\stables.\nTicket\s#3038.\s(CVS\s4976) -D 2008-04-10T14:00:10 +C Add\ssource\sfile\stest_osinst.c.\sA\swrapper\svfs\swith\sinstrumentation\scapabilities.\s(CVS\s4977) +D 2008-04-10T14:51:01 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in b861627d91df5ee422c54237aa38296954dc0151 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -66,7 +66,7 @@ F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33 F ext/icu/icu.c 12e763d288d23b5a49de37caa30737b971a2f1e2 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh 56abb507100ed2d4261f6dd1653dec3cf4066387 -F main.mk fb8589de4dff06de85d456ba9d6191447111a61b +F main.mk bab1f708404c928af4769336aa97931062cfe987 F mkdll.sh 712e74f3efe08a6ba12b2945d018a29a89d7fe3b F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextw.sh 1a866b53637dab137191341cc875575a5ca110fb @@ -143,7 +143,7 @@ F src/sqlite3ext.h faacd0e6a81aabee0861c6d7883c9172e74ef5b3 F src/sqliteInt.h 52c381c2f15054a5199e5359cf5deb6d48624ede F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/table.c 2c48c575dd59b3a6c5c306bc55f51a9402cf429a -F src/tclsqlite.c 0d53336f1fc3c8a019adb56fb8daeb0f5b5238aa +F src/tclsqlite.c c4892f48927cb3db19faeb448ea8abddfd4846a8 F src/test1.c aada95d7a7229366e51c71055d5764c920d3364c F src/test2.c f0808cc643528b9620e4059ca9bda8346f526121 F src/test3.c c715b5a8a6415d7b2c67f97c394eef488b6f7e63 @@ -164,6 +164,7 @@ F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8 F src/test_malloc.c c92a65e8f9b31bb2b332448d92d2016c000a963d F src/test_md5.c bca40b727c57462ddb415e57c5323445a1bb1a40 F src/test_onefile.c 2fea6d22f13f5f286356c80c77ffd41f995f2b7a +F src/test_osinst.c b6ef38b4b363a83597f9228d8bf9f63d7dc1f801 F src/test_schema.c 12c9de7661d6294eec2d57afbb52e2af1128084f F src/test_server.c a6ece6c835e7eae835054124e09e947e422b1ac5 F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59 @@ -625,7 +626,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 6f07968ec4c9d773a852ecc8343df416d17af2a4 -R bd0175fc475a5bdf6485d3176fb40c11 -U drh -Z 0137cb2b33b517f6dae0cbba0b9baee6 +P 55591fc49c8ab8146c1f3eff733e637501bff627 +R eb917bb84cf56955a047ec767653c982 +U danielk1977 +Z 1f007475942ab467fd58433a4982bf4d diff --git a/manifest.uuid b/manifest.uuid index 4470063800..4a7287595d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -55591fc49c8ab8146c1f3eff733e637501bff627 \ No newline at end of file +d9a6b653d3cb608610f13d2492fe9b3887acb3b9 \ No newline at end of file diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 47402217a5..d9a3fa44c5 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -12,7 +12,7 @@ ** A TCL Interface to SQLite. Append this file to sqlite3.c and ** compile the whole thing to build a TCL-enabled version of SQLite. ** -** $Id: tclsqlite.c,v 1.214 2008/04/10 13:42:56 drh Exp $ +** $Id: tclsqlite.c,v 1.215 2008/04/10 14:51:01 danielk1977 Exp $ */ #include "tcl.h" #include @@ -2531,6 +2531,7 @@ int TCLSH_MAIN(int argc, char **argv){ extern int Sqlitetesttclvar_Init(Tcl_Interp*); extern int SqlitetestThread_Init(Tcl_Interp*); extern int SqlitetestOnefile_Init(); + extern int SqlitetestOsinst_Init(Tcl_Interp*); Md5_Init(interp); Sqliteconfig_Init(interp); @@ -2552,6 +2553,7 @@ int TCLSH_MAIN(int argc, char **argv){ Sqlitetesttclvar_Init(interp); SqlitetestThread_Init(interp); SqlitetestOnefile_Init(interp); + SqlitetestOsinst_Init(interp); #ifdef SQLITE_SSE Sqlitetestsse_Init(interp); diff --git a/src/test_osinst.c b/src/test_osinst.c new file mode 100644 index 0000000000..28f8fd3f4c --- /dev/null +++ b/src/test_osinst.c @@ -0,0 +1,746 @@ +/* +** 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. +*/ +#if SQLITE_TEST /* This file is used for testing only */ + +/* +** Public interface: +** +** sqlite3_instvfs_create() +** sqlite3_instvfs_destroy() +** sqlite3_instvfs_configure() +** +** sqlite3_instvfs_reset() +** sqlite3_instvfs_get() +** +** Tcl interface: +** +** sqlite3_instvfs create NAME ?PARENT? +** +** Create and register new vfs called $NAME, which is a wrapper around +** the existing vfs $PARENT. If the PARENT argument is omitted, the +** new vfs is a wrapper around the current default vfs. +** +** sqlite3_instvfs destroy NAME +** +** Deregister and destroy the vfs named $NAME, which must have been +** created by an earlier invocation of [sqlite3_instvfs create]. +** +** sqlite3_instvfs configure NAME SCRIPT +** +** Configure the callback script for the vfs $NAME, which much have +** been created by an earlier invocation of [sqlite3_instvfs create]. +** After a callback script has been configured, it is invoked each +** time a vfs or file method is called by SQLite. Before invoking +** the callback script, five arguments are appended to it: +** +** * The name of the invoked method - i.e. "xRead". +** +** * The time consumed by the method call as measured by hwtime() (an +** integer value) +** +** * A string value with a different meaning for different calls. +** For file methods, the name of the file being operated on. For +** other methods it is the filename argument, if any. +** +** * A 32-bit integer value with a call-specific meaning. +** +** * A 64-bit integer value. For xRead() and xWrite() calls this +** is the file offset being written to or read from. Unused by +** all other calls. +** +** sqlite3_instvfs reset NAME +** +** Zero the internal event counters associated with vfs $NAME, +** which must have been created by an earlier invocation of +** [sqlite3_instvfs create]. +** +** sqlite3_instvfs report NAME +** +** Return the values of the internal event counters associated +** with vfs $NAME. The report format is a list with one element +** for each method call (xWrite, xRead etc.). Each element is +** itself a list with three elements: +** +** * The name of the method call - i.e. "xWrite", +** * The total number of calls to the method (an integer). +** * The aggregate time consumed by all calls to the method as +** measured by hwtime() (an integer). +*/ + +#include "sqlite3.h" +#include "sqliteInt.h" + +/* +** Maximum pathname length supported by the inst backend. +*/ +#define INST_MAX_PATHNAME 512 + + +/* File methods */ +#define OS_CLOSE 1 +#define OS_READ 2 +#define OS_WRITE 3 +#define OS_TRUNCATE 4 +#define OS_SYNC 5 +#define OS_FILESIZE 6 +#define OS_LOCK 7 +#define OS_UNLOCK 8 +#define OS_CHECKRESERVEDLOCK 9 +#define OS_FILECONTROL 10 +#define OS_SECTORSIZE 11 +#define OS_DEVCHAR 12 + +/* Vfs methods */ +#define OS_OPEN 13 +#define OS_DELETE 14 +#define OS_ACCESS 15 +#define OS_GETTEMPNAME 16 +#define OS_FULLPATHNAME 17 +#define OS_RANDOMNESS 18 +#define OS_SLEEP 19 +#define OS_CURRENTTIME 20 + +#define OS_NUMEVENTS 21 + +struct InstVfs { + sqlite3_vfs base; + sqlite3_vfs *pVfs; + + void *pClient; + void (*xDel)(void *); + void (*xCall)(void *, int, sqlite3_int64, const char *, int, sqlite3_int64); + + /* Counters */ + i64 aTime[OS_NUMEVENTS]; + int aCount[OS_NUMEVENTS]; +}; +typedef struct InstVfs InstVfs; + +#define REALVFS(p) (((InstVfs *)(p))->pVfs) + +typedef struct inst_file inst_file; +struct inst_file { + sqlite3_file base; + sqlite3_file *pReal; + InstVfs *pInstVfs; + const char *zName; +}; + +/* +** Method declarations for inst_file. +*/ +static int instClose(sqlite3_file*); +static int instRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); +static int instWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); +static int instTruncate(sqlite3_file*, sqlite3_int64 size); +static int instSync(sqlite3_file*, int flags); +static int instFileSize(sqlite3_file*, sqlite3_int64 *pSize); +static int instLock(sqlite3_file*, int); +static int instUnlock(sqlite3_file*, int); +static int instCheckReservedLock(sqlite3_file*); +static int instFileControl(sqlite3_file*, int op, void *pArg); +static int instSectorSize(sqlite3_file*); +static int instDeviceCharacteristics(sqlite3_file*); + +/* +** Method declarations for inst_vfs. +*/ +static int instOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); +static int instDelete(sqlite3_vfs*, const char *zName, int syncDir); +static int instAccess(sqlite3_vfs*, const char *zName, int flags); +static int instGetTempName(sqlite3_vfs*, int nOut, char *zOut); +static int instFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); +static void *instDlOpen(sqlite3_vfs*, const char *zFilename); +static void instDlError(sqlite3_vfs*, int nByte, char *zErrMsg); +static void *instDlSym(sqlite3_vfs*,void*, const char *zSymbol); +static void instDlClose(sqlite3_vfs*, void*); +static int instRandomness(sqlite3_vfs*, int nByte, char *zOut); +static int instSleep(sqlite3_vfs*, int microseconds); +static int instCurrentTime(sqlite3_vfs*, double*); + +static sqlite3_vfs inst_vfs = { + 1, /* iVersion */ + sizeof(inst_file), /* szOsFile */ + INST_MAX_PATHNAME, /* mxPathname */ + 0, /* pNext */ + 0, /* zName */ + 0, /* pAppData */ + instOpen, /* xOpen */ + instDelete, /* xDelete */ + instAccess, /* xAccess */ + instGetTempName, /* xGetTempName */ + instFullPathname, /* xFullPathname */ + instDlOpen, /* xDlOpen */ + instDlError, /* xDlError */ + instDlSym, /* xDlSym */ + instDlClose, /* xDlClose */ + instRandomness, /* xRandomness */ + instSleep, /* xSleep */ + instCurrentTime /* xCurrentTime */ +}; + +static sqlite3_io_methods inst_io_methods = { + 1, /* iVersion */ + instClose, /* xClose */ + instRead, /* xRead */ + instWrite, /* xWrite */ + instTruncate, /* xTruncate */ + instSync, /* xSync */ + instFileSize, /* xFileSize */ + instLock, /* xLock */ + instUnlock, /* xUnlock */ + instCheckReservedLock, /* xCheckReservedLock */ + instFileControl, /* xFileControl */ + instSectorSize, /* xSectorSize */ + instDeviceCharacteristics /* xDeviceCharacteristics */ +}; + +/* +** The following routine only works on pentium-class processors. +** It uses the RDTSC opcode to read the cycle count value out of the +** processor and returns that value. This can be used for high-res +** profiling. +*/ +__inline__ unsigned long long int hwtime(void){ + unsigned long long int x; + __asm__("rdtsc\n\t" + "mov %%edx, %%ecx\n\t" + :"=A" (x)); + return x; +} + +#define OS_TIME_IO(eEvent, A, B, Call) { \ + inst_file *p = (inst_file *)pFile; \ + InstVfs *pInstVfs = p->pInstVfs; \ + int rc; \ + i64 t = hwtime(); \ + rc = Call; \ + t = hwtime() - t; \ + pInstVfs->aTime[eEvent] += t; \ + pInstVfs->aCount[eEvent] += 1; \ + if( pInstVfs->xCall ){ \ + pInstVfs->xCall(pInstVfs->pClient, eEvent, t, p->zName, A, B); \ + } \ + return rc; \ +} + +#define OS_TIME_VFS(eEvent, Z, A, B, Call) { \ + InstVfs *pInstVfs = (InstVfs *)pVfs; \ + int rc; \ + i64 t = hwtime(); \ + rc = Call; \ + t = hwtime() - t; \ + pInstVfs->aTime[eEvent] += t; \ + pInstVfs->aCount[eEvent] += 1; \ + if( pInstVfs->xCall ){ \ + pInstVfs->xCall(pInstVfs->pClient, eEvent, t, Z, A, B); \ + } \ + return rc; \ +} + +/* +** Close an inst-file. +*/ +static int instClose(sqlite3_file *pFile){ + OS_TIME_IO(OS_CLOSE, 0, 0, sqlite3OsClose(p->pReal)); +} + +/* +** Read data from an inst-file. +*/ +static int instRead( + sqlite3_file *pFile, + void *zBuf, + int iAmt, + sqlite_int64 iOfst +){ + OS_TIME_IO(OS_READ, iAmt, iOfst, sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst)); +} + +/* +** Write data to an inst-file. +*/ +static int instWrite( + sqlite3_file *pFile, + const void *z, + int iAmt, + sqlite_int64 iOfst +){ + OS_TIME_IO(OS_WRITE, iAmt, iOfst, sqlite3OsWrite(p->pReal, z, iAmt, iOfst)); +} + +/* +** Truncate an inst-file. +*/ +static int instTruncate(sqlite3_file *pFile, sqlite_int64 size){ + OS_TIME_IO(OS_TRUNCATE, 0, size, sqlite3OsTruncate(p->pReal, size)); +} + +/* +** Sync an inst-file. +*/ +static int instSync(sqlite3_file *pFile, int flags){ + OS_TIME_IO(OS_SYNC, flags, 0, sqlite3OsSync(p->pReal, flags)); +} + +/* +** Return the current file-size of an inst-file. +*/ +static int instFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ + OS_TIME_IO(OS_FILESIZE, 0, 0, sqlite3OsFileSize(p->pReal, pSize)); +} + +/* +** Lock an inst-file. +*/ +static int instLock(sqlite3_file *pFile, int eLock){ + OS_TIME_IO(OS_LOCK, eLock, 0, sqlite3OsLock(p->pReal, eLock)); +} + +/* +** Unlock an inst-file. +*/ +static int instUnlock(sqlite3_file *pFile, int eLock){ + OS_TIME_IO(OS_UNLOCK, eLock, 0, sqlite3OsUnlock(p->pReal, eLock)); +} + +/* +** Check if another file-handle holds a RESERVED lock on an inst-file. +*/ +static int instCheckReservedLock(sqlite3_file *pFile){ + OS_TIME_IO(OS_CHECKRESERVEDLOCK, 0, 0, sqlite3OsCheckReservedLock(p->pReal)); +} + +/* +** File control method. For custom operations on an inst-file. +*/ +static int instFileControl(sqlite3_file *pFile, int op, void *pArg){ + OS_TIME_IO(OS_FILECONTROL, 0, 0, sqlite3OsFileControl(p->pReal, op, pArg)); +} + +/* +** Return the sector-size in bytes for an inst-file. +*/ +static int instSectorSize(sqlite3_file *pFile){ + OS_TIME_IO(OS_SECTORSIZE, 0, 0, sqlite3OsSectorSize(p->pReal)); +} + +/* +** Return the device characteristic flags supported by an inst-file. +*/ +static int instDeviceCharacteristics(sqlite3_file *pFile){ + OS_TIME_IO(OS_DEVCHAR, 0, 0, sqlite3OsDeviceCharacteristics(p->pReal)); +} + +/* +** Open an inst file handle. +*/ +static int instOpen( + sqlite3_vfs *pVfs, + const char *zName, + sqlite3_file *pFile, + int flags, + int *pOutFlags +){ + inst_file *p = (inst_file *)pFile; + pFile->pMethods = &inst_io_methods; + p->pReal = (sqlite3_file *)&p[1]; + p->pInstVfs = (InstVfs *)pVfs; + p->zName = zName; + + OS_TIME_VFS(OS_OPEN, zName, flags, 0, + sqlite3OsOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags) + ); +} + +/* +** 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 instDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ + OS_TIME_VFS(OS_DELETE, zPath, dirSync, 0, + sqlite3OsDelete(REALVFS(pVfs), zPath, dirSync) + ); +} + +/* +** Test for access permissions. Return true if the requested permission +** is available, or false otherwise. +*/ +static int instAccess(sqlite3_vfs *pVfs, const char *zPath, int flags){ + OS_TIME_VFS(OS_ACCESS, zPath, flags, 0, + sqlite3OsAccess(REALVFS(pVfs), zPath, flags) + ); +} + +/* +** Populate buffer zBufOut with a pathname suitable for use as a +** temporary file. zBufOut is guaranteed to point to a buffer of +** at least (INST_MAX_PATHNAME+1) bytes. +*/ +static int instGetTempName(sqlite3_vfs *pVfs, int nOut, char *zBufOut){ + OS_TIME_VFS( OS_GETTEMPNAME, 0, 0, 0, + sqlite3OsGetTempname(REALVFS(pVfs), nOut, zBufOut); + ); +} + +/* +** 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 instFullPathname( + sqlite3_vfs *pVfs, + const char *zPath, + int nOut, + char *zOut +){ + OS_TIME_VFS( OS_FULLPATHNAME, zPath, 0, 0, + sqlite3OsFullPathname(REALVFS(pVfs), zPath, nOut, zOut); + ); +} + +/* +** Open the dynamic library located at zPath and return a handle. +*/ +static void *instDlOpen(sqlite3_vfs *pVfs, const char *zPath){ + return sqlite3OsDlOpen(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 instDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ + sqlite3OsDlError(REALVFS(pVfs), nByte, zErrMsg); +} + +/* +** Return a pointer to the symbol zSymbol in the dynamic library pHandle. +*/ +static void *instDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ + return sqlite3OsDlSym(REALVFS(pVfs), pHandle, zSymbol); +} + +/* +** Close the dynamic library handle pHandle. +*/ +static void instDlClose(sqlite3_vfs *pVfs, void *pHandle){ + sqlite3OsDlClose(REALVFS(pVfs), pHandle); +} + +/* +** Populate the buffer pointed to by zBufOut with nByte bytes of +** random data. +*/ +static int instRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ + OS_TIME_VFS( OS_RANDOMNESS, 0, nByte, 0, + sqlite3OsRandomness(REALVFS(pVfs), nByte, zBufOut); + ); +} + +/* +** Sleep for nMicro microseconds. Return the number of microseconds +** actually slept. +*/ +static int instSleep(sqlite3_vfs *pVfs, int nMicro){ + OS_TIME_VFS( OS_SLEEP, 0, nMicro, 0, + sqlite3OsSleep(REALVFS(pVfs), nMicro) + ); +} + +/* +** Return the current time as a Julian Day number in *pTimeOut. +*/ +static int instCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ + OS_TIME_VFS( OS_CURRENTTIME, 0, 0, 0, + sqlite3OsCurrentTime(REALVFS(pVfs), pTimeOut) + ); +} + +sqlite3_vfs *sqlite3_instvfs_create(char *zName, char *zParent){ + int nByte; + InstVfs *p; + sqlite3_vfs *pParent; + + pParent = sqlite3_vfs_find(zParent); + if( !pParent ){ + return 0; + } + + nByte = strlen(zName) + 1 + sizeof(InstVfs); + p = (InstVfs *)sqlite3_malloc(nByte); + if( p ){ + char *zCopy = (char *)&p[1]; + memset(p, 0, nByte); + memcpy(p, &inst_vfs, sizeof(sqlite3_vfs)); + p->pVfs = pParent; + memcpy(zCopy, zName, strlen(zName)); + p->base.zName = (const char *)zCopy; + p->base.szOsFile += pParent->szOsFile; + sqlite3_vfs_register((sqlite3_vfs *)p, 0); + } + + return (sqlite3_vfs *)p; +} + +void sqlite3_instvfs_configure( + sqlite3_vfs *pVfs, + void (*xCall)(void *, int, sqlite3_int64, const char *, int, sqlite3_int64), + void *pClient, + void (*xDel)(void *) +){ + InstVfs *p = (InstVfs *)pVfs; + assert( pVfs->xOpen==instOpen ); + if( p->xDel ){ + p->xDel(p->pClient); + } + p->xCall = xCall; + p->xDel = xDel; + p->pClient = pClient; +} + +void sqlite3_instvfs_destroy(sqlite3_vfs *pVfs){ + sqlite3_vfs_unregister(pVfs); + sqlite3_free(pVfs); +} + +void sqlite3_instvfs_reset(sqlite3_vfs *pVfs){ + InstVfs *p = (InstVfs *)pVfs; + assert( pVfs->xOpen==instOpen ); + memset(p->aTime, 0, sizeof(i64)*OS_NUMEVENTS); + memset(p->aCount, 0, sizeof(int)*OS_NUMEVENTS); +} + +const char *sqlite3_instvfs_name(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 = "xCheckReservedLock"; break; + case OS_FILECONTROL: zEvent = "xFileControl"; break; + case OS_SECTORSIZE: zEvent = "xSectorSize"; break; + case OS_DEVCHAR: zEvent = "xDeviceCharacteristics"; break; + case OS_OPEN: zEvent = "xOpen"; break; + case OS_DELETE: zEvent = "xDelete"; break; + case OS_ACCESS: zEvent = "xAccess"; break; + case OS_GETTEMPNAME: zEvent = "xGetTempName"; 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; + } + + return zEvent; +} + +void sqlite3_instvfs_get( + sqlite3_vfs *pVfs, + int eEvent, + const char **pzEvent, + sqlite3_int64 *pnClick, + int *pnCall +){ + InstVfs *p = (InstVfs *)pVfs; + assert( pVfs->xOpen==instOpen ); + if( eEvent<1 || eEvent>=OS_NUMEVENTS ){ + *pzEvent = 0; + *pnClick = 0; + *pnCall = 0; + return; + } + + *pzEvent = sqlite3_instvfs_name(eEvent); + *pnClick = p->aTime[eEvent]; + *pnCall = p->aCount[eEvent]; +} + +/************************************************************************** +*************************************************************************** +** Tcl interface starts here. +*/ + +#include + +struct InstVfsCall { + Tcl_Interp *interp; + Tcl_Obj *pScript; +}; +typedef struct InstVfsCall InstVfsCall; + +static void test_instvfs_xcall( + void *p, + int eEvent, + sqlite3_int64 nClick, + const char *zName, + int nByte, + sqlite3_int64 iOffset +){ + int rc; + InstVfsCall *pCall = (InstVfsCall *)p; + Tcl_Obj *pObj = Tcl_DuplicateObj( pCall->pScript); + const char *zEvent = sqlite3_instvfs_name(eEvent); + + Tcl_IncrRefCount(pObj); + Tcl_ListObjAppendElement(0, pObj, Tcl_NewStringObj(zEvent, -1)); + Tcl_ListObjAppendElement(0, pObj, Tcl_NewWideIntObj(nClick)); + Tcl_ListObjAppendElement(0, pObj, Tcl_NewStringObj(zName, -1)); + Tcl_ListObjAppendElement(0, pObj, Tcl_NewIntObj(nByte)); + Tcl_ListObjAppendElement(0, pObj, Tcl_NewWideIntObj(iOffset)); + + rc = Tcl_EvalObjEx(pCall->interp, pObj, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); + if( rc ){ + Tcl_BackgroundError(pCall->interp); + } + Tcl_DecrRefCount(pObj); +} + +static void test_instvfs_xdel(void *p){ + InstVfsCall *pCall = (InstVfsCall *)p; + Tcl_DecrRefCount(pCall->pScript); + sqlite3_free(pCall); +} + +static int test_sqlite3_instvfs( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + static const char *IV_strs[] = + { "create", "destroy", "reset", "report", "configure", 0 }; + enum IV_enum { IV_CREATE, IV_DESTROY, IV_RESET, IV_REPORT, IV_CONFIGURE }; + int iSub; + + if( objc<2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ..."); + } + if( Tcl_GetIndexFromObj(interp, objv[1], IV_strs, "sub-command", 0, &iSub) ){ + return TCL_ERROR; + } + + switch( (enum IV_enum)iSub ){ + case IV_CREATE: { + char *zParent = 0; + sqlite3_vfs *p; + if( objc!=4 && objc!=3 ){ + Tcl_WrongNumArgs(interp, 2, objv, "NAME ?PARENT-VFS?"); + return TCL_ERROR; + } + if( objc==4 ){ + zParent = Tcl_GetString(objv[3]); + } + p = sqlite3_instvfs_create(Tcl_GetString(objv[2]), zParent); + if( !p ){ + Tcl_AppendResult(interp, "error creating vfs ", 0); + return TCL_ERROR; + } + Tcl_SetObjResult(interp, objv[2]); + break; + } + + case IV_CONFIGURE: { + InstVfsCall *pCall; + + sqlite3_vfs *p; + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); + return TCL_ERROR; + } + p = sqlite3_vfs_find(Tcl_GetString(objv[2])); + if( !p || p->xOpen!=instOpen ){ + Tcl_AppendResult(interp, "no such vfs: ", Tcl_GetString(objv[2]), 0); + return TCL_ERROR; + } + + if( strlen(Tcl_GetString(objv[3])) ){ + pCall = (InstVfsCall *)sqlite3_malloc(sizeof(InstVfsCall)); + pCall->interp = interp; + pCall->pScript = Tcl_DuplicateObj(objv[3]); + Tcl_IncrRefCount(pCall->pScript); + sqlite3_instvfs_configure(p, + test_instvfs_xcall, (void *)pCall, test_instvfs_xdel + ); + }else{ + sqlite3_instvfs_configure(p, 0, 0, 0); + } + break; + } + + case IV_REPORT: + case IV_DESTROY: + case IV_RESET: { + sqlite3_vfs *p; + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 2, objv, "NAME"); + return TCL_ERROR; + } + p = sqlite3_vfs_find(Tcl_GetString(objv[2])); + if( !p || p->xOpen!=instOpen ){ + Tcl_AppendResult(interp, "no such vfs: ", Tcl_GetString(objv[2]), 0); + return TCL_ERROR; + } + + if( ((enum IV_enum)iSub)==IV_DESTROY ){ + sqlite3_instvfs_destroy(p); + } + if( ((enum IV_enum)iSub)==IV_RESET ){ + sqlite3_instvfs_reset(p); + } + if( ((enum IV_enum)iSub)==IV_REPORT ){ + int ii; + Tcl_Obj *pRet = Tcl_NewObj(); + + const char *zName = (char *)1; + i64 nClick; + int nCall; + for(ii=1; zName; ii++){ + sqlite3_instvfs_get(p, ii, &zName, &nClick, &nCall); + if( zName ){ + Tcl_Obj *pElem = Tcl_NewObj(); + Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj(zName, -1)); + Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(nCall)); + Tcl_ListObjAppendElement(0, pElem, Tcl_NewWideIntObj(nClick)); + Tcl_ListObjAppendElement(0, pRet, pElem); + } + } + + Tcl_SetObjResult(interp, pRet); + } + + break; + } + } + + return TCL_OK; +} + +int SqlitetestOsinst_Init(Tcl_Interp *interp){ + Tcl_CreateObjCommand(interp, "sqlite3_instvfs", test_sqlite3_instvfs, 0, 0); + return TCL_OK; +} + +#endif