xref: /sqlite-3.40.0/ext/misc/vfsstat.c (revision a959bf53)
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