/ Check-in [f97d8945]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add a logfile option to test_osinst.c. (CVS 4994)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:f97d89458259978b7b1b5c5e5a0d19cabcb9e536
User & Date: danielk1977 2008-04-12 10:53:11
Context
2008-04-12
11:30
Modify test_osinst.c so that it only uses public interfaces. (CVS 4995) check-in: 3866a5da user: danielk1977 tags: trunk
10:53
Add a logfile option to test_osinst.c. (CVS 4994) check-in: f97d8945 user: danielk1977 tags: trunk
2008-04-11
21:20
Add the speedtest8inst1.c program for running speed tests with an instrumented VFS. (CVS 4993) check-in: baa8056c user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/test_osinst.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28


29
30
31
32
33
34
35
36
..
87
88
89
90
91
92
93



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108


109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
...
134
135
136
137
138
139
140

141
142
143
144
145
146
147
...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
...
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
...
361
362
363
364
365
366
367

368
369
370
371
372
373
374
...
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
...
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
...
578
579
580
581
582
583
584
585




































































































586
587
588
589

590
591
592
593
594
595
596
...
597
598
599
600
601
602
603

604
605
606
607
608
609
610
...
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
...
659
660
661
662
663
664
665

























666
667
668
669
670
671
672
**
******************************************************************************
**
** This file contains the implementation of an SQLite vfs wrapper that
** adds instrumentation to all vfs and file methods. C and Tcl interfaces
** are provided to control the instrumentation.
*/
#if SQLITE_TEST          /* This file is used for testing only */

/*
** Public interface:
**
**   sqlite3_instvfs_create()
**   sqlite3_instvfs_destroy()
**   sqlite3_instvfs_configure()
**
**   sqlite3_instvfs_reset()
**   sqlite3_instvfs_get()
**


** Tcl interface:
** 
**   sqlite3_instvfs create NAME ?PARENT?
**
**       Create and register new vfs called $NAME, which is a wrapper around
**       the existing vfs $PARENT. If the PARENT argument is omitted, the
**       new vfs is a wrapper around the current default vfs.
**
................................................................................
/*
** Maximum pathname length supported by the inst backend.
*/
#define INST_MAX_PATHNAME 512


/* File methods */



#define OS_CLOSE              1
#define OS_READ               2
#define OS_WRITE              3
#define OS_TRUNCATE           4
#define OS_SYNC               5
#define OS_FILESIZE           6
#define OS_LOCK               7
#define OS_UNLOCK             8
#define OS_CHECKRESERVEDLOCK  9
#define OS_FILECONTROL       10
#define OS_SECTORSIZE        11
#define OS_DEVCHAR           12

/* Vfs methods */
#define OS_OPEN              13


#define OS_DELETE            14
#define OS_ACCESS            15
#define OS_GETTEMPNAME       16
#define OS_FULLPATHNAME      17
#define OS_RANDOMNESS        18
#define OS_SLEEP             19
#define OS_CURRENTTIME       20

#define OS_NUMEVENTS         21

struct InstVfs {
  sqlite3_vfs base;
  sqlite3_vfs *pVfs;
  
  void *pClient;
  void (*xDel)(void *);
  void (*xCall)(void *, int, sqlite3_int64, const char *, int, sqlite3_int64);

  /* Counters */
  i64 aTime[OS_NUMEVENTS];
  int aCount[OS_NUMEVENTS];
};
typedef struct InstVfs InstVfs;

................................................................................

typedef struct inst_file inst_file;
struct inst_file {
  sqlite3_file base;
  sqlite3_file *pReal;
  InstVfs *pInstVfs;
  const char *zName;

};

/*
** Method declarations for inst_file.
*/
static int instClose(sqlite3_file*);
static int instRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
................................................................................
** The following routine only works on pentium-class processors.
** It uses the RDTSC opcode to read the cycle count value out of the
** processor and returns that value.  This can be used for high-res
** profiling.
*/
#if defined(i386) || defined(__i386__) || defined(_M_IX86)
__inline__ unsigned long long int hwtime(void){
  unsigned long long int x;
  __asm__("rdtsc\n\t"
          "mov %%edx, %%ecx\n\t"
          :"=A" (x));
  return x;
}
#else
  static unsigned long long int hwtime(void){ return 0; }
#endif

#define OS_TIME_IO(eEvent, A, B, Call) {     \
  inst_file *p = (inst_file *)pFile;         \
................................................................................
  int rc;                                    \
  i64 t = hwtime();                          \
  rc = Call;                                 \
  t = hwtime() - t;                          \
  pInstVfs->aTime[eEvent] += t;              \
  pInstVfs->aCount[eEvent] += 1;             \
  if( pInstVfs->xCall ){                     \
    pInstVfs->xCall(pInstVfs->pClient, eEvent, t, p->zName, A, B); \
  }                                          \
  return rc;                                 \
}

#define OS_TIME_VFS(eEvent, Z, A, B, Call) {      \
  InstVfs *pInstVfs = (InstVfs *)pVfs;   \
  int rc;                                \
  i64 t = hwtime();                      \
  rc = Call;                             \
  t = hwtime() - t;                      \
  pInstVfs->aTime[eEvent] += t;          \
  pInstVfs->aCount[eEvent] += 1;         \
  if( pInstVfs->xCall ){                 \
    pInstVfs->xCall(pInstVfs->pClient, eEvent, t, Z, A, B); \
  }                                      \
  return rc;                             \
}

/*
** Close an inst-file.
*/
................................................................................
  int *pOutFlags
){
  inst_file *p = (inst_file *)pFile;
  pFile->pMethods = &inst_io_methods;
  p->pReal = (sqlite3_file *)&p[1];
  p->pInstVfs = (InstVfs *)pVfs;
  p->zName = zName;


  OS_TIME_VFS(OS_OPEN, zName, flags, 0,
    sqlite3OsOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags)
  );
}

/*
................................................................................
*/
static int instCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
  OS_TIME_VFS( OS_CURRENTTIME, 0, 0, 0,
    sqlite3OsCurrentTime(REALVFS(pVfs), pTimeOut) 
  );
}

sqlite3_vfs *sqlite3_instvfs_create(char *zName, char *zParent){
  int nByte;
  InstVfs *p;
  sqlite3_vfs *pParent;

  pParent = sqlite3_vfs_find(zParent);
  if( !pParent ){
    return 0;
................................................................................
  }

  return (sqlite3_vfs *)p;
}

void sqlite3_instvfs_configure(
  sqlite3_vfs *pVfs,
  void (*xCall)(void *, int, sqlite3_int64, const char *, int, sqlite3_int64),
  void *pClient,
  void (*xDel)(void *)
){
  InstVfs *p = (InstVfs *)pVfs;
  assert( pVfs->xOpen==instOpen );
  if( p->xDel ){
    p->xDel(p->pClient);
................................................................................
    return;
  }

  *pzEvent = sqlite3_instvfs_name(eEvent);
  *pnClick = p->aTime[eEvent];
  *pnCall = p->aCount[eEvent];
}





































































































/**************************************************************************
***************************************************************************
** Tcl interface starts here.
*/


#include <tcl.h>

struct InstVfsCall {
  Tcl_Interp *interp;
  Tcl_Obj *pScript;
};
................................................................................
typedef struct InstVfsCall InstVfsCall;

static void test_instvfs_xcall(
  void *p,
  int eEvent,
  sqlite3_int64 nClick,
  const char *zName,

  int nByte,
  sqlite3_int64 iOffset
){
  int rc;
  InstVfsCall *pCall = (InstVfsCall *)p;
  Tcl_Obj *pObj = Tcl_DuplicateObj( pCall->pScript);
  const char *zEvent = sqlite3_instvfs_name(eEvent);
................................................................................
static int test_sqlite3_instvfs(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  static const char *IV_strs[] = 
               { "create",  "destroy",  "reset",  "report", "configure", 0 };
  enum IV_enum { IV_CREATE, IV_DESTROY, IV_RESET, IV_REPORT, IV_CONFIGURE };
  int iSub;

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
  }
  if( Tcl_GetIndexFromObj(interp, objv[1], IV_strs, "sub-command", 0, &iSub) ){
    return TCL_ERROR;
................................................................................
        Tcl_WrongNumArgs(interp, 2, objv, "?-default? NAME ?PARENT-VFS?");
        return TCL_ERROR;
      }
      if( objc==(4+isDefault) ){
        zParent = Tcl_GetString(objv[3+isDefault]);
      }
      p = sqlite3_instvfs_create(Tcl_GetString(objv[2+isDefault]), zParent);

























      if( !p ){
        Tcl_AppendResult(interp, "error creating vfs ", 0);
        return TCL_ERROR;
      }
      if( isDefault ){
        sqlite3_vfs_register(p, 1);
      }







<


|








>
>
|







 







>
>
>
|
|
|
|
|
|
<
<
<
|
|
|
<
<
|
>
>
|
|
|
|
|
|
<









|







 







>







 







|
|
|
|
<







 







|













|







 







>







 







|







 







|







 








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




>







 







>







 







|
|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103



104
105
106


107
108
109
110
111
112
113
114
115

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
...
214
215
216
217
218
219
220
221
222
223
224

225
226
227
228
229
230
231
...
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
...
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
...
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
...
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
...
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
...
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
...
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
**
******************************************************************************
**
** This file contains the implementation of an SQLite vfs wrapper that
** adds instrumentation to all vfs and file methods. C and Tcl interfaces
** are provided to control the instrumentation.
*/


/*
** C interface:
**
**   sqlite3_instvfs_create()
**   sqlite3_instvfs_destroy()
**   sqlite3_instvfs_configure()
**
**   sqlite3_instvfs_reset()
**   sqlite3_instvfs_get()
**
**   sqlite3_instvfs_binarylog
**
** Tcl interface (omitted if SQLITE_TEST is not set):
** 
**   sqlite3_instvfs create NAME ?PARENT?
**
**       Create and register new vfs called $NAME, which is a wrapper around
**       the existing vfs $PARENT. If the PARENT argument is omitted, the
**       new vfs is a wrapper around the current default vfs.
**
................................................................................
/*
** Maximum pathname length supported by the inst backend.
*/
#define INST_MAX_PATHNAME 512


/* File methods */
/* Vfs methods */
#define OS_ACCESS            1
#define OS_CHECKRESERVEDLOCK 2
#define OS_CLOSE             3
#define OS_CURRENTTIME       4
#define OS_DELETE            5
#define OS_DEVCHAR           6
#define OS_FILECONTROL       7
#define OS_FILESIZE          8



#define OS_FULLPATHNAME      9
#define OS_GETTEMPNAME       10
#define OS_LOCK              11


#define OS_OPEN              12
#define OS_RANDOMNESS        13
#define OS_READ              14 
#define OS_SECTORSIZE        15
#define OS_SLEEP             16
#define OS_SYNC              17
#define OS_TRUNCATE          18
#define OS_UNLOCK            19
#define OS_WRITE             20


#define OS_NUMEVENTS         21

struct InstVfs {
  sqlite3_vfs base;
  sqlite3_vfs *pVfs;
  
  void *pClient;
  void (*xDel)(void *);
  void (*xCall)(void *, int, sqlite3_int64, const char *, int, int, sqlite3_int64);

  /* Counters */
  i64 aTime[OS_NUMEVENTS];
  int aCount[OS_NUMEVENTS];
};
typedef struct InstVfs InstVfs;

................................................................................

typedef struct inst_file inst_file;
struct inst_file {
  sqlite3_file base;
  sqlite3_file *pReal;
  InstVfs *pInstVfs;
  const char *zName;
  int flags;
};

/*
** Method declarations for inst_file.
*/
static int instClose(sqlite3_file*);
static int instRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
................................................................................
** The following routine only works on pentium-class processors.
** It uses the RDTSC opcode to read the cycle count value out of the
** processor and returns that value.  This can be used for high-res
** profiling.
*/
#if defined(i386) || defined(__i386__) || defined(_M_IX86)
__inline__ unsigned long long int hwtime(void){
   unsigned int lo, hi;
   /* We cannot use "=A", since this would use %rax on x86_64 */
   __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
   return (unsigned long long int)hi << 32 | lo;

}
#else
  static unsigned long long int hwtime(void){ return 0; }
#endif

#define OS_TIME_IO(eEvent, A, B, Call) {     \
  inst_file *p = (inst_file *)pFile;         \
................................................................................
  int rc;                                    \
  i64 t = hwtime();                          \
  rc = Call;                                 \
  t = hwtime() - t;                          \
  pInstVfs->aTime[eEvent] += t;              \
  pInstVfs->aCount[eEvent] += 1;             \
  if( pInstVfs->xCall ){                     \
    pInstVfs->xCall(pInstVfs->pClient, eEvent, t, p->zName, p->flags, A, B); \
  }                                          \
  return rc;                                 \
}

#define OS_TIME_VFS(eEvent, Z, A, B, Call) {      \
  InstVfs *pInstVfs = (InstVfs *)pVfs;   \
  int rc;                                \
  i64 t = hwtime();                      \
  rc = Call;                             \
  t = hwtime() - t;                      \
  pInstVfs->aTime[eEvent] += t;          \
  pInstVfs->aCount[eEvent] += 1;         \
  if( pInstVfs->xCall ){                 \
    pInstVfs->xCall(pInstVfs->pClient, eEvent, t, Z, 0, A, B); \
  }                                      \
  return rc;                             \
}

/*
** Close an inst-file.
*/
................................................................................
  int *pOutFlags
){
  inst_file *p = (inst_file *)pFile;
  pFile->pMethods = &inst_io_methods;
  p->pReal = (sqlite3_file *)&p[1];
  p->pInstVfs = (InstVfs *)pVfs;
  p->zName = zName;
  p->flags = flags;

  OS_TIME_VFS(OS_OPEN, zName, flags, 0,
    sqlite3OsOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags)
  );
}

/*
................................................................................
*/
static int instCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
  OS_TIME_VFS( OS_CURRENTTIME, 0, 0, 0,
    sqlite3OsCurrentTime(REALVFS(pVfs), pTimeOut) 
  );
}

sqlite3_vfs *sqlite3_instvfs_create(const char *zName, const char *zParent){
  int nByte;
  InstVfs *p;
  sqlite3_vfs *pParent;

  pParent = sqlite3_vfs_find(zParent);
  if( !pParent ){
    return 0;
................................................................................
  }

  return (sqlite3_vfs *)p;
}

void sqlite3_instvfs_configure(
  sqlite3_vfs *pVfs,
  void (*xCall)(void*, int, sqlite3_int64, const char*, int, int, i64),
  void *pClient,
  void (*xDel)(void *)
){
  InstVfs *p = (InstVfs *)pVfs;
  assert( pVfs->xOpen==instOpen );
  if( p->xDel ){
    p->xDel(p->pClient);
................................................................................
    return;
  }

  *pzEvent = sqlite3_instvfs_name(eEvent);
  *pnClick = p->aTime[eEvent];
  *pnCall = p->aCount[eEvent];
}

#define BINARYLOG_BUFFERSIZE 1024

struct InstVfsBinaryLog {
  int nBuf;
  char *zBuf;
  sqlite3_int64 iOffset;
  sqlite3_file *pOut;
};
typedef struct InstVfsBinaryLog InstVfsBinaryLog;

static void put32bits(unsigned char *p, u32 v){
  p[0] = v>>24;
  p[1] = v>>16;
  p[2] = v>>8;
  p[3] = v;
}

static void binarylog_xcall(
  void *p,
  int eEvent,
  sqlite3_int64 nClick,
  const char *zName,
  int flags,
  int nByte,
  sqlite3_int64 iOffset
){
  InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)p;
  unsigned char *zRec;
  if( (20+pLog->nBuf)>BINARYLOG_BUFFERSIZE ){
    sqlite3_file *pFile = pLog->pOut;
    pFile->pMethods->xWrite(pFile, pLog->zBuf, pLog->nBuf, pLog->iOffset);
    pLog->iOffset += pLog->nBuf;
    pLog->nBuf = 0;
  }
  zRec = (unsigned char *)&pLog->zBuf[pLog->nBuf];
  put32bits(&zRec[0], eEvent);
  put32bits(&zRec[4], (int)nClick);
  put32bits(&zRec[8], flags);
  put32bits(&zRec[12], nByte);
  put32bits(&zRec[16], (int)iOffset);
  pLog->nBuf += 20;
}

static void binarylog_xdel(void *p){
  /* Close the log file and free the memory allocated for the 
  ** InstVfsBinaryLog structure.
  */
  InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)p;
  sqlite3_file *pFile = pLog->pOut;
  if( pLog->nBuf ){
    pFile->pMethods->xWrite(pFile, pLog->zBuf, pLog->nBuf, pLog->iOffset);
  }
  pFile->pMethods->xClose(pFile);
  sqlite3_free(pLog->zBuf);
  sqlite3_free(pLog);
}

sqlite3_vfs *sqlite3_instvfs_binarylog(
  const char *zVfs,
  const char *zParentVfs, 
  const char *zLog
){
  InstVfsBinaryLog *p;
  sqlite3_vfs *pVfs;
  sqlite3_vfs *pParent;
  int nByte;
  int flags;
  int rc;

  pParent = sqlite3_vfs_find(zParentVfs);
  if( !pParent ){
    return 0;
  }

  nByte = sizeof(InstVfsBinaryLog) + pParent->szOsFile;

  p = (InstVfsBinaryLog *)sqlite3_malloc(nByte);
  memset(p, 0, nByte);
  p->zBuf = sqlite3_malloc(BINARYLOG_BUFFERSIZE);
  p->pOut = (sqlite3_file *)&p[1];

  flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MASTER_JOURNAL;
  rc = pParent->xOpen(pParent, zLog, p->pOut, flags, &flags);
  if( rc==SQLITE_OK ){
    rc = p->pOut->pMethods->xWrite(p->pOut, "sqlite_ostrace1.....", 20, 0);
    p->iOffset = 20;
  }
  if( rc ){
    binarylog_xdel(p);
    return 0;
  }

  pVfs = sqlite3_instvfs_create(zVfs, zParentVfs);
  if( pVfs ){
    sqlite3_instvfs_configure(pVfs, binarylog_xcall, p, binarylog_xdel);
  }

  return pVfs;
}

/**************************************************************************
***************************************************************************
** Tcl interface starts here.
*/
#if SQLITE_TEST

#include <tcl.h>

struct InstVfsCall {
  Tcl_Interp *interp;
  Tcl_Obj *pScript;
};
................................................................................
typedef struct InstVfsCall InstVfsCall;

static void test_instvfs_xcall(
  void *p,
  int eEvent,
  sqlite3_int64 nClick,
  const char *zName,
  int flags,
  int nByte,
  sqlite3_int64 iOffset
){
  int rc;
  InstVfsCall *pCall = (InstVfsCall *)p;
  Tcl_Obj *pObj = Tcl_DuplicateObj( pCall->pScript);
  const char *zEvent = sqlite3_instvfs_name(eEvent);
................................................................................
static int test_sqlite3_instvfs(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  static const char *IV_strs[] = 
               { "create",  "destroy",  "reset",  "report", "configure", "binarylog", 0 };
  enum IV_enum { IV_CREATE, IV_DESTROY, IV_RESET, IV_REPORT, IV_CONFIGURE, IV_BINARYLOG };
  int iSub;

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
  }
  if( Tcl_GetIndexFromObj(interp, objv[1], IV_strs, "sub-command", 0, &iSub) ){
    return TCL_ERROR;
................................................................................
        Tcl_WrongNumArgs(interp, 2, objv, "?-default? NAME ?PARENT-VFS?");
        return TCL_ERROR;
      }
      if( objc==(4+isDefault) ){
        zParent = Tcl_GetString(objv[3+isDefault]);
      }
      p = sqlite3_instvfs_create(Tcl_GetString(objv[2+isDefault]), zParent);
      if( !p ){
        Tcl_AppendResult(interp, "error creating vfs ", 0);
        return TCL_ERROR;
      }
      if( isDefault ){
        sqlite3_vfs_register(p, 1);
      }
      Tcl_SetObjResult(interp, objv[2]);
      break;
    }
    case IV_BINARYLOG: {
      char *zName = 0;
      char *zLog = 0;
      sqlite3_vfs *p;
      int isDefault = 0;
      if( objc>2 && 0==strcmp("-default", Tcl_GetString(objv[2])) ){
        isDefault = 1;
      }
      if( (objc-isDefault)!=4 ){
        Tcl_WrongNumArgs(interp, 2, objv, "?-default? NAME LOGFILE");
        return TCL_ERROR;
      }
      zName = Tcl_GetString(objv[2+isDefault]);
      zLog = Tcl_GetString(objv[3+isDefault]);
      p = sqlite3_instvfs_binarylog(zName, 0, zLog);
      if( !p ){
        Tcl_AppendResult(interp, "error creating vfs ", 0);
        return TCL_ERROR;
      }
      if( isDefault ){
        sqlite3_vfs_register(p, 1);
      }