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 ** $Id: test_osinst.c,v 1.18 2008/07/25 13:32:45 drh Exp $ 18 */ 19 20 #ifdef SQLITE_ENABLE_INSTVFS 21 /* 22 ** C interface: 23 ** 24 ** sqlite3_instvfs_create() 25 ** sqlite3_instvfs_destroy() 26 ** sqlite3_instvfs_configure() 27 ** 28 ** sqlite3_instvfs_reset() 29 ** sqlite3_instvfs_get() 30 ** 31 ** sqlite3_instvfs_binarylog 32 ** sqlite3_instvfs_binarylog_marker 33 ** 34 ** Tcl interface (omitted if SQLITE_TEST is not set): 35 ** 36 ** sqlite3_instvfs create NAME ?PARENT? 37 ** 38 ** Create and register new vfs called $NAME, which is a wrapper around 39 ** the existing vfs $PARENT. If the PARENT argument is omitted, the 40 ** new vfs is a wrapper around the current default vfs. 41 ** 42 ** sqlite3_instvfs destroy NAME 43 ** 44 ** Deregister and destroy the vfs named $NAME, which must have been 45 ** created by an earlier invocation of [sqlite3_instvfs create]. 46 ** 47 ** sqlite3_instvfs configure NAME SCRIPT 48 ** 49 ** Configure the callback script for the vfs $NAME, which much have 50 ** been created by an earlier invocation of [sqlite3_instvfs create]. 51 ** After a callback script has been configured, it is invoked each 52 ** time a vfs or file method is called by SQLite. Before invoking 53 ** the callback script, five arguments are appended to it: 54 ** 55 ** * The name of the invoked method - i.e. "xRead". 56 ** 57 ** * The time consumed by the method call as measured by 58 ** sqlite3Hwtime() (an integer value) 59 ** 60 ** * A string value with a different meaning for different calls. 61 ** For file methods, the name of the file being operated on. For 62 ** other methods it is the filename argument, if any. 63 ** 64 ** * A 32-bit integer value with a call-specific meaning. 65 ** 66 ** * A 64-bit integer value. For xRead() and xWrite() calls this 67 ** is the file offset being written to or read from. Unused by 68 ** all other calls. 69 ** 70 ** sqlite3_instvfs reset NAME 71 ** 72 ** Zero the internal event counters associated with vfs $NAME, 73 ** which must have been created by an earlier invocation of 74 ** [sqlite3_instvfs create]. 75 ** 76 ** sqlite3_instvfs report NAME 77 ** 78 ** Return the values of the internal event counters associated 79 ** with vfs $NAME. The report format is a list with one element 80 ** for each method call (xWrite, xRead etc.). Each element is 81 ** itself a list with three elements: 82 ** 83 ** * The name of the method call - i.e. "xWrite", 84 ** * The total number of calls to the method (an integer). 85 ** * The aggregate time consumed by all calls to the method as 86 ** measured by sqlite3Hwtime() (an integer). 87 */ 88 89 #include "sqlite3.h" 90 #include <string.h> 91 #include <assert.h> 92 93 /* 94 ** Maximum pathname length supported by the inst backend. 95 */ 96 #define INST_MAX_PATHNAME 512 97 98 99 /* File methods */ 100 /* Vfs methods */ 101 #define OS_ACCESS 1 102 #define OS_CHECKRESERVEDLOCK 2 103 #define OS_CLOSE 3 104 #define OS_CURRENTTIME 4 105 #define OS_DELETE 5 106 #define OS_DEVCHAR 6 107 #define OS_FILECONTROL 7 108 #define OS_FILESIZE 8 109 #define OS_FULLPATHNAME 9 110 #define OS_LOCK 11 111 #define OS_OPEN 12 112 #define OS_RANDOMNESS 13 113 #define OS_READ 14 114 #define OS_SECTORSIZE 15 115 #define OS_SLEEP 16 116 #define OS_SYNC 17 117 #define OS_TRUNCATE 18 118 #define OS_UNLOCK 19 119 #define OS_WRITE 20 120 121 #define OS_NUMEVENTS 21 122 123 #define BINARYLOG_STRING 30 124 #define BINARYLOG_MARKER 31 125 126 #define BINARYLOG_PREPARE_V2 64 127 #define BINARYLOG_STEP 65 128 #define BINARYLOG_FINALIZE 66 129 130 struct InstVfs { 131 sqlite3_vfs base; 132 sqlite3_vfs *pVfs; 133 134 void *pClient; 135 void (*xDel)(void *); 136 void (*xCall)(void *, int, int, sqlite3_int64, int, const char *, int, int, sqlite3_int64); 137 138 /* Counters */ 139 sqlite3_int64 aTime[OS_NUMEVENTS]; 140 int aCount[OS_NUMEVENTS]; 141 142 int iNextFileId; 143 }; 144 typedef struct InstVfs InstVfs; 145 146 #define REALVFS(p) (((InstVfs *)(p))->pVfs) 147 148 typedef struct inst_file inst_file; 149 struct inst_file { 150 sqlite3_file base; 151 sqlite3_file *pReal; 152 InstVfs *pInstVfs; 153 const char *zName; 154 int iFileId; /* File id number */ 155 int flags; 156 }; 157 158 /* 159 ** Method declarations for inst_file. 160 */ 161 static int instClose(sqlite3_file*); 162 static int instRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); 163 static int instWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); 164 static int instTruncate(sqlite3_file*, sqlite3_int64 size); 165 static int instSync(sqlite3_file*, int flags); 166 static int instFileSize(sqlite3_file*, sqlite3_int64 *pSize); 167 static int instLock(sqlite3_file*, int); 168 static int instUnlock(sqlite3_file*, int); 169 static int instCheckReservedLock(sqlite3_file*, int *pResOut); 170 static int instFileControl(sqlite3_file*, int op, void *pArg); 171 static int instSectorSize(sqlite3_file*); 172 static int instDeviceCharacteristics(sqlite3_file*); 173 174 /* 175 ** Method declarations for inst_vfs. 176 */ 177 static int instOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); 178 static int instDelete(sqlite3_vfs*, const char *zName, int syncDir); 179 static int instAccess(sqlite3_vfs*, const char *zName, int flags, int *); 180 static int instFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); 181 static void *instDlOpen(sqlite3_vfs*, const char *zFilename); 182 static void instDlError(sqlite3_vfs*, int nByte, char *zErrMsg); 183 static void *instDlSym(sqlite3_vfs*,void*, const char *zSymbol); 184 static void instDlClose(sqlite3_vfs*, void*); 185 static int instRandomness(sqlite3_vfs*, int nByte, char *zOut); 186 static int instSleep(sqlite3_vfs*, int microseconds); 187 static int instCurrentTime(sqlite3_vfs*, double*); 188 189 static void binarylog_blob(sqlite3_vfs *, const char *, int, int); 190 191 static sqlite3_vfs inst_vfs = { 192 1, /* iVersion */ 193 sizeof(inst_file), /* szOsFile */ 194 INST_MAX_PATHNAME, /* mxPathname */ 195 0, /* pNext */ 196 0, /* zName */ 197 0, /* pAppData */ 198 instOpen, /* xOpen */ 199 instDelete, /* xDelete */ 200 instAccess, /* xAccess */ 201 instFullPathname, /* xFullPathname */ 202 instDlOpen, /* xDlOpen */ 203 instDlError, /* xDlError */ 204 instDlSym, /* xDlSym */ 205 instDlClose, /* xDlClose */ 206 instRandomness, /* xRandomness */ 207 instSleep, /* xSleep */ 208 instCurrentTime /* xCurrentTime */ 209 }; 210 211 static sqlite3_io_methods inst_io_methods = { 212 1, /* iVersion */ 213 instClose, /* xClose */ 214 instRead, /* xRead */ 215 instWrite, /* xWrite */ 216 instTruncate, /* xTruncate */ 217 instSync, /* xSync */ 218 instFileSize, /* xFileSize */ 219 instLock, /* xLock */ 220 instUnlock, /* xUnlock */ 221 instCheckReservedLock, /* xCheckReservedLock */ 222 instFileControl, /* xFileControl */ 223 instSectorSize, /* xSectorSize */ 224 instDeviceCharacteristics /* xDeviceCharacteristics */ 225 }; 226 227 /* 228 ** hwtime.h contains inline assembler code for implementing 229 ** high-performance timing routines. 230 */ 231 #include "hwtime.h" 232 233 #define OS_TIME_IO(eEvent, A, B, Call) { \ 234 inst_file *p = (inst_file *)pFile; \ 235 InstVfs *pInstVfs = p->pInstVfs; \ 236 int rc; \ 237 sqlite_uint64 t = sqlite3Hwtime(); \ 238 rc = Call; \ 239 t = sqlite3Hwtime() - t; \ 240 pInstVfs->aTime[eEvent] += t; \ 241 pInstVfs->aCount[eEvent] += 1; \ 242 if( pInstVfs->xCall ){ \ 243 pInstVfs->xCall( \ 244 pInstVfs->pClient,eEvent,p->iFileId,t,rc,p->zName,p->flags,A,B \ 245 ); \ 246 } \ 247 return rc; \ 248 } 249 250 #define OS_TIME_VFS(eEvent, Z, flags, A, B, Call) { \ 251 InstVfs *pInstVfs = (InstVfs *)pVfs; \ 252 int rc; \ 253 sqlite_uint64 t = sqlite3Hwtime(); \ 254 rc = Call; \ 255 t = sqlite3Hwtime() - t; \ 256 pInstVfs->aTime[eEvent] += t; \ 257 pInstVfs->aCount[eEvent] += 1; \ 258 if( pInstVfs->xCall ){ \ 259 pInstVfs->xCall(pInstVfs->pClient,eEvent,0, t, rc, Z, flags, A, B); \ 260 } \ 261 return rc; \ 262 } 263 264 /* 265 ** Close an inst-file. 266 */ 267 static int instClose(sqlite3_file *pFile){ 268 OS_TIME_IO(OS_CLOSE, 0, 0, 269 (p->pReal->pMethods ? p->pReal->pMethods->xClose(p->pReal) : SQLITE_OK) 270 ); 271 } 272 273 /* 274 ** Read data from an inst-file. 275 */ 276 static int instRead( 277 sqlite3_file *pFile, 278 void *zBuf, 279 int iAmt, 280 sqlite_int64 iOfst 281 ){ 282 sqlite3_vfs *pVfs = (sqlite3_vfs *)(((inst_file *)pFile)->pInstVfs); 283 OS_TIME_IO(OS_READ, iAmt, (binarylog_blob(pVfs, zBuf, iAmt, 1), iOfst), 284 p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst) 285 ); 286 } 287 288 /* 289 ** Write data to an inst-file. 290 */ 291 static int instWrite( 292 sqlite3_file *pFile, 293 const void *z, 294 int iAmt, 295 sqlite_int64 iOfst 296 ){ 297 sqlite3_vfs *pVfs = (sqlite3_vfs *)(((inst_file *)pFile)->pInstVfs); 298 binarylog_blob(pVfs, z, iAmt, 1); 299 OS_TIME_IO(OS_WRITE, iAmt, iOfst, 300 p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst) 301 ); 302 } 303 304 /* 305 ** Truncate an inst-file. 306 */ 307 static int instTruncate(sqlite3_file *pFile, sqlite_int64 size){ 308 OS_TIME_IO(OS_TRUNCATE, 0, (int)size, 309 p->pReal->pMethods->xTruncate(p->pReal, size) 310 ); 311 } 312 313 /* 314 ** Sync an inst-file. 315 */ 316 static int instSync(sqlite3_file *pFile, int flags){ 317 OS_TIME_IO(OS_SYNC, flags, 0, p->pReal->pMethods->xSync(p->pReal, flags)); 318 } 319 320 /* 321 ** Return the current file-size of an inst-file. 322 */ 323 static int instFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ 324 OS_TIME_IO(OS_FILESIZE, (int)(*pSize), 0, 325 p->pReal->pMethods->xFileSize(p->pReal, pSize) 326 ); 327 } 328 329 /* 330 ** Lock an inst-file. 331 */ 332 static int instLock(sqlite3_file *pFile, int eLock){ 333 OS_TIME_IO(OS_LOCK, eLock, 0, p->pReal->pMethods->xLock(p->pReal, eLock)); 334 } 335 336 /* 337 ** Unlock an inst-file. 338 */ 339 static int instUnlock(sqlite3_file *pFile, int eLock){ 340 OS_TIME_IO(OS_UNLOCK, eLock, 0, p->pReal->pMethods->xUnlock(p->pReal, eLock)); 341 } 342 343 /* 344 ** Check if another file-handle holds a RESERVED lock on an inst-file. 345 */ 346 static int instCheckReservedLock(sqlite3_file *pFile, int *pResOut){ 347 OS_TIME_IO(OS_CHECKRESERVEDLOCK, 0, 0, 348 p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut) 349 ); 350 } 351 352 /* 353 ** File control method. For custom operations on an inst-file. 354 */ 355 static int instFileControl(sqlite3_file *pFile, int op, void *pArg){ 356 OS_TIME_IO(OS_FILECONTROL, 0, 0, p->pReal->pMethods->xFileControl(p->pReal, op, pArg)); 357 } 358 359 /* 360 ** Return the sector-size in bytes for an inst-file. 361 */ 362 static int instSectorSize(sqlite3_file *pFile){ 363 OS_TIME_IO(OS_SECTORSIZE, 0, 0, p->pReal->pMethods->xSectorSize(p->pReal)); 364 } 365 366 /* 367 ** Return the device characteristic flags supported by an inst-file. 368 */ 369 static int instDeviceCharacteristics(sqlite3_file *pFile){ 370 OS_TIME_IO(OS_DEVCHAR, 0, 0, p->pReal->pMethods->xDeviceCharacteristics(p->pReal)); 371 } 372 373 /* 374 ** Open an inst file handle. 375 */ 376 static int instOpen( 377 sqlite3_vfs *pVfs, 378 const char *zName, 379 sqlite3_file *pFile, 380 int flags, 381 int *pOutFlags 382 ){ 383 inst_file *p = (inst_file *)pFile; 384 pFile->pMethods = &inst_io_methods; 385 p->pReal = (sqlite3_file *)&p[1]; 386 p->pInstVfs = (InstVfs *)pVfs; 387 p->zName = zName; 388 p->flags = flags; 389 p->iFileId = ++p->pInstVfs->iNextFileId; 390 391 binarylog_blob(pVfs, zName, -1, 0); 392 OS_TIME_VFS(OS_OPEN, zName, flags, p->iFileId, 0, 393 REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags) 394 ); 395 } 396 397 /* 398 ** Delete the file located at zPath. If the dirSync argument is true, 399 ** ensure the file-system modifications are synced to disk before 400 ** returning. 401 */ 402 static int instDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ 403 binarylog_blob(pVfs, zPath, -1, 0); 404 OS_TIME_VFS(OS_DELETE, zPath, 0, dirSync, 0, 405 REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync) 406 ); 407 } 408 409 /* 410 ** Test for access permissions. Return true if the requested permission 411 ** is available, or false otherwise. 412 */ 413 static int instAccess( 414 sqlite3_vfs *pVfs, 415 const char *zPath, 416 int flags, 417 int *pResOut 418 ){ 419 binarylog_blob(pVfs, zPath, -1, 0); 420 OS_TIME_VFS(OS_ACCESS, zPath, 0, flags, *pResOut, 421 REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut) 422 ); 423 } 424 425 /* 426 ** Populate buffer zOut with the full canonical pathname corresponding 427 ** to the pathname in zPath. zOut is guaranteed to point to a buffer 428 ** of at least (INST_MAX_PATHNAME+1) bytes. 429 */ 430 static int instFullPathname( 431 sqlite3_vfs *pVfs, 432 const char *zPath, 433 int nOut, 434 char *zOut 435 ){ 436 OS_TIME_VFS( OS_FULLPATHNAME, zPath, 0, 0, 0, 437 REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut); 438 ); 439 } 440 441 /* 442 ** Open the dynamic library located at zPath and return a handle. 443 */ 444 static void *instDlOpen(sqlite3_vfs *pVfs, const char *zPath){ 445 return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath); 446 } 447 448 /* 449 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable 450 ** utf-8 string describing the most recent error encountered associated 451 ** with dynamic libraries. 452 */ 453 static void instDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ 454 REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg); 455 } 456 457 /* 458 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle. 459 */ 460 static void *instDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){ 461 return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), pHandle, zSymbol); 462 } 463 464 /* 465 ** Close the dynamic library handle pHandle. 466 */ 467 static void instDlClose(sqlite3_vfs *pVfs, void *pHandle){ 468 REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle); 469 } 470 471 /* 472 ** Populate the buffer pointed to by zBufOut with nByte bytes of 473 ** random data. 474 */ 475 static int instRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ 476 OS_TIME_VFS( OS_RANDOMNESS, 0, 0, nByte, 0, 477 REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut); 478 ); 479 } 480 481 /* 482 ** Sleep for nMicro microseconds. Return the number of microseconds 483 ** actually slept. 484 */ 485 static int instSleep(sqlite3_vfs *pVfs, int nMicro){ 486 OS_TIME_VFS( OS_SLEEP, 0, 0, nMicro, 0, 487 REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro) 488 ); 489 } 490 491 /* 492 ** Return the current time as a Julian Day number in *pTimeOut. 493 */ 494 static int instCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ 495 OS_TIME_VFS( OS_CURRENTTIME, 0, 0, 0, 0, 496 REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut) 497 ); 498 } 499 500 sqlite3_vfs *sqlite3_instvfs_create(const char *zName, const char *zParent){ 501 int nByte; 502 InstVfs *p; 503 sqlite3_vfs *pParent; 504 505 pParent = sqlite3_vfs_find(zParent); 506 if( !pParent ){ 507 return 0; 508 } 509 510 nByte = strlen(zName) + 1 + sizeof(InstVfs); 511 p = (InstVfs *)sqlite3_malloc(nByte); 512 if( p ){ 513 char *zCopy = (char *)&p[1]; 514 memset(p, 0, nByte); 515 memcpy(p, &inst_vfs, sizeof(sqlite3_vfs)); 516 p->pVfs = pParent; 517 memcpy(zCopy, zName, strlen(zName)); 518 p->base.zName = (const char *)zCopy; 519 p->base.szOsFile += pParent->szOsFile; 520 sqlite3_vfs_register((sqlite3_vfs *)p, 0); 521 } 522 523 return (sqlite3_vfs *)p; 524 } 525 526 void sqlite3_instvfs_configure( 527 sqlite3_vfs *pVfs, 528 void (*xCall)( 529 void*, 530 int, /* File id */ 531 int, /* Event code */ 532 sqlite3_int64, 533 int, /* Return code */ 534 const char*, /* File name */ 535 int, 536 int, 537 sqlite3_int64 538 ), 539 void *pClient, 540 void (*xDel)(void *) 541 ){ 542 InstVfs *p = (InstVfs *)pVfs; 543 assert( pVfs->xOpen==instOpen ); 544 if( p->xDel ){ 545 p->xDel(p->pClient); 546 } 547 p->xCall = xCall; 548 p->xDel = xDel; 549 p->pClient = pClient; 550 } 551 552 void sqlite3_instvfs_destroy(sqlite3_vfs *pVfs){ 553 if( pVfs ){ 554 sqlite3_vfs_unregister(pVfs); 555 sqlite3_instvfs_configure(pVfs, 0, 0, 0); 556 sqlite3_free(pVfs); 557 } 558 } 559 560 void sqlite3_instvfs_reset(sqlite3_vfs *pVfs){ 561 InstVfs *p = (InstVfs *)pVfs; 562 assert( pVfs->xOpen==instOpen ); 563 memset(p->aTime, 0, sizeof(sqlite3_int64)*OS_NUMEVENTS); 564 memset(p->aCount, 0, sizeof(int)*OS_NUMEVENTS); 565 } 566 567 const char *sqlite3_instvfs_name(int eEvent){ 568 const char *zEvent = 0; 569 570 switch( eEvent ){ 571 case OS_CLOSE: zEvent = "xClose"; break; 572 case OS_READ: zEvent = "xRead"; break; 573 case OS_WRITE: zEvent = "xWrite"; break; 574 case OS_TRUNCATE: zEvent = "xTruncate"; break; 575 case OS_SYNC: zEvent = "xSync"; break; 576 case OS_FILESIZE: zEvent = "xFilesize"; break; 577 case OS_LOCK: zEvent = "xLock"; break; 578 case OS_UNLOCK: zEvent = "xUnlock"; break; 579 case OS_CHECKRESERVEDLOCK: zEvent = "xCheckReservedLock"; break; 580 case OS_FILECONTROL: zEvent = "xFileControl"; break; 581 case OS_SECTORSIZE: zEvent = "xSectorSize"; break; 582 case OS_DEVCHAR: zEvent = "xDeviceCharacteristics"; break; 583 case OS_OPEN: zEvent = "xOpen"; break; 584 case OS_DELETE: zEvent = "xDelete"; break; 585 case OS_ACCESS: zEvent = "xAccess"; break; 586 case OS_FULLPATHNAME: zEvent = "xFullPathname"; break; 587 case OS_RANDOMNESS: zEvent = "xRandomness"; break; 588 case OS_SLEEP: zEvent = "xSleep"; break; 589 case OS_CURRENTTIME: zEvent = "xCurrentTime"; break; 590 } 591 592 return zEvent; 593 } 594 595 void sqlite3_instvfs_get( 596 sqlite3_vfs *pVfs, 597 int eEvent, 598 const char **pzEvent, 599 sqlite3_int64 *pnClick, 600 int *pnCall 601 ){ 602 InstVfs *p = (InstVfs *)pVfs; 603 assert( pVfs->xOpen==instOpen ); 604 if( eEvent<1 || eEvent>=OS_NUMEVENTS ){ 605 *pzEvent = 0; 606 *pnClick = 0; 607 *pnCall = 0; 608 return; 609 } 610 611 *pzEvent = sqlite3_instvfs_name(eEvent); 612 *pnClick = p->aTime[eEvent]; 613 *pnCall = p->aCount[eEvent]; 614 } 615 616 #define BINARYLOG_BUFFERSIZE 8192 617 618 struct InstVfsBinaryLog { 619 int nBuf; 620 char *zBuf; 621 sqlite3_int64 iOffset; 622 int log_data; 623 sqlite3_file *pOut; 624 char *zOut; /* Log file name */ 625 }; 626 typedef struct InstVfsBinaryLog InstVfsBinaryLog; 627 628 static void put32bits(unsigned char *p, unsigned int v){ 629 p[0] = v>>24; 630 p[1] = v>>16; 631 p[2] = v>>8; 632 p[3] = v; 633 } 634 635 static void binarylog_flush(InstVfsBinaryLog *pLog){ 636 sqlite3_file *pFile = pLog->pOut; 637 638 #ifdef SQLITE_TEST 639 extern int sqlite3_io_error_pending; 640 extern int sqlite3_io_error_persist; 641 extern int sqlite3_diskfull_pending; 642 643 int pending = sqlite3_io_error_pending; 644 int persist = sqlite3_io_error_persist; 645 int diskfull = sqlite3_diskfull_pending; 646 647 sqlite3_io_error_pending = 0; 648 sqlite3_io_error_persist = 0; 649 sqlite3_diskfull_pending = 0; 650 #endif 651 652 pFile->pMethods->xWrite(pFile, pLog->zBuf, pLog->nBuf, pLog->iOffset); 653 pLog->iOffset += pLog->nBuf; 654 pLog->nBuf = 0; 655 656 #ifdef SQLITE_TEST 657 sqlite3_io_error_pending = pending; 658 sqlite3_io_error_persist = persist; 659 sqlite3_diskfull_pending = diskfull; 660 #endif 661 } 662 663 static void binarylog_xcall( 664 void *p, 665 int eEvent, 666 int iFileId, 667 sqlite3_int64 nClick, 668 int return_code, 669 const char *zName, 670 int flags, 671 int nByte, 672 sqlite3_int64 iOffset 673 ){ 674 InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)p; 675 unsigned char *zRec; 676 if( (28+pLog->nBuf)>BINARYLOG_BUFFERSIZE ){ 677 binarylog_flush(pLog); 678 } 679 zRec = (unsigned char *)&pLog->zBuf[pLog->nBuf]; 680 put32bits(&zRec[0], eEvent); 681 put32bits(&zRec[4], (int)iFileId); 682 put32bits(&zRec[8], (int)nClick); 683 put32bits(&zRec[12], return_code); 684 put32bits(&zRec[16], flags); 685 put32bits(&zRec[20], nByte); 686 put32bits(&zRec[24], (int)iOffset); 687 pLog->nBuf += 28; 688 } 689 690 static void binarylog_xdel(void *p){ 691 /* Close the log file and free the memory allocated for the 692 ** InstVfsBinaryLog structure. 693 */ 694 InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)p; 695 sqlite3_file *pFile = pLog->pOut; 696 if( pLog->nBuf ){ 697 binarylog_flush(pLog); 698 } 699 pFile->pMethods->xClose(pFile); 700 sqlite3_free(pLog->pOut); 701 sqlite3_free(pLog->zBuf); 702 sqlite3_free(pLog); 703 } 704 705 static void binarylog_blob( 706 sqlite3_vfs *pVfs, 707 const char *zBlob, 708 int nBlob, 709 int isBinary 710 ){ 711 InstVfsBinaryLog *pLog; 712 InstVfs *pInstVfs = (InstVfs *)pVfs; 713 714 if( pVfs->xOpen!=instOpen || pInstVfs->xCall!=binarylog_xcall ){ 715 return; 716 } 717 pLog = (InstVfsBinaryLog *)pInstVfs->pClient; 718 if( zBlob && (!isBinary || pLog->log_data) ){ 719 unsigned char *zRec; 720 int nWrite; 721 722 if( nBlob<0 ){ 723 nBlob = strlen(zBlob); 724 } 725 nWrite = nBlob + 28; 726 727 if( (nWrite+pLog->nBuf)>BINARYLOG_BUFFERSIZE ){ 728 binarylog_flush(pLog); 729 } 730 731 zRec = (unsigned char *)&pLog->zBuf[pLog->nBuf]; 732 memset(zRec, 0, nWrite); 733 put32bits(&zRec[0], BINARYLOG_STRING); 734 put32bits(&zRec[4], (int)nBlob); 735 put32bits(&zRec[8], (int)isBinary); 736 memcpy(&zRec[28], zBlob, nBlob); 737 pLog->nBuf += nWrite; 738 } 739 } 740 741 void sqlite3_instvfs_binarylog_call( 742 sqlite3_vfs *pVfs, 743 int eEvent, 744 sqlite3_int64 nClick, 745 int return_code, 746 const char *zString 747 ){ 748 InstVfs *pInstVfs = (InstVfs *)pVfs; 749 InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)pInstVfs->pClient; 750 751 if( zString ){ 752 binarylog_blob(pVfs, zString, -1, 0); 753 } 754 binarylog_xcall(pLog, eEvent, 0, nClick, return_code, 0, 0, 0, 0); 755 } 756 757 void sqlite3_instvfs_binarylog_marker( 758 sqlite3_vfs *pVfs, 759 const char *zMarker 760 ){ 761 InstVfs *pInstVfs = (InstVfs *)pVfs; 762 InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)pInstVfs->pClient; 763 binarylog_blob(pVfs, zMarker, -1, 0); 764 binarylog_xcall(pLog, BINARYLOG_MARKER, 0, 0, 0, 0, 0, 0, 0); 765 } 766 767 sqlite3_vfs *sqlite3_instvfs_binarylog( 768 const char *zVfs, 769 const char *zParentVfs, 770 const char *zLog, 771 int log_data 772 ){ 773 InstVfsBinaryLog *p; 774 sqlite3_vfs *pVfs; 775 sqlite3_vfs *pParent; 776 int nByte; 777 int flags; 778 int rc; 779 780 pParent = sqlite3_vfs_find(zParentVfs); 781 if( !pParent ){ 782 return 0; 783 } 784 785 nByte = sizeof(InstVfsBinaryLog) + pParent->mxPathname+1; 786 p = (InstVfsBinaryLog *)sqlite3_malloc(nByte); 787 memset(p, 0, nByte); 788 p->zBuf = sqlite3_malloc(BINARYLOG_BUFFERSIZE); 789 p->zOut = (char *)&p[1]; 790 p->pOut = (sqlite3_file *)sqlite3_malloc(pParent->szOsFile); 791 p->log_data = log_data; 792 pParent->xFullPathname(pParent, zLog, pParent->mxPathname, p->zOut); 793 flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MASTER_JOURNAL; 794 pParent->xDelete(pParent, p->zOut, 0); 795 rc = pParent->xOpen(pParent, p->zOut, p->pOut, flags, &flags); 796 if( rc==SQLITE_OK ){ 797 memcpy(p->zBuf, "sqlite_ostrace1.....", 20); 798 p->iOffset = 0; 799 p->nBuf = 20; 800 } 801 if( rc ){ 802 binarylog_xdel(p); 803 return 0; 804 } 805 806 pVfs = sqlite3_instvfs_create(zVfs, zParentVfs); 807 if( pVfs ){ 808 sqlite3_instvfs_configure(pVfs, binarylog_xcall, p, binarylog_xdel); 809 } 810 811 return pVfs; 812 } 813 #endif /* SQLITE_ENABLE_INSTVFS */ 814 815 /************************************************************************** 816 *************************************************************************** 817 ** Tcl interface starts here. 818 */ 819 #if SQLITE_TEST 820 821 #include <tcl.h> 822 823 #ifdef SQLITE_ENABLE_INSTVFS 824 struct InstVfsCall { 825 Tcl_Interp *interp; 826 Tcl_Obj *pScript; 827 }; 828 typedef struct InstVfsCall InstVfsCall; 829 830 static void test_instvfs_xcall( 831 void *p, 832 int eEvent, 833 int iFileId, 834 sqlite3_int64 nClick, 835 int return_code, 836 const char *zName, 837 int flags, 838 int nByte, 839 sqlite3_int64 iOffset 840 ){ 841 int rc; 842 InstVfsCall *pCall = (InstVfsCall *)p; 843 Tcl_Obj *pObj = Tcl_DuplicateObj( pCall->pScript); 844 const char *zEvent = sqlite3_instvfs_name(eEvent); 845 846 Tcl_IncrRefCount(pObj); 847 Tcl_ListObjAppendElement(0, pObj, Tcl_NewStringObj(zEvent, -1)); 848 Tcl_ListObjAppendElement(0, pObj, Tcl_NewWideIntObj(nClick)); 849 Tcl_ListObjAppendElement(0, pObj, Tcl_NewStringObj(zName, -1)); 850 Tcl_ListObjAppendElement(0, pObj, Tcl_NewIntObj(nByte)); 851 Tcl_ListObjAppendElement(0, pObj, Tcl_NewWideIntObj(iOffset)); 852 853 rc = Tcl_EvalObjEx(pCall->interp, pObj, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); 854 if( rc ){ 855 Tcl_BackgroundError(pCall->interp); 856 } 857 Tcl_DecrRefCount(pObj); 858 } 859 860 static void test_instvfs_xdel(void *p){ 861 InstVfsCall *pCall = (InstVfsCall *)p; 862 Tcl_DecrRefCount(pCall->pScript); 863 sqlite3_free(pCall); 864 } 865 866 static int test_sqlite3_instvfs( 867 void * clientData, 868 Tcl_Interp *interp, 869 int objc, 870 Tcl_Obj *CONST objv[] 871 ){ 872 static const char *IV_strs[] = 873 { "create", "destroy", "reset", "report", "configure", "binarylog", "marker", 0 }; 874 enum IV_enum { IV_CREATE, IV_DESTROY, IV_RESET, IV_REPORT, IV_CONFIGURE, IV_BINARYLOG, IV_MARKER }; 875 int iSub; 876 877 if( objc<2 ){ 878 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ..."); 879 } 880 if( Tcl_GetIndexFromObj(interp, objv[1], IV_strs, "sub-command", 0, &iSub) ){ 881 return TCL_ERROR; 882 } 883 884 switch( (enum IV_enum)iSub ){ 885 case IV_CREATE: { 886 char *zParent = 0; 887 sqlite3_vfs *p; 888 int isDefault = 0; 889 if( objc>2 && 0==strcmp("-default", Tcl_GetString(objv[2])) ){ 890 isDefault = 1; 891 } 892 if( (objc-isDefault)!=4 && (objc-isDefault)!=3 ){ 893 Tcl_WrongNumArgs(interp, 2, objv, "?-default? NAME ?PARENT-VFS?"); 894 return TCL_ERROR; 895 } 896 if( objc==(4+isDefault) ){ 897 zParent = Tcl_GetString(objv[3+isDefault]); 898 } 899 p = sqlite3_instvfs_create(Tcl_GetString(objv[2+isDefault]), zParent); 900 if( !p ){ 901 Tcl_AppendResult(interp, "error creating vfs ", 0); 902 return TCL_ERROR; 903 } 904 if( isDefault ){ 905 sqlite3_vfs_register(p, 1); 906 } 907 Tcl_SetObjResult(interp, objv[2]); 908 break; 909 } 910 case IV_BINARYLOG: { 911 char *zName = 0; 912 char *zLog = 0; 913 char *zParent = 0; 914 sqlite3_vfs *p; 915 int isDefault = 0; 916 int isLogdata = 0; 917 int argbase = 2; 918 919 for(argbase=2; argbase<(objc-2); argbase++){ 920 if( 0==strcmp("-default", Tcl_GetString(objv[argbase])) ){ 921 isDefault = 1; 922 } 923 else if( 0==strcmp("-parent", Tcl_GetString(objv[argbase])) ){ 924 argbase++; 925 zParent = Tcl_GetString(objv[argbase]); 926 } 927 else if( 0==strcmp("-logdata", Tcl_GetString(objv[argbase])) ){ 928 isLogdata = 1; 929 }else{ 930 break; 931 } 932 } 933 934 if( (objc-argbase)!=2 ){ 935 Tcl_WrongNumArgs( 936 interp, 2, objv, "?-default? ?-parent VFS? ?-logdata? NAME LOGFILE" 937 ); 938 return TCL_ERROR; 939 } 940 zName = Tcl_GetString(objv[argbase]); 941 zLog = Tcl_GetString(objv[argbase+1]); 942 p = sqlite3_instvfs_binarylog(zName, zParent, zLog, isLogdata); 943 if( !p ){ 944 Tcl_AppendResult(interp, "error creating vfs ", 0); 945 return TCL_ERROR; 946 } 947 if( isDefault ){ 948 sqlite3_vfs_register(p, 1); 949 } 950 Tcl_SetObjResult(interp, objv[2]); 951 break; 952 } 953 954 case IV_MARKER: { 955 sqlite3_vfs *p; 956 if( objc!=4 ){ 957 Tcl_WrongNumArgs(interp, 2, objv, "VFS MARKER"); 958 return TCL_ERROR; 959 } 960 p = sqlite3_vfs_find(Tcl_GetString(objv[2])); 961 if( !p || p->xOpen!=instOpen ){ 962 Tcl_AppendResult(interp, "no such vfs: ", Tcl_GetString(objv[2]), 0); 963 return TCL_ERROR; 964 } 965 sqlite3_instvfs_binarylog_marker(p, Tcl_GetString(objv[3])); 966 Tcl_ResetResult(interp); 967 break; 968 } 969 970 case IV_CONFIGURE: { 971 InstVfsCall *pCall; 972 973 sqlite3_vfs *p; 974 if( objc!=4 ){ 975 Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); 976 return TCL_ERROR; 977 } 978 p = sqlite3_vfs_find(Tcl_GetString(objv[2])); 979 if( !p || p->xOpen!=instOpen ){ 980 Tcl_AppendResult(interp, "no such vfs: ", Tcl_GetString(objv[2]), 0); 981 return TCL_ERROR; 982 } 983 984 if( strlen(Tcl_GetString(objv[3])) ){ 985 pCall = (InstVfsCall *)sqlite3_malloc(sizeof(InstVfsCall)); 986 pCall->interp = interp; 987 pCall->pScript = Tcl_DuplicateObj(objv[3]); 988 Tcl_IncrRefCount(pCall->pScript); 989 sqlite3_instvfs_configure(p, 990 test_instvfs_xcall, (void *)pCall, test_instvfs_xdel 991 ); 992 }else{ 993 sqlite3_instvfs_configure(p, 0, 0, 0); 994 } 995 break; 996 } 997 998 case IV_REPORT: 999 case IV_DESTROY: 1000 case IV_RESET: { 1001 sqlite3_vfs *p; 1002 if( objc!=3 ){ 1003 Tcl_WrongNumArgs(interp, 2, objv, "NAME"); 1004 return TCL_ERROR; 1005 } 1006 p = sqlite3_vfs_find(Tcl_GetString(objv[2])); 1007 if( !p || p->xOpen!=instOpen ){ 1008 Tcl_AppendResult(interp, "no such vfs: ", Tcl_GetString(objv[2]), 0); 1009 return TCL_ERROR; 1010 } 1011 1012 if( ((enum IV_enum)iSub)==IV_DESTROY ){ 1013 sqlite3_instvfs_destroy(p); 1014 } 1015 if( ((enum IV_enum)iSub)==IV_RESET ){ 1016 sqlite3_instvfs_reset(p); 1017 } 1018 if( ((enum IV_enum)iSub)==IV_REPORT ){ 1019 int ii; 1020 Tcl_Obj *pRet = Tcl_NewObj(); 1021 1022 const char *zName = (char *)1; 1023 sqlite3_int64 nClick; 1024 int nCall; 1025 for(ii=1; zName; ii++){ 1026 sqlite3_instvfs_get(p, ii, &zName, &nClick, &nCall); 1027 if( zName ){ 1028 Tcl_Obj *pElem = Tcl_NewObj(); 1029 Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj(zName, -1)); 1030 Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(nCall)); 1031 Tcl_ListObjAppendElement(0, pElem, Tcl_NewWideIntObj(nClick)); 1032 Tcl_ListObjAppendElement(0, pRet, pElem); 1033 } 1034 } 1035 1036 Tcl_SetObjResult(interp, pRet); 1037 } 1038 1039 break; 1040 } 1041 } 1042 1043 return TCL_OK; 1044 } 1045 #endif /* SQLITE_ENABLE_INSTVFS */ 1046 1047 /* Alternative implementation of sqlite3_instvfs when the real 1048 ** implementation is unavailable. 1049 */ 1050 #ifndef SQLITE_ENABLE_INSTVFS 1051 static int test_sqlite3_instvfs( 1052 void * clientData, 1053 Tcl_Interp *interp, 1054 int objc, 1055 Tcl_Obj *CONST objv[] 1056 ){ 1057 Tcl_AppendResult(interp, 1058 "not compiled with -DSQLITE_ENABLE_INSTVFS; sqlite3_instvfs is " 1059 "unavailable", (char*)0); 1060 return TCL_ERROR; 1061 } 1062 #endif /* !defined(SQLITE_ENABLE_INSTVFS) */ 1063 1064 int SqlitetestOsinst_Init(Tcl_Interp *interp){ 1065 Tcl_CreateObjCommand(interp, "sqlite3_instvfs", test_sqlite3_instvfs, 0, 0); 1066 return TCL_OK; 1067 } 1068 1069 #endif /* SQLITE_TEST */ 1070