| Index: third_party/sqlite/src/ext/misc/vfsstat.c
|
| diff --git a/third_party/sqlite/src/ext/misc/vfsstat.c b/third_party/sqlite/src/ext/misc/vfsstat.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..14753d277d6282683137f93b6707603fe53c78b8
|
| --- /dev/null
|
| +++ b/third_party/sqlite/src/ext/misc/vfsstat.c
|
| @@ -0,0 +1,816 @@
|
| +/*
|
| +** 2016-05-27
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +******************************************************************************
|
| +**
|
| +** This file contains the implementation of an SQLite vfs shim that
|
| +** tracks I/O. Access to the accumulated status counts is provided using
|
| +** an eponymous virtual table.
|
| +*/
|
| +#include <sqlite3ext.h>
|
| +SQLITE_EXTENSION_INIT1
|
| +
|
| +/*
|
| +** This module contains code for a wrapper VFS that cause stats for
|
| +** most VFS calls to be recorded.
|
| +**
|
| +** To use this module, first compile it as a loadable extension. See
|
| +** https://www.sqlite.org/loadext.html#build for compilations instructions.
|
| +**
|
| +** After compliing, load this extension, then open database connections to be
|
| +** measured. Query usages status using the vfsstat virtual table:
|
| +**
|
| +** SELECT * FROM vfsstat;
|
| +**
|
| +** Reset counters using UPDATE statements against vfsstat:
|
| +**
|
| +** UPDATE vfsstat SET count=0;
|
| +**
|
| +** EXAMPLE SCRIPT:
|
| +**
|
| +** .load ./vfsstat
|
| +** .open test.db
|
| +** DROP TABLE IF EXISTS t1;
|
| +** CREATE TABLE t1(x,y);
|
| +** INSERT INTO t1 VALUES(123, randomblob(5000));
|
| +** CREATE INDEX t1x ON t1(x);
|
| +** DROP TABLE t1;
|
| +** VACUUM;
|
| +** SELECT * FROM vfsstat WHERE count>0;
|
| +**
|
| +** LIMITATIONS:
|
| +**
|
| +** This module increments counters without using mutex protection. So if
|
| +** two or more threads try to use this module at the same time, race conditions
|
| +** may occur which mess up the counts. This is harmless, other than giving
|
| +** incorrect statistics.
|
| +*/
|
| +#include <string.h>
|
| +#include <stdlib.h>
|
| +#include <assert.h>
|
| +
|
| +/*
|
| +** File types
|
| +*/
|
| +#define VFSSTAT_MAIN 0 /* Main database file */
|
| +#define VFSSTAT_JOURNAL 1 /* Rollback journal */
|
| +#define VFSSTAT_WAL 2 /* Write-ahead log file */
|
| +#define VFSSTAT_MASTERJRNL 3 /* Master journal */
|
| +#define VFSSTAT_SUBJRNL 4 /* Subjournal */
|
| +#define VFSSTAT_TEMPDB 5 /* TEMP database */
|
| +#define VFSSTAT_TEMPJRNL 6 /* Journal for TEMP database */
|
| +#define VFSSTAT_TRANSIENT 7 /* Transient database */
|
| +#define VFSSTAT_ANY 8 /* Unspecified file type */
|
| +#define VFSSTAT_nFile 9 /* This many file types */
|
| +
|
| +/* Names of the file types. These are allowed values for the
|
| +** first column of the vfsstat virtual table.
|
| +*/
|
| +static const char *azFile[] = {
|
| + "database", "journal", "wal", "master-journal", "sub-journal",
|
| + "temp-database", "temp-journal", "transient-db", "*"
|
| +};
|
| +
|
| +/*
|
| +** Stat types
|
| +*/
|
| +#define VFSSTAT_BYTESIN 0 /* Bytes read in */
|
| +#define VFSSTAT_BYTESOUT 1 /* Bytes written out */
|
| +#define VFSSTAT_READ 2 /* Read requests */
|
| +#define VFSSTAT_WRITE 3 /* Write requests */
|
| +#define VFSSTAT_SYNC 4 /* Syncs */
|
| +#define VFSSTAT_OPEN 5 /* File opens */
|
| +#define VFSSTAT_LOCK 6 /* Lock requests */
|
| +#define VFSSTAT_ACCESS 0 /* xAccess calls. filetype==ANY only */
|
| +#define VFSSTAT_DELETE 1 /* xDelete calls. filetype==ANY only */
|
| +#define VFSSTAT_FULLPATH 2 /* xFullPathname calls. ANY only */
|
| +#define VFSSTAT_RANDOM 3 /* xRandomness calls. ANY only */
|
| +#define VFSSTAT_SLEEP 4 /* xSleep calls. ANY only */
|
| +#define VFSSTAT_CURTIME 5 /* xCurrentTime calls. ANY only */
|
| +#define VFSSTAT_nStat 7 /* This many stat types */
|
| +
|
| +
|
| +/* Names for the second column of the vfsstat virtual table for all
|
| +** cases except when the first column is "*" or VFSSTAT_ANY. */
|
| +static const char *azStat[] = {
|
| + "bytes-in", "bytes-out", "read", "write", "sync", "open", "lock",
|
| +};
|
| +static const char *azStatAny[] = {
|
| + "access", "delete", "fullpathname", "randomness", "sleep", "currenttimestamp",
|
| + "not-used"
|
| +};
|
| +
|
| +/* Total number of counters */
|
| +#define VFSSTAT_MXCNT (VFSSTAT_nStat*VFSSTAT_nFile)
|
| +
|
| +/*
|
| +** Performance stats are collected in an instance of the following
|
| +** global array.
|
| +*/
|
| +static sqlite3_uint64 aVfsCnt[VFSSTAT_MXCNT];
|
| +
|
| +/*
|
| +** Access to a specific counter
|
| +*/
|
| +#define STATCNT(filetype,stat) (aVfsCnt[(filetype)*VFSSTAT_nStat+(stat)])
|
| +
|
| +/*
|
| +** Forward declaration of objects used by this utility
|
| +*/
|
| +typedef struct VStatVfs VStatVfs;
|
| +typedef struct VStatFile VStatFile;
|
| +
|
| +/* An instance of the VFS */
|
| +struct VStatVfs {
|
| + sqlite3_vfs base; /* VFS methods */
|
| + sqlite3_vfs *pVfs; /* Parent VFS */
|
| +};
|
| +
|
| +/* An open file */
|
| +struct VStatFile {
|
| + sqlite3_file base; /* IO methods */
|
| + sqlite3_file *pReal; /* Underlying file handle */
|
| + unsigned char eFiletype; /* What type of file is this */
|
| +};
|
| +
|
| +#define REALVFS(p) (((VStatVfs*)(p))->pVfs)
|
| +
|
| +/*
|
| +** Methods for VStatFile
|
| +*/
|
| +static int vstatClose(sqlite3_file*);
|
| +static int vstatRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
|
| +static int vstatWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
|
| +static int vstatTruncate(sqlite3_file*, sqlite3_int64 size);
|
| +static int vstatSync(sqlite3_file*, int flags);
|
| +static int vstatFileSize(sqlite3_file*, sqlite3_int64 *pSize);
|
| +static int vstatLock(sqlite3_file*, int);
|
| +static int vstatUnlock(sqlite3_file*, int);
|
| +static int vstatCheckReservedLock(sqlite3_file*, int *pResOut);
|
| +static int vstatFileControl(sqlite3_file*, int op, void *pArg);
|
| +static int vstatSectorSize(sqlite3_file*);
|
| +static int vstatDeviceCharacteristics(sqlite3_file*);
|
| +static int vstatShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
|
| +static int vstatShmLock(sqlite3_file*, int offset, int n, int flags);
|
| +static void vstatShmBarrier(sqlite3_file*);
|
| +static int vstatShmUnmap(sqlite3_file*, int deleteFlag);
|
| +static int vstatFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
|
| +static int vstatUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
|
| +
|
| +/*
|
| +** Methods for VStatVfs
|
| +*/
|
| +static int vstatOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
|
| +static int vstatDelete(sqlite3_vfs*, const char *zName, int syncDir);
|
| +static int vstatAccess(sqlite3_vfs*, const char *zName, int flags, int *);
|
| +static int vstatFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
|
| +static void *vstatDlOpen(sqlite3_vfs*, const char *zFilename);
|
| +static void vstatDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
|
| +static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
|
| +static void vstatDlClose(sqlite3_vfs*, void*);
|
| +static int vstatRandomness(sqlite3_vfs*, int nByte, char *zOut);
|
| +static int vstatSleep(sqlite3_vfs*, int microseconds);
|
| +static int vstatCurrentTime(sqlite3_vfs*, double*);
|
| +static int vstatGetLastError(sqlite3_vfs*, int, char *);
|
| +static int vstatCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
|
| +
|
| +static VStatVfs vstat_vfs = {
|
| + {
|
| + 2, /* iVersion */
|
| + 0, /* szOsFile (set by register_vstat()) */
|
| + 1024, /* mxPathname */
|
| + 0, /* pNext */
|
| + "vfslog", /* zName */
|
| + 0, /* pAppData */
|
| + vstatOpen, /* xOpen */
|
| + vstatDelete, /* xDelete */
|
| + vstatAccess, /* xAccess */
|
| + vstatFullPathname, /* xFullPathname */
|
| + vstatDlOpen, /* xDlOpen */
|
| + vstatDlError, /* xDlError */
|
| + vstatDlSym, /* xDlSym */
|
| + vstatDlClose, /* xDlClose */
|
| + vstatRandomness, /* xRandomness */
|
| + vstatSleep, /* xSleep */
|
| + vstatCurrentTime, /* xCurrentTime */
|
| + vstatGetLastError, /* xGetLastError */
|
| + vstatCurrentTimeInt64 /* xCurrentTimeInt64 */
|
| + },
|
| + 0
|
| +};
|
| +
|
| +static const sqlite3_io_methods vstat_io_methods = {
|
| + 3, /* iVersion */
|
| + vstatClose, /* xClose */
|
| + vstatRead, /* xRead */
|
| + vstatWrite, /* xWrite */
|
| + vstatTruncate, /* xTruncate */
|
| + vstatSync, /* xSync */
|
| + vstatFileSize, /* xFileSize */
|
| + vstatLock, /* xLock */
|
| + vstatUnlock, /* xUnlock */
|
| + vstatCheckReservedLock, /* xCheckReservedLock */
|
| + vstatFileControl, /* xFileControl */
|
| + vstatSectorSize, /* xSectorSize */
|
| + vstatDeviceCharacteristics, /* xDeviceCharacteristics */
|
| + vstatShmMap, /* xShmMap */
|
| + vstatShmLock, /* xShmLock */
|
| + vstatShmBarrier, /* xShmBarrier */
|
| + vstatShmUnmap, /* xShmUnmap */
|
| + vstatFetch, /* xFetch */
|
| + vstatUnfetch /* xUnfetch */
|
| +};
|
| +
|
| +
|
| +
|
| +/*
|
| +** Close an vstat-file.
|
| +*/
|
| +static int vstatClose(sqlite3_file *pFile){
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + int rc = SQLITE_OK;
|
| +
|
| + if( p->pReal->pMethods ){
|
| + rc = p->pReal->pMethods->xClose(p->pReal);
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Read data from an vstat-file.
|
| +*/
|
| +static int vstatRead(
|
| + sqlite3_file *pFile,
|
| + void *zBuf,
|
| + int iAmt,
|
| + sqlite_int64 iOfst
|
| +){
|
| + int rc;
|
| + VStatFile *p = (VStatFile *)pFile;
|
| +
|
| + rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
|
| + STATCNT(p->eFiletype,VFSSTAT_READ)++;
|
| + if( rc==SQLITE_OK ){
|
| + STATCNT(p->eFiletype,VFSSTAT_BYTESIN) += iAmt;
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Write data to an vstat-file.
|
| +*/
|
| +static int vstatWrite(
|
| + sqlite3_file *pFile,
|
| + const void *z,
|
| + int iAmt,
|
| + sqlite_int64 iOfst
|
| +){
|
| + int rc;
|
| + VStatFile *p = (VStatFile *)pFile;
|
| +
|
| + rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
|
| + STATCNT(p->eFiletype,VFSSTAT_WRITE)++;
|
| + if( rc==SQLITE_OK ){
|
| + STATCNT(p->eFiletype,VFSSTAT_BYTESOUT) += iAmt;
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Truncate an vstat-file.
|
| +*/
|
| +static int vstatTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
| + int rc;
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + rc = p->pReal->pMethods->xTruncate(p->pReal, size);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Sync an vstat-file.
|
| +*/
|
| +static int vstatSync(sqlite3_file *pFile, int flags){
|
| + int rc;
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + rc = p->pReal->pMethods->xSync(p->pReal, flags);
|
| + STATCNT(p->eFiletype,VFSSTAT_SYNC)++;
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Return the current file-size of an vstat-file.
|
| +*/
|
| +static int vstatFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
| + int rc;
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Lock an vstat-file.
|
| +*/
|
| +static int vstatLock(sqlite3_file *pFile, int eLock){
|
| + int rc;
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + rc = p->pReal->pMethods->xLock(p->pReal, eLock);
|
| + STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Unlock an vstat-file.
|
| +*/
|
| +static int vstatUnlock(sqlite3_file *pFile, int eLock){
|
| + int rc;
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
|
| + STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Check if another file-handle holds a RESERVED lock on an vstat-file.
|
| +*/
|
| +static int vstatCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
| + int rc;
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
|
| + STATCNT(p->eFiletype,VFSSTAT_LOCK)++;
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** File control method. For custom operations on an vstat-file.
|
| +*/
|
| +static int vstatFileControl(sqlite3_file *pFile, int op, void *pArg){
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + int rc;
|
| + rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
|
| + if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
|
| + *(char**)pArg = sqlite3_mprintf("vstat/%z", *(char**)pArg);
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Return the sector-size in bytes for an vstat-file.
|
| +*/
|
| +static int vstatSectorSize(sqlite3_file *pFile){
|
| + int rc;
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + rc = p->pReal->pMethods->xSectorSize(p->pReal);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Return the device characteristic flags supported by an vstat-file.
|
| +*/
|
| +static int vstatDeviceCharacteristics(sqlite3_file *pFile){
|
| + int rc;
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
|
| + return rc;
|
| +}
|
| +
|
| +/* Create a shared memory file mapping */
|
| +static int vstatShmMap(
|
| + sqlite3_file *pFile,
|
| + int iPg,
|
| + int pgsz,
|
| + int bExtend,
|
| + void volatile **pp
|
| +){
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + return p->pReal->pMethods->xShmMap(p->pReal, iPg, pgsz, bExtend, pp);
|
| +}
|
| +
|
| +/* Perform locking on a shared-memory segment */
|
| +static int vstatShmLock(sqlite3_file *pFile, int offset, int n, int flags){
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + return p->pReal->pMethods->xShmLock(p->pReal, offset, n, flags);
|
| +}
|
| +
|
| +/* Memory barrier operation on shared memory */
|
| +static void vstatShmBarrier(sqlite3_file *pFile){
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + p->pReal->pMethods->xShmBarrier(p->pReal);
|
| +}
|
| +
|
| +/* Unmap a shared memory segment */
|
| +static int vstatShmUnmap(sqlite3_file *pFile, int deleteFlag){
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + return p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
|
| +}
|
| +
|
| +/* Fetch a page of a memory-mapped file */
|
| +static int vstatFetch(
|
| + sqlite3_file *pFile,
|
| + sqlite3_int64 iOfst,
|
| + int iAmt,
|
| + void **pp
|
| +){
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + return p->pReal->pMethods->xFetch(p->pReal, iOfst, iAmt, pp);
|
| +}
|
| +
|
| +/* Release a memory-mapped page */
|
| +static int vstatUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
|
| + VStatFile *p = (VStatFile *)pFile;
|
| + return p->pReal->pMethods->xUnfetch(p->pReal, iOfst, pPage);
|
| +}
|
| +
|
| +/*
|
| +** Open an vstat file handle.
|
| +*/
|
| +static int vstatOpen(
|
| + sqlite3_vfs *pVfs,
|
| + const char *zName,
|
| + sqlite3_file *pFile,
|
| + int flags,
|
| + int *pOutFlags
|
| +){
|
| + int rc;
|
| + VStatFile *p = (VStatFile*)pFile;
|
| +
|
| + p->pReal = (sqlite3_file*)&p[1];
|
| + rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
|
| + if( flags & SQLITE_OPEN_MAIN_DB ){
|
| + p->eFiletype = VFSSTAT_MAIN;
|
| + }else if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
|
| + p->eFiletype = VFSSTAT_JOURNAL;
|
| + }else if( flags & SQLITE_OPEN_WAL ){
|
| + p->eFiletype = VFSSTAT_WAL;
|
| + }else if( flags & SQLITE_OPEN_MASTER_JOURNAL ){
|
| + p->eFiletype = VFSSTAT_MASTERJRNL;
|
| + }else if( flags & SQLITE_OPEN_SUBJOURNAL ){
|
| + p->eFiletype = VFSSTAT_SUBJRNL;
|
| + }else if( flags & SQLITE_OPEN_TEMP_DB ){
|
| + p->eFiletype = VFSSTAT_TEMPDB;
|
| + }else if( flags & SQLITE_OPEN_TEMP_JOURNAL ){
|
| + p->eFiletype = VFSSTAT_TEMPJRNL;
|
| + }else{
|
| + p->eFiletype = VFSSTAT_TRANSIENT;
|
| + }
|
| + STATCNT(p->eFiletype,VFSSTAT_OPEN)++;
|
| + pFile->pMethods = rc ? 0 : &vstat_io_methods;
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Delete the file located at zPath. If the dirSync argument is true,
|
| +** ensure the file-system modifications are synced to disk before
|
| +** returning.
|
| +*/
|
| +static int vstatDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
| + int rc;
|
| + rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
|
| + STATCNT(VFSSTAT_ANY,VFSSTAT_DELETE)++;
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Test for access permissions. Return true if the requested permission
|
| +** is available, or false otherwise.
|
| +*/
|
| +static int vstatAccess(
|
| + sqlite3_vfs *pVfs,
|
| + const char *zPath,
|
| + int flags,
|
| + int *pResOut
|
| +){
|
| + int rc;
|
| + rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
|
| + STATCNT(VFSSTAT_ANY,VFSSTAT_ACCESS)++;
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Populate buffer zOut with the full canonical pathname corresponding
|
| +** to the pathname in zPath. zOut is guaranteed to point to a buffer
|
| +** of at least (INST_MAX_PATHNAME+1) bytes.
|
| +*/
|
| +static int vstatFullPathname(
|
| + sqlite3_vfs *pVfs,
|
| + const char *zPath,
|
| + int nOut,
|
| + char *zOut
|
| +){
|
| + STATCNT(VFSSTAT_ANY,VFSSTAT_FULLPATH)++;
|
| + return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
|
| +}
|
| +
|
| +/*
|
| +** Open the dynamic library located at zPath and return a handle.
|
| +*/
|
| +static void *vstatDlOpen(sqlite3_vfs *pVfs, const char *zPath){
|
| + return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
|
| +}
|
| +
|
| +/*
|
| +** Populate the buffer zErrMsg (size nByte bytes) with a human readable
|
| +** utf-8 string describing the most recent error encountered associated
|
| +** with dynamic libraries.
|
| +*/
|
| +static void vstatDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
|
| + REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
|
| +}
|
| +
|
| +/*
|
| +** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
|
| +*/
|
| +static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
|
| + return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
|
| +}
|
| +
|
| +/*
|
| +** Close the dynamic library handle pHandle.
|
| +*/
|
| +static void vstatDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
| + REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
|
| +}
|
| +
|
| +/*
|
| +** Populate the buffer pointed to by zBufOut with nByte bytes of
|
| +** random data.
|
| +*/
|
| +static int vstatRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
| + STATCNT(VFSSTAT_ANY,VFSSTAT_RANDOM)++;
|
| + return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
|
| +}
|
| +
|
| +/*
|
| +** Sleep for nMicro microseconds. Return the number of microseconds
|
| +** actually slept.
|
| +*/
|
| +static int vstatSleep(sqlite3_vfs *pVfs, int nMicro){
|
| + STATCNT(VFSSTAT_ANY,VFSSTAT_SLEEP)++;
|
| + return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
|
| +}
|
| +
|
| +/*
|
| +** Return the current time as a Julian Day number in *pTimeOut.
|
| +*/
|
| +static int vstatCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
| + STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++;
|
| + return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
|
| +}
|
| +
|
| +static int vstatGetLastError(sqlite3_vfs *pVfs, int a, char *b){
|
| + return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
|
| +}
|
| +static int vstatCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
|
| + STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++;
|
| + return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
|
| +}
|
| +
|
| +/*
|
| +** A virtual table for accessing the stats collected by this VFS shim
|
| +*/
|
| +static int vstattabConnect(sqlite3*, void*, int, const char*const*,
|
| + sqlite3_vtab**,char**);
|
| +static int vstattabBestIndex(sqlite3_vtab*,sqlite3_index_info*);
|
| +static int vstattabDisconnect(sqlite3_vtab*);
|
| +static int vstattabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**);
|
| +static int vstattabClose(sqlite3_vtab_cursor*);
|
| +static int vstattabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
|
| + int argc, sqlite3_value **argv);
|
| +static int vstattabNext(sqlite3_vtab_cursor*);
|
| +static int vstattabEof(sqlite3_vtab_cursor*);
|
| +static int vstattabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int);
|
| +static int vstattabRowid(sqlite3_vtab_cursor*,sqlite3_int64*);
|
| +static int vstattabUpdate(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
|
| +
|
| +/* A cursor for the vfsstat virtual table */
|
| +typedef struct VfsStatCursor {
|
| + sqlite3_vtab_cursor base; /* Base class. Must be first */
|
| + int i; /* Pointing to this aVfsCnt[] value */
|
| +} VfsStatCursor;
|
| +
|
| +
|
| +static int vstattabConnect(
|
| + sqlite3 *db,
|
| + void *pAux,
|
| + int argc, const char *const*argv,
|
| + sqlite3_vtab **ppVtab,
|
| + char **pzErr
|
| +){
|
| + sqlite3_vtab *pNew;
|
| + int rc;
|
| +
|
| +/* Column numbers */
|
| +#define VSTAT_COLUMN_FILE 0
|
| +#define VSTAT_COLUMN_STAT 1
|
| +#define VSTAT_COLUMN_COUNT 2
|
| +
|
| + rc = sqlite3_declare_vtab(db,"CREATE TABLE x(file,stat,count)");
|
| + if( rc==SQLITE_OK ){
|
| + pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
| + if( pNew==0 ) return SQLITE_NOMEM;
|
| + memset(pNew, 0, sizeof(*pNew));
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** This method is the destructor for vstat table object.
|
| +*/
|
| +static int vstattabDisconnect(sqlite3_vtab *pVtab){
|
| + sqlite3_free(pVtab);
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** Constructor for a new vstat table cursor object.
|
| +*/
|
| +static int vstattabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
| + VfsStatCursor *pCur;
|
| + pCur = sqlite3_malloc( sizeof(*pCur) );
|
| + if( pCur==0 ) return SQLITE_NOMEM;
|
| + memset(pCur, 0, sizeof(*pCur));
|
| + *ppCursor = &pCur->base;
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Destructor for a VfsStatCursor.
|
| +*/
|
| +static int vstattabClose(sqlite3_vtab_cursor *cur){
|
| + sqlite3_free(cur);
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Advance a VfsStatCursor to its next row of output.
|
| +*/
|
| +static int vstattabNext(sqlite3_vtab_cursor *cur){
|
| + ((VfsStatCursor*)cur)->i++;
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** Return values of columns for the row at which the VfsStatCursor
|
| +** is currently pointing.
|
| +*/
|
| +static int vstattabColumn(
|
| + sqlite3_vtab_cursor *cur, /* The cursor */
|
| + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
| + int i /* Which column to return */
|
| +){
|
| + VfsStatCursor *pCur = (VfsStatCursor*)cur;
|
| + switch( i ){
|
| + case VSTAT_COLUMN_FILE: {
|
| + sqlite3_result_text(ctx, azFile[pCur->i/VFSSTAT_nStat], -1, SQLITE_STATIC);
|
| + break;
|
| + }
|
| + case VSTAT_COLUMN_STAT: {
|
| + const char **az;
|
| + az = (pCur->i/VFSSTAT_nStat)==VFSSTAT_ANY ? azStatAny : azStat;
|
| + sqlite3_result_text(ctx, az[pCur->i%VFSSTAT_nStat], -1, SQLITE_STATIC);
|
| + break;
|
| + }
|
| + case VSTAT_COLUMN_COUNT: {
|
| + sqlite3_result_int64(ctx, aVfsCnt[pCur->i]);
|
| + break;
|
| + }
|
| + }
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** Return the rowid for the current row.
|
| +*/
|
| +static int vstattabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
| + VfsStatCursor *pCur = (VfsStatCursor*)cur;
|
| + *pRowid = pCur->i;
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** Return TRUE if the cursor has been moved off of the last
|
| +** row of output.
|
| +*/
|
| +static int vstattabEof(sqlite3_vtab_cursor *cur){
|
| + VfsStatCursor *pCur = (VfsStatCursor*)cur;
|
| + return pCur->i >= VFSSTAT_MXCNT;
|
| +}
|
| +
|
| +/*
|
| +** Only a full table scan is supported. So xFilter simply rewinds to
|
| +** the beginning.
|
| +*/
|
| +static int vstattabFilter(
|
| + sqlite3_vtab_cursor *pVtabCursor,
|
| + int idxNum, const char *idxStr,
|
| + int argc, sqlite3_value **argv
|
| +){
|
| + VfsStatCursor *pCur = (VfsStatCursor*)pVtabCursor;
|
| + pCur->i = 0;
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** Only a forwards full table scan is supported. xBestIndex is a no-op.
|
| +*/
|
| +static int vstattabBestIndex(
|
| + sqlite3_vtab *tab,
|
| + sqlite3_index_info *pIdxInfo
|
| +){
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +/*
|
| +** Any VSTAT_COLUMN_COUNT can be changed to a positive integer.
|
| +** No deletions or insertions are allowed. No changes to other
|
| +** columns are allowed.
|
| +*/
|
| +static int vstattabUpdate(
|
| + sqlite3_vtab *tab,
|
| + int argc, sqlite3_value **argv,
|
| + sqlite3_int64 *pRowid
|
| +){
|
| + sqlite3_int64 iRowid, x;
|
| + if( argc==1 ) return SQLITE_ERROR;
|
| + if( sqlite3_value_type(argv[0])!=SQLITE_INTEGER ) return SQLITE_ERROR;
|
| + iRowid = sqlite3_value_int64(argv[0]);
|
| + if( iRowid!=sqlite3_value_int64(argv[1]) ) return SQLITE_ERROR;
|
| + if( iRowid<0 || iRowid>=VFSSTAT_MXCNT ) return SQLITE_ERROR;
|
| + if( sqlite3_value_type(argv[VSTAT_COLUMN_COUNT+2])!=SQLITE_INTEGER ){
|
| + return SQLITE_ERROR;
|
| + }
|
| + x = sqlite3_value_int64(argv[VSTAT_COLUMN_COUNT+2]);
|
| + if( x<0 ) return SQLITE_ERROR;
|
| + aVfsCnt[iRowid] = x;
|
| + return SQLITE_OK;
|
| +}
|
| +
|
| +static sqlite3_module VfsStatModule = {
|
| + 0, /* iVersion */
|
| + 0, /* xCreate */
|
| + vstattabConnect, /* xConnect */
|
| + vstattabBestIndex, /* xBestIndex */
|
| + vstattabDisconnect, /* xDisconnect */
|
| + 0, /* xDestroy */
|
| + vstattabOpen, /* xOpen - open a cursor */
|
| + vstattabClose, /* xClose - close a cursor */
|
| + vstattabFilter, /* xFilter - configure scan constraints */
|
| + vstattabNext, /* xNext - advance a cursor */
|
| + vstattabEof, /* xEof - check for end of scan */
|
| + vstattabColumn, /* xColumn - read data */
|
| + vstattabRowid, /* xRowid - read data */
|
| + vstattabUpdate, /* xUpdate */
|
| + 0, /* xBegin */
|
| + 0, /* xSync */
|
| + 0, /* xCommit */
|
| + 0, /* xRollback */
|
| + 0, /* xFindMethod */
|
| + 0, /* xRename */
|
| +};
|
| +
|
| +/*
|
| +** This routine is an sqlite3_auto_extension() callback, invoked to register
|
| +** the vfsstat virtual table for all new database connections.
|
| +*/
|
| +static int vstatRegister(
|
| + sqlite3 *db,
|
| + const char **pzErrMsg,
|
| + const struct sqlite3_api_routines *pThunk
|
| +){
|
| + return sqlite3_create_module(db, "vfsstat", &VfsStatModule, 0);
|
| +}
|
| +
|
| +#ifdef _WIN32
|
| +__declspec(dllexport)
|
| +#endif
|
| +/*
|
| +** This routine is called when the extension is loaded.
|
| +**
|
| +** Register the new VFS. Make arrangement to register the virtual table
|
| +** for each new database connection.
|
| +*/
|
| +int sqlite3_vfsstat_init(
|
| + sqlite3 *db,
|
| + char **pzErrMsg,
|
| + const sqlite3_api_routines *pApi
|
| +){
|
| + int rc = SQLITE_OK;
|
| + SQLITE_EXTENSION_INIT2(pApi);
|
| + vstat_vfs.pVfs = sqlite3_vfs_find(0);
|
| + vstat_vfs.base.szOsFile = sizeof(VStatFile) + vstat_vfs.pVfs->szOsFile;
|
| + rc = sqlite3_vfs_register(&vstat_vfs.base, 1);
|
| + if( rc==SQLITE_OK ){
|
| + rc = sqlite3_auto_extension(vstatRegister);
|
| + }
|
| + if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
|
| + return rc;
|
| +}
|
|
|