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