1 /* 2 ** 2008 April 10 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 wrapper that 14 ** adds instrumentation to all vfs and file methods. C and Tcl interfaces 15 ** are provided to control the instrumentation. 16 */ 17 18 /* 19 ** This module contains code for a wrapper VFS that causes a log of 20 ** all (well, technically "most") VFS calls to be written into a nominated 21 ** file on disk. The log is stored in a compressed binary format to 22 ** reduce the amount of IO overhead introduced into the application 23 ** by logging. 24 ** 25 ** The binary log files are read using a virtual table implementation 26 ** also contained in this file. 27 ** 28 ** CREATING LOG FILES: 29 ** 30 ** int sqlite3_vfslog_new( 31 ** const char *zVfs, // Name of new VFS 32 ** const char *zParentVfs, // Name of parent VFS (or NULL) 33 ** const char *zLog // Name of log file to write to 34 ** ); 35 ** 36 ** int sqlite3_vfslog_finalize(const char *zVfs); 37 ** 38 ** ANNOTATING LOG FILES: 39 ** 40 ** To write an arbitrary message into a log file: 41 ** 42 ** int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg); 43 ** 44 ** READING LOG FILES: 45 ** 46 ** Log files are read using the "vfslog" virtual table implementation 47 ** in this file. To register the virtual table with SQLite, use: 48 ** 49 ** int sqlite3_vfslog_register(sqlite3 *db); 50 ** 51 ** Then, if the log file is named "vfs.log", the following SQL command: 52 ** 53 ** CREATE VIRTUAL TABLE v USING vfslog('vfs.log'); 54 ** 55 ** creates a virtual table with 6 columns, as follows: 56 ** 57 ** CREATE TABLE v( 58 ** event TEXT, // "xOpen", "xRead" etc. 59 ** file TEXT, // Name of file this call applies to 60 ** clicks INTEGER, // Time spent in call 61 ** rc INTEGER, // Return value 62 ** size INTEGER, // Bytes read or written 63 ** offset INTEGER // File offset read or written 64 ** ); 65 */ 66 67 #include "sqlite3.h" 68 #include <string.h> 69 #include <assert.h> 70 71 72 /* 73 ** Maximum pathname length supported by the vfslog backend. 74 */ 75 #define INST_MAX_PATHNAME 512 76 77 #define OS_ACCESS 1 78 #define OS_CHECKRESERVEDLOCK 2 79 #define OS_CLOSE 3 80 #define OS_CURRENTTIME 4 81 #define OS_DELETE 5 82 #define OS_DEVCHAR 6 83 #define OS_FILECONTROL 7 84 #define OS_FILESIZE 8 85 #define OS_FULLPATHNAME 9 86 #define OS_LOCK 11 87 #define OS_OPEN 12 88 #define OS_RANDOMNESS 13 89 #define OS_READ 14 90 #define OS_SECTORSIZE 15 91 #define OS_SLEEP 16 92 #define OS_SYNC 17 93 #define OS_TRUNCATE 18 94 #define OS_UNLOCK 19 95 #define OS_WRITE 20 96 #define OS_SHMOPEN 21 97 #define OS_SHMCLOSE 22 98 #define OS_SHMGET 23 99 #define OS_SHMRELEASE 24 100 #define OS_SHMLOCK 25 101 #define OS_SHMSIZE 26 102 #define OS_ANNOTATE 27 103 104 #define OS_NUMEVENTS 28 105 106 #define VFSLOG_BUFFERSIZE 8192 107 108 typedef struct VfslogVfs VfslogVfs; 109 typedef struct VfslogFile VfslogFile; 110 111 struct VfslogVfs { 112 sqlite3_vfs base; /* VFS methods */ 113 sqlite3_vfs *pVfs; /* Parent VFS */ 114 int iNextFileId; /* Next file id */ 115 sqlite3_file *pLog; /* Log file handle */ 116 sqlite3_int64 iOffset; /* Log file offset of start of write buffer */ 117 int nBuf; /* Number of valid bytes in aBuf[] */ 118 char aBuf[VFSLOG_BUFFERSIZE]; /* Write buffer */ 119 }; 120 121 struct VfslogFile { 122 sqlite3_file base; /* IO methods */ 123 sqlite3_file *pReal; /* Underlying file handle */ 124 sqlite3_vfs *pVfslog; /* Associated VsflogVfs object */ 125 int iFileId; /* File id number */ 126 }; 127 128 #define REALVFS(p) (((VfslogVfs *)(p))->pVfs) 129 130 131 132 /* 133 ** Method declarations for vfslog_file. 134 */ 135 static int vfslogClose(sqlite3_file*); 136 static int vfslogRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); 137 static int vfslogWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); 138 static int vfslogTruncate(sqlite3_file*, sqlite3_int64 size); 139 static int vfslogSync(sqlite3_file*, int flags); 140 static int vfslogFileSize(sqlite3_file*, sqlite3_int64 *pSize); 141 static int vfslogLock(sqlite3_file*, int); 142 static int vfslogUnlock(sqlite3_file*, int); 143 static int vfslogCheckReservedLock(sqlite3_file*, int *pResOut); 144 static int vfslogFileControl(sqlite3_file*, int op, void *pArg); 145 static int vfslogSectorSize(sqlite3_file*); 146 static int vfslogDeviceCharacteristics(sqlite3_file*); 147 148 static int vfslogShmOpen(sqlite3_file *pFile); 149 static int vfslogShmSize(sqlite3_file *pFile, int reqSize, int *pNewSize); 150 static int vfslogShmGet(sqlite3_file *pFile, int req, int *pSize, void **pp); 151 static int vfslogShmRelease(sqlite3_file *pFile); 152 static int vfslogShmLock(sqlite3_file *pFile, int desiredLock, int *gotLock); 153 static int vfslogShmClose(sqlite3_file *pFile, int deleteFlag); 154 155 /* 156 ** Method declarations for vfslog_vfs. 157 */ 158 static int vfslogOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); 159 static int vfslogDelete(sqlite3_vfs*, const char *zName, int syncDir); 160 static int vfslogAccess(sqlite3_vfs*, const char *zName, int flags, int *); 161 static int vfslogFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); 162 static void *vfslogDlOpen(sqlite3_vfs*, const char *zFilename); 163 static void vfslogDlError(sqlite3_vfs*, int nByte, char *zErrMsg); 164 static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); 165 static void vfslogDlClose(sqlite3_vfs*, void*); 166 static int vfslogRandomness(sqlite3_vfs*, int nByte, char *zOut); 167 static int vfslogSleep(sqlite3_vfs*, int microseconds); 168 static int vfslogCurrentTime(sqlite3_vfs*, double*); 169 170 static sqlite3_vfs vfslog_vfs = { 171 1, /* iVersion */ 172 sizeof(VfslogFile), /* szOsFile */ 173 INST_MAX_PATHNAME, /* mxPathname */ 174 0, /* pNext */ 175 0, /* zName */ 176 0, /* pAppData */ 177 vfslogOpen, /* xOpen */ 178 vfslogDelete, /* xDelete */ 179 vfslogAccess, /* xAccess */ 180 vfslogFullPathname, /* xFullPathname */ 181 vfslogDlOpen, /* xDlOpen */ 182 vfslogDlError, /* xDlError */ 183 vfslogDlSym, /* xDlSym */ 184 vfslogDlClose, /* xDlClose */ 185 vfslogRandomness, /* xRandomness */ 186 vfslogSleep, /* xSleep */ 187 vfslogCurrentTime, /* xCurrentTime */ 188 }; 189 190 static sqlite3_io_methods vfslog_io_methods = { 191 2, /* iVersion */ 192 vfslogClose, /* xClose */ 193 vfslogRead, /* xRead */ 194 vfslogWrite, /* xWrite */ 195 vfslogTruncate, /* xTruncate */ 196 vfslogSync, /* xSync */ 197 vfslogFileSize, /* xFileSize */ 198 vfslogLock, /* xLock */ 199 vfslogUnlock, /* xUnlock */ 200 vfslogCheckReservedLock, /* xCheckReservedLock */ 201 vfslogFileControl, /* xFileControl */ 202 vfslogSectorSize, /* xSectorSize */ 203 vfslogDeviceCharacteristics, /* xDeviceCharacteristics */ 204 vfslogShmOpen, /* xShmOpen */ 205 vfslogShmSize, /* xShmSize */ 206 vfslogShmGet, /* xShmGet */ 207 vfslogShmRelease, /* xShmRelease */ 208 vfslogShmLock, /* xShmLock */ 209 vfslogShmClose /* xShmClose */ 210 }; 211 212 #if defined(SQLITE_OS_UNIX) && !defined(NO_GETTOD) 213 #include <sys/time.h> 214 static sqlite3_uint64 vfslog_time(){ 215 struct timeval sTime; 216 gettimeofday(&sTime, 0); 217 return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000; 218 } 219 #else 220 static sqlite3_uint64 vfslog_time(){ 221 return 0; 222 } 223 #endif 224 225 static void vfslog_call(sqlite3_vfs *, int, int, int, int, int, int); 226 static void vfslog_string(sqlite3_vfs *, const char *); 227 228 /* 229 ** Close an vfslog-file. 230 */ 231 static int vfslogClose(sqlite3_file *pFile){ 232 sqlite3_uint64 t; 233 int rc = SQLITE_OK; 234 VfslogFile *p = (VfslogFile *)pFile; 235 236 t = vfslog_time(); 237 if( p->pReal->pMethods ){ 238 rc = p->pReal->pMethods->xClose(p->pReal); 239 } 240 t = vfslog_time() - t; 241 vfslog_call(p->pVfslog, OS_CLOSE, p->iFileId, t, rc, 0, 0); 242 return rc; 243 } 244 245 /* 246 ** Read data from an vfslog-file. 247 */ 248 static int vfslogRead( 249 sqlite3_file *pFile, 250 void *zBuf, 251 int iAmt, 252 sqlite_int64 iOfst 253 ){ 254 int rc; 255 sqlite3_uint64 t; 256 VfslogFile *p = (VfslogFile *)pFile; 257 t = vfslog_time(); 258 rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst); 259 t = vfslog_time() - t; 260 vfslog_call(p->pVfslog, OS_READ, p->iFileId, t, rc, iAmt, (int)iOfst); 261 return rc; 262 } 263 264 /* 265 ** Write data to an vfslog-file. 266 */ 267 static int vfslogWrite( 268 sqlite3_file *pFile, 269 const void *z, 270 int iAmt, 271 sqlite_int64 iOfst 272 ){ 273 int rc; 274 sqlite3_uint64 t; 275 VfslogFile *p = (VfslogFile *)pFile; 276 t = vfslog_time(); 277 rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst); 278 t = vfslog_time() - t; 279 vfslog_call(p->pVfslog, OS_WRITE, p->iFileId, t, rc, iAmt, (int)iOfst); 280 return rc; 281 } 282 283 /* 284 ** Truncate an vfslog-file. 285 */ 286 static int vfslogTruncate(sqlite3_file *pFile, sqlite_int64 size){ 287 int rc; 288 sqlite3_uint64 t; 289 VfslogFile *p = (VfslogFile *)pFile; 290 t = vfslog_time(); 291 rc = p->pReal->pMethods->xTruncate(p->pReal, size); 292 t = vfslog_time() - t; 293 vfslog_call(p->pVfslog, OS_TRUNCATE, p->iFileId, t, rc, 0, (int)size); 294 return rc; 295 } 296 297 /* 298 ** Sync an vfslog-file. 299 */ 300 static int vfslogSync(sqlite3_file *pFile, int flags){ 301 int rc; 302 sqlite3_uint64 t; 303 VfslogFile *p = (VfslogFile *)pFile; 304 t = vfslog_time(); 305 rc = p->pReal->pMethods->xSync(p->pReal, flags); 306 t = vfslog_time() - t; 307 vfslog_call(p->pVfslog, OS_SYNC, p->iFileId, t, rc, flags, 0); 308 return rc; 309 } 310 311 /* 312 ** Return the current file-size of an vfslog-file. 313 */ 314 static int vfslogFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ 315 int rc; 316 sqlite3_uint64 t; 317 VfslogFile *p = (VfslogFile *)pFile; 318 t = vfslog_time(); 319 rc = p->pReal->pMethods->xFileSize(p->pReal, pSize); 320 t = vfslog_time() - t; 321 vfslog_call(p->pVfslog, OS_FILESIZE, p->iFileId, t, rc, 0, (int)*pSize); 322 return rc; 323 } 324 325 /* 326 ** Lock an vfslog-file. 327 */ 328 static int vfslogLock(sqlite3_file *pFile, int eLock){ 329 int rc; 330 sqlite3_uint64 t; 331 VfslogFile *p = (VfslogFile *)pFile; 332 t = vfslog_time(); 333 rc = p->pReal->pMethods->xLock(p->pReal, eLock); 334 t = vfslog_time() - t; 335 vfslog_call(p->pVfslog, OS_LOCK, p->iFileId, t, rc, eLock, 0); 336 return rc; 337 } 338 339 /* 340 ** Unlock an vfslog-file. 341 */ 342 static int vfslogUnlock(sqlite3_file *pFile, int eLock){ 343 int rc; 344 sqlite3_uint64 t; 345 VfslogFile *p = (VfslogFile *)pFile; 346 t = vfslog_time(); 347 rc = p->pReal->pMethods->xUnlock(p->pReal, eLock); 348 t = vfslog_time() - t; 349 vfslog_call(p->pVfslog, OS_UNLOCK, p->iFileId, t, rc, eLock, 0); 350 return rc; 351 } 352 353 /* 354 ** Check if another file-handle holds a RESERVED lock on an vfslog-file. 355 */ 356 static int vfslogCheckReservedLock(sqlite3_file *pFile, int *pResOut){ 357 int rc; 358 sqlite3_uint64 t; 359 VfslogFile *p = (VfslogFile *)pFile; 360 t = vfslog_time(); 361 rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut); 362 t = vfslog_time() - t; 363 vfslog_call(p->pVfslog, OS_CHECKRESERVEDLOCK, p->iFileId, t, rc, *pResOut, 0); 364 return rc; 365 } 366 367 /* 368 ** File control method. For custom operations on an vfslog-file. 369 */ 370 static int vfslogFileControl(sqlite3_file *pFile, int op, void *pArg){ 371 VfslogFile *p = (VfslogFile *)pFile; 372 return p->pReal->pMethods->xFileControl(p->pReal, op, pArg); 373 } 374 375 /* 376 ** Return the sector-size in bytes for an vfslog-file. 377 */ 378 static int vfslogSectorSize(sqlite3_file *pFile){ 379 int rc; 380 sqlite3_uint64 t; 381 VfslogFile *p = (VfslogFile *)pFile; 382 t = vfslog_time(); 383 rc = p->pReal->pMethods->xSectorSize(p->pReal); 384 t = vfslog_time() - t; 385 vfslog_call(p->pVfslog, OS_SECTORSIZE, p->iFileId, t, rc, 0, 0); 386 return rc; 387 } 388 389 /* 390 ** Return the device characteristic flags supported by an vfslog-file. 391 */ 392 static int vfslogDeviceCharacteristics(sqlite3_file *pFile){ 393 int rc; 394 sqlite3_uint64 t; 395 VfslogFile *p = (VfslogFile *)pFile; 396 t = vfslog_time(); 397 rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal); 398 t = vfslog_time() - t; 399 vfslog_call(p->pVfslog, OS_DEVCHAR, p->iFileId, t, rc, 0, 0); 400 return rc; 401 } 402 403 static int vfslogShmOpen(sqlite3_file *pFile){ 404 int rc; 405 sqlite3_uint64 t; 406 VfslogFile *p = (VfslogFile *)pFile; 407 t = vfslog_time(); 408 rc = p->pReal->pMethods->xShmOpen(p->pReal); 409 t = vfslog_time() - t; 410 vfslog_call(p->pVfslog, OS_SHMOPEN, p->iFileId, t, rc, 0, 0); 411 return rc; 412 } 413 static int vfslogShmSize(sqlite3_file *pFile, int reqSize, int *pNewSize){ 414 int rc; 415 sqlite3_uint64 t; 416 VfslogFile *p = (VfslogFile *)pFile; 417 t = vfslog_time(); 418 rc = p->pReal->pMethods->xShmSize(p->pReal, reqSize, pNewSize); 419 t = vfslog_time() - t; 420 vfslog_call(p->pVfslog, OS_SHMSIZE, p->iFileId, t, rc, 0, 0); 421 return rc; 422 } 423 static int vfslogShmGet(sqlite3_file *pFile, int req, int *pSize, void **pp){ 424 int rc; 425 sqlite3_uint64 t; 426 VfslogFile *p = (VfslogFile *)pFile; 427 t = vfslog_time(); 428 rc = p->pReal->pMethods->xShmGet(p->pReal, req, pSize, pp); 429 t = vfslog_time() - t; 430 vfslog_call(p->pVfslog, OS_SHMGET, p->iFileId, t, rc, 0, 0); 431 return rc; 432 } 433 static int vfslogShmRelease(sqlite3_file *pFile){ 434 int rc; 435 sqlite3_uint64 t; 436 VfslogFile *p = (VfslogFile *)pFile; 437 t = vfslog_time(); 438 rc = p->pReal->pMethods->xShmRelease(p->pReal); 439 t = vfslog_time() - t; 440 vfslog_call(p->pVfslog, OS_SHMRELEASE, p->iFileId, t, rc, 0, 0); 441 return rc; 442 } 443 static int vfslogShmLock(sqlite3_file *pFile, int desiredLock, int *gotLock){ 444 int rc; 445 sqlite3_uint64 t; 446 VfslogFile *p = (VfslogFile *)pFile; 447 t = vfslog_time(); 448 rc = p->pReal->pMethods->xShmLock(p->pReal, desiredLock, gotLock); 449 t = vfslog_time() - t; 450 vfslog_call(p->pVfslog, OS_SHMLOCK, p->iFileId, t, rc, 0, 0); 451 return rc; 452 } 453 static int vfslogShmClose(sqlite3_file *pFile, int deleteFlag){ 454 int rc; 455 sqlite3_uint64 t; 456 VfslogFile *p = (VfslogFile *)pFile; 457 t = vfslog_time(); 458 rc = p->pReal->pMethods->xShmClose(p->pReal, deleteFlag); 459 t = vfslog_time() - t; 460 vfslog_call(p->pVfslog, OS_SHMCLOSE, p->iFileId, t, rc, 0, 0); 461 return rc; 462 } 463 464 465 /* 466 ** Open an vfslog file handle. 467 */ 468 static int vfslogOpen( 469 sqlite3_vfs *pVfs, 470 const char *zName, 471 sqlite3_file *pFile, 472 int flags, 473 int *pOutFlags 474 ){ 475 int rc; 476 sqlite3_uint64 t; 477 VfslogFile *p = (VfslogFile *)pFile; 478 VfslogVfs *pLog = (VfslogVfs *)pVfs; 479 480 pFile->pMethods = &vfslog_io_methods; 481 p->pReal = (sqlite3_file *)&p[1]; 482 p->pVfslog = pVfs; 483 p->iFileId = ++pLog->iNextFileId; 484 485 t = vfslog_time(); 486 rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags); 487 t = vfslog_time() - t; 488 489 vfslog_call(pVfs, OS_OPEN, p->iFileId, t, rc, 0, 0); 490 vfslog_string(pVfs, zName); 491 return rc; 492 } 493 494 /* 495 ** Delete the file located at zPath. If the dirSync argument is true, 496 ** ensure the file-system modifications are synced to disk before 497 ** returning. 498 */ 499 static int vfslogDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ 500 int rc; 501 sqlite3_uint64 t; 502 t = vfslog_time(); 503 rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync); 504 t = vfslog_time() - t; 505 vfslog_call(pVfs, OS_DELETE, 0, t, rc, dirSync, 0); 506 vfslog_string(pVfs, zPath); 507 return rc; 508 } 509 510 /* 511 ** Test for access permissions. Return true if the requested permission 512 ** is available, or false otherwise. 513 */ 514 static int vfslogAccess( 515 sqlite3_vfs *pVfs, 516 const char *zPath, 517 int flags, 518 int *pResOut 519 ){ 520 int rc; 521 sqlite3_uint64 t; 522 t = vfslog_time(); 523 rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut); 524 t = vfslog_time() - t; 525 vfslog_call(pVfs, OS_ACCESS, 0, t, rc, flags, *pResOut); 526 vfslog_string(pVfs, zPath); 527 return rc; 528 } 529 530 /* 531 ** Populate buffer zOut with the full canonical pathname corresponding 532 ** to the pathname in zPath. zOut is guaranteed to point to a buffer 533 ** of at least (INST_MAX_PATHNAME+1) bytes. 534 */ 535 static int vfslogFullPathname( 536 sqlite3_vfs *pVfs, 537 const char *zPath, 538 int nOut, 539 char *zOut 540 ){ 541 return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut); 542 } 543 544 /* 545 ** Open the dynamic library located at zPath and return a handle. 546 */ 547 static void *vfslogDlOpen(sqlite3_vfs *pVfs, const char *zPath){ 548 return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath); 549 } 550 551 /* 552 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable 553 ** utf-8 string describing the most recent error encountered associated 554 ** with dynamic libraries. 555 */ 556 static void vfslogDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ 557 REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg); 558 } 559 560 /* 561 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle. 562 */ 563 static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ 564 return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym); 565 } 566 567 /* 568 ** Close the dynamic library handle pHandle. 569 */ 570 static void vfslogDlClose(sqlite3_vfs *pVfs, void *pHandle){ 571 REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle); 572 } 573 574 /* 575 ** Populate the buffer pointed to by zBufOut with nByte bytes of 576 ** random data. 577 */ 578 static int vfslogRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ 579 return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut); 580 } 581 582 /* 583 ** Sleep for nMicro microseconds. Return the number of microseconds 584 ** actually slept. 585 */ 586 static int vfslogSleep(sqlite3_vfs *pVfs, int nMicro){ 587 return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro); 588 } 589 590 /* 591 ** Return the current time as a Julian Day number in *pTimeOut. 592 */ 593 static int vfslogCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ 594 return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut); 595 } 596 597 static void vfslog_flush(VfslogVfs *p){ 598 #ifdef SQLITE_TEST 599 extern int sqlite3_io_error_pending; 600 extern int sqlite3_io_error_persist; 601 extern int sqlite3_diskfull_pending; 602 603 int pending = sqlite3_io_error_pending; 604 int persist = sqlite3_io_error_persist; 605 int diskfull = sqlite3_diskfull_pending; 606 607 sqlite3_io_error_pending = 0; 608 sqlite3_io_error_persist = 0; 609 sqlite3_diskfull_pending = 0; 610 #endif 611 612 if( p->nBuf ){ 613 p->pLog->pMethods->xWrite(p->pLog, p->aBuf, p->nBuf, p->iOffset); 614 p->iOffset += p->nBuf; 615 p->nBuf = 0; 616 } 617 618 #ifdef SQLITE_TEST 619 sqlite3_io_error_pending = pending; 620 sqlite3_io_error_persist = persist; 621 sqlite3_diskfull_pending = diskfull; 622 #endif 623 } 624 625 static void put32bits(unsigned char *p, unsigned int v){ 626 p[0] = v>>24; 627 p[1] = v>>16; 628 p[2] = v>>8; 629 p[3] = v; 630 } 631 632 static void vfslog_call( 633 sqlite3_vfs *pVfs, 634 int eEvent, 635 int iFileid, 636 int nClick, 637 int return_code, 638 int size, 639 int offset 640 ){ 641 VfslogVfs *p = (VfslogVfs *)pVfs; 642 unsigned char *zRec; 643 if( (24+p->nBuf)>sizeof(p->aBuf) ){ 644 vfslog_flush(p); 645 } 646 zRec = (unsigned char *)&p->aBuf[p->nBuf]; 647 put32bits(&zRec[0], eEvent); 648 put32bits(&zRec[4], iFileid); 649 put32bits(&zRec[8], nClick); 650 put32bits(&zRec[12], return_code); 651 put32bits(&zRec[16], size); 652 put32bits(&zRec[20], offset); 653 p->nBuf += 24; 654 } 655 656 static void vfslog_string(sqlite3_vfs *pVfs, const char *zStr){ 657 VfslogVfs *p = (VfslogVfs *)pVfs; 658 unsigned char *zRec; 659 int nStr = zStr ? strlen(zStr) : 0; 660 if( (4+nStr+p->nBuf)>sizeof(p->aBuf) ){ 661 vfslog_flush(p); 662 } 663 zRec = (unsigned char *)&p->aBuf[p->nBuf]; 664 put32bits(&zRec[0], nStr); 665 if( zStr ){ 666 memcpy(&zRec[4], zStr, nStr); 667 } 668 p->nBuf += (4 + nStr); 669 } 670 671 static void vfslog_finalize(VfslogVfs *p){ 672 if( p->pLog->pMethods ){ 673 vfslog_flush(p); 674 p->pLog->pMethods->xClose(p->pLog); 675 } 676 sqlite3_free(p); 677 } 678 679 int sqlite3_vfslog_finalize(const char *zVfs){ 680 sqlite3_vfs *pVfs; 681 pVfs = sqlite3_vfs_find(zVfs); 682 if( !pVfs || pVfs->xOpen!=vfslogOpen ){ 683 return SQLITE_ERROR; 684 } 685 sqlite3_vfs_unregister(pVfs); 686 vfslog_finalize((VfslogVfs *)pVfs); 687 return SQLITE_OK; 688 } 689 690 int sqlite3_vfslog_new( 691 const char *zVfs, /* New VFS name */ 692 const char *zParentVfs, /* Parent VFS name (or NULL) */ 693 const char *zLog /* Log file name */ 694 ){ 695 VfslogVfs *p; 696 sqlite3_vfs *pParent; 697 int nByte; 698 int flags; 699 int rc; 700 char *zFile; 701 int nVfs; 702 703 pParent = sqlite3_vfs_find(zParentVfs); 704 if( !pParent ){ 705 return SQLITE_ERROR; 706 } 707 708 nVfs = strlen(zVfs); 709 nByte = sizeof(VfslogVfs) + pParent->szOsFile + nVfs+1+pParent->mxPathname+1; 710 p = (VfslogVfs *)sqlite3_malloc(nByte); 711 memset(p, 0, nByte); 712 713 p->pVfs = pParent; 714 p->pLog = (sqlite3_file *)&p[1]; 715 memcpy(&p->base, &vfslog_vfs, sizeof(sqlite3_vfs)); 716 p->base.zName = &((char *)p->pLog)[pParent->szOsFile]; 717 p->base.szOsFile += pParent->szOsFile; 718 memcpy((char *)p->base.zName, zVfs, nVfs); 719 720 zFile = (char *)&p->base.zName[nVfs+1]; 721 pParent->xFullPathname(pParent, zLog, pParent->mxPathname, zFile); 722 723 flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MASTER_JOURNAL; 724 pParent->xDelete(pParent, zFile, 0); 725 rc = pParent->xOpen(pParent, zFile, p->pLog, flags, &flags); 726 if( rc==SQLITE_OK ){ 727 memcpy(p->aBuf, "sqlite_ostrace1.....", 20); 728 p->iOffset = 0; 729 p->nBuf = 20; 730 rc = sqlite3_vfs_register((sqlite3_vfs *)p, 1); 731 } 732 if( rc ){ 733 vfslog_finalize(p); 734 } 735 return rc; 736 } 737 738 int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg){ 739 sqlite3_vfs *pVfs; 740 pVfs = sqlite3_vfs_find(zVfs); 741 if( !pVfs || pVfs->xOpen!=vfslogOpen ){ 742 return SQLITE_ERROR; 743 } 744 vfslog_call(pVfs, OS_ANNOTATE, 0, 0, 0, 0, 0); 745 vfslog_string(pVfs, zMsg); 746 return SQLITE_OK; 747 } 748 749 static const char *vfslog_eventname(int eEvent){ 750 const char *zEvent = 0; 751 752 switch( eEvent ){ 753 case OS_CLOSE: zEvent = "xClose"; break; 754 case OS_READ: zEvent = "xRead"; break; 755 case OS_WRITE: zEvent = "xWrite"; break; 756 case OS_TRUNCATE: zEvent = "xTruncate"; break; 757 case OS_SYNC: zEvent = "xSync"; break; 758 case OS_FILESIZE: zEvent = "xFilesize"; break; 759 case OS_LOCK: zEvent = "xLock"; break; 760 case OS_UNLOCK: zEvent = "xUnlock"; break; 761 case OS_CHECKRESERVEDLOCK: zEvent = "xCheckResLock"; break; 762 case OS_FILECONTROL: zEvent = "xFileControl"; break; 763 case OS_SECTORSIZE: zEvent = "xSectorSize"; break; 764 case OS_DEVCHAR: zEvent = "xDeviceChar"; break; 765 case OS_OPEN: zEvent = "xOpen"; break; 766 case OS_DELETE: zEvent = "xDelete"; break; 767 case OS_ACCESS: zEvent = "xAccess"; break; 768 case OS_FULLPATHNAME: zEvent = "xFullPathname"; break; 769 case OS_RANDOMNESS: zEvent = "xRandomness"; break; 770 case OS_SLEEP: zEvent = "xSleep"; break; 771 case OS_CURRENTTIME: zEvent = "xCurrentTime"; break; 772 773 case OS_SHMCLOSE: zEvent = "xShmClose"; break; 774 case OS_SHMOPEN: zEvent = "xShmOpen"; break; 775 case OS_SHMGET: zEvent = "xShmGet"; break; 776 case OS_SHMSIZE: zEvent = "xShmSize"; break; 777 case OS_SHMRELEASE: zEvent = "xShmRelease"; break; 778 case OS_SHMLOCK: zEvent = "xShmLock"; break; 779 780 case OS_ANNOTATE: zEvent = "annotation"; break; 781 } 782 783 return zEvent; 784 } 785 786 typedef struct VfslogVtab VfslogVtab; 787 typedef struct VfslogCsr VfslogCsr; 788 789 /* 790 ** Virtual table type for the vfslog reader module. 791 */ 792 struct VfslogVtab { 793 sqlite3_vtab base; /* Base class */ 794 sqlite3_file *pFd; /* File descriptor open on vfslog file */ 795 sqlite3_int64 nByte; /* Size of file in bytes */ 796 char *zFile; /* File name for pFd */ 797 }; 798 799 /* 800 ** Virtual table cursor type for the vfslog reader module. 801 */ 802 struct VfslogCsr { 803 sqlite3_vtab_cursor base; /* Base class */ 804 sqlite3_int64 iRowid; /* Current rowid. */ 805 sqlite3_int64 iOffset; /* Offset of next record in file */ 806 char *zTransient; /* Transient 'file' string */ 807 int nFile; /* Size of array azFile[] */ 808 char **azFile; /* File strings */ 809 unsigned char aBuf[1024]; /* Current vfs log entry (read from file) */ 810 }; 811 812 static unsigned int get32bits(unsigned char *p){ 813 return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; 814 } 815 816 /* 817 ** The argument must point to a buffer containing a nul-terminated string. 818 ** If the string begins with an SQL quote character it is overwritten by 819 ** the dequoted version. Otherwise the buffer is left unmodified. 820 */ 821 static void dequote(char *z){ 822 char quote; /* Quote character (if any ) */ 823 quote = z[0]; 824 if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){ 825 int iIn = 1; /* Index of next byte to read from input */ 826 int iOut = 0; /* Index of next byte to write to output */ 827 if( quote=='[' ) quote = ']'; 828 while( z[iIn] ){ 829 if( z[iIn]==quote ){ 830 if( z[iIn+1]!=quote ) break; 831 z[iOut++] = quote; 832 iIn += 2; 833 }else{ 834 z[iOut++] = z[iIn++]; 835 } 836 } 837 z[iOut] = '\0'; 838 } 839 } 840 841 /* 842 ** Connect to or create a vfslog virtual table. 843 */ 844 static int vlogConnect( 845 sqlite3 *db, 846 void *pAux, 847 int argc, const char *const*argv, 848 sqlite3_vtab **ppVtab, 849 char **pzErr 850 ){ 851 sqlite3_vfs *pVfs; /* VFS used to read log file */ 852 int flags; /* flags passed to pVfs->xOpen() */ 853 VfslogVtab *p; 854 int rc; 855 int nByte; 856 char *zFile; 857 858 *ppVtab = 0; 859 pVfs = sqlite3_vfs_find(0); 860 nByte = sizeof(VfslogVtab) + pVfs->szOsFile + pVfs->mxPathname; 861 p = sqlite3_malloc(nByte); 862 if( p==0 ) return SQLITE_NOMEM; 863 memset(p, 0, nByte); 864 865 p->pFd = (sqlite3_file *)&p[1]; 866 p->zFile = &((char *)p->pFd)[pVfs->szOsFile]; 867 868 zFile = sqlite3_mprintf("%s", argv[3]); 869 if( !zFile ){ 870 sqlite3_free(p); 871 return SQLITE_NOMEM; 872 } 873 dequote(zFile); 874 pVfs->xFullPathname(pVfs, zFile, pVfs->mxPathname, p->zFile); 875 sqlite3_free(zFile); 876 877 flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MASTER_JOURNAL; 878 rc = pVfs->xOpen(pVfs, p->zFile, p->pFd, flags, &flags); 879 880 if( rc==SQLITE_OK ){ 881 p->pFd->pMethods->xFileSize(p->pFd, &p->nByte); 882 sqlite3_declare_vtab(db, 883 "CREATE TABLE xxx(event, file, click, rc, size, offset)" 884 ); 885 *ppVtab = &p->base; 886 }else{ 887 sqlite3_free(p); 888 } 889 890 return rc; 891 } 892 893 /* 894 ** There is no "best-index". This virtual table always does a linear 895 ** scan of the binary VFS log file. 896 */ 897 static int vlogBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ 898 pIdxInfo->estimatedCost = 10.0; 899 return SQLITE_OK; 900 } 901 902 /* 903 ** Disconnect from or destroy a vfslog virtual table. 904 */ 905 static int vlogDisconnect(sqlite3_vtab *pVtab){ 906 VfslogVtab *p = (VfslogVtab *)pVtab; 907 if( p->pFd->pMethods ){ 908 p->pFd->pMethods->xClose(p->pFd); 909 p->pFd->pMethods = 0; 910 } 911 sqlite3_free(p); 912 return SQLITE_OK; 913 } 914 915 /* 916 ** Open a new vfslog cursor. 917 */ 918 static int vlogOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ 919 VfslogCsr *pCsr; /* Newly allocated cursor object */ 920 921 pCsr = sqlite3_malloc(sizeof(VfslogCsr)); 922 if( !pCsr ) return SQLITE_NOMEM; 923 memset(pCsr, 0, sizeof(VfslogCsr)); 924 *ppCursor = &pCsr->base; 925 return SQLITE_OK; 926 } 927 928 /* 929 ** Close a vfslog cursor. 930 */ 931 static int vlogClose(sqlite3_vtab_cursor *pCursor){ 932 VfslogCsr *p = (VfslogCsr *)pCursor; 933 int i; 934 for(i=0; i<p->nFile; i++){ 935 sqlite3_free(p->azFile[i]); 936 } 937 sqlite3_free(p->azFile); 938 sqlite3_free(p->zTransient); 939 sqlite3_free(p); 940 return SQLITE_OK; 941 } 942 943 /* 944 ** Move a vfslog cursor to the next entry in the file. 945 */ 946 static int vlogNext(sqlite3_vtab_cursor *pCursor){ 947 VfslogCsr *pCsr = (VfslogCsr *)pCursor; 948 VfslogVtab *p = (VfslogVtab *)pCursor->pVtab; 949 int rc = SQLITE_OK; 950 int nRead; 951 952 sqlite3_free(pCsr->zTransient); 953 pCsr->zTransient = 0; 954 955 nRead = 24; 956 if( pCsr->iOffset+nRead<=p->nByte ){ 957 int eEvent; 958 rc = p->pFd->pMethods->xRead(p->pFd, pCsr->aBuf, nRead, pCsr->iOffset); 959 960 eEvent = get32bits(pCsr->aBuf); 961 if( (rc==SQLITE_OK) 962 && (eEvent==OS_OPEN || eEvent==OS_DELETE || eEvent==OS_ACCESS) 963 ){ 964 char buf[4]; 965 rc = p->pFd->pMethods->xRead(p->pFd, buf, 4, pCsr->iOffset+nRead); 966 nRead += 4; 967 if( rc==SQLITE_OK ){ 968 int nStr = get32bits((unsigned char *)buf); 969 char *zStr = sqlite3_malloc(nStr+1); 970 rc = p->pFd->pMethods->xRead(p->pFd, zStr, nStr, pCsr->iOffset+nRead); 971 zStr[nStr] = '\0'; 972 nRead += nStr; 973 974 if( eEvent==OS_OPEN ){ 975 int iFileid = get32bits(&pCsr->aBuf[4]); 976 if( iFileid>=pCsr->nFile ){ 977 int nNew = sizeof(pCsr->azFile[0])*(iFileid+1); 978 pCsr->azFile = (char **)sqlite3_realloc(pCsr->azFile, nNew); 979 nNew -= sizeof(pCsr->azFile[0])*pCsr->nFile; 980 memset(&pCsr->azFile[pCsr->nFile], 0, nNew); 981 pCsr->nFile = iFileid+1; 982 } 983 sqlite3_free(pCsr->azFile[iFileid]); 984 pCsr->azFile[iFileid] = zStr; 985 }else{ 986 pCsr->zTransient = zStr; 987 } 988 } 989 } 990 } 991 992 pCsr->iRowid += 1; 993 pCsr->iOffset += nRead; 994 return rc; 995 } 996 997 static int vlogEof(sqlite3_vtab_cursor *pCursor){ 998 VfslogCsr *pCsr = (VfslogCsr *)pCursor; 999 VfslogVtab *p = (VfslogVtab *)pCursor->pVtab; 1000 return (pCsr->iOffset>=p->nByte); 1001 } 1002 1003 static int vlogFilter( 1004 sqlite3_vtab_cursor *pCursor, 1005 int idxNum, const char *idxStr, 1006 int argc, sqlite3_value **argv 1007 ){ 1008 VfslogCsr *pCsr = (VfslogCsr *)pCursor; 1009 pCsr->iRowid = 0; 1010 pCsr->iOffset = 20; 1011 return vlogNext(pCursor); 1012 } 1013 1014 static int vlogColumn( 1015 sqlite3_vtab_cursor *pCursor, 1016 sqlite3_context *ctx, 1017 int i 1018 ){ 1019 unsigned int val; 1020 VfslogCsr *pCsr = (VfslogCsr *)pCursor; 1021 1022 assert( i<7 ); 1023 val = get32bits(&pCsr->aBuf[4*i]); 1024 1025 switch( i ){ 1026 case 0: { 1027 sqlite3_result_text(ctx, vfslog_eventname(val), -1, SQLITE_STATIC); 1028 break; 1029 } 1030 case 1: { 1031 char *zStr = pCsr->zTransient; 1032 if( val!=0 && val<pCsr->nFile ){ 1033 zStr = pCsr->azFile[val]; 1034 } 1035 sqlite3_result_text(ctx, zStr, -1, SQLITE_TRANSIENT); 1036 break; 1037 } 1038 default: 1039 sqlite3_result_int(ctx, val); 1040 break; 1041 } 1042 1043 return SQLITE_OK; 1044 } 1045 1046 static int vlogRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ 1047 VfslogCsr *pCsr = (VfslogCsr *)pCursor; 1048 *pRowid = pCsr->iRowid; 1049 return SQLITE_OK; 1050 } 1051 1052 int sqlite3_vfslog_register(sqlite3 *db){ 1053 static sqlite3_module vfslog_module = { 1054 0, /* iVersion */ 1055 vlogConnect, /* xCreate */ 1056 vlogConnect, /* xConnect */ 1057 vlogBestIndex, /* xBestIndex */ 1058 vlogDisconnect, /* xDisconnect */ 1059 vlogDisconnect, /* xDestroy */ 1060 vlogOpen, /* xOpen - open a cursor */ 1061 vlogClose, /* xClose - close a cursor */ 1062 vlogFilter, /* xFilter - configure scan constraints */ 1063 vlogNext, /* xNext - advance a cursor */ 1064 vlogEof, /* xEof - check for end of scan */ 1065 vlogColumn, /* xColumn - read data */ 1066 vlogRowid, /* xRowid - read data */ 1067 0, /* xUpdate */ 1068 0, /* xBegin */ 1069 0, /* xSync */ 1070 0, /* xCommit */ 1071 0, /* xRollback */ 1072 0, /* xFindMethod */ 1073 0, /* xRename */ 1074 }; 1075 1076 sqlite3_create_module(db, "vfslog", &vfslog_module, 0); 1077 return SQLITE_OK; 1078 } 1079 1080 1081 /************************************************************************** 1082 *************************************************************************** 1083 ** Tcl interface starts here. 1084 */ 1085 1086 #if defined(SQLITE_TEST) || defined(TCLSH) 1087 1088 #include <tcl.h> 1089 1090 static int test_vfslog( 1091 void *clientData, 1092 Tcl_Interp *interp, 1093 int objc, 1094 Tcl_Obj *CONST objv[] 1095 ){ 1096 struct SqliteDb { sqlite3 *db; }; 1097 sqlite3 *db; 1098 Tcl_CmdInfo cmdInfo; 1099 int rc = SQLITE_ERROR; 1100 1101 static const char *strs[] = { "annotate", "finalize", "new", "register", 0 }; 1102 enum VL_enum { VL_ANNOTATE, VL_FINALIZE, VL_NEW, VL_REGISTER }; 1103 int iSub; 1104 1105 if( objc<2 ){ 1106 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ..."); 1107 return TCL_ERROR; 1108 } 1109 if( Tcl_GetIndexFromObj(interp, objv[1], strs, "sub-command", 0, &iSub) ){ 1110 return TCL_ERROR; 1111 } 1112 1113 switch( (enum VL_enum)iSub ){ 1114 case VL_ANNOTATE: { 1115 int rc; 1116 char *zVfs; 1117 char *zMsg; 1118 if( objc!=4 ){ 1119 Tcl_WrongNumArgs(interp, 3, objv, "VFS"); 1120 return TCL_ERROR; 1121 } 1122 zVfs = Tcl_GetString(objv[2]); 1123 zMsg = Tcl_GetString(objv[3]); 1124 rc = sqlite3_vfslog_annotate(zVfs, zMsg); 1125 if( rc!=SQLITE_OK ){ 1126 Tcl_AppendResult(interp, "failed", 0); 1127 return TCL_ERROR; 1128 } 1129 break; 1130 } 1131 case VL_FINALIZE: { 1132 int rc; 1133 char *zVfs; 1134 if( objc!=3 ){ 1135 Tcl_WrongNumArgs(interp, 2, objv, "VFS"); 1136 return TCL_ERROR; 1137 } 1138 zVfs = Tcl_GetString(objv[2]); 1139 rc = sqlite3_vfslog_finalize(zVfs); 1140 if( rc!=SQLITE_OK ){ 1141 Tcl_AppendResult(interp, "failed", 0); 1142 return TCL_ERROR; 1143 } 1144 break; 1145 }; 1146 1147 case VL_NEW: { 1148 int rc; 1149 char *zVfs; 1150 char *zParent; 1151 char *zLog; 1152 if( objc!=5 ){ 1153 Tcl_WrongNumArgs(interp, 2, objv, "VFS PARENT LOGFILE"); 1154 return TCL_ERROR; 1155 } 1156 zVfs = Tcl_GetString(objv[2]); 1157 zParent = Tcl_GetString(objv[3]); 1158 zLog = Tcl_GetString(objv[4]); 1159 if( *zParent=='\0' ) zParent = 0; 1160 rc = sqlite3_vfslog_new(zVfs, zParent, zLog); 1161 if( rc!=SQLITE_OK ){ 1162 Tcl_AppendResult(interp, "failed", 0); 1163 return TCL_ERROR; 1164 } 1165 break; 1166 }; 1167 1168 case VL_REGISTER: { 1169 char *zDb; 1170 if( objc!=3 ){ 1171 Tcl_WrongNumArgs(interp, 2, objv, "DB"); 1172 return TCL_ERROR; 1173 } 1174 zDb = Tcl_GetString(objv[2]); 1175 if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){ 1176 db = ((struct SqliteDb*)cmdInfo.objClientData)->db; 1177 rc = sqlite3_vfslog_register(db); 1178 } 1179 if( rc!=SQLITE_OK ){ 1180 Tcl_AppendResult(interp, "Bad sqlite3 handle: ", zDb, 0); 1181 return TCL_ERROR; 1182 } 1183 break; 1184 }; 1185 } 1186 1187 return TCL_OK; 1188 } 1189 1190 int SqlitetestOsinst_Init(Tcl_Interp *interp){ 1191 Tcl_CreateObjCommand(interp, "vfslog", test_vfslog, 0, 0); 1192 return TCL_OK; 1193 } 1194 1195 #endif /* SQLITE_TEST */ 1196 1197