13c40ae7dSdrh /*
23c40ae7dSdrh ** 2016-05-27
33c40ae7dSdrh **
43c40ae7dSdrh ** The author disclaims copyright to this source code. In place of
53c40ae7dSdrh ** a legal notice, here is a blessing:
63c40ae7dSdrh **
73c40ae7dSdrh ** May you do good and not evil.
83c40ae7dSdrh ** May you find forgiveness for yourself and forgive others.
93c40ae7dSdrh ** May you share freely, never taking more than you give.
103c40ae7dSdrh **
113c40ae7dSdrh ******************************************************************************
123c40ae7dSdrh **
133c40ae7dSdrh ** This file contains the implementation of an SQLite vfs shim that
143c40ae7dSdrh ** tracks I/O. Access to the accumulated status counts is provided using
153c40ae7dSdrh ** an eponymous virtual table.
163c40ae7dSdrh */
173c40ae7dSdrh #include <sqlite3ext.h>
183c40ae7dSdrh SQLITE_EXTENSION_INIT1
193c40ae7dSdrh
203c40ae7dSdrh /*
213c40ae7dSdrh ** This module contains code for a wrapper VFS that cause stats for
223c40ae7dSdrh ** most VFS calls to be recorded.
233c40ae7dSdrh **
243c40ae7dSdrh ** To use this module, first compile it as a loadable extension. See
253c40ae7dSdrh ** https://www.sqlite.org/loadext.html#build for compilations instructions.
263c40ae7dSdrh **
273c40ae7dSdrh ** After compliing, load this extension, then open database connections to be
283c40ae7dSdrh ** measured. Query usages status using the vfsstat virtual table:
293c40ae7dSdrh **
303c40ae7dSdrh ** SELECT * FROM vfsstat;
313c40ae7dSdrh **
323c40ae7dSdrh ** Reset counters using UPDATE statements against vfsstat:
333c40ae7dSdrh **
343c40ae7dSdrh ** UPDATE vfsstat SET count=0;
353c40ae7dSdrh **
363c40ae7dSdrh ** EXAMPLE SCRIPT:
373c40ae7dSdrh **
383c40ae7dSdrh ** .load ./vfsstat
393c40ae7dSdrh ** .open test.db
403c40ae7dSdrh ** DROP TABLE IF EXISTS t1;
413c40ae7dSdrh ** CREATE TABLE t1(x,y);
423c40ae7dSdrh ** INSERT INTO t1 VALUES(123, randomblob(5000));
433c40ae7dSdrh ** CREATE INDEX t1x ON t1(x);
443c40ae7dSdrh ** DROP TABLE t1;
453c40ae7dSdrh ** VACUUM;
463c40ae7dSdrh ** SELECT * FROM vfsstat WHERE count>0;
473c40ae7dSdrh **
483c40ae7dSdrh ** LIMITATIONS:
493c40ae7dSdrh **
503c40ae7dSdrh ** This module increments counters without using mutex protection. So if
513c40ae7dSdrh ** two or more threads try to use this module at the same time, race conditions
523c40ae7dSdrh ** may occur which mess up the counts. This is harmless, other than giving
533c40ae7dSdrh ** incorrect statistics.
543c40ae7dSdrh */
553c40ae7dSdrh #include <string.h>
563c40ae7dSdrh #include <stdlib.h>
573c40ae7dSdrh #include <assert.h>
583c40ae7dSdrh
593c40ae7dSdrh /*
603c40ae7dSdrh ** File types
613c40ae7dSdrh */
623c40ae7dSdrh #define VFSSTAT_MAIN 0 /* Main database file */
633c40ae7dSdrh #define VFSSTAT_JOURNAL 1 /* Rollback journal */
643c40ae7dSdrh #define VFSSTAT_WAL 2 /* Write-ahead log file */
653c40ae7dSdrh #define VFSSTAT_MASTERJRNL 3 /* Master journal */
663c40ae7dSdrh #define VFSSTAT_SUBJRNL 4 /* Subjournal */
673c40ae7dSdrh #define VFSSTAT_TEMPDB 5 /* TEMP database */
683c40ae7dSdrh #define VFSSTAT_TEMPJRNL 6 /* Journal for TEMP database */
693c40ae7dSdrh #define VFSSTAT_TRANSIENT 7 /* Transient database */
703c40ae7dSdrh #define VFSSTAT_ANY 8 /* Unspecified file type */
713c40ae7dSdrh #define VFSSTAT_nFile 9 /* This many file types */
723c40ae7dSdrh
733c40ae7dSdrh /* Names of the file types. These are allowed values for the
743c40ae7dSdrh ** first column of the vfsstat virtual table.
753c40ae7dSdrh */
763c40ae7dSdrh static const char *azFile[] = {
773c40ae7dSdrh "database", "journal", "wal", "master-journal", "sub-journal",
783c40ae7dSdrh "temp-database", "temp-journal", "transient-db", "*"
793c40ae7dSdrh };
803c40ae7dSdrh
813c40ae7dSdrh /*
823c40ae7dSdrh ** Stat types
833c40ae7dSdrh */
843c40ae7dSdrh #define VFSSTAT_BYTESIN 0 /* Bytes read in */
853c40ae7dSdrh #define VFSSTAT_BYTESOUT 1 /* Bytes written out */
863c40ae7dSdrh #define VFSSTAT_READ 2 /* Read requests */
873c40ae7dSdrh #define VFSSTAT_WRITE 3 /* Write requests */
883c40ae7dSdrh #define VFSSTAT_SYNC 4 /* Syncs */
893c40ae7dSdrh #define VFSSTAT_OPEN 5 /* File opens */
903c40ae7dSdrh #define VFSSTAT_LOCK 6 /* Lock requests */
913c40ae7dSdrh #define VFSSTAT_ACCESS 0 /* xAccess calls. filetype==ANY only */
923c40ae7dSdrh #define VFSSTAT_DELETE 1 /* xDelete calls. filetype==ANY only */
933c40ae7dSdrh #define VFSSTAT_FULLPATH 2 /* xFullPathname calls. ANY only */
943c40ae7dSdrh #define VFSSTAT_RANDOM 3 /* xRandomness calls. ANY only */
953c40ae7dSdrh #define VFSSTAT_SLEEP 4 /* xSleep calls. ANY only */
963c40ae7dSdrh #define VFSSTAT_CURTIME 5 /* xCurrentTime calls. ANY only */
973c40ae7dSdrh #define VFSSTAT_nStat 7 /* This many stat types */
983c40ae7dSdrh
993c40ae7dSdrh
1003c40ae7dSdrh /* Names for the second column of the vfsstat virtual table for all
1013c40ae7dSdrh ** cases except when the first column is "*" or VFSSTAT_ANY. */
1023c40ae7dSdrh static const char *azStat[] = {
1033c40ae7dSdrh "bytes-in", "bytes-out", "read", "write", "sync", "open", "lock",
1043c40ae7dSdrh };
1053c40ae7dSdrh static const char *azStatAny[] = {
1063c40ae7dSdrh "access", "delete", "fullpathname", "randomness", "sleep", "currenttimestamp",
1073c40ae7dSdrh "not-used"
1083c40ae7dSdrh };
1093c40ae7dSdrh
1103c40ae7dSdrh /* Total number of counters */
1113c40ae7dSdrh #define VFSSTAT_MXCNT (VFSSTAT_nStat*VFSSTAT_nFile)
1123c40ae7dSdrh
1133c40ae7dSdrh /*
1143c40ae7dSdrh ** Performance stats are collected in an instance of the following
1153c40ae7dSdrh ** global array.
1163c40ae7dSdrh */
1173c40ae7dSdrh static sqlite3_uint64 aVfsCnt[VFSSTAT_MXCNT];
1183c40ae7dSdrh
1193c40ae7dSdrh /*
1203c40ae7dSdrh ** Access to a specific counter
1213c40ae7dSdrh */
1223c40ae7dSdrh #define STATCNT(filetype,stat) (aVfsCnt[(filetype)*VFSSTAT_nStat+(stat)])
1233c40ae7dSdrh
1243c40ae7dSdrh /*
1253c40ae7dSdrh ** Forward declaration of objects used by this utility
1263c40ae7dSdrh */
1273c40ae7dSdrh typedef struct VStatVfs VStatVfs;
1283c40ae7dSdrh typedef struct VStatFile VStatFile;
1293c40ae7dSdrh
1303c40ae7dSdrh /* An instance of the VFS */
1313c40ae7dSdrh struct VStatVfs {
1323c40ae7dSdrh sqlite3_vfs base; /* VFS methods */
1333c40ae7dSdrh sqlite3_vfs *pVfs; /* Parent VFS */
1343c40ae7dSdrh };
1353c40ae7dSdrh
1363c40ae7dSdrh /* An open file */
1373c40ae7dSdrh struct VStatFile {
1383c40ae7dSdrh sqlite3_file base; /* IO methods */
1393c40ae7dSdrh sqlite3_file *pReal; /* Underlying file handle */
1403c40ae7dSdrh unsigned char eFiletype; /* What type of file is this */
1413c40ae7dSdrh };
1423c40ae7dSdrh
1433c40ae7dSdrh #define REALVFS(p) (((VStatVfs*)(p))->pVfs)
1443c40ae7dSdrh
1453c40ae7dSdrh /*
1463c40ae7dSdrh ** Methods for VStatFile
1473c40ae7dSdrh */
1483c40ae7dSdrh static int vstatClose(sqlite3_file*);
1493c40ae7dSdrh static int vstatRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
1503c40ae7dSdrh static int vstatWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
1513c40ae7dSdrh static int vstatTruncate(sqlite3_file*, sqlite3_int64 size);
1523c40ae7dSdrh static int vstatSync(sqlite3_file*, int flags);
1533c40ae7dSdrh static int vstatFileSize(sqlite3_file*, sqlite3_int64 *pSize);
1543c40ae7dSdrh static int vstatLock(sqlite3_file*, int);
1553c40ae7dSdrh static int vstatUnlock(sqlite3_file*, int);
1563c40ae7dSdrh static int vstatCheckReservedLock(sqlite3_file*, int *pResOut);
1573c40ae7dSdrh static int vstatFileControl(sqlite3_file*, int op, void *pArg);
1583c40ae7dSdrh static int vstatSectorSize(sqlite3_file*);
1593c40ae7dSdrh static int vstatDeviceCharacteristics(sqlite3_file*);
1603c40ae7dSdrh static int vstatShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
1613c40ae7dSdrh static int vstatShmLock(sqlite3_file*, int offset, int n, int flags);
1623c40ae7dSdrh static void vstatShmBarrier(sqlite3_file*);
1633c40ae7dSdrh static int vstatShmUnmap(sqlite3_file*, int deleteFlag);
1643c40ae7dSdrh static int vstatFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
1653c40ae7dSdrh static int vstatUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
1663c40ae7dSdrh
1673c40ae7dSdrh /*
1683c40ae7dSdrh ** Methods for VStatVfs
1693c40ae7dSdrh */
1703c40ae7dSdrh static int vstatOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
1713c40ae7dSdrh static int vstatDelete(sqlite3_vfs*, const char *zName, int syncDir);
1723c40ae7dSdrh static int vstatAccess(sqlite3_vfs*, const char *zName, int flags, int *);
1733c40ae7dSdrh static int vstatFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
1743c40ae7dSdrh static void *vstatDlOpen(sqlite3_vfs*, const char *zFilename);
1753c40ae7dSdrh static void vstatDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
1763c40ae7dSdrh static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
1773c40ae7dSdrh static void vstatDlClose(sqlite3_vfs*, void*);
1783c40ae7dSdrh static int vstatRandomness(sqlite3_vfs*, int nByte, char *zOut);
1793c40ae7dSdrh static int vstatSleep(sqlite3_vfs*, int microseconds);
1803c40ae7dSdrh static int vstatCurrentTime(sqlite3_vfs*, double*);
1813c40ae7dSdrh static int vstatGetLastError(sqlite3_vfs*, int, char *);
1823c40ae7dSdrh static int vstatCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
1833c40ae7dSdrh
1843c40ae7dSdrh static VStatVfs vstat_vfs = {
1853c40ae7dSdrh {
1863c40ae7dSdrh 2, /* iVersion */
1873c40ae7dSdrh 0, /* szOsFile (set by register_vstat()) */
1883c40ae7dSdrh 1024, /* mxPathname */
1893c40ae7dSdrh 0, /* pNext */
1903c40ae7dSdrh "vfslog", /* zName */
1913c40ae7dSdrh 0, /* pAppData */
1923c40ae7dSdrh vstatOpen, /* xOpen */
1933c40ae7dSdrh vstatDelete, /* xDelete */
1943c40ae7dSdrh vstatAccess, /* xAccess */
1953c40ae7dSdrh vstatFullPathname, /* xFullPathname */
1963c40ae7dSdrh vstatDlOpen, /* xDlOpen */
1973c40ae7dSdrh vstatDlError, /* xDlError */
1983c40ae7dSdrh vstatDlSym, /* xDlSym */
1993c40ae7dSdrh vstatDlClose, /* xDlClose */
2003c40ae7dSdrh vstatRandomness, /* xRandomness */
2013c40ae7dSdrh vstatSleep, /* xSleep */
2023c40ae7dSdrh vstatCurrentTime, /* xCurrentTime */
2033c40ae7dSdrh vstatGetLastError, /* xGetLastError */
2043c40ae7dSdrh vstatCurrentTimeInt64 /* xCurrentTimeInt64 */
2053c40ae7dSdrh },
2063c40ae7dSdrh 0
2073c40ae7dSdrh };
2083c40ae7dSdrh
2093c40ae7dSdrh static const sqlite3_io_methods vstat_io_methods = {
2103c40ae7dSdrh 3, /* iVersion */
2113c40ae7dSdrh vstatClose, /* xClose */
2123c40ae7dSdrh vstatRead, /* xRead */
2133c40ae7dSdrh vstatWrite, /* xWrite */
2143c40ae7dSdrh vstatTruncate, /* xTruncate */
2153c40ae7dSdrh vstatSync, /* xSync */
2163c40ae7dSdrh vstatFileSize, /* xFileSize */
2173c40ae7dSdrh vstatLock, /* xLock */
2183c40ae7dSdrh vstatUnlock, /* xUnlock */
2193c40ae7dSdrh vstatCheckReservedLock, /* xCheckReservedLock */
2203c40ae7dSdrh vstatFileControl, /* xFileControl */
2213c40ae7dSdrh vstatSectorSize, /* xSectorSize */
2223c40ae7dSdrh vstatDeviceCharacteristics, /* xDeviceCharacteristics */
2233c40ae7dSdrh vstatShmMap, /* xShmMap */
2243c40ae7dSdrh vstatShmLock, /* xShmLock */
2253c40ae7dSdrh vstatShmBarrier, /* xShmBarrier */
2263c40ae7dSdrh vstatShmUnmap, /* xShmUnmap */
2273c40ae7dSdrh vstatFetch, /* xFetch */
2283c40ae7dSdrh vstatUnfetch /* xUnfetch */
2293c40ae7dSdrh };
2303c40ae7dSdrh
2313c40ae7dSdrh
2323c40ae7dSdrh
2333c40ae7dSdrh /*
2343c40ae7dSdrh ** Close an vstat-file.
2353c40ae7dSdrh */
vstatClose(sqlite3_file * pFile)2363c40ae7dSdrh static int vstatClose(sqlite3_file *pFile){
2373c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
2383c40ae7dSdrh int rc = SQLITE_OK;
2393c40ae7dSdrh
2403c40ae7dSdrh if( p->pReal->pMethods ){
2413c40ae7dSdrh rc = p->pReal->pMethods->xClose(p->pReal);
2423c40ae7dSdrh }
2433c40ae7dSdrh return rc;
2443c40ae7dSdrh }
2453c40ae7dSdrh
2463c40ae7dSdrh
2473c40ae7dSdrh /*
2483c40ae7dSdrh ** Read data from an vstat-file.
2493c40ae7dSdrh */
vstatRead(sqlite3_file * pFile,void * zBuf,int iAmt,sqlite_int64 iOfst)2503c40ae7dSdrh static int vstatRead(
2513c40ae7dSdrh sqlite3_file *pFile,
2523c40ae7dSdrh void *zBuf,
2533c40ae7dSdrh int iAmt,
2543c40ae7dSdrh sqlite_int64 iOfst
2553c40ae7dSdrh ){
2563c40ae7dSdrh int rc;
2573c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
2583c40ae7dSdrh
2593c40ae7dSdrh rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
2603c40ae7dSdrh STATCNT(p->eFiletype,VFSSTAT_READ)++;
2613c40ae7dSdrh if( rc==SQLITE_OK ){
2623c40ae7dSdrh STATCNT(p->eFiletype,VFSSTAT_BYTESIN) += iAmt;
2633c40ae7dSdrh }
2643c40ae7dSdrh return rc;
2653c40ae7dSdrh }
2663c40ae7dSdrh
2673c40ae7dSdrh /*
2683c40ae7dSdrh ** Write data to an vstat-file.
2693c40ae7dSdrh */
vstatWrite(sqlite3_file * pFile,const void * z,int iAmt,sqlite_int64 iOfst)2703c40ae7dSdrh static int vstatWrite(
2713c40ae7dSdrh sqlite3_file *pFile,
2723c40ae7dSdrh const void *z,
2733c40ae7dSdrh int iAmt,
2743c40ae7dSdrh sqlite_int64 iOfst
2753c40ae7dSdrh ){
2763c40ae7dSdrh int rc;
2773c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
2783c40ae7dSdrh
2793c40ae7dSdrh rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
2803c40ae7dSdrh STATCNT(p->eFiletype,VFSSTAT_WRITE)++;
2813c40ae7dSdrh if( rc==SQLITE_OK ){
2823c40ae7dSdrh STATCNT(p->eFiletype,VFSSTAT_BYTESOUT) += iAmt;
2833c40ae7dSdrh }
2843c40ae7dSdrh return rc;
2853c40ae7dSdrh }
2863c40ae7dSdrh
2873c40ae7dSdrh /*
2883c40ae7dSdrh ** Truncate an vstat-file.
2893c40ae7dSdrh */
vstatTruncate(sqlite3_file * pFile,sqlite_int64 size)2903c40ae7dSdrh static int vstatTruncate(sqlite3_file *pFile, sqlite_int64 size){
2913c40ae7dSdrh int rc;
2923c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
2933c40ae7dSdrh rc = p->pReal->pMethods->xTruncate(p->pReal, size);
2943c40ae7dSdrh return rc;
2953c40ae7dSdrh }
2963c40ae7dSdrh
2973c40ae7dSdrh /*
2983c40ae7dSdrh ** Sync an vstat-file.
2993c40ae7dSdrh */
vstatSync(sqlite3_file * pFile,int flags)3003c40ae7dSdrh static int vstatSync(sqlite3_file *pFile, int flags){
3013c40ae7dSdrh int rc;
3023c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
3033c40ae7dSdrh rc = p->pReal->pMethods->xSync(p->pReal, flags);
3043c40ae7dSdrh STATCNT(p->eFiletype,VFSSTAT_SYNC)++;
3053c40ae7dSdrh return rc;
3063c40ae7dSdrh }
3073c40ae7dSdrh
3083c40ae7dSdrh /*
3093c40ae7dSdrh ** Return the current file-size of an vstat-file.
3103c40ae7dSdrh */
vstatFileSize(sqlite3_file * pFile,sqlite_int64 * pSize)3113c40ae7dSdrh static int vstatFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
3123c40ae7dSdrh int rc;
3133c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
3143c40ae7dSdrh rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
3153c40ae7dSdrh return rc;
3163c40ae7dSdrh }
3173c40ae7dSdrh
3183c40ae7dSdrh /*
3193c40ae7dSdrh ** Lock an vstat-file.
3203c40ae7dSdrh */
vstatLock(sqlite3_file * pFile,int eLock)3213c40ae7dSdrh static int vstatLock(sqlite3_file *pFile, int eLock){
3223c40ae7dSdrh int rc;
3233c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
3243c40ae7dSdrh rc = p->pReal->pMethods->xLock(p->pReal, eLock);
3253c40ae7dSdrh STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
3263c40ae7dSdrh return rc;
3273c40ae7dSdrh }
3283c40ae7dSdrh
3293c40ae7dSdrh /*
3303c40ae7dSdrh ** Unlock an vstat-file.
3313c40ae7dSdrh */
vstatUnlock(sqlite3_file * pFile,int eLock)3323c40ae7dSdrh static int vstatUnlock(sqlite3_file *pFile, int eLock){
3333c40ae7dSdrh int rc;
3343c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
3353c40ae7dSdrh rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
3363c40ae7dSdrh STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
3373c40ae7dSdrh return rc;
3383c40ae7dSdrh }
3393c40ae7dSdrh
3403c40ae7dSdrh /*
3413c40ae7dSdrh ** Check if another file-handle holds a RESERVED lock on an vstat-file.
3423c40ae7dSdrh */
vstatCheckReservedLock(sqlite3_file * pFile,int * pResOut)3433c40ae7dSdrh static int vstatCheckReservedLock(sqlite3_file *pFile, int *pResOut){
3443c40ae7dSdrh int rc;
3453c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
3463c40ae7dSdrh rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
3473c40ae7dSdrh STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
3483c40ae7dSdrh return rc;
3493c40ae7dSdrh }
3503c40ae7dSdrh
3513c40ae7dSdrh /*
3523c40ae7dSdrh ** File control method. For custom operations on an vstat-file.
3533c40ae7dSdrh */
vstatFileControl(sqlite3_file * pFile,int op,void * pArg)3543c40ae7dSdrh static int vstatFileControl(sqlite3_file *pFile, int op, void *pArg){
3553c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
3563c40ae7dSdrh int rc;
3573c40ae7dSdrh rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
3583c40ae7dSdrh if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
3593c40ae7dSdrh *(char**)pArg = sqlite3_mprintf("vstat/%z", *(char**)pArg);
3603c40ae7dSdrh }
3613c40ae7dSdrh return rc;
3623c40ae7dSdrh }
3633c40ae7dSdrh
3643c40ae7dSdrh /*
3653c40ae7dSdrh ** Return the sector-size in bytes for an vstat-file.
3663c40ae7dSdrh */
vstatSectorSize(sqlite3_file * pFile)3673c40ae7dSdrh static int vstatSectorSize(sqlite3_file *pFile){
3683c40ae7dSdrh int rc;
3693c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
3703c40ae7dSdrh rc = p->pReal->pMethods->xSectorSize(p->pReal);
3713c40ae7dSdrh return rc;
3723c40ae7dSdrh }
3733c40ae7dSdrh
3743c40ae7dSdrh /*
3753c40ae7dSdrh ** Return the device characteristic flags supported by an vstat-file.
3763c40ae7dSdrh */
vstatDeviceCharacteristics(sqlite3_file * pFile)3773c40ae7dSdrh static int vstatDeviceCharacteristics(sqlite3_file *pFile){
3783c40ae7dSdrh int rc;
3793c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
3803c40ae7dSdrh rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
3813c40ae7dSdrh return rc;
3823c40ae7dSdrh }
3833c40ae7dSdrh
3843c40ae7dSdrh /* Create a shared memory file mapping */
vstatShmMap(sqlite3_file * pFile,int iPg,int pgsz,int bExtend,void volatile ** pp)3853c40ae7dSdrh static int vstatShmMap(
3863c40ae7dSdrh sqlite3_file *pFile,
3873c40ae7dSdrh int iPg,
3883c40ae7dSdrh int pgsz,
3893c40ae7dSdrh int bExtend,
3903c40ae7dSdrh void volatile **pp
3913c40ae7dSdrh ){
3923c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
3933c40ae7dSdrh return p->pReal->pMethods->xShmMap(p->pReal, iPg, pgsz, bExtend, pp);
3943c40ae7dSdrh }
3953c40ae7dSdrh
3963c40ae7dSdrh /* Perform locking on a shared-memory segment */
vstatShmLock(sqlite3_file * pFile,int offset,int n,int flags)3973c40ae7dSdrh static int vstatShmLock(sqlite3_file *pFile, int offset, int n, int flags){
3983c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
3993c40ae7dSdrh return p->pReal->pMethods->xShmLock(p->pReal, offset, n, flags);
4003c40ae7dSdrh }
4013c40ae7dSdrh
4023c40ae7dSdrh /* Memory barrier operation on shared memory */
vstatShmBarrier(sqlite3_file * pFile)4033c40ae7dSdrh static void vstatShmBarrier(sqlite3_file *pFile){
4043c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
4059f6e686fSmistachkin p->pReal->pMethods->xShmBarrier(p->pReal);
4063c40ae7dSdrh }
4073c40ae7dSdrh
4083c40ae7dSdrh /* Unmap a shared memory segment */
vstatShmUnmap(sqlite3_file * pFile,int deleteFlag)4093c40ae7dSdrh static int vstatShmUnmap(sqlite3_file *pFile, int deleteFlag){
4103c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
4113c40ae7dSdrh return p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
4123c40ae7dSdrh }
4133c40ae7dSdrh
4143c40ae7dSdrh /* Fetch a page of a memory-mapped file */
vstatFetch(sqlite3_file * pFile,sqlite3_int64 iOfst,int iAmt,void ** pp)4153c40ae7dSdrh static int vstatFetch(
4163c40ae7dSdrh sqlite3_file *pFile,
4173c40ae7dSdrh sqlite3_int64 iOfst,
4183c40ae7dSdrh int iAmt,
4193c40ae7dSdrh void **pp
4203c40ae7dSdrh ){
4213c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
4223c40ae7dSdrh return p->pReal->pMethods->xFetch(p->pReal, iOfst, iAmt, pp);
4233c40ae7dSdrh }
4243c40ae7dSdrh
4253c40ae7dSdrh /* Release a memory-mapped page */
vstatUnfetch(sqlite3_file * pFile,sqlite3_int64 iOfst,void * pPage)4263c40ae7dSdrh static int vstatUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
4273c40ae7dSdrh VStatFile *p = (VStatFile *)pFile;
4283c40ae7dSdrh return p->pReal->pMethods->xUnfetch(p->pReal, iOfst, pPage);
4293c40ae7dSdrh }
4303c40ae7dSdrh
4313c40ae7dSdrh /*
4323c40ae7dSdrh ** Open an vstat file handle.
4333c40ae7dSdrh */
vstatOpen(sqlite3_vfs * pVfs,const char * zName,sqlite3_file * pFile,int flags,int * pOutFlags)4343c40ae7dSdrh static int vstatOpen(
4353c40ae7dSdrh sqlite3_vfs *pVfs,
4363c40ae7dSdrh const char *zName,
4373c40ae7dSdrh sqlite3_file *pFile,
4383c40ae7dSdrh int flags,
4393c40ae7dSdrh int *pOutFlags
4403c40ae7dSdrh ){
4413c40ae7dSdrh int rc;
4423c40ae7dSdrh VStatFile *p = (VStatFile*)pFile;
4433c40ae7dSdrh
4443c40ae7dSdrh p->pReal = (sqlite3_file*)&p[1];
4453c40ae7dSdrh rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
4463c40ae7dSdrh if( flags & SQLITE_OPEN_MAIN_DB ){
4473c40ae7dSdrh p->eFiletype = VFSSTAT_MAIN;
4483c40ae7dSdrh }else if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
4493c40ae7dSdrh p->eFiletype = VFSSTAT_JOURNAL;
4503c40ae7dSdrh }else if( flags & SQLITE_OPEN_WAL ){
4513c40ae7dSdrh p->eFiletype = VFSSTAT_WAL;
4523c40ae7dSdrh }else if( flags & SQLITE_OPEN_MASTER_JOURNAL ){
4533c40ae7dSdrh p->eFiletype = VFSSTAT_MASTERJRNL;
4543c40ae7dSdrh }else if( flags & SQLITE_OPEN_SUBJOURNAL ){
4553c40ae7dSdrh p->eFiletype = VFSSTAT_SUBJRNL;
4563c40ae7dSdrh }else if( flags & SQLITE_OPEN_TEMP_DB ){
4573c40ae7dSdrh p->eFiletype = VFSSTAT_TEMPDB;
4583c40ae7dSdrh }else if( flags & SQLITE_OPEN_TEMP_JOURNAL ){
4593c40ae7dSdrh p->eFiletype = VFSSTAT_TEMPJRNL;
4603c40ae7dSdrh }else{
4613c40ae7dSdrh p->eFiletype = VFSSTAT_TRANSIENT;
4623c40ae7dSdrh }
4633c40ae7dSdrh STATCNT(p->eFiletype,VFSSTAT_OPEN)++;
4643c40ae7dSdrh pFile->pMethods = rc ? 0 : &vstat_io_methods;
4653c40ae7dSdrh return rc;
4663c40ae7dSdrh }
4673c40ae7dSdrh
4683c40ae7dSdrh /*
4693c40ae7dSdrh ** Delete the file located at zPath. If the dirSync argument is true,
4703c40ae7dSdrh ** ensure the file-system modifications are synced to disk before
4713c40ae7dSdrh ** returning.
4723c40ae7dSdrh */
vstatDelete(sqlite3_vfs * pVfs,const char * zPath,int dirSync)4733c40ae7dSdrh static int vstatDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
4743c40ae7dSdrh int rc;
4753c40ae7dSdrh rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
4763c40ae7dSdrh STATCNT(VFSSTAT_ANY,VFSSTAT_DELETE)++;
4773c40ae7dSdrh return rc;
4783c40ae7dSdrh }
4793c40ae7dSdrh
4803c40ae7dSdrh /*
4813c40ae7dSdrh ** Test for access permissions. Return true if the requested permission
4823c40ae7dSdrh ** is available, or false otherwise.
4833c40ae7dSdrh */
vstatAccess(sqlite3_vfs * pVfs,const char * zPath,int flags,int * pResOut)4843c40ae7dSdrh static int vstatAccess(
4853c40ae7dSdrh sqlite3_vfs *pVfs,
4863c40ae7dSdrh const char *zPath,
4873c40ae7dSdrh int flags,
4883c40ae7dSdrh int *pResOut
4893c40ae7dSdrh ){
4903c40ae7dSdrh int rc;
4913c40ae7dSdrh rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
4923c40ae7dSdrh STATCNT(VFSSTAT_ANY,VFSSTAT_ACCESS)++;
4933c40ae7dSdrh return rc;
4943c40ae7dSdrh }
4953c40ae7dSdrh
4963c40ae7dSdrh /*
4973c40ae7dSdrh ** Populate buffer zOut with the full canonical pathname corresponding
4983c40ae7dSdrh ** to the pathname in zPath. zOut is guaranteed to point to a buffer
4993c40ae7dSdrh ** of at least (INST_MAX_PATHNAME+1) bytes.
5003c40ae7dSdrh */
vstatFullPathname(sqlite3_vfs * pVfs,const char * zPath,int nOut,char * zOut)5013c40ae7dSdrh static int vstatFullPathname(
5023c40ae7dSdrh sqlite3_vfs *pVfs,
5033c40ae7dSdrh const char *zPath,
5043c40ae7dSdrh int nOut,
5053c40ae7dSdrh char *zOut
5063c40ae7dSdrh ){
5073c40ae7dSdrh STATCNT(VFSSTAT_ANY,VFSSTAT_FULLPATH)++;
5083c40ae7dSdrh return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
5093c40ae7dSdrh }
5103c40ae7dSdrh
5113c40ae7dSdrh /*
5123c40ae7dSdrh ** Open the dynamic library located at zPath and return a handle.
5133c40ae7dSdrh */
vstatDlOpen(sqlite3_vfs * pVfs,const char * zPath)5143c40ae7dSdrh static void *vstatDlOpen(sqlite3_vfs *pVfs, const char *zPath){
5153c40ae7dSdrh return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
5163c40ae7dSdrh }
5173c40ae7dSdrh
5183c40ae7dSdrh /*
5193c40ae7dSdrh ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
5203c40ae7dSdrh ** utf-8 string describing the most recent error encountered associated
5213c40ae7dSdrh ** with dynamic libraries.
5223c40ae7dSdrh */
vstatDlError(sqlite3_vfs * pVfs,int nByte,char * zErrMsg)5233c40ae7dSdrh static void vstatDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
5243c40ae7dSdrh REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
5253c40ae7dSdrh }
5263c40ae7dSdrh
5273c40ae7dSdrh /*
5283c40ae7dSdrh ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
5293c40ae7dSdrh */
vstatDlSym(sqlite3_vfs * pVfs,void * p,const char * zSym)5303c40ae7dSdrh static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
5313c40ae7dSdrh return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
5323c40ae7dSdrh }
5333c40ae7dSdrh
5343c40ae7dSdrh /*
5353c40ae7dSdrh ** Close the dynamic library handle pHandle.
5363c40ae7dSdrh */
vstatDlClose(sqlite3_vfs * pVfs,void * pHandle)5373c40ae7dSdrh static void vstatDlClose(sqlite3_vfs *pVfs, void *pHandle){
5383c40ae7dSdrh REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
5393c40ae7dSdrh }
5403c40ae7dSdrh
5413c40ae7dSdrh /*
5423c40ae7dSdrh ** Populate the buffer pointed to by zBufOut with nByte bytes of
5433c40ae7dSdrh ** random data.
5443c40ae7dSdrh */
vstatRandomness(sqlite3_vfs * pVfs,int nByte,char * zBufOut)5453c40ae7dSdrh static int vstatRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
5463c40ae7dSdrh STATCNT(VFSSTAT_ANY,VFSSTAT_RANDOM)++;
5473c40ae7dSdrh return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
5483c40ae7dSdrh }
5493c40ae7dSdrh
5503c40ae7dSdrh /*
5513c40ae7dSdrh ** Sleep for nMicro microseconds. Return the number of microseconds
5523c40ae7dSdrh ** actually slept.
5533c40ae7dSdrh */
vstatSleep(sqlite3_vfs * pVfs,int nMicro)5543c40ae7dSdrh static int vstatSleep(sqlite3_vfs *pVfs, int nMicro){
5553c40ae7dSdrh STATCNT(VFSSTAT_ANY,VFSSTAT_SLEEP)++;
5563c40ae7dSdrh return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
5573c40ae7dSdrh }
5583c40ae7dSdrh
5593c40ae7dSdrh /*
5603c40ae7dSdrh ** Return the current time as a Julian Day number in *pTimeOut.
5613c40ae7dSdrh */
vstatCurrentTime(sqlite3_vfs * pVfs,double * pTimeOut)5623c40ae7dSdrh static int vstatCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
5633c40ae7dSdrh STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++;
5643c40ae7dSdrh return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
5653c40ae7dSdrh }
5663c40ae7dSdrh
vstatGetLastError(sqlite3_vfs * pVfs,int a,char * b)5673c40ae7dSdrh static int vstatGetLastError(sqlite3_vfs *pVfs, int a, char *b){
5683c40ae7dSdrh return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
5693c40ae7dSdrh }
vstatCurrentTimeInt64(sqlite3_vfs * pVfs,sqlite3_int64 * p)5703c40ae7dSdrh static int vstatCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
5713c40ae7dSdrh STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++;
5723c40ae7dSdrh return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
5733c40ae7dSdrh }
5743c40ae7dSdrh
5753c40ae7dSdrh /*
5763c40ae7dSdrh ** A virtual table for accessing the stats collected by this VFS shim
5773c40ae7dSdrh */
5783c40ae7dSdrh static int vstattabConnect(sqlite3*, void*, int, const char*const*,
5793c40ae7dSdrh sqlite3_vtab**,char**);
5803c40ae7dSdrh static int vstattabBestIndex(sqlite3_vtab*,sqlite3_index_info*);
5813c40ae7dSdrh static int vstattabDisconnect(sqlite3_vtab*);
5823c40ae7dSdrh static int vstattabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**);
5833c40ae7dSdrh static int vstattabClose(sqlite3_vtab_cursor*);
5843c40ae7dSdrh static int vstattabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
5853c40ae7dSdrh int argc, sqlite3_value **argv);
5863c40ae7dSdrh static int vstattabNext(sqlite3_vtab_cursor*);
5873c40ae7dSdrh static int vstattabEof(sqlite3_vtab_cursor*);
5883c40ae7dSdrh static int vstattabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int);
5893c40ae7dSdrh static int vstattabRowid(sqlite3_vtab_cursor*,sqlite3_int64*);
5903c40ae7dSdrh static int vstattabUpdate(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
5913c40ae7dSdrh
5923c40ae7dSdrh /* A cursor for the vfsstat virtual table */
5933c40ae7dSdrh typedef struct VfsStatCursor {
5943c40ae7dSdrh sqlite3_vtab_cursor base; /* Base class. Must be first */
5953c40ae7dSdrh int i; /* Pointing to this aVfsCnt[] value */
5963c40ae7dSdrh } VfsStatCursor;
5973c40ae7dSdrh
5983c40ae7dSdrh
vstattabConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)5993c40ae7dSdrh static int vstattabConnect(
6003c40ae7dSdrh sqlite3 *db,
6013c40ae7dSdrh void *pAux,
6023c40ae7dSdrh int argc, const char *const*argv,
6033c40ae7dSdrh sqlite3_vtab **ppVtab,
6043c40ae7dSdrh char **pzErr
6053c40ae7dSdrh ){
6063c40ae7dSdrh sqlite3_vtab *pNew;
6073c40ae7dSdrh int rc;
6083c40ae7dSdrh
6093c40ae7dSdrh /* Column numbers */
6103c40ae7dSdrh #define VSTAT_COLUMN_FILE 0
6113c40ae7dSdrh #define VSTAT_COLUMN_STAT 1
6123c40ae7dSdrh #define VSTAT_COLUMN_COUNT 2
6133c40ae7dSdrh
6143c40ae7dSdrh rc = sqlite3_declare_vtab(db,"CREATE TABLE x(file,stat,count)");
6153c40ae7dSdrh if( rc==SQLITE_OK ){
6163c40ae7dSdrh pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
6173c40ae7dSdrh if( pNew==0 ) return SQLITE_NOMEM;
6183c40ae7dSdrh memset(pNew, 0, sizeof(*pNew));
6193c40ae7dSdrh }
6203c40ae7dSdrh return rc;
6213c40ae7dSdrh }
6223c40ae7dSdrh
6233c40ae7dSdrh /*
6243c40ae7dSdrh ** This method is the destructor for vstat table object.
6253c40ae7dSdrh */
vstattabDisconnect(sqlite3_vtab * pVtab)6263c40ae7dSdrh static int vstattabDisconnect(sqlite3_vtab *pVtab){
6273c40ae7dSdrh sqlite3_free(pVtab);
6283c40ae7dSdrh return SQLITE_OK;
6293c40ae7dSdrh }
6303c40ae7dSdrh
6313c40ae7dSdrh /*
6323c40ae7dSdrh ** Constructor for a new vstat table cursor object.
6333c40ae7dSdrh */
vstattabOpen(sqlite3_vtab * p,sqlite3_vtab_cursor ** ppCursor)6343c40ae7dSdrh static int vstattabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
6353c40ae7dSdrh VfsStatCursor *pCur;
6363c40ae7dSdrh pCur = sqlite3_malloc( sizeof(*pCur) );
6373c40ae7dSdrh if( pCur==0 ) return SQLITE_NOMEM;
6383c40ae7dSdrh memset(pCur, 0, sizeof(*pCur));
6393c40ae7dSdrh *ppCursor = &pCur->base;
6403c40ae7dSdrh return SQLITE_OK;
6413c40ae7dSdrh }
6423c40ae7dSdrh
6433c40ae7dSdrh
6443c40ae7dSdrh /*
6453c40ae7dSdrh ** Destructor for a VfsStatCursor.
6463c40ae7dSdrh */
vstattabClose(sqlite3_vtab_cursor * cur)6473c40ae7dSdrh static int vstattabClose(sqlite3_vtab_cursor *cur){
6483c40ae7dSdrh sqlite3_free(cur);
6493c40ae7dSdrh return SQLITE_OK;
6503c40ae7dSdrh }
6513c40ae7dSdrh
6523c40ae7dSdrh
6533c40ae7dSdrh /*
6543c40ae7dSdrh ** Advance a VfsStatCursor to its next row of output.
6553c40ae7dSdrh */
vstattabNext(sqlite3_vtab_cursor * cur)6563c40ae7dSdrh static int vstattabNext(sqlite3_vtab_cursor *cur){
6573c40ae7dSdrh ((VfsStatCursor*)cur)->i++;
6583c40ae7dSdrh return SQLITE_OK;
6593c40ae7dSdrh }
6603c40ae7dSdrh
6613c40ae7dSdrh /*
6623c40ae7dSdrh ** Return values of columns for the row at which the VfsStatCursor
6633c40ae7dSdrh ** is currently pointing.
6643c40ae7dSdrh */
vstattabColumn(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int i)6653c40ae7dSdrh static int vstattabColumn(
6663c40ae7dSdrh sqlite3_vtab_cursor *cur, /* The cursor */
6673c40ae7dSdrh sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
6683c40ae7dSdrh int i /* Which column to return */
6693c40ae7dSdrh ){
6703c40ae7dSdrh VfsStatCursor *pCur = (VfsStatCursor*)cur;
6713c40ae7dSdrh switch( i ){
6723c40ae7dSdrh case VSTAT_COLUMN_FILE: {
6733c40ae7dSdrh sqlite3_result_text(ctx, azFile[pCur->i/VFSSTAT_nStat], -1, SQLITE_STATIC);
6743c40ae7dSdrh break;
6753c40ae7dSdrh }
6763c40ae7dSdrh case VSTAT_COLUMN_STAT: {
6773c40ae7dSdrh const char **az;
6783c40ae7dSdrh az = (pCur->i/VFSSTAT_nStat)==VFSSTAT_ANY ? azStatAny : azStat;
6793c40ae7dSdrh sqlite3_result_text(ctx, az[pCur->i%VFSSTAT_nStat], -1, SQLITE_STATIC);
6803c40ae7dSdrh break;
6813c40ae7dSdrh }
6823c40ae7dSdrh case VSTAT_COLUMN_COUNT: {
6833c40ae7dSdrh sqlite3_result_int64(ctx, aVfsCnt[pCur->i]);
6843c40ae7dSdrh break;
6853c40ae7dSdrh }
6863c40ae7dSdrh }
6873c40ae7dSdrh return SQLITE_OK;
6883c40ae7dSdrh }
6893c40ae7dSdrh
6903c40ae7dSdrh /*
6913c40ae7dSdrh ** Return the rowid for the current row.
6923c40ae7dSdrh */
vstattabRowid(sqlite3_vtab_cursor * cur,sqlite_int64 * pRowid)6933c40ae7dSdrh static int vstattabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
6943c40ae7dSdrh VfsStatCursor *pCur = (VfsStatCursor*)cur;
6953c40ae7dSdrh *pRowid = pCur->i;
6963c40ae7dSdrh return SQLITE_OK;
6973c40ae7dSdrh }
6983c40ae7dSdrh
6993c40ae7dSdrh /*
7003c40ae7dSdrh ** Return TRUE if the cursor has been moved off of the last
7013c40ae7dSdrh ** row of output.
7023c40ae7dSdrh */
vstattabEof(sqlite3_vtab_cursor * cur)7033c40ae7dSdrh static int vstattabEof(sqlite3_vtab_cursor *cur){
7043c40ae7dSdrh VfsStatCursor *pCur = (VfsStatCursor*)cur;
7053c40ae7dSdrh return pCur->i >= VFSSTAT_MXCNT;
7063c40ae7dSdrh }
7073c40ae7dSdrh
7083c40ae7dSdrh /*
7093c40ae7dSdrh ** Only a full table scan is supported. So xFilter simply rewinds to
7103c40ae7dSdrh ** the beginning.
7113c40ae7dSdrh */
vstattabFilter(sqlite3_vtab_cursor * pVtabCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)7123c40ae7dSdrh static int vstattabFilter(
7133c40ae7dSdrh sqlite3_vtab_cursor *pVtabCursor,
7143c40ae7dSdrh int idxNum, const char *idxStr,
7153c40ae7dSdrh int argc, sqlite3_value **argv
7163c40ae7dSdrh ){
7173c40ae7dSdrh VfsStatCursor *pCur = (VfsStatCursor*)pVtabCursor;
7183c40ae7dSdrh pCur->i = 0;
7193c40ae7dSdrh return SQLITE_OK;
7203c40ae7dSdrh }
7213c40ae7dSdrh
7223c40ae7dSdrh /*
7233c40ae7dSdrh ** Only a forwards full table scan is supported. xBestIndex is a no-op.
7243c40ae7dSdrh */
vstattabBestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)7253c40ae7dSdrh static int vstattabBestIndex(
7263c40ae7dSdrh sqlite3_vtab *tab,
7273c40ae7dSdrh sqlite3_index_info *pIdxInfo
7283c40ae7dSdrh ){
7293c40ae7dSdrh return SQLITE_OK;
7303c40ae7dSdrh }
7313c40ae7dSdrh
7323c40ae7dSdrh /*
7333c40ae7dSdrh ** Any VSTAT_COLUMN_COUNT can be changed to a positive integer.
7343c40ae7dSdrh ** No deletions or insertions are allowed. No changes to other
7353c40ae7dSdrh ** columns are allowed.
7363c40ae7dSdrh */
vstattabUpdate(sqlite3_vtab * tab,int argc,sqlite3_value ** argv,sqlite3_int64 * pRowid)7373c40ae7dSdrh static int vstattabUpdate(
7383c40ae7dSdrh sqlite3_vtab *tab,
7393c40ae7dSdrh int argc, sqlite3_value **argv,
7403c40ae7dSdrh sqlite3_int64 *pRowid
7413c40ae7dSdrh ){
7423c40ae7dSdrh sqlite3_int64 iRowid, x;
7433c40ae7dSdrh if( argc==1 ) return SQLITE_ERROR;
7443c40ae7dSdrh if( sqlite3_value_type(argv[0])!=SQLITE_INTEGER ) return SQLITE_ERROR;
7453c40ae7dSdrh iRowid = sqlite3_value_int64(argv[0]);
7463c40ae7dSdrh if( iRowid!=sqlite3_value_int64(argv[1]) ) return SQLITE_ERROR;
7473c40ae7dSdrh if( iRowid<0 || iRowid>=VFSSTAT_MXCNT ) return SQLITE_ERROR;
7483c40ae7dSdrh if( sqlite3_value_type(argv[VSTAT_COLUMN_COUNT+2])!=SQLITE_INTEGER ){
7493c40ae7dSdrh return SQLITE_ERROR;
7503c40ae7dSdrh }
7513c40ae7dSdrh x = sqlite3_value_int64(argv[VSTAT_COLUMN_COUNT+2]);
7523c40ae7dSdrh if( x<0 ) return SQLITE_ERROR;
7533c40ae7dSdrh aVfsCnt[iRowid] = x;
7543c40ae7dSdrh return SQLITE_OK;
7553c40ae7dSdrh }
7563c40ae7dSdrh
7573c40ae7dSdrh static sqlite3_module VfsStatModule = {
7583c40ae7dSdrh 0, /* iVersion */
7593c40ae7dSdrh 0, /* xCreate */
7603c40ae7dSdrh vstattabConnect, /* xConnect */
7613c40ae7dSdrh vstattabBestIndex, /* xBestIndex */
7623c40ae7dSdrh vstattabDisconnect, /* xDisconnect */
7633c40ae7dSdrh 0, /* xDestroy */
7643c40ae7dSdrh vstattabOpen, /* xOpen - open a cursor */
7653c40ae7dSdrh vstattabClose, /* xClose - close a cursor */
7663c40ae7dSdrh vstattabFilter, /* xFilter - configure scan constraints */
7673c40ae7dSdrh vstattabNext, /* xNext - advance a cursor */
7683c40ae7dSdrh vstattabEof, /* xEof - check for end of scan */
7693c40ae7dSdrh vstattabColumn, /* xColumn - read data */
7703c40ae7dSdrh vstattabRowid, /* xRowid - read data */
7713c40ae7dSdrh vstattabUpdate, /* xUpdate */
7723c40ae7dSdrh 0, /* xBegin */
7733c40ae7dSdrh 0, /* xSync */
7743c40ae7dSdrh 0, /* xCommit */
7753c40ae7dSdrh 0, /* xRollback */
7763c40ae7dSdrh 0, /* xFindMethod */
7773c40ae7dSdrh 0, /* xRename */
7783c40ae7dSdrh };
7793c40ae7dSdrh
7803c40ae7dSdrh /*
7813c40ae7dSdrh ** This routine is an sqlite3_auto_extension() callback, invoked to register
7823c40ae7dSdrh ** the vfsstat virtual table for all new database connections.
7833c40ae7dSdrh */
vstatRegister(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pThunk)7843c40ae7dSdrh static int vstatRegister(
7853c40ae7dSdrh sqlite3 *db,
786f9101623Sdrh char **pzErrMsg,
787f9101623Sdrh const sqlite3_api_routines *pThunk
7883c40ae7dSdrh ){
7893c40ae7dSdrh return sqlite3_create_module(db, "vfsstat", &VfsStatModule, 0);
7903c40ae7dSdrh }
7913c40ae7dSdrh
7923c40ae7dSdrh #ifdef _WIN32
7933c40ae7dSdrh __declspec(dllexport)
7943c40ae7dSdrh #endif
7953c40ae7dSdrh /*
7963c40ae7dSdrh ** This routine is called when the extension is loaded.
7973c40ae7dSdrh **
7983c40ae7dSdrh ** Register the new VFS. Make arrangement to register the virtual table
7993c40ae7dSdrh ** for each new database connection.
8003c40ae7dSdrh */
sqlite3_vfsstat_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)8013c40ae7dSdrh int sqlite3_vfsstat_init(
8023c40ae7dSdrh sqlite3 *db,
8033c40ae7dSdrh char **pzErrMsg,
8043c40ae7dSdrh const sqlite3_api_routines *pApi
8053c40ae7dSdrh ){
8063c40ae7dSdrh int rc = SQLITE_OK;
8073c40ae7dSdrh SQLITE_EXTENSION_INIT2(pApi);
80866bf8104Sdrh vstat_vfs.pVfs = sqlite3_vfs_find(0);
809*a959bf53Sdrh if( vstat_vfs.pVfs==0 ) return SQLITE_ERROR;
8109f6e686fSmistachkin vstat_vfs.base.szOsFile = sizeof(VStatFile) + vstat_vfs.pVfs->szOsFile;
81166bf8104Sdrh rc = sqlite3_vfs_register(&vstat_vfs.base, 1);
8123c40ae7dSdrh if( rc==SQLITE_OK ){
813f9101623Sdrh rc = vstatRegister(db, pzErrMsg, pApi);
814f9101623Sdrh if( rc==SQLITE_OK ){
815efc752b1Sdrh rc = sqlite3_auto_extension((void(*)(void))vstatRegister);
8163c40ae7dSdrh }
817f9101623Sdrh }
818c1502e2fSdrh if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
8193c40ae7dSdrh return rc;
8203c40ae7dSdrh }
821