| Index: third_party/sqlite/src/ext/misc/vfslog.c
|
| diff --git a/third_party/sqlite/src/ext/misc/vfslog.c b/third_party/sqlite/src/ext/misc/vfslog.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b55b06fcf3a7429bd9e78efbb5ec3d9f3b3de892
|
| --- /dev/null
|
| +++ b/third_party/sqlite/src/ext/misc/vfslog.c
|
| @@ -0,0 +1,759 @@
|
| +/*
|
| +** 2013-10-09
|
| +**
|
| +** The author disclaims copyright to this source code. In place of
|
| +** a legal notice, here is a blessing:
|
| +**
|
| +** May you do good and not evil.
|
| +** May you find forgiveness for yourself and forgive others.
|
| +** May you share freely, never taking more than you give.
|
| +**
|
| +******************************************************************************
|
| +**
|
| +** This file contains the implementation of an SQLite vfs wrapper for
|
| +** unix that generates per-database log files of all disk activity.
|
| +*/
|
| +
|
| +/*
|
| +** This module contains code for a wrapper VFS that causes a log of
|
| +** most VFS calls to be written into a file on disk.
|
| +**
|
| +** Each database connection creates a separate log file in the same
|
| +** directory as the original database and named after the original
|
| +** database. A unique suffix is added to avoid name collisions.
|
| +** Separate log files are used so that concurrent processes do not
|
| +** try to write log operations to the same file at the same instant,
|
| +** resulting in overwritten or comingled log text.
|
| +**
|
| +** Each individual log file records operations by a single database
|
| +** connection on both the original database and its associated rollback
|
| +** journal.
|
| +**
|
| +** The log files are in the comma-separated-value (CSV) format. The
|
| +** log files can be imported into an SQLite database using the ".import"
|
| +** command of the SQLite command-line shell for analysis.
|
| +**
|
| +** One technique for using this module is to append the text of this
|
| +** module to the end of a standard "sqlite3.c" amalgamation file then
|
| +** add the following compile-time options:
|
| +**
|
| +** -DSQLITE_EXTRA_INIT=sqlite3_register_vfslog
|
| +** -DSQLITE_USE_FCNTL_TRACE
|
| +**
|
| +** The first compile-time option causes the sqlite3_register_vfslog()
|
| +** function, defined below, to be invoked when SQLite is initialized.
|
| +** That causes this custom VFS to become the default VFS for all
|
| +** subsequent connections. The SQLITE_USE_FCNTL_TRACE option causes
|
| +** the SQLite core to issue extra sqlite3_file_control() operations
|
| +** with SQLITE_FCNTL_TRACE to give some indication of what is going
|
| +** on in the core.
|
| +*/
|
| +
|
| +#include "sqlite3.h"
|
| +#include <string.h>
|
| +#include <assert.h>
|
| +#include <stdio.h>
|
| +#if SQLITE_OS_UNIX
|
| +# include <unistd.h>
|
| +#endif
|
| +
|
| +/*
|
| +** Forward declaration of objects used by this utility
|
| +*/
|
| +typedef struct VLogLog VLogLog;
|
| +typedef struct VLogVfs VLogVfs;
|
| +typedef struct VLogFile VLogFile;
|
| +
|
| +/* There is a pair (an array of size 2) of the following objects for
|
| +** each database file being logged. The first contains the filename
|
| +** and is used to log I/O with the main database. The second has
|
| +** a NULL filename and is used to log I/O for the journal. Both
|
| +** out pointers are the same.
|
| +*/
|
| +struct VLogLog {
|
| + VLogLog *pNext; /* Next in a list of all active logs */
|
| + VLogLog **ppPrev; /* Pointer to this in the list */
|
| + int nRef; /* Number of references to this object */
|
| + int nFilename; /* Length of zFilename in bytes */
|
| + char *zFilename; /* Name of database file. NULL for journal */
|
| + FILE *out; /* Write information here */
|
| +};
|
| +
|
| +struct VLogVfs {
|
| + sqlite3_vfs base; /* VFS methods */
|
| + sqlite3_vfs *pVfs; /* Parent VFS */
|
| +};
|
| +
|
| +struct VLogFile {
|
| + sqlite3_file base; /* IO methods */
|
| + sqlite3_file *pReal; /* Underlying file handle */
|
| + VLogLog *pLog; /* The log file for this file */
|
| +};
|
| +
|
| +#define REALVFS(p) (((VLogVfs*)(p))->pVfs)
|
| +
|
| +/*
|
| +** Methods for VLogFile
|
| +*/
|
| +static int vlogClose(sqlite3_file*);
|
| +static int vlogRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
|
| +static int vlogWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
|
| +static int vlogTruncate(sqlite3_file*, sqlite3_int64 size);
|
| +static int vlogSync(sqlite3_file*, int flags);
|
| +static int vlogFileSize(sqlite3_file*, sqlite3_int64 *pSize);
|
| +static int vlogLock(sqlite3_file*, int);
|
| +static int vlogUnlock(sqlite3_file*, int);
|
| +static int vlogCheckReservedLock(sqlite3_file*, int *pResOut);
|
| +static int vlogFileControl(sqlite3_file*, int op, void *pArg);
|
| +static int vlogSectorSize(sqlite3_file*);
|
| +static int vlogDeviceCharacteristics(sqlite3_file*);
|
| +
|
| +/*
|
| +** Methods for VLogVfs
|
| +*/
|
| +static int vlogOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
|
| +static int vlogDelete(sqlite3_vfs*, const char *zName, int syncDir);
|
| +static int vlogAccess(sqlite3_vfs*, const char *zName, int flags, int *);
|
| +static int vlogFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
|
| +static void *vlogDlOpen(sqlite3_vfs*, const char *zFilename);
|
| +static void vlogDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
|
| +static void (*vlogDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
|
| +static void vlogDlClose(sqlite3_vfs*, void*);
|
| +static int vlogRandomness(sqlite3_vfs*, int nByte, char *zOut);
|
| +static int vlogSleep(sqlite3_vfs*, int microseconds);
|
| +static int vlogCurrentTime(sqlite3_vfs*, double*);
|
| +static int vlogGetLastError(sqlite3_vfs*, int, char *);
|
| +static int vlogCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
|
| +
|
| +static VLogVfs vlog_vfs = {
|
| + {
|
| + 1, /* iVersion */
|
| + 0, /* szOsFile (set by register_vlog()) */
|
| + 1024, /* mxPathname */
|
| + 0, /* pNext */
|
| + "vfslog", /* zName */
|
| + 0, /* pAppData */
|
| + vlogOpen, /* xOpen */
|
| + vlogDelete, /* xDelete */
|
| + vlogAccess, /* xAccess */
|
| + vlogFullPathname, /* xFullPathname */
|
| + vlogDlOpen, /* xDlOpen */
|
| + vlogDlError, /* xDlError */
|
| + vlogDlSym, /* xDlSym */
|
| + vlogDlClose, /* xDlClose */
|
| + vlogRandomness, /* xRandomness */
|
| + vlogSleep, /* xSleep */
|
| + vlogCurrentTime, /* xCurrentTime */
|
| + vlogGetLastError, /* xGetLastError */
|
| + vlogCurrentTimeInt64 /* xCurrentTimeInt64 */
|
| + },
|
| + 0
|
| +};
|
| +
|
| +static sqlite3_io_methods vlog_io_methods = {
|
| + 1, /* iVersion */
|
| + vlogClose, /* xClose */
|
| + vlogRead, /* xRead */
|
| + vlogWrite, /* xWrite */
|
| + vlogTruncate, /* xTruncate */
|
| + vlogSync, /* xSync */
|
| + vlogFileSize, /* xFileSize */
|
| + vlogLock, /* xLock */
|
| + vlogUnlock, /* xUnlock */
|
| + vlogCheckReservedLock, /* xCheckReservedLock */
|
| + vlogFileControl, /* xFileControl */
|
| + vlogSectorSize, /* xSectorSize */
|
| + vlogDeviceCharacteristics, /* xDeviceCharacteristics */
|
| + 0, /* xShmMap */
|
| + 0, /* xShmLock */
|
| + 0, /* xShmBarrier */
|
| + 0 /* xShmUnmap */
|
| +};
|
| +
|
| +#if SQLITE_OS_UNIX && !defined(NO_GETTOD)
|
| +#include <sys/time.h>
|
| +static sqlite3_uint64 vlog_time(){
|
| + struct timeval sTime;
|
| + gettimeofday(&sTime, 0);
|
| + return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000;
|
| +}
|
| +#elif SQLITE_OS_WIN
|
| +#include <windows.h>
|
| +#include <time.h>
|
| +static sqlite3_uint64 vlog_time(){
|
| + FILETIME ft;
|
| + sqlite3_uint64 u64time = 0;
|
| +
|
| + GetSystemTimeAsFileTime(&ft);
|
| +
|
| + u64time |= ft.dwHighDateTime;
|
| + u64time <<= 32;
|
| + u64time |= ft.dwLowDateTime;
|
| +
|
| + /* ft is 100-nanosecond intervals, we want microseconds */
|
| + return u64time /(sqlite3_uint64)10;
|
| +}
|
| +#else
|
| +static sqlite3_uint64 vlog_time(){
|
| + return 0;
|
| +}
|
| +#endif
|
| +
|
| +
|
| +/*
|
| +** Write a message to the log file
|
| +*/
|
| +static void vlogLogPrint(
|
| + VLogLog *pLog, /* The log file to write into */
|
| + sqlite3_int64 tStart, /* Start time of system call */
|
| + sqlite3_int64 tElapse, /* Elapse time of system call */
|
| + const char *zOp, /* Type of system call */
|
| + sqlite3_int64 iArg1, /* First argument */
|
| + sqlite3_int64 iArg2, /* Second argument */
|
| + const char *zArg3, /* Third argument */
|
| + int iRes /* Result */
|
| +){
|
| + char z1[40], z2[40], z3[2000];
|
| + if( pLog==0 ) return;
|
| + if( iArg1>=0 ){
|
| + sqlite3_snprintf(sizeof(z1), z1, "%lld", iArg1);
|
| + }else{
|
| + z1[0] = 0;
|
| + }
|
| + if( iArg2>=0 ){
|
| + sqlite3_snprintf(sizeof(z2), z2, "%lld", iArg2);
|
| + }else{
|
| + z2[0] = 0;
|
| + }
|
| + if( zArg3 ){
|
| + sqlite3_snprintf(sizeof(z3), z3, "\"%.*w\"", sizeof(z3)-4, zArg3);
|
| + }else{
|
| + z3[0] = 0;
|
| + }
|
| + fprintf(pLog->out,"%lld,%lld,%s,%d,%s,%s,%s,%d\n",
|
| + tStart, tElapse, zOp, pLog->zFilename==0, z1, z2, z3, iRes);
|
| +}
|
| +
|
| +/*
|
| +** List of all active log connections. Protected by the master mutex.
|
| +*/
|
| +static VLogLog *allLogs = 0;
|
| +
|
| +/*
|
| +** Close a VLogLog object
|
| +*/
|
| +static void vlogLogClose(VLogLog *p){
|
| + if( p ){
|
| + sqlite3_mutex *pMutex;
|
| + p->nRef--;
|
| + if( p->nRef>0 || p->zFilename==0 ) return;
|
| + pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
|
| + sqlite3_mutex_enter(pMutex);
|
| + *p->ppPrev = p->pNext;
|
| + if( p->pNext ) p->pNext->ppPrev = p->ppPrev;
|
| + sqlite3_mutex_leave(pMutex);
|
| + fclose(p->out);
|
| + sqlite3_free(p);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Open a VLogLog object on the given file
|
| +*/
|
| +static VLogLog *vlogLogOpen(const char *zFilename){
|
| + int nName = (int)strlen(zFilename);
|
| + int isJournal = 0;
|
| + sqlite3_mutex *pMutex;
|
| + VLogLog *pLog, *pTemp;
|
| + sqlite3_int64 tNow = 0;
|
| + if( nName>4 && strcmp(zFilename+nName-4,"-wal")==0 ){
|
| + return 0; /* Do not log wal files */
|
| + }else
|
| + if( nName>8 && strcmp(zFilename+nName-8,"-journal")==0 ){
|
| + nName -= 8;
|
| + isJournal = 1;
|
| + }else if( nName>12
|
| + && sqlite3_strglob("-mj??????9??", zFilename+nName-12)==0 ){
|
| + return 0; /* Do not log master journal files */
|
| + }
|
| + pTemp = sqlite3_malloc( sizeof(*pLog)*2 + nName + 60 );
|
| + if( pTemp==0 ) return 0;
|
| + pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
|
| + sqlite3_mutex_enter(pMutex);
|
| + for(pLog=allLogs; pLog; pLog=pLog->pNext){
|
| + if( pLog->nFilename==nName && !memcmp(pLog->zFilename, zFilename, nName) ){
|
| + break;
|
| + }
|
| + }
|
| + if( pLog==0 ){
|
| + pLog = pTemp;
|
| + pTemp = 0;
|
| + memset(pLog, 0, sizeof(*pLog)*2);
|
| + pLog->zFilename = (char*)&pLog[2];
|
| + tNow = vlog_time();
|
| + sqlite3_snprintf(nName+60, pLog->zFilename, "%.*s-debuglog-%lld",
|
| + nName, zFilename, tNow);
|
| + pLog->out = fopen(pLog->zFilename, "a");
|
| + if( pLog->out==0 ){
|
| + sqlite3_mutex_leave(pMutex);
|
| + sqlite3_free(pLog);
|
| + return 0;
|
| + }
|
| + pLog->nFilename = nName;
|
| + pLog[1].out = pLog[0].out;
|
| + pLog->ppPrev = &allLogs;
|
| + if( allLogs ) allLogs->ppPrev = &pLog->pNext;
|
| + pLog->pNext = allLogs;
|
| + allLogs = pLog;
|
| + }
|
| + sqlite3_mutex_leave(pMutex);
|
| + if( pTemp ){
|
| + sqlite3_free(pTemp);
|
| + }else{
|
| +#if SQLITE_OS_UNIX
|
| + char zHost[200];
|
| + zHost[0] = 0;
|
| + gethostname(zHost, sizeof(zHost)-1);
|
| + zHost[sizeof(zHost)-1] = 0;
|
| + vlogLogPrint(pLog, tNow, 0, "IDENT", getpid(), -1, zHost, 0);
|
| +#endif
|
| + }
|
| + if( pLog && isJournal ) pLog++;
|
| + pLog->nRef++;
|
| + return pLog;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Close an vlog-file.
|
| +*/
|
| +static int vlogClose(sqlite3_file *pFile){
|
| + sqlite3_uint64 tStart, tElapse;
|
| + int rc = SQLITE_OK;
|
| + VLogFile *p = (VLogFile *)pFile;
|
| +
|
| + tStart = vlog_time();
|
| + if( p->pReal->pMethods ){
|
| + rc = p->pReal->pMethods->xClose(p->pReal);
|
| + }
|
| + tElapse = vlog_time() - tStart;
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "CLOSE", -1, -1, 0, rc);
|
| + vlogLogClose(p->pLog);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Compute signature for a block of content.
|
| +**
|
| +** For blocks of 16 or fewer bytes, the signature is just a hex dump of
|
| +** the entire block.
|
| +**
|
| +** For blocks of more than 16 bytes, the signature is a hex dump of the
|
| +** first 8 bytes followed by a 64-bit has of the entire block.
|
| +*/
|
| +static void vlogSignature(unsigned char *p, int n, char *zCksum){
|
| + unsigned int s0 = 0, s1 = 0;
|
| + unsigned int *pI;
|
| + int i;
|
| + if( n<=16 ){
|
| + for(i=0; i<n; i++) sqlite3_snprintf(3, zCksum+i*2, "%02x", p[i]);
|
| + }else{
|
| + pI = (unsigned int*)p;
|
| + for(i=0; i<n-7; i+=8){
|
| + s0 += pI[0] + s1;
|
| + s1 += pI[1] + s0;
|
| + pI += 2;
|
| + }
|
| + for(i=0; i<8; i++) sqlite3_snprintf(3, zCksum+i*2, "%02x", p[i]);
|
| + sqlite3_snprintf(18, zCksum+i*2, "-%08x%08x", s0, s1);
|
| + }
|
| +}
|
| +
|
| +/*
|
| +** Convert a big-endian 32-bit integer into a native integer
|
| +*/
|
| +static int bigToNative(const unsigned char *x){
|
| + return (x[0]<<24) + (x[1]<<16) + (x[2]<<8) + x[3];
|
| +}
|
| +
|
| +/*
|
| +** Read data from an vlog-file.
|
| +*/
|
| +static int vlogRead(
|
| + sqlite3_file *pFile,
|
| + void *zBuf,
|
| + int iAmt,
|
| + sqlite_int64 iOfst
|
| +){
|
| + int rc;
|
| + sqlite3_uint64 tStart, tElapse;
|
| + VLogFile *p = (VLogFile *)pFile;
|
| + char zSig[40];
|
| +
|
| + tStart = vlog_time();
|
| + rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
|
| + tElapse = vlog_time() - tStart;
|
| + if( rc==SQLITE_OK ){
|
| + vlogSignature(zBuf, iAmt, zSig);
|
| + }else{
|
| + zSig[0] = 0;
|
| + }
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "READ", iAmt, iOfst, zSig, rc);
|
| + if( rc==SQLITE_OK
|
| + && p->pLog
|
| + && p->pLog->zFilename
|
| + && iOfst<=24
|
| + && iOfst+iAmt>=28
|
| + ){
|
| + unsigned char *x = ((unsigned char*)zBuf)+(24-iOfst);
|
| + unsigned iCtr, nFree = -1;
|
| + char *zFree = 0;
|
| + char zStr[12];
|
| + iCtr = bigToNative(x);
|
| + if( iOfst+iAmt>=40 ){
|
| + zFree = zStr;
|
| + sqlite3_snprintf(sizeof(zStr), zStr, "%d", bigToNative(x+8));
|
| + nFree = bigToNative(x+12);
|
| + }
|
| + vlogLogPrint(p->pLog, tStart, 0, "CHNGCTR-READ", iCtr, nFree, zFree, 0);
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Write data to an vlog-file.
|
| +*/
|
| +static int vlogWrite(
|
| + sqlite3_file *pFile,
|
| + const void *z,
|
| + int iAmt,
|
| + sqlite_int64 iOfst
|
| +){
|
| + int rc;
|
| + sqlite3_uint64 tStart, tElapse;
|
| + VLogFile *p = (VLogFile *)pFile;
|
| + char zSig[40];
|
| +
|
| + tStart = vlog_time();
|
| + vlogSignature((unsigned char*)z, iAmt, zSig);
|
| + rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
|
| + tElapse = vlog_time() - tStart;
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "WRITE", iAmt, iOfst, zSig, rc);
|
| + if( rc==SQLITE_OK
|
| + && p->pLog
|
| + && p->pLog->zFilename
|
| + && iOfst<=24
|
| + && iOfst+iAmt>=28
|
| + ){
|
| + unsigned char *x = ((unsigned char*)z)+(24-iOfst);
|
| + unsigned iCtr, nFree = -1;
|
| + char *zFree = 0;
|
| + char zStr[12];
|
| + iCtr = bigToNative(x);
|
| + if( iOfst+iAmt>=40 ){
|
| + zFree = zStr;
|
| + sqlite3_snprintf(sizeof(zStr), zStr, "%d", bigToNative(x+8));
|
| + nFree = bigToNative(x+12);
|
| + }
|
| + vlogLogPrint(p->pLog, tStart, 0, "CHNGCTR-WRITE", iCtr, nFree, zFree, 0);
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Truncate an vlog-file.
|
| +*/
|
| +static int vlogTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
| + int rc;
|
| + sqlite3_uint64 tStart, tElapse;
|
| + VLogFile *p = (VLogFile *)pFile;
|
| + tStart = vlog_time();
|
| + rc = p->pReal->pMethods->xTruncate(p->pReal, size);
|
| + tElapse = vlog_time() - tStart;
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "TRUNCATE", size, -1, 0, rc);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Sync an vlog-file.
|
| +*/
|
| +static int vlogSync(sqlite3_file *pFile, int flags){
|
| + int rc;
|
| + sqlite3_uint64 tStart, tElapse;
|
| + VLogFile *p = (VLogFile *)pFile;
|
| + tStart = vlog_time();
|
| + rc = p->pReal->pMethods->xSync(p->pReal, flags);
|
| + tElapse = vlog_time() - tStart;
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "SYNC", flags, -1, 0, rc);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Return the current file-size of an vlog-file.
|
| +*/
|
| +static int vlogFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
| + int rc;
|
| + sqlite3_uint64 tStart, tElapse;
|
| + VLogFile *p = (VLogFile *)pFile;
|
| + tStart = vlog_time();
|
| + rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
|
| + tElapse = vlog_time() - tStart;
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "FILESIZE", *pSize, -1, 0, rc);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Lock an vlog-file.
|
| +*/
|
| +static int vlogLock(sqlite3_file *pFile, int eLock){
|
| + int rc;
|
| + sqlite3_uint64 tStart, tElapse;
|
| + VLogFile *p = (VLogFile *)pFile;
|
| + tStart = vlog_time();
|
| + rc = p->pReal->pMethods->xLock(p->pReal, eLock);
|
| + tElapse = vlog_time() - tStart;
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "LOCK", eLock, -1, 0, rc);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Unlock an vlog-file.
|
| +*/
|
| +static int vlogUnlock(sqlite3_file *pFile, int eLock){
|
| + int rc;
|
| + sqlite3_uint64 tStart;
|
| + VLogFile *p = (VLogFile *)pFile;
|
| + tStart = vlog_time();
|
| + vlogLogPrint(p->pLog, tStart, 0, "UNLOCK", eLock, -1, 0, 0);
|
| + rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Check if another file-handle holds a RESERVED lock on an vlog-file.
|
| +*/
|
| +static int vlogCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
| + int rc;
|
| + sqlite3_uint64 tStart, tElapse;
|
| + VLogFile *p = (VLogFile *)pFile;
|
| + tStart = vlog_time();
|
| + rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
|
| + tElapse = vlog_time() - tStart;
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "CHECKRESERVEDLOCK",
|
| + *pResOut, -1, "", rc);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** File control method. For custom operations on an vlog-file.
|
| +*/
|
| +static int vlogFileControl(sqlite3_file *pFile, int op, void *pArg){
|
| + VLogFile *p = (VLogFile *)pFile;
|
| + sqlite3_uint64 tStart, tElapse;
|
| + int rc;
|
| + tStart = vlog_time();
|
| + rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
|
| + if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
|
| + *(char**)pArg = sqlite3_mprintf("vlog/%z", *(char**)pArg);
|
| + }
|
| + tElapse = vlog_time() - tStart;
|
| + if( op==SQLITE_FCNTL_TRACE ){
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "TRACE", op, -1, pArg, rc);
|
| + }else if( op==SQLITE_FCNTL_PRAGMA ){
|
| + const char **azArg = (const char **)pArg;
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "FILECONTROL", op, -1, azArg[1], rc);
|
| + }else if( op==SQLITE_FCNTL_SIZE_HINT ){
|
| + sqlite3_int64 sz = *(sqlite3_int64*)pArg;
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "FILECONTROL", op, sz, 0, rc);
|
| + }else{
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "FILECONTROL", op, -1, 0, rc);
|
| + }
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Return the sector-size in bytes for an vlog-file.
|
| +*/
|
| +static int vlogSectorSize(sqlite3_file *pFile){
|
| + int rc;
|
| + sqlite3_uint64 tStart, tElapse;
|
| + VLogFile *p = (VLogFile *)pFile;
|
| + tStart = vlog_time();
|
| + rc = p->pReal->pMethods->xSectorSize(p->pReal);
|
| + tElapse = vlog_time() - tStart;
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "SECTORSIZE", -1, -1, 0, rc);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Return the device characteristic flags supported by an vlog-file.
|
| +*/
|
| +static int vlogDeviceCharacteristics(sqlite3_file *pFile){
|
| + int rc;
|
| + sqlite3_uint64 tStart, tElapse;
|
| + VLogFile *p = (VLogFile *)pFile;
|
| + tStart = vlog_time();
|
| + rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
|
| + tElapse = vlog_time() - tStart;
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "DEVCHAR", -1, -1, 0, rc);
|
| + return rc;
|
| +}
|
| +
|
| +
|
| +/*
|
| +** Open an vlog file handle.
|
| +*/
|
| +static int vlogOpen(
|
| + sqlite3_vfs *pVfs,
|
| + const char *zName,
|
| + sqlite3_file *pFile,
|
| + int flags,
|
| + int *pOutFlags
|
| +){
|
| + int rc;
|
| + sqlite3_uint64 tStart, tElapse;
|
| + sqlite3_int64 iArg2;
|
| + VLogFile *p = (VLogFile*)pFile;
|
| +
|
| + p->pReal = (sqlite3_file*)&p[1];
|
| + if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_MAIN_JOURNAL))!=0 ){
|
| + p->pLog = vlogLogOpen(zName);
|
| + }else{
|
| + p->pLog = 0;
|
| + }
|
| + tStart = vlog_time();
|
| + rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
|
| + tElapse = vlog_time() - tStart;
|
| + iArg2 = pOutFlags ? *pOutFlags : -1;
|
| + vlogLogPrint(p->pLog, tStart, tElapse, "OPEN", flags, iArg2, 0, rc);
|
| + if( rc==SQLITE_OK ){
|
| + pFile->pMethods = &vlog_io_methods;
|
| + }else{
|
| + if( p->pLog ) vlogLogClose(p->pLog);
|
| + p->pLog = 0;
|
| + }
|
| + 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 vlogDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
| + int rc;
|
| + sqlite3_uint64 tStart, tElapse;
|
| + VLogLog *pLog;
|
| + tStart = vlog_time();
|
| + rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
|
| + tElapse = vlog_time() - tStart;
|
| + pLog = vlogLogOpen(zPath);
|
| + vlogLogPrint(pLog, tStart, tElapse, "DELETE", dirSync, -1, 0, rc);
|
| + vlogLogClose(pLog);
|
| + return rc;
|
| +}
|
| +
|
| +/*
|
| +** Test for access permissions. Return true if the requested permission
|
| +** is available, or false otherwise.
|
| +*/
|
| +static int vlogAccess(
|
| + sqlite3_vfs *pVfs,
|
| + const char *zPath,
|
| + int flags,
|
| + int *pResOut
|
| +){
|
| + int rc;
|
| + sqlite3_uint64 tStart, tElapse;
|
| + VLogLog *pLog;
|
| + tStart = vlog_time();
|
| + rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
|
| + tElapse = vlog_time() - tStart;
|
| + pLog = vlogLogOpen(zPath);
|
| + vlogLogPrint(pLog, tStart, tElapse, "ACCESS", flags, *pResOut, 0, rc);
|
| + vlogLogClose(pLog);
|
| + 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 vlogFullPathname(
|
| + sqlite3_vfs *pVfs,
|
| + const char *zPath,
|
| + int nOut,
|
| + char *zOut
|
| +){
|
| + return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
|
| +}
|
| +
|
| +/*
|
| +** Open the dynamic library located at zPath and return a handle.
|
| +*/
|
| +static void *vlogDlOpen(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 vlogDlError(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 (*vlogDlSym(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 vlogDlClose(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 vlogRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
| + return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
|
| +}
|
| +
|
| +/*
|
| +** Sleep for nMicro microseconds. Return the number of microseconds
|
| +** actually slept.
|
| +*/
|
| +static int vlogSleep(sqlite3_vfs *pVfs, int nMicro){
|
| + return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
|
| +}
|
| +
|
| +/*
|
| +** Return the current time as a Julian Day number in *pTimeOut.
|
| +*/
|
| +static int vlogCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
| + return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
|
| +}
|
| +
|
| +static int vlogGetLastError(sqlite3_vfs *pVfs, int a, char *b){
|
| + return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
|
| +}
|
| +static int vlogCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
|
| + return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
|
| +}
|
| +
|
| +/*
|
| +** Register debugvfs as the default VFS for this process.
|
| +*/
|
| +int sqlite3_register_vfslog(const char *zArg){
|
| + vlog_vfs.pVfs = sqlite3_vfs_find(0);
|
| + vlog_vfs.base.szOsFile = sizeof(VLogFile) + vlog_vfs.pVfs->szOsFile;
|
| + return sqlite3_vfs_register(&vlog_vfs.base, 1);
|
| +}
|
|
|