modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/misc/vfsstat.c (about)

     1  /*
     2  ** 2016-05-27
     3  **
     4  ** The author disclaims copyright to this source code.  In place of
     5  ** a legal notice, here is a blessing:
     6  **
     7  **    May you do good and not evil.
     8  **    May you find forgiveness for yourself and forgive others.
     9  **    May you share freely, never taking more than you give.
    10  **
    11  ******************************************************************************
    12  **
    13  ** This file contains the implementation of an SQLite vfs shim that
    14  ** tracks I/O.  Access to the accumulated status counts is provided using
    15  ** an eponymous virtual table.
    16  */
    17  #include <sqlite3ext.h>
    18  SQLITE_EXTENSION_INIT1
    19  
    20  /*
    21  ** This module contains code for a wrapper VFS that cause stats for
    22  ** most VFS calls to be recorded.
    23  **
    24  ** To use this module, first compile it as a loadable extension.  See
    25  ** https://www.sqlite.org/loadext.html#build for compilations instructions.
    26  **
    27  ** After compliing, load this extension, then open database connections to be
    28  ** measured.  Query usages status using the vfsstat virtual table:
    29  **
    30  **         SELECT * FROM vfsstat;
    31  **
    32  ** Reset counters using UPDATE statements against vfsstat:
    33  **
    34  **         UPDATE vfsstat SET count=0;
    35  **
    36  ** EXAMPLE SCRIPT:
    37  **
    38  **      .load ./vfsstat
    39  **      .open test.db
    40  **      DROP TABLE IF EXISTS t1;
    41  **      CREATE TABLE t1(x,y);
    42  **      INSERT INTO t1 VALUES(123, randomblob(5000));
    43  **      CREATE INDEX t1x ON t1(x);
    44  **      DROP TABLE t1;
    45  **      VACUUM;
    46  **      SELECT * FROM vfsstat WHERE count>0;
    47  **
    48  ** LIMITATIONS:
    49  ** 
    50  ** This module increments counters without using mutex protection.  So if
    51  ** two or more threads try to use this module at the same time, race conditions
    52  ** may occur which mess up the counts.  This is harmless, other than giving
    53  ** incorrect statistics.
    54  */
    55  #include <string.h>
    56  #include <stdlib.h>
    57  #include <assert.h>
    58  
    59  /*
    60  ** File types
    61  */
    62  #define VFSSTAT_MAIN         0   /* Main database file */
    63  #define VFSSTAT_JOURNAL      1   /* Rollback journal */
    64  #define VFSSTAT_WAL          2   /* Write-ahead log file */
    65  #define VFSSTAT_MASTERJRNL   3   /* Master journal */
    66  #define VFSSTAT_SUBJRNL      4   /* Subjournal */
    67  #define VFSSTAT_TEMPDB       5   /* TEMP database */
    68  #define VFSSTAT_TEMPJRNL     6   /* Journal for TEMP database */
    69  #define VFSSTAT_TRANSIENT    7   /* Transient database */
    70  #define VFSSTAT_ANY          8   /* Unspecified file type */
    71  #define VFSSTAT_nFile        9   /* This many file types */
    72  
    73  /* Names of the file types.  These are allowed values for the
    74  ** first column of the vfsstat virtual table.
    75  */
    76  static const char *azFile[] = {
    77    "database", "journal", "wal", "master-journal", "sub-journal",
    78    "temp-database", "temp-journal", "transient-db", "*"
    79  };
    80  
    81  /*
    82  ** Stat types
    83  */
    84  #define VFSSTAT_BYTESIN      0   /* Bytes read in */
    85  #define VFSSTAT_BYTESOUT     1   /* Bytes written out */   
    86  #define VFSSTAT_READ         2   /* Read requests */
    87  #define VFSSTAT_WRITE        3   /* Write requests */
    88  #define VFSSTAT_SYNC         4   /* Syncs */
    89  #define VFSSTAT_OPEN         5   /* File opens */
    90  #define VFSSTAT_LOCK         6   /* Lock requests */
    91  #define VFSSTAT_ACCESS       0   /* xAccess calls.  filetype==ANY only */
    92  #define VFSSTAT_DELETE       1   /* xDelete calls.  filetype==ANY only */
    93  #define VFSSTAT_FULLPATH     2   /* xFullPathname calls.  ANY only */
    94  #define VFSSTAT_RANDOM       3   /* xRandomness calls.    ANY only */
    95  #define VFSSTAT_SLEEP        4   /* xSleep calls.         ANY only */
    96  #define VFSSTAT_CURTIME      5   /* xCurrentTime calls.   ANY only */
    97  #define VFSSTAT_nStat        7   /* This many stat types */
    98  
    99  
   100  /* Names for the second column of the vfsstat virtual table for all
   101  ** cases except when the first column is "*" or VFSSTAT_ANY. */
   102  static const char *azStat[] = {
   103    "bytes-in", "bytes-out", "read", "write", "sync", "open", "lock",
   104  };
   105  static const char *azStatAny[] = {
   106    "access", "delete", "fullpathname", "randomness", "sleep", "currenttimestamp",
   107    "not-used"
   108  };
   109  
   110  /* Total number of counters */
   111  #define VFSSTAT_MXCNT  (VFSSTAT_nStat*VFSSTAT_nFile)
   112  
   113  /*
   114  ** Performance stats are collected in an instance of the following
   115  ** global array.
   116  */
   117  static sqlite3_uint64 aVfsCnt[VFSSTAT_MXCNT];
   118  
   119  /*
   120  ** Access to a specific counter
   121  */
   122  #define STATCNT(filetype,stat) (aVfsCnt[(filetype)*VFSSTAT_nStat+(stat)])
   123  
   124  /*
   125  ** Forward declaration of objects used by this utility
   126  */
   127  typedef struct VStatVfs VStatVfs;
   128  typedef struct VStatFile VStatFile;
   129  
   130  /* An instance of the VFS */
   131  struct VStatVfs {
   132    sqlite3_vfs base;               /* VFS methods */
   133    sqlite3_vfs *pVfs;              /* Parent VFS */
   134  };
   135  
   136  /* An open file */
   137  struct VStatFile {
   138    sqlite3_file base;              /* IO methods */
   139    sqlite3_file *pReal;            /* Underlying file handle */
   140    unsigned char eFiletype;        /* What type of file is this */
   141  };
   142  
   143  #define REALVFS(p) (((VStatVfs*)(p))->pVfs)
   144  
   145  /*
   146  ** Methods for VStatFile
   147  */
   148  static int vstatClose(sqlite3_file*);
   149  static int vstatRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
   150  static int vstatWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
   151  static int vstatTruncate(sqlite3_file*, sqlite3_int64 size);
   152  static int vstatSync(sqlite3_file*, int flags);
   153  static int vstatFileSize(sqlite3_file*, sqlite3_int64 *pSize);
   154  static int vstatLock(sqlite3_file*, int);
   155  static int vstatUnlock(sqlite3_file*, int);
   156  static int vstatCheckReservedLock(sqlite3_file*, int *pResOut);
   157  static int vstatFileControl(sqlite3_file*, int op, void *pArg);
   158  static int vstatSectorSize(sqlite3_file*);
   159  static int vstatDeviceCharacteristics(sqlite3_file*);
   160  static int vstatShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
   161  static int vstatShmLock(sqlite3_file*, int offset, int n, int flags);
   162  static void vstatShmBarrier(sqlite3_file*);
   163  static int vstatShmUnmap(sqlite3_file*, int deleteFlag);
   164  static int vstatFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
   165  static int vstatUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
   166  
   167  /*
   168  ** Methods for VStatVfs
   169  */
   170  static int vstatOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
   171  static int vstatDelete(sqlite3_vfs*, const char *zName, int syncDir);
   172  static int vstatAccess(sqlite3_vfs*, const char *zName, int flags, int *);
   173  static int vstatFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
   174  static void *vstatDlOpen(sqlite3_vfs*, const char *zFilename);
   175  static void vstatDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
   176  static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
   177  static void vstatDlClose(sqlite3_vfs*, void*);
   178  static int vstatRandomness(sqlite3_vfs*, int nByte, char *zOut);
   179  static int vstatSleep(sqlite3_vfs*, int microseconds);
   180  static int vstatCurrentTime(sqlite3_vfs*, double*);
   181  static int vstatGetLastError(sqlite3_vfs*, int, char *);
   182  static int vstatCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
   183  
   184  static VStatVfs vstat_vfs = {
   185    {
   186      2,                            /* iVersion */
   187      0,                            /* szOsFile (set by register_vstat()) */
   188      1024,                         /* mxPathname */
   189      0,                            /* pNext */
   190      "vfslog",                     /* zName */
   191      0,                            /* pAppData */
   192      vstatOpen,                     /* xOpen */
   193      vstatDelete,                   /* xDelete */
   194      vstatAccess,                   /* xAccess */
   195      vstatFullPathname,             /* xFullPathname */
   196      vstatDlOpen,                   /* xDlOpen */
   197      vstatDlError,                  /* xDlError */
   198      vstatDlSym,                    /* xDlSym */
   199      vstatDlClose,                  /* xDlClose */
   200      vstatRandomness,               /* xRandomness */
   201      vstatSleep,                    /* xSleep */
   202      vstatCurrentTime,              /* xCurrentTime */
   203      vstatGetLastError,             /* xGetLastError */
   204      vstatCurrentTimeInt64          /* xCurrentTimeInt64 */
   205    },
   206    0
   207  };
   208  
   209  static const sqlite3_io_methods vstat_io_methods = {
   210    3,                              /* iVersion */
   211    vstatClose,                      /* xClose */
   212    vstatRead,                       /* xRead */
   213    vstatWrite,                      /* xWrite */
   214    vstatTruncate,                   /* xTruncate */
   215    vstatSync,                       /* xSync */
   216    vstatFileSize,                   /* xFileSize */
   217    vstatLock,                       /* xLock */
   218    vstatUnlock,                     /* xUnlock */
   219    vstatCheckReservedLock,          /* xCheckReservedLock */
   220    vstatFileControl,                /* xFileControl */
   221    vstatSectorSize,                 /* xSectorSize */
   222    vstatDeviceCharacteristics,      /* xDeviceCharacteristics */
   223    vstatShmMap,                     /* xShmMap */
   224    vstatShmLock,                    /* xShmLock */
   225    vstatShmBarrier,                 /* xShmBarrier */
   226    vstatShmUnmap,                   /* xShmUnmap */
   227    vstatFetch,                      /* xFetch */
   228    vstatUnfetch                     /* xUnfetch */
   229  };
   230  
   231  
   232  
   233  /*
   234  ** Close an vstat-file.
   235  */
   236  static int vstatClose(sqlite3_file *pFile){
   237    VStatFile *p = (VStatFile *)pFile;
   238    int rc = SQLITE_OK;
   239  
   240    if( p->pReal->pMethods ){
   241      rc = p->pReal->pMethods->xClose(p->pReal);
   242    }
   243    return rc;
   244  }
   245  
   246  
   247  /*
   248  ** Read data from an vstat-file.
   249  */
   250  static int vstatRead(
   251    sqlite3_file *pFile, 
   252    void *zBuf, 
   253    int iAmt, 
   254    sqlite_int64 iOfst
   255  ){
   256    int rc;
   257    VStatFile *p = (VStatFile *)pFile;
   258  
   259    rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
   260    STATCNT(p->eFiletype,VFSSTAT_READ)++;
   261    if( rc==SQLITE_OK ){
   262      STATCNT(p->eFiletype,VFSSTAT_BYTESIN) += iAmt;
   263    }
   264    return rc;
   265  }
   266  
   267  /*
   268  ** Write data to an vstat-file.
   269  */
   270  static int vstatWrite(
   271    sqlite3_file *pFile,
   272    const void *z,
   273    int iAmt,
   274    sqlite_int64 iOfst
   275  ){
   276    int rc;
   277    VStatFile *p = (VStatFile *)pFile;
   278  
   279    rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
   280    STATCNT(p->eFiletype,VFSSTAT_WRITE)++;
   281    if( rc==SQLITE_OK ){
   282      STATCNT(p->eFiletype,VFSSTAT_BYTESOUT) += iAmt;
   283    }
   284    return rc;
   285  }
   286  
   287  /*
   288  ** Truncate an vstat-file.
   289  */
   290  static int vstatTruncate(sqlite3_file *pFile, sqlite_int64 size){
   291    int rc;
   292    VStatFile *p = (VStatFile *)pFile;
   293    rc = p->pReal->pMethods->xTruncate(p->pReal, size);
   294    return rc;
   295  }
   296  
   297  /*
   298  ** Sync an vstat-file.
   299  */
   300  static int vstatSync(sqlite3_file *pFile, int flags){
   301    int rc;
   302    VStatFile *p = (VStatFile *)pFile;
   303    rc = p->pReal->pMethods->xSync(p->pReal, flags);
   304    STATCNT(p->eFiletype,VFSSTAT_SYNC)++;
   305    return rc;
   306  }
   307  
   308  /*
   309  ** Return the current file-size of an vstat-file.
   310  */
   311  static int vstatFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
   312    int rc;
   313    VStatFile *p = (VStatFile *)pFile;
   314    rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
   315    return rc;
   316  }
   317  
   318  /*
   319  ** Lock an vstat-file.
   320  */
   321  static int vstatLock(sqlite3_file *pFile, int eLock){
   322    int rc;
   323    VStatFile *p = (VStatFile *)pFile;
   324    rc = p->pReal->pMethods->xLock(p->pReal, eLock);
   325    STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
   326    return rc;
   327  }
   328  
   329  /*
   330  ** Unlock an vstat-file.
   331  */
   332  static int vstatUnlock(sqlite3_file *pFile, int eLock){
   333    int rc;
   334    VStatFile *p = (VStatFile *)pFile;
   335    rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
   336    STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
   337    return rc;
   338  }
   339  
   340  /*
   341  ** Check if another file-handle holds a RESERVED lock on an vstat-file.
   342  */
   343  static int vstatCheckReservedLock(sqlite3_file *pFile, int *pResOut){
   344    int rc;
   345    VStatFile *p = (VStatFile *)pFile;
   346    rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
   347    STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
   348    return rc;
   349  }
   350  
   351  /*
   352  ** File control method. For custom operations on an vstat-file.
   353  */
   354  static int vstatFileControl(sqlite3_file *pFile, int op, void *pArg){
   355    VStatFile *p = (VStatFile *)pFile;
   356    int rc;
   357    rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
   358    if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
   359      *(char**)pArg = sqlite3_mprintf("vstat/%z", *(char**)pArg);
   360    }
   361    return rc;
   362  }
   363  
   364  /*
   365  ** Return the sector-size in bytes for an vstat-file.
   366  */
   367  static int vstatSectorSize(sqlite3_file *pFile){
   368    int rc;
   369    VStatFile *p = (VStatFile *)pFile;
   370    rc = p->pReal->pMethods->xSectorSize(p->pReal);
   371    return rc;
   372  }
   373  
   374  /*
   375  ** Return the device characteristic flags supported by an vstat-file.
   376  */
   377  static int vstatDeviceCharacteristics(sqlite3_file *pFile){
   378    int rc;
   379    VStatFile *p = (VStatFile *)pFile;
   380    rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
   381    return rc;
   382  }
   383  
   384  /* Create a shared memory file mapping */
   385  static int vstatShmMap(
   386    sqlite3_file *pFile,
   387    int iPg,
   388    int pgsz,
   389    int bExtend,
   390    void volatile **pp
   391  ){
   392    VStatFile *p = (VStatFile *)pFile;
   393    return p->pReal->pMethods->xShmMap(p->pReal, iPg, pgsz, bExtend, pp);
   394  }
   395  
   396  /* Perform locking on a shared-memory segment */
   397  static int vstatShmLock(sqlite3_file *pFile, int offset, int n, int flags){
   398    VStatFile *p = (VStatFile *)pFile;
   399    return p->pReal->pMethods->xShmLock(p->pReal, offset, n, flags);
   400  }
   401  
   402  /* Memory barrier operation on shared memory */
   403  static void vstatShmBarrier(sqlite3_file *pFile){
   404    VStatFile *p = (VStatFile *)pFile;
   405    p->pReal->pMethods->xShmBarrier(p->pReal);
   406  }
   407  
   408  /* Unmap a shared memory segment */
   409  static int vstatShmUnmap(sqlite3_file *pFile, int deleteFlag){
   410    VStatFile *p = (VStatFile *)pFile;
   411    return p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
   412  }
   413  
   414  /* Fetch a page of a memory-mapped file */
   415  static int vstatFetch(
   416    sqlite3_file *pFile,
   417    sqlite3_int64 iOfst,
   418    int iAmt,
   419    void **pp
   420  ){
   421    VStatFile *p = (VStatFile *)pFile;
   422    return p->pReal->pMethods->xFetch(p->pReal, iOfst, iAmt, pp);
   423  }
   424  
   425  /* Release a memory-mapped page */
   426  static int vstatUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
   427    VStatFile *p = (VStatFile *)pFile;
   428    return p->pReal->pMethods->xUnfetch(p->pReal, iOfst, pPage);
   429  }
   430  
   431  /*
   432  ** Open an vstat file handle.
   433  */
   434  static int vstatOpen(
   435    sqlite3_vfs *pVfs,
   436    const char *zName,
   437    sqlite3_file *pFile,
   438    int flags,
   439    int *pOutFlags
   440  ){
   441    int rc;
   442    VStatFile *p = (VStatFile*)pFile;
   443  
   444    p->pReal = (sqlite3_file*)&p[1];
   445    rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
   446    if( flags & SQLITE_OPEN_MAIN_DB ){
   447      p->eFiletype = VFSSTAT_MAIN;
   448    }else if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
   449      p->eFiletype = VFSSTAT_JOURNAL;
   450    }else if( flags & SQLITE_OPEN_WAL ){
   451      p->eFiletype = VFSSTAT_WAL;
   452    }else if( flags & SQLITE_OPEN_MASTER_JOURNAL ){
   453      p->eFiletype = VFSSTAT_MASTERJRNL;
   454    }else if( flags & SQLITE_OPEN_SUBJOURNAL ){
   455      p->eFiletype = VFSSTAT_SUBJRNL;
   456    }else if( flags & SQLITE_OPEN_TEMP_DB ){
   457      p->eFiletype = VFSSTAT_TEMPDB;
   458    }else if( flags & SQLITE_OPEN_TEMP_JOURNAL ){
   459      p->eFiletype = VFSSTAT_TEMPJRNL;
   460    }else{
   461      p->eFiletype = VFSSTAT_TRANSIENT;
   462    }
   463    STATCNT(p->eFiletype,VFSSTAT_OPEN)++;
   464    pFile->pMethods = rc ? 0 : &vstat_io_methods;
   465    return rc;
   466  }
   467  
   468  /*
   469  ** Delete the file located at zPath. If the dirSync argument is true,
   470  ** ensure the file-system modifications are synced to disk before
   471  ** returning.
   472  */
   473  static int vstatDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
   474    int rc;
   475    rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
   476    STATCNT(VFSSTAT_ANY,VFSSTAT_DELETE)++;
   477    return rc;
   478  }
   479  
   480  /*
   481  ** Test for access permissions. Return true if the requested permission
   482  ** is available, or false otherwise.
   483  */
   484  static int vstatAccess(
   485    sqlite3_vfs *pVfs, 
   486    const char *zPath, 
   487    int flags, 
   488    int *pResOut
   489  ){
   490    int rc;
   491    rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
   492    STATCNT(VFSSTAT_ANY,VFSSTAT_ACCESS)++;
   493    return rc;
   494  }
   495  
   496  /*
   497  ** Populate buffer zOut with the full canonical pathname corresponding
   498  ** to the pathname in zPath. zOut is guaranteed to point to a buffer
   499  ** of at least (INST_MAX_PATHNAME+1) bytes.
   500  */
   501  static int vstatFullPathname(
   502    sqlite3_vfs *pVfs, 
   503    const char *zPath, 
   504    int nOut, 
   505    char *zOut
   506  ){
   507    STATCNT(VFSSTAT_ANY,VFSSTAT_FULLPATH)++;
   508    return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
   509  }
   510  
   511  /*
   512  ** Open the dynamic library located at zPath and return a handle.
   513  */
   514  static void *vstatDlOpen(sqlite3_vfs *pVfs, const char *zPath){
   515    return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
   516  }
   517  
   518  /*
   519  ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
   520  ** utf-8 string describing the most recent error encountered associated 
   521  ** with dynamic libraries.
   522  */
   523  static void vstatDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
   524    REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
   525  }
   526  
   527  /*
   528  ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
   529  */
   530  static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
   531    return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
   532  }
   533  
   534  /*
   535  ** Close the dynamic library handle pHandle.
   536  */
   537  static void vstatDlClose(sqlite3_vfs *pVfs, void *pHandle){
   538    REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
   539  }
   540  
   541  /*
   542  ** Populate the buffer pointed to by zBufOut with nByte bytes of 
   543  ** random data.
   544  */
   545  static int vstatRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
   546    STATCNT(VFSSTAT_ANY,VFSSTAT_RANDOM)++;
   547    return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
   548  }
   549  
   550  /*
   551  ** Sleep for nMicro microseconds. Return the number of microseconds 
   552  ** actually slept.
   553  */
   554  static int vstatSleep(sqlite3_vfs *pVfs, int nMicro){
   555    STATCNT(VFSSTAT_ANY,VFSSTAT_SLEEP)++;
   556    return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
   557  }
   558  
   559  /*
   560  ** Return the current time as a Julian Day number in *pTimeOut.
   561  */
   562  static int vstatCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
   563    STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++;
   564    return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
   565  }
   566  
   567  static int vstatGetLastError(sqlite3_vfs *pVfs, int a, char *b){
   568    return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
   569  }
   570  static int vstatCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
   571    STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++;
   572    return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
   573  }
   574  
   575  /*
   576  ** A virtual table for accessing the stats collected by this VFS shim
   577  */
   578  static int vstattabConnect(sqlite3*, void*, int, const char*const*, 
   579                             sqlite3_vtab**,char**);
   580  static int vstattabBestIndex(sqlite3_vtab*,sqlite3_index_info*);
   581  static int vstattabDisconnect(sqlite3_vtab*);
   582  static int vstattabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**);
   583  static int vstattabClose(sqlite3_vtab_cursor*);
   584  static int vstattabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
   585                            int argc, sqlite3_value **argv);
   586  static int vstattabNext(sqlite3_vtab_cursor*);
   587  static int vstattabEof(sqlite3_vtab_cursor*);
   588  static int vstattabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int);
   589  static int vstattabRowid(sqlite3_vtab_cursor*,sqlite3_int64*);
   590  static int vstattabUpdate(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
   591  
   592  /* A cursor for the vfsstat virtual table */
   593  typedef struct VfsStatCursor {
   594    sqlite3_vtab_cursor base;       /* Base class.  Must be first */
   595    int i;                          /* Pointing to this aVfsCnt[] value */
   596  } VfsStatCursor;
   597  
   598  
   599  static int vstattabConnect(
   600    sqlite3 *db,
   601    void *pAux,
   602    int argc, const char *const*argv,
   603    sqlite3_vtab **ppVtab,
   604    char **pzErr
   605  ){
   606    sqlite3_vtab *pNew;
   607    int rc;
   608  
   609  /* Column numbers */
   610  #define VSTAT_COLUMN_FILE  0 
   611  #define VSTAT_COLUMN_STAT  1
   612  #define VSTAT_COLUMN_COUNT 2
   613  
   614    rc = sqlite3_declare_vtab(db,"CREATE TABLE x(file,stat,count)");
   615    if( rc==SQLITE_OK ){
   616      pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
   617      if( pNew==0 ) return SQLITE_NOMEM;
   618      memset(pNew, 0, sizeof(*pNew));
   619    }
   620    return rc;
   621  }
   622  
   623  /*
   624  ** This method is the destructor for vstat table object.
   625  */
   626  static int vstattabDisconnect(sqlite3_vtab *pVtab){
   627    sqlite3_free(pVtab);
   628    return SQLITE_OK;
   629  }
   630  
   631  /*
   632  ** Constructor for a new vstat table cursor object.
   633  */
   634  static int vstattabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
   635    VfsStatCursor *pCur;
   636    pCur = sqlite3_malloc( sizeof(*pCur) );
   637    if( pCur==0 ) return SQLITE_NOMEM;
   638    memset(pCur, 0, sizeof(*pCur));
   639    *ppCursor = &pCur->base;
   640    return SQLITE_OK;
   641  }
   642  
   643  
   644  /*
   645  ** Destructor for a VfsStatCursor.
   646  */
   647  static int vstattabClose(sqlite3_vtab_cursor *cur){
   648    sqlite3_free(cur);
   649    return SQLITE_OK;
   650  }
   651  
   652  
   653  /*
   654  ** Advance a VfsStatCursor to its next row of output.
   655  */
   656  static int vstattabNext(sqlite3_vtab_cursor *cur){
   657    ((VfsStatCursor*)cur)->i++;
   658    return SQLITE_OK;
   659  }
   660  
   661  /*
   662  ** Return values of columns for the row at which the VfsStatCursor
   663  ** is currently pointing.
   664  */
   665  static int vstattabColumn(
   666    sqlite3_vtab_cursor *cur,   /* The cursor */
   667    sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
   668    int i                       /* Which column to return */
   669  ){
   670    VfsStatCursor *pCur = (VfsStatCursor*)cur;
   671    switch( i ){
   672      case VSTAT_COLUMN_FILE: {
   673        sqlite3_result_text(ctx, azFile[pCur->i/VFSSTAT_nStat], -1, SQLITE_STATIC);
   674        break;
   675      }
   676      case VSTAT_COLUMN_STAT: {
   677        const char **az;
   678        az = (pCur->i/VFSSTAT_nStat)==VFSSTAT_ANY ? azStatAny : azStat;
   679        sqlite3_result_text(ctx, az[pCur->i%VFSSTAT_nStat], -1, SQLITE_STATIC);
   680        break;
   681      }
   682      case VSTAT_COLUMN_COUNT: {
   683        sqlite3_result_int64(ctx, aVfsCnt[pCur->i]);
   684        break;
   685      }
   686    }
   687    return SQLITE_OK;
   688  }
   689  
   690  /*
   691  ** Return the rowid for the current row.
   692  */
   693  static int vstattabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
   694    VfsStatCursor *pCur = (VfsStatCursor*)cur;
   695    *pRowid = pCur->i;
   696    return SQLITE_OK;
   697  }
   698  
   699  /*
   700  ** Return TRUE if the cursor has been moved off of the last
   701  ** row of output.
   702  */
   703  static int vstattabEof(sqlite3_vtab_cursor *cur){
   704    VfsStatCursor *pCur = (VfsStatCursor*)cur;
   705    return pCur->i >= VFSSTAT_MXCNT;
   706  }
   707  
   708  /*
   709  ** Only a full table scan is supported.  So xFilter simply rewinds to
   710  ** the beginning.
   711  */
   712  static int vstattabFilter(
   713    sqlite3_vtab_cursor *pVtabCursor, 
   714    int idxNum, const char *idxStr,
   715    int argc, sqlite3_value **argv
   716  ){
   717    VfsStatCursor *pCur = (VfsStatCursor*)pVtabCursor;
   718    pCur->i = 0;
   719    return SQLITE_OK;
   720  }
   721  
   722  /*
   723  ** Only a forwards full table scan is supported.  xBestIndex is a no-op.
   724  */
   725  static int vstattabBestIndex(
   726    sqlite3_vtab *tab,
   727    sqlite3_index_info *pIdxInfo
   728  ){
   729    return SQLITE_OK;
   730  }
   731  
   732  /*
   733  ** Any VSTAT_COLUMN_COUNT can be changed to a positive integer.
   734  ** No deletions or insertions are allowed.  No changes to other
   735  ** columns are allowed.
   736  */
   737  static int vstattabUpdate(
   738    sqlite3_vtab *tab,
   739    int argc, sqlite3_value **argv,
   740    sqlite3_int64 *pRowid
   741  ){
   742    sqlite3_int64 iRowid, x;
   743    if( argc==1 ) return SQLITE_ERROR;
   744    if( sqlite3_value_type(argv[0])!=SQLITE_INTEGER ) return SQLITE_ERROR;
   745    iRowid = sqlite3_value_int64(argv[0]);
   746    if( iRowid!=sqlite3_value_int64(argv[1]) ) return SQLITE_ERROR;
   747    if( iRowid<0 || iRowid>=VFSSTAT_MXCNT ) return SQLITE_ERROR;
   748    if( sqlite3_value_type(argv[VSTAT_COLUMN_COUNT+2])!=SQLITE_INTEGER ){
   749      return SQLITE_ERROR;
   750    }
   751    x = sqlite3_value_int64(argv[VSTAT_COLUMN_COUNT+2]);
   752    if( x<0 ) return SQLITE_ERROR;
   753    aVfsCnt[iRowid] = x;
   754    return SQLITE_OK;
   755  }
   756  
   757  static sqlite3_module VfsStatModule = {
   758    0,                         /* iVersion */
   759    0,                         /* xCreate */
   760    vstattabConnect,           /* xConnect */
   761    vstattabBestIndex,         /* xBestIndex */
   762    vstattabDisconnect,        /* xDisconnect */
   763    0,                         /* xDestroy */
   764    vstattabOpen,              /* xOpen - open a cursor */
   765    vstattabClose,             /* xClose - close a cursor */
   766    vstattabFilter,            /* xFilter - configure scan constraints */
   767    vstattabNext,              /* xNext - advance a cursor */
   768    vstattabEof,               /* xEof - check for end of scan */
   769    vstattabColumn,            /* xColumn - read data */
   770    vstattabRowid,             /* xRowid - read data */
   771    vstattabUpdate,            /* xUpdate */
   772    0,                         /* xBegin */
   773    0,                         /* xSync */
   774    0,                         /* xCommit */
   775    0,                         /* xRollback */
   776    0,                         /* xFindMethod */
   777    0,                         /* xRename */
   778  };
   779  
   780  /*
   781  ** This routine is an sqlite3_auto_extension() callback, invoked to register
   782  ** the vfsstat virtual table for all new database connections.
   783  */
   784  static int vstatRegister(
   785    sqlite3 *db,
   786    const char **pzErrMsg,
   787    const struct sqlite3_api_routines *pThunk
   788  ){
   789    return sqlite3_create_module(db, "vfsstat", &VfsStatModule, 0);
   790  }
   791  
   792  #ifdef _WIN32
   793  __declspec(dllexport)
   794  #endif
   795  /* 
   796  ** This routine is called when the extension is loaded.
   797  **
   798  ** Register the new VFS.  Make arrangement to register the virtual table
   799  ** for each new database connection.
   800  */
   801  int sqlite3_vfsstat_init(
   802    sqlite3 *db, 
   803    char **pzErrMsg, 
   804    const sqlite3_api_routines *pApi
   805  ){
   806    int rc = SQLITE_OK;
   807    SQLITE_EXTENSION_INIT2(pApi);
   808    vstat_vfs.pVfs = sqlite3_vfs_find(0);
   809    vstat_vfs.base.szOsFile = sizeof(VStatFile) + vstat_vfs.pVfs->szOsFile;
   810    rc = sqlite3_vfs_register(&vstat_vfs.base, 1);
   811    if( rc==SQLITE_OK ){
   812      rc = sqlite3_auto_extension(vstatRegister);
   813    }
   814    if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
   815    return rc;
   816  }