vfsstat.c 24 KB

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