modernc.org/cc@v1.0.1/v2/testdata/_sqlite/src/test_multiplex.c (about)

     1  /*
     2  ** 2010 October 28
     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 a VFS "shim" - a layer that sits in between the
    14  ** pager and the real VFS - that breaks up a very large database file
    15  ** into two or more smaller files on disk.  This is useful, for example,
    16  ** in order to support large, multi-gigabyte databases on older filesystems
    17  ** that limit the maximum file size to 2 GiB.
    18  **
    19  ** USAGE:
    20  **
    21  ** Compile this source file and link it with your application.  Then
    22  ** at start-time, invoke the following procedure:
    23  **
    24  **   int sqlite3_multiplex_initialize(
    25  **      const char *zOrigVfsName,    // The underlying real VFS
    26  **      int makeDefault              // True to make multiplex the default VFS
    27  **   );
    28  **
    29  ** The procedure call above will create and register a new VFS shim named
    30  ** "multiplex".  The multiplex VFS will use the VFS named by zOrigVfsName to
    31  ** do the actual disk I/O.  (The zOrigVfsName parameter may be NULL, in 
    32  ** which case the default VFS at the moment sqlite3_multiplex_initialize()
    33  ** is called will be used as the underlying real VFS.)  
    34  **
    35  ** If the makeDefault parameter is TRUE then multiplex becomes the new
    36  ** default VFS.  Otherwise, you can use the multiplex VFS by specifying
    37  ** "multiplex" as the 4th parameter to sqlite3_open_v2() or by employing
    38  ** URI filenames and adding "vfs=multiplex" as a parameter to the filename
    39  ** URI.
    40  **
    41  ** The multiplex VFS allows databases up to 32 GiB in size.  But it splits
    42  ** the files up into smaller pieces, so that they will work even on 
    43  ** filesystems that do not support large files.  The default chunk size
    44  ** is 2147418112 bytes (which is 64KiB less than 2GiB) but this can be
    45  ** changed at compile-time by defining the SQLITE_MULTIPLEX_CHUNK_SIZE
    46  ** macro.  Use the "chunksize=NNNN" query parameter with a URI filename
    47  ** in order to select an alternative chunk size for individual connections
    48  ** at run-time.
    49  */
    50  #include "sqlite3.h"
    51  #include <string.h>
    52  #include <assert.h>
    53  #include <stdlib.h>
    54  #include "test_multiplex.h"
    55  
    56  #ifndef SQLITE_CORE
    57    #define SQLITE_CORE 1  /* Disable the API redefinition in sqlite3ext.h */
    58  #endif
    59  #include "sqlite3ext.h"
    60  
    61  /* 
    62  ** These should be defined to be the same as the values in 
    63  ** sqliteInt.h.  They are defined separately here so that
    64  ** the multiplex VFS shim can be built as a loadable 
    65  ** module.
    66  */
    67  #define UNUSED_PARAMETER(x) (void)(x)
    68  #define MAX_PAGE_SIZE       0x10000
    69  #define DEFAULT_SECTOR_SIZE 0x1000
    70  
    71  /* Maximum chunk number */
    72  #define MX_CHUNK_NUMBER 299
    73  
    74  /* First chunk for rollback journal files */
    75  #define SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET 400
    76  #define SQLITE_MULTIPLEX_WAL_8_3_OFFSET 700
    77  
    78  
    79  /************************ Shim Definitions ******************************/
    80  
    81  #ifndef SQLITE_MULTIPLEX_VFS_NAME
    82  # define SQLITE_MULTIPLEX_VFS_NAME "multiplex"
    83  #endif
    84  
    85  /* This is the limit on the chunk size.  It may be changed by calling
    86  ** the xFileControl() interface.  It will be rounded up to a 
    87  ** multiple of MAX_PAGE_SIZE.  We default it here to 2GiB less 64KiB.
    88  */
    89  #ifndef SQLITE_MULTIPLEX_CHUNK_SIZE
    90  # define SQLITE_MULTIPLEX_CHUNK_SIZE 2147418112
    91  #endif
    92  
    93  /* This used to be the default limit on number of chunks, but
    94  ** it is no longer enforced. There is currently no limit to the
    95  ** number of chunks.
    96  **
    97  ** May be changed by calling the xFileControl() interface.
    98  */
    99  #ifndef SQLITE_MULTIPLEX_MAX_CHUNKS
   100  # define SQLITE_MULTIPLEX_MAX_CHUNKS 12
   101  #endif
   102  
   103  /************************ Object Definitions ******************************/
   104  
   105  /* Forward declaration of all object types */
   106  typedef struct multiplexGroup multiplexGroup;
   107  typedef struct multiplexConn multiplexConn;
   108  
   109  /*
   110  ** A "multiplex group" is a collection of files that collectively
   111  ** makeup a single SQLite DB file.  This allows the size of the DB
   112  ** to exceed the limits imposed by the file system.
   113  **
   114  ** There is an instance of the following object for each defined multiplex
   115  ** group.
   116  */
   117  struct multiplexGroup {
   118    struct multiplexReal {           /* For each chunk */
   119      sqlite3_file *p;                  /* Handle for the chunk */
   120      char *z;                          /* Name of this chunk */
   121    } *aReal;                        /* list of all chunks */
   122    int nReal;                       /* Number of chunks */
   123    char *zName;                     /* Base filename of this group */
   124    int nName;                       /* Length of base filename */
   125    int flags;                       /* Flags used for original opening */
   126    unsigned int szChunk;            /* Chunk size used for this group */
   127    unsigned char bEnabled;          /* TRUE to use Multiplex VFS for this file */
   128    unsigned char bTruncate;         /* TRUE to enable truncation of databases */
   129  };
   130  
   131  /*
   132  ** An instance of the following object represents each open connection
   133  ** to a file that is multiplex'ed.  This object is a 
   134  ** subclass of sqlite3_file.  The sqlite3_file object for the underlying
   135  ** VFS is appended to this structure.
   136  */
   137  struct multiplexConn {
   138    sqlite3_file base;              /* Base class - must be first */
   139    multiplexGroup *pGroup;         /* The underlying group of files */
   140  };
   141  
   142  /************************* Global Variables **********************************/
   143  /*
   144  ** All global variables used by this file are containing within the following
   145  ** gMultiplex structure.
   146  */
   147  static struct {
   148    /* The pOrigVfs is the real, original underlying VFS implementation.
   149    ** Most operations pass-through to the real VFS.  This value is read-only
   150    ** during operation.  It is only modified at start-time and thus does not
   151    ** require a mutex.
   152    */
   153    sqlite3_vfs *pOrigVfs;
   154  
   155    /* The sThisVfs is the VFS structure used by this shim.  It is initialized
   156    ** at start-time and thus does not require a mutex
   157    */
   158    sqlite3_vfs sThisVfs;
   159  
   160    /* The sIoMethods defines the methods used by sqlite3_file objects 
   161    ** associated with this shim.  It is initialized at start-time and does
   162    ** not require a mutex.
   163    **
   164    ** When the underlying VFS is called to open a file, it might return 
   165    ** either a version 1 or a version 2 sqlite3_file object.  This shim
   166    ** has to create a wrapper sqlite3_file of the same version.  Hence
   167    ** there are two I/O method structures, one for version 1 and the other
   168    ** for version 2.
   169    */
   170    sqlite3_io_methods sIoMethodsV1;
   171    sqlite3_io_methods sIoMethodsV2;
   172  
   173    /* True when this shim has been initialized.
   174    */
   175    int isInitialized;
   176  } gMultiplex;
   177  
   178  /************************* Utility Routines *********************************/
   179  /*
   180  ** Compute a string length that is limited to what can be stored in
   181  ** lower 30 bits of a 32-bit signed integer.
   182  **
   183  ** The value returned will never be negative.  Nor will it ever be greater
   184  ** than the actual length of the string.  For very long strings (greater
   185  ** than 1GiB) the value returned might be less than the true string length.
   186  */
   187  static int multiplexStrlen30(const char *z){
   188    const char *z2 = z;
   189    if( z==0 ) return 0;
   190    while( *z2 ){ z2++; }
   191    return 0x3fffffff & (int)(z2 - z);
   192  }
   193  
   194  /*
   195  ** Generate the file-name for chunk iChunk of the group with base name
   196  ** zBase. The file-name is written to buffer zOut before returning. Buffer
   197  ** zOut must be allocated by the caller so that it is at least (nBase+5)
   198  ** bytes in size, where nBase is the length of zBase, not including the
   199  ** nul-terminator.
   200  **
   201  ** If iChunk is 0 (or 400 - the number for the first journal file chunk),
   202  ** the output is a copy of the input string. Otherwise, if 
   203  ** SQLITE_ENABLE_8_3_NAMES is not defined or the input buffer does not contain
   204  ** a "." character, then the output is a copy of the input string with the 
   205  ** three-digit zero-padded decimal representation if iChunk appended to it. 
   206  ** For example:
   207  **
   208  **   zBase="test.db", iChunk=4  ->  zOut="test.db004"
   209  **
   210  ** Or, if SQLITE_ENABLE_8_3_NAMES is defined and the input buffer contains
   211  ** a "." character, then everything after the "." is replaced by the 
   212  ** three-digit representation of iChunk.
   213  **
   214  **   zBase="test.db", iChunk=4  ->  zOut="test.004"
   215  **
   216  ** The output buffer string is terminated by 2 0x00 bytes. This makes it safe
   217  ** to pass to sqlite3_uri_parameter() and similar.
   218  */
   219  static void multiplexFilename(
   220    const char *zBase,              /* Filename for chunk 0 */
   221    int nBase,                      /* Size of zBase in bytes (without \0) */
   222    int flags,                      /* Flags used to open file */
   223    int iChunk,                     /* Chunk to generate filename for */
   224    char *zOut                      /* Buffer to write generated name to */
   225  ){
   226    int n = nBase;
   227    memcpy(zOut, zBase, n+1);
   228    if( iChunk!=0 && iChunk<=MX_CHUNK_NUMBER ){
   229  #ifdef SQLITE_ENABLE_8_3_NAMES
   230      int i;
   231      for(i=n-1; i>0 && i>=n-4 && zOut[i]!='.'; i--){}
   232      if( i>=n-4 ) n = i+1;
   233      if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
   234        /* The extensions on overflow files for main databases are 001, 002,
   235        ** 003 and so forth.  To avoid name collisions, add 400 to the 
   236        ** extensions of journal files so that they are 401, 402, 403, ....
   237        */
   238        iChunk += SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET;
   239      }else if( flags & SQLITE_OPEN_WAL ){
   240        /* To avoid name collisions, add 700 to the 
   241        ** extensions of WAL files so that they are 701, 702, 703, ....
   242        */
   243        iChunk += SQLITE_MULTIPLEX_WAL_8_3_OFFSET;
   244      }
   245  #endif
   246      sqlite3_snprintf(4,&zOut[n],"%03d",iChunk);
   247      n += 3;
   248    }
   249  
   250    assert( zOut[n]=='\0' );
   251    zOut[n+1] = '\0';
   252  }
   253  
   254  /* Compute the filename for the iChunk-th chunk
   255  */
   256  static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){
   257    if( iChunk>=pGroup->nReal ){
   258      struct multiplexReal *p;
   259      p = sqlite3_realloc64(pGroup->aReal, (iChunk+1)*sizeof(*p));
   260      if( p==0 ){
   261        return SQLITE_NOMEM;
   262      }
   263      memset(&p[pGroup->nReal], 0, sizeof(p[0])*(iChunk+1-pGroup->nReal));
   264      pGroup->aReal = p;
   265      pGroup->nReal = iChunk+1;
   266    }
   267    if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){
   268      char *z;
   269      int n = pGroup->nName;
   270      pGroup->aReal[iChunk].z = z = sqlite3_malloc64( n+5 );
   271      if( z==0 ){
   272        return SQLITE_NOMEM;
   273      }
   274      multiplexFilename(pGroup->zName, pGroup->nName, pGroup->flags, iChunk, z);
   275    }
   276    return SQLITE_OK;
   277  }
   278  
   279  /* Translate an sqlite3_file* that is really a multiplexGroup* into
   280  ** the sqlite3_file* for the underlying original VFS.
   281  **
   282  ** For chunk 0, the pGroup->flags determines whether or not a new file
   283  ** is created if it does not already exist.  For chunks 1 and higher, the
   284  ** file is created only if createFlag is 1.
   285  */
   286  static sqlite3_file *multiplexSubOpen(
   287    multiplexGroup *pGroup,    /* The multiplexor group */
   288    int iChunk,                /* Which chunk to open.  0==original file */
   289    int *rc,                   /* Result code in and out */
   290    int *pOutFlags,            /* Output flags */
   291    int createFlag             /* True to create if iChunk>0 */
   292  ){
   293    sqlite3_file *pSubOpen = 0;
   294    sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;        /* Real VFS */
   295  
   296  #ifdef SQLITE_ENABLE_8_3_NAMES
   297    /* If JOURNAL_8_3_OFFSET is set to (say) 400, then any overflow files are 
   298    ** part of a database journal are named db.401, db.402, and so on. A 
   299    ** database may therefore not grow to larger than 400 chunks. Attempting
   300    ** to open chunk 401 indicates the database is full. */
   301    if( iChunk>=SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET ){
   302      sqlite3_log(SQLITE_FULL, "multiplexed chunk overflow: %s", pGroup->zName);
   303      *rc = SQLITE_FULL;
   304      return 0;
   305    }
   306  #endif
   307  
   308    *rc = multiplexSubFilename(pGroup, iChunk);
   309    if( (*rc)==SQLITE_OK && (pSubOpen = pGroup->aReal[iChunk].p)==0 ){
   310      int flags, bExists;
   311      flags = pGroup->flags;
   312      if( createFlag ){
   313        flags |= SQLITE_OPEN_CREATE;
   314      }else if( iChunk==0 ){
   315        /* Fall through */
   316      }else if( pGroup->aReal[iChunk].z==0 ){
   317        return 0;
   318      }else{
   319        *rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[iChunk].z,
   320                                SQLITE_ACCESS_EXISTS, &bExists);
   321       if( *rc || !bExists ){
   322          if( *rc ){
   323            sqlite3_log(*rc, "multiplexor.xAccess failure on %s",
   324                        pGroup->aReal[iChunk].z);
   325          }
   326          return 0;
   327        }
   328        flags &= ~SQLITE_OPEN_CREATE;
   329      }
   330      pSubOpen = sqlite3_malloc64( pOrigVfs->szOsFile );
   331      if( pSubOpen==0 ){
   332        *rc = SQLITE_IOERR_NOMEM;
   333        return 0;
   334      }
   335      pGroup->aReal[iChunk].p = pSubOpen;
   336      *rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen,
   337                            flags, pOutFlags);
   338      if( (*rc)!=SQLITE_OK ){
   339        sqlite3_log(*rc, "multiplexor.xOpen failure on %s",
   340                    pGroup->aReal[iChunk].z);
   341        sqlite3_free(pSubOpen);
   342        pGroup->aReal[iChunk].p = 0;
   343        return 0;
   344      }
   345    }
   346    return pSubOpen;
   347  }
   348  
   349  /*
   350  ** Return the size, in bytes, of chunk number iChunk.  If that chunk
   351  ** does not exist, then return 0.  This function does not distingish between
   352  ** non-existant files and zero-length files.
   353  */
   354  static sqlite3_int64 multiplexSubSize(
   355    multiplexGroup *pGroup,    /* The multiplexor group */
   356    int iChunk,                /* Which chunk to open.  0==original file */
   357    int *rc                    /* Result code in and out */
   358  ){
   359    sqlite3_file *pSub;
   360    sqlite3_int64 sz = 0;
   361  
   362    if( *rc ) return 0;
   363    pSub = multiplexSubOpen(pGroup, iChunk, rc, NULL, 0);
   364    if( pSub==0 ) return 0;
   365    *rc = pSub->pMethods->xFileSize(pSub, &sz);
   366    return sz;
   367  }    
   368  
   369  /*
   370  ** This is the implementation of the multiplex_control() SQL function.
   371  */
   372  static void multiplexControlFunc(
   373    sqlite3_context *context,
   374    int argc,
   375    sqlite3_value **argv
   376  ){
   377    int rc = SQLITE_OK;
   378    sqlite3 *db = sqlite3_context_db_handle(context);
   379    int op = 0;
   380    int iVal;
   381  
   382    if( !db || argc!=2 ){ 
   383      rc = SQLITE_ERROR; 
   384    }else{
   385      /* extract params */
   386      op = sqlite3_value_int(argv[0]);
   387      iVal = sqlite3_value_int(argv[1]);
   388      /* map function op to file_control op */
   389      switch( op ){
   390        case 1: 
   391          op = MULTIPLEX_CTRL_ENABLE; 
   392          break;
   393        case 2: 
   394          op = MULTIPLEX_CTRL_SET_CHUNK_SIZE; 
   395          break;
   396        case 3: 
   397          op = MULTIPLEX_CTRL_SET_MAX_CHUNKS; 
   398          break;
   399        default:
   400          rc = SQLITE_NOTFOUND;
   401          break;
   402      }
   403    }
   404    if( rc==SQLITE_OK ){
   405      rc = sqlite3_file_control(db, 0, op, &iVal);
   406    }
   407    sqlite3_result_error_code(context, rc);
   408  }
   409  
   410  /*
   411  ** This is the entry point to register the auto-extension for the 
   412  ** multiplex_control() function.
   413  */
   414  static int multiplexFuncInit(
   415    sqlite3 *db, 
   416    char **pzErrMsg, 
   417    const sqlite3_api_routines *pApi
   418  ){
   419    int rc;
   420    rc = sqlite3_create_function(db, "multiplex_control", 2, SQLITE_ANY, 
   421        0, multiplexControlFunc, 0, 0);
   422    return rc;
   423  }
   424  
   425  /*
   426  ** Close a single sub-file in the connection group.
   427  */
   428  static void multiplexSubClose(
   429    multiplexGroup *pGroup,
   430    int iChunk,
   431    sqlite3_vfs *pOrigVfs
   432  ){
   433    sqlite3_file *pSubOpen = pGroup->aReal[iChunk].p;
   434    if( pSubOpen ){
   435      pSubOpen->pMethods->xClose(pSubOpen);
   436      if( pOrigVfs && pGroup->aReal[iChunk].z ){
   437        pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
   438      }
   439      sqlite3_free(pGroup->aReal[iChunk].p);
   440    }
   441    sqlite3_free(pGroup->aReal[iChunk].z);
   442    memset(&pGroup->aReal[iChunk], 0, sizeof(pGroup->aReal[iChunk]));
   443  }
   444  
   445  /*
   446  ** Deallocate memory held by a multiplexGroup
   447  */
   448  static void multiplexFreeComponents(multiplexGroup *pGroup){
   449    int i;
   450    for(i=0; i<pGroup->nReal; i++){ multiplexSubClose(pGroup, i, 0); }
   451    sqlite3_free(pGroup->aReal);
   452    pGroup->aReal = 0;
   453    pGroup->nReal = 0;
   454  }
   455  
   456  
   457  /************************* VFS Method Wrappers *****************************/
   458  
   459  /*
   460  ** This is the xOpen method used for the "multiplex" VFS.
   461  **
   462  ** Most of the work is done by the underlying original VFS.  This method
   463  ** simply links the new file into the appropriate multiplex group if it is a
   464  ** file that needs to be tracked.
   465  */
   466  static int multiplexOpen(
   467    sqlite3_vfs *pVfs,         /* The multiplex VFS */
   468    const char *zName,         /* Name of file to be opened */
   469    sqlite3_file *pConn,       /* Fill in this file descriptor */
   470    int flags,                 /* Flags to control the opening */
   471    int *pOutFlags             /* Flags showing results of opening */
   472  ){
   473    int rc = SQLITE_OK;                  /* Result code */
   474    multiplexConn *pMultiplexOpen;       /* The new multiplex file descriptor */
   475    multiplexGroup *pGroup = 0;          /* Corresponding multiplexGroup object */
   476    sqlite3_file *pSubOpen = 0;                    /* Real file descriptor */
   477    sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
   478    int nName = 0;
   479    int sz = 0;
   480    char *zToFree = 0;
   481  
   482    UNUSED_PARAMETER(pVfs);
   483    memset(pConn, 0, pVfs->szOsFile);
   484    assert( zName || (flags & SQLITE_OPEN_DELETEONCLOSE) );
   485  
   486    /* We need to create a group structure and manage
   487    ** access to this group of files.
   488    */
   489    pMultiplexOpen = (multiplexConn*)pConn;
   490  
   491    if( rc==SQLITE_OK ){
   492      /* allocate space for group */
   493      nName = zName ? multiplexStrlen30(zName) : 0;
   494      sz = sizeof(multiplexGroup)                             /* multiplexGroup */
   495         + nName + 1;                                         /* zName */
   496      pGroup = sqlite3_malloc64( sz );
   497      if( pGroup==0 ){
   498        rc = SQLITE_NOMEM;
   499      }
   500    }
   501  
   502    if( rc==SQLITE_OK ){
   503      const char *zUri = (flags & SQLITE_OPEN_URI) ? zName : 0;
   504      /* assign pointers to extra space allocated */
   505      memset(pGroup, 0, sz);
   506      pMultiplexOpen->pGroup = pGroup;
   507      pGroup->bEnabled = (unsigned char)-1;
   508      pGroup->bTruncate = (unsigned char)sqlite3_uri_boolean(zUri, "truncate", 
   509                                     (flags & SQLITE_OPEN_MAIN_DB)==0);
   510      pGroup->szChunk = (int)sqlite3_uri_int64(zUri, "chunksize",
   511                                          SQLITE_MULTIPLEX_CHUNK_SIZE);
   512      pGroup->szChunk = (pGroup->szChunk+0xffff)&~0xffff;
   513      if( zName ){
   514        char *p = (char *)&pGroup[1];
   515        pGroup->zName = p;
   516        memcpy(pGroup->zName, zName, nName+1);
   517        pGroup->nName = nName;
   518      }
   519      if( pGroup->bEnabled ){
   520        /* Make sure that the chunksize is such that the pending byte does not
   521        ** falls at the end of a chunk.  A region of up to 64K following
   522        ** the pending byte is never written, so if the pending byte occurs
   523        ** near the end of a chunk, that chunk will be too small. */
   524  #ifndef SQLITE_OMIT_WSD
   525        extern int sqlite3PendingByte;
   526  #else
   527        int sqlite3PendingByte = 0x40000000;
   528  #endif
   529        while( (sqlite3PendingByte % pGroup->szChunk)>=(pGroup->szChunk-65536) ){
   530          pGroup->szChunk += 65536;
   531        }
   532      }
   533      pGroup->flags = flags;
   534      rc = multiplexSubFilename(pGroup, 1);
   535      if( rc==SQLITE_OK ){
   536        pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags, 0);
   537        if( pSubOpen==0 && rc==SQLITE_OK ) rc = SQLITE_CANTOPEN;
   538      }
   539      if( rc==SQLITE_OK ){
   540        sqlite3_int64 sz64;
   541  
   542        rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz64);
   543        if( rc==SQLITE_OK && zName ){
   544          int bExists;
   545          if( flags & SQLITE_OPEN_MASTER_JOURNAL ){
   546            pGroup->bEnabled = 0;
   547          }else
   548          if( sz64==0 ){
   549            if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
   550              /* If opening a main journal file and the first chunk is zero
   551              ** bytes in size, delete any subsequent chunks from the 
   552              ** file-system. */
   553              int iChunk = 1;
   554              do {
   555                rc = pOrigVfs->xAccess(pOrigVfs, 
   556                    pGroup->aReal[iChunk].z, SQLITE_ACCESS_EXISTS, &bExists
   557                );
   558                if( rc==SQLITE_OK && bExists ){
   559                  rc = pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
   560                  if( rc==SQLITE_OK ){
   561                    rc = multiplexSubFilename(pGroup, ++iChunk);
   562                  }
   563                }
   564              }while( rc==SQLITE_OK && bExists );
   565            }
   566          }else{
   567            /* If the first overflow file exists and if the size of the main file
   568            ** is different from the chunk size, that means the chunk size is set
   569            ** set incorrectly.  So fix it.
   570            **
   571            ** Or, if the first overflow file does not exist and the main file is
   572            ** larger than the chunk size, that means the chunk size is too small.
   573            ** But we have no way of determining the intended chunk size, so 
   574            ** just disable the multiplexor all togethre.
   575            */
   576            rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z,
   577                SQLITE_ACCESS_EXISTS, &bExists);
   578            bExists = multiplexSubSize(pGroup, 1, &rc)>0;
   579            if( rc==SQLITE_OK && bExists && sz64==(sz64&0xffff0000) && sz64>0
   580                && sz64!=pGroup->szChunk ){
   581              pGroup->szChunk = (int)sz64;
   582            }else if( rc==SQLITE_OK && !bExists && sz64>pGroup->szChunk ){
   583              pGroup->bEnabled = 0;
   584            }
   585          }
   586        }
   587      }
   588  
   589      if( rc==SQLITE_OK ){
   590        if( pSubOpen->pMethods->iVersion==1 ){
   591          pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1;
   592        }else{
   593          pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV2;
   594        }
   595      }else{
   596        multiplexFreeComponents(pGroup);
   597        sqlite3_free(pGroup);
   598      }
   599    }
   600    sqlite3_free(zToFree);
   601    return rc;
   602  }
   603  
   604  /*
   605  ** This is the xDelete method used for the "multiplex" VFS.
   606  ** It attempts to delete the filename specified.
   607  */
   608  static int multiplexDelete(
   609    sqlite3_vfs *pVfs,         /* The multiplex VFS */
   610    const char *zName,         /* Name of file to delete */
   611    int syncDir
   612  ){
   613    int rc;
   614    sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
   615    rc = pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
   616    if( rc==SQLITE_OK ){
   617      /* If the main chunk was deleted successfully, also delete any subsequent
   618      ** chunks - starting with the last (highest numbered). 
   619      */
   620      int nName = (int)strlen(zName);
   621      char *z;
   622      z = sqlite3_malloc64(nName + 5);
   623      if( z==0 ){
   624        rc = SQLITE_IOERR_NOMEM;
   625      }else{
   626        int iChunk = 0;
   627        int bExists;
   628        do{
   629          multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, ++iChunk, z);
   630          rc = pOrigVfs->xAccess(pOrigVfs, z, SQLITE_ACCESS_EXISTS, &bExists);
   631        }while( rc==SQLITE_OK && bExists );
   632        while( rc==SQLITE_OK && iChunk>1 ){
   633          multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, --iChunk, z);
   634          rc = pOrigVfs->xDelete(pOrigVfs, z, syncDir);
   635        }
   636        if( rc==SQLITE_OK ){
   637          iChunk = 0;
   638          do{
   639            multiplexFilename(zName, nName, SQLITE_OPEN_WAL, ++iChunk, z);
   640            rc = pOrigVfs->xAccess(pOrigVfs, z, SQLITE_ACCESS_EXISTS, &bExists);
   641          }while( rc==SQLITE_OK && bExists );
   642          while( rc==SQLITE_OK && iChunk>1 ){
   643            multiplexFilename(zName, nName, SQLITE_OPEN_WAL, --iChunk, z);
   644            rc = pOrigVfs->xDelete(pOrigVfs, z, syncDir);
   645          }
   646        }
   647      }
   648      sqlite3_free(z);
   649    }
   650    return rc;
   651  }
   652  
   653  static int multiplexAccess(sqlite3_vfs *a, const char *b, int c, int *d){
   654    return gMultiplex.pOrigVfs->xAccess(gMultiplex.pOrigVfs, b, c, d);
   655  }
   656  static int multiplexFullPathname(sqlite3_vfs *a, const char *b, int c, char *d){
   657    return gMultiplex.pOrigVfs->xFullPathname(gMultiplex.pOrigVfs, b, c, d);
   658  }
   659  static void *multiplexDlOpen(sqlite3_vfs *a, const char *b){
   660    return gMultiplex.pOrigVfs->xDlOpen(gMultiplex.pOrigVfs, b);
   661  }
   662  static void multiplexDlError(sqlite3_vfs *a, int b, char *c){
   663    gMultiplex.pOrigVfs->xDlError(gMultiplex.pOrigVfs, b, c);
   664  }
   665  static void (*multiplexDlSym(sqlite3_vfs *a, void *b, const char *c))(void){
   666    return gMultiplex.pOrigVfs->xDlSym(gMultiplex.pOrigVfs, b, c);
   667  }
   668  static void multiplexDlClose(sqlite3_vfs *a, void *b){
   669    gMultiplex.pOrigVfs->xDlClose(gMultiplex.pOrigVfs, b);
   670  }
   671  static int multiplexRandomness(sqlite3_vfs *a, int b, char *c){
   672    return gMultiplex.pOrigVfs->xRandomness(gMultiplex.pOrigVfs, b, c);
   673  }
   674  static int multiplexSleep(sqlite3_vfs *a, int b){
   675    return gMultiplex.pOrigVfs->xSleep(gMultiplex.pOrigVfs, b);
   676  }
   677  static int multiplexCurrentTime(sqlite3_vfs *a, double *b){
   678    return gMultiplex.pOrigVfs->xCurrentTime(gMultiplex.pOrigVfs, b);
   679  }
   680  static int multiplexGetLastError(sqlite3_vfs *a, int b, char *c){
   681    if( gMultiplex.pOrigVfs->xGetLastError ){
   682      return gMultiplex.pOrigVfs->xGetLastError(gMultiplex.pOrigVfs, b, c);
   683    }else{
   684      return 0;
   685    }
   686  }
   687  static int multiplexCurrentTimeInt64(sqlite3_vfs *a, sqlite3_int64 *b){
   688    return gMultiplex.pOrigVfs->xCurrentTimeInt64(gMultiplex.pOrigVfs, b);
   689  }
   690  
   691  /************************ I/O Method Wrappers *******************************/
   692  
   693  /* xClose requests get passed through to the original VFS.
   694  ** We loop over all open chunk handles and close them.
   695  ** The group structure for this file is unlinked from 
   696  ** our list of groups and freed.
   697  */
   698  static int multiplexClose(sqlite3_file *pConn){
   699    multiplexConn *p = (multiplexConn*)pConn;
   700    multiplexGroup *pGroup = p->pGroup;
   701    int rc = SQLITE_OK;
   702    multiplexFreeComponents(pGroup);
   703    sqlite3_free(pGroup);
   704    return rc;
   705  }
   706  
   707  /* Pass xRead requests thru to the original VFS after
   708  ** determining the correct chunk to operate on.
   709  ** Break up reads across chunk boundaries.
   710  */
   711  static int multiplexRead(
   712    sqlite3_file *pConn,
   713    void *pBuf,
   714    int iAmt,
   715    sqlite3_int64 iOfst
   716  ){
   717    multiplexConn *p = (multiplexConn*)pConn;
   718    multiplexGroup *pGroup = p->pGroup;
   719    int rc = SQLITE_OK;
   720    if( !pGroup->bEnabled ){
   721      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
   722      if( pSubOpen==0 ){
   723        rc = SQLITE_IOERR_READ;
   724      }else{
   725        rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst);
   726      }
   727    }else{
   728      while( iAmt > 0 ){
   729        int i = (int)(iOfst / pGroup->szChunk);
   730        sqlite3_file *pSubOpen;
   731        pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1);
   732        if( pSubOpen ){
   733          int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) - pGroup->szChunk;
   734          if( extra<0 ) extra = 0;
   735          iAmt -= extra;
   736          rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt,
   737                                         iOfst % pGroup->szChunk);
   738          if( rc!=SQLITE_OK ) break;
   739          pBuf = (char *)pBuf + iAmt;
   740          iOfst += iAmt;
   741          iAmt = extra;
   742        }else{
   743          rc = SQLITE_IOERR_READ;
   744          break;
   745        }
   746      }
   747    }
   748  
   749    return rc;
   750  }
   751  
   752  /* Pass xWrite requests thru to the original VFS after
   753  ** determining the correct chunk to operate on.
   754  ** Break up writes across chunk boundaries.
   755  */
   756  static int multiplexWrite(
   757    sqlite3_file *pConn,
   758    const void *pBuf,
   759    int iAmt,
   760    sqlite3_int64 iOfst
   761  ){
   762    multiplexConn *p = (multiplexConn*)pConn;
   763    multiplexGroup *pGroup = p->pGroup;
   764    int rc = SQLITE_OK;
   765    if( !pGroup->bEnabled ){
   766      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
   767      if( pSubOpen==0 ){
   768        rc = SQLITE_IOERR_WRITE;
   769      }else{
   770        rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst);
   771      }
   772    }else{
   773      while( rc==SQLITE_OK && iAmt>0 ){
   774        int i = (int)(iOfst / pGroup->szChunk);
   775        sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1);
   776        if( pSubOpen ){
   777          int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) -
   778                      pGroup->szChunk;
   779          if( extra<0 ) extra = 0;
   780          iAmt -= extra;
   781          rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt,
   782                                          iOfst % pGroup->szChunk);
   783          pBuf = (char *)pBuf + iAmt;
   784          iOfst += iAmt;
   785          iAmt = extra;
   786        }
   787      }
   788    }
   789    return rc;
   790  }
   791  
   792  /* Pass xTruncate requests thru to the original VFS after
   793  ** determining the correct chunk to operate on.  Delete any
   794  ** chunks above the truncate mark.
   795  */
   796  static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){
   797    multiplexConn *p = (multiplexConn*)pConn;
   798    multiplexGroup *pGroup = p->pGroup;
   799    int rc = SQLITE_OK;
   800    if( !pGroup->bEnabled ){
   801      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
   802      if( pSubOpen==0 ){
   803        rc = SQLITE_IOERR_TRUNCATE;
   804      }else{
   805        rc = pSubOpen->pMethods->xTruncate(pSubOpen, size);
   806      }
   807    }else{
   808      int i;
   809      int iBaseGroup = (int)(size / pGroup->szChunk);
   810      sqlite3_file *pSubOpen;
   811      sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
   812      /* delete the chunks above the truncate limit */
   813      for(i = pGroup->nReal-1; i>iBaseGroup && rc==SQLITE_OK; i--){
   814        if( pGroup->bTruncate ){
   815          multiplexSubClose(pGroup, i, pOrigVfs);
   816        }else{
   817          pSubOpen = multiplexSubOpen(pGroup, i, &rc, 0, 0);
   818          if( pSubOpen ){
   819            rc = pSubOpen->pMethods->xTruncate(pSubOpen, 0);
   820          }
   821        }
   822      }
   823      if( rc==SQLITE_OK ){
   824        pSubOpen = multiplexSubOpen(pGroup, iBaseGroup, &rc, 0, 0);
   825        if( pSubOpen ){
   826          rc = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->szChunk);
   827        }
   828      }
   829      if( rc ) rc = SQLITE_IOERR_TRUNCATE;
   830    }
   831    return rc;
   832  }
   833  
   834  /* Pass xSync requests through to the original VFS without change
   835  */
   836  static int multiplexSync(sqlite3_file *pConn, int flags){
   837    multiplexConn *p = (multiplexConn*)pConn;
   838    multiplexGroup *pGroup = p->pGroup;
   839    int rc = SQLITE_OK;
   840    int i;
   841    for(i=0; i<pGroup->nReal; i++){
   842      sqlite3_file *pSubOpen = pGroup->aReal[i].p;
   843      if( pSubOpen ){
   844        int rc2 = pSubOpen->pMethods->xSync(pSubOpen, flags);
   845        if( rc2!=SQLITE_OK ) rc = rc2;
   846      }
   847    }
   848    return rc;
   849  }
   850  
   851  /* Pass xFileSize requests through to the original VFS.
   852  ** Aggregate the size of all the chunks before returning.
   853  */
   854  static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
   855    multiplexConn *p = (multiplexConn*)pConn;
   856    multiplexGroup *pGroup = p->pGroup;
   857    int rc = SQLITE_OK;
   858    int i;
   859    if( !pGroup->bEnabled ){
   860      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
   861      if( pSubOpen==0 ){
   862        rc = SQLITE_IOERR_FSTAT;
   863      }else{
   864        rc = pSubOpen->pMethods->xFileSize(pSubOpen, pSize);
   865      }
   866    }else{
   867      *pSize = 0;
   868      for(i=0; rc==SQLITE_OK; i++){
   869        sqlite3_int64 sz = multiplexSubSize(pGroup, i, &rc);
   870        if( sz==0 ) break;
   871        *pSize = i*(sqlite3_int64)pGroup->szChunk + sz;
   872      }
   873    }
   874    return rc;
   875  }
   876  
   877  /* Pass xLock requests through to the original VFS unchanged.
   878  */
   879  static int multiplexLock(sqlite3_file *pConn, int lock){
   880    multiplexConn *p = (multiplexConn*)pConn;
   881    int rc;
   882    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
   883    if( pSubOpen ){
   884      return pSubOpen->pMethods->xLock(pSubOpen, lock);
   885    }
   886    return SQLITE_BUSY;
   887  }
   888  
   889  /* Pass xUnlock requests through to the original VFS unchanged.
   890  */
   891  static int multiplexUnlock(sqlite3_file *pConn, int lock){
   892    multiplexConn *p = (multiplexConn*)pConn;
   893    int rc;
   894    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
   895    if( pSubOpen ){
   896      return pSubOpen->pMethods->xUnlock(pSubOpen, lock);
   897    }
   898    return SQLITE_IOERR_UNLOCK;
   899  }
   900  
   901  /* Pass xCheckReservedLock requests through to the original VFS unchanged.
   902  */
   903  static int multiplexCheckReservedLock(sqlite3_file *pConn, int *pResOut){
   904    multiplexConn *p = (multiplexConn*)pConn;
   905    int rc;
   906    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
   907    if( pSubOpen ){
   908      return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut);
   909    }
   910    return SQLITE_IOERR_CHECKRESERVEDLOCK;
   911  }
   912  
   913  /* Pass xFileControl requests through to the original VFS unchanged,
   914  ** except for any MULTIPLEX_CTRL_* requests here.
   915  */
   916  static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
   917    multiplexConn *p = (multiplexConn*)pConn;
   918    multiplexGroup *pGroup = p->pGroup;
   919    int rc = SQLITE_ERROR;
   920    sqlite3_file *pSubOpen;
   921  
   922    if( !gMultiplex.isInitialized ) return SQLITE_MISUSE;
   923    switch( op ){
   924      case MULTIPLEX_CTRL_ENABLE:
   925        if( pArg ) {
   926          int bEnabled = *(int *)pArg;
   927          pGroup->bEnabled = (unsigned char)bEnabled;
   928          rc = SQLITE_OK;
   929        }
   930        break;
   931      case MULTIPLEX_CTRL_SET_CHUNK_SIZE:
   932        if( pArg ) {
   933          unsigned int szChunk = *(unsigned*)pArg;
   934          if( szChunk<1 ){
   935            rc = SQLITE_MISUSE;
   936          }else{
   937            /* Round up to nearest multiple of MAX_PAGE_SIZE. */
   938            szChunk = (szChunk + (MAX_PAGE_SIZE-1));
   939            szChunk &= ~(MAX_PAGE_SIZE-1);
   940            pGroup->szChunk = szChunk;
   941            rc = SQLITE_OK;
   942          }
   943        }
   944        break;
   945      case MULTIPLEX_CTRL_SET_MAX_CHUNKS:
   946        rc = SQLITE_OK;
   947        break;
   948      case SQLITE_FCNTL_SIZE_HINT:
   949      case SQLITE_FCNTL_CHUNK_SIZE:
   950        /* no-op these */
   951        rc = SQLITE_OK;
   952        break;
   953      case SQLITE_FCNTL_PRAGMA: {
   954        char **aFcntl = (char**)pArg;
   955        /*
   956        ** EVIDENCE-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA
   957        ** file control is an array of pointers to strings (char**) in which the
   958        ** second element of the array is the name of the pragma and the third
   959        ** element is the argument to the pragma or NULL if the pragma has no
   960        ** argument.
   961        */
   962        if( aFcntl[1] && sqlite3_stricmp(aFcntl[1],"multiplex_truncate")==0 ){
   963          if( aFcntl[2] && aFcntl[2][0] ){
   964            if( sqlite3_stricmp(aFcntl[2], "on")==0
   965             || sqlite3_stricmp(aFcntl[2], "1")==0 ){
   966              pGroup->bTruncate = 1;
   967            }else
   968            if( sqlite3_stricmp(aFcntl[2], "off")==0
   969             || sqlite3_stricmp(aFcntl[2], "0")==0 ){
   970              pGroup->bTruncate = 0;
   971            }
   972          }
   973          /* EVIDENCE-OF: R-27806-26076 The handler for an SQLITE_FCNTL_PRAGMA
   974          ** file control can optionally make the first element of the char**
   975          ** argument point to a string obtained from sqlite3_mprintf() or the
   976          ** equivalent and that string will become the result of the pragma
   977          ** or the error message if the pragma fails.
   978          */
   979          aFcntl[0] = sqlite3_mprintf(pGroup->bTruncate ? "on" : "off");
   980          rc = SQLITE_OK;
   981          break;
   982        }
   983        /* If the multiplexor does not handle the pragma, pass it through
   984        ** into the default case. */
   985      }
   986      default:
   987        pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
   988        if( pSubOpen ){
   989          rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
   990          if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
   991           *(char**)pArg = sqlite3_mprintf("multiplex/%z", *(char**)pArg);
   992          }
   993        }
   994        break;
   995    }
   996    return rc;
   997  }
   998  
   999  /* Pass xSectorSize requests through to the original VFS unchanged.
  1000  */
  1001  static int multiplexSectorSize(sqlite3_file *pConn){
  1002    multiplexConn *p = (multiplexConn*)pConn;
  1003    int rc;
  1004    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
  1005    if( pSubOpen && pSubOpen->pMethods->xSectorSize ){
  1006      return pSubOpen->pMethods->xSectorSize(pSubOpen);
  1007    }
  1008    return DEFAULT_SECTOR_SIZE;
  1009  }
  1010  
  1011  /* Pass xDeviceCharacteristics requests through to the original VFS unchanged.
  1012  */
  1013  static int multiplexDeviceCharacteristics(sqlite3_file *pConn){
  1014    multiplexConn *p = (multiplexConn*)pConn;
  1015    int rc;
  1016    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
  1017    if( pSubOpen ){
  1018      return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen);
  1019    }
  1020    return 0;
  1021  }
  1022  
  1023  /* Pass xShmMap requests through to the original VFS unchanged.
  1024  */
  1025  static int multiplexShmMap(
  1026    sqlite3_file *pConn,            /* Handle open on database file */
  1027    int iRegion,                    /* Region to retrieve */
  1028    int szRegion,                   /* Size of regions */
  1029    int bExtend,                    /* True to extend file if necessary */
  1030    void volatile **pp              /* OUT: Mapped memory */
  1031  ){
  1032    multiplexConn *p = (multiplexConn*)pConn;
  1033    int rc;
  1034    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
  1035    if( pSubOpen ){
  1036      return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend,pp);
  1037    }
  1038    return SQLITE_IOERR;
  1039  }
  1040  
  1041  /* Pass xShmLock requests through to the original VFS unchanged.
  1042  */
  1043  static int multiplexShmLock(
  1044    sqlite3_file *pConn,       /* Database file holding the shared memory */
  1045    int ofst,                  /* First lock to acquire or release */
  1046    int n,                     /* Number of locks to acquire or release */
  1047    int flags                  /* What to do with the lock */
  1048  ){
  1049    multiplexConn *p = (multiplexConn*)pConn;
  1050    int rc;
  1051    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
  1052    if( pSubOpen ){
  1053      return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags);
  1054    }
  1055    return SQLITE_BUSY;
  1056  }
  1057  
  1058  /* Pass xShmBarrier requests through to the original VFS unchanged.
  1059  */
  1060  static void multiplexShmBarrier(sqlite3_file *pConn){
  1061    multiplexConn *p = (multiplexConn*)pConn;
  1062    int rc;
  1063    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
  1064    if( pSubOpen ){
  1065      pSubOpen->pMethods->xShmBarrier(pSubOpen);
  1066    }
  1067  }
  1068  
  1069  /* Pass xShmUnmap requests through to the original VFS unchanged.
  1070  */
  1071  static int multiplexShmUnmap(sqlite3_file *pConn, int deleteFlag){
  1072    multiplexConn *p = (multiplexConn*)pConn;
  1073    int rc;
  1074    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
  1075    if( pSubOpen ){
  1076      return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag);
  1077    }
  1078    return SQLITE_OK;
  1079  }
  1080  
  1081  /************************** Public Interfaces *****************************/
  1082  /*
  1083  ** CAPI: Initialize the multiplex VFS shim - sqlite3_multiplex_initialize()
  1084  **
  1085  ** Use the VFS named zOrigVfsName as the VFS that does the actual work.  
  1086  ** Use the default if zOrigVfsName==NULL.  
  1087  **
  1088  ** The multiplex VFS shim is named "multiplex".  It will become the default
  1089  ** VFS if makeDefault is non-zero.
  1090  **
  1091  ** THIS ROUTINE IS NOT THREADSAFE.  Call this routine exactly once
  1092  ** during start-up.
  1093  */
  1094  int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){
  1095    sqlite3_vfs *pOrigVfs;
  1096    if( gMultiplex.isInitialized ) return SQLITE_MISUSE;
  1097    pOrigVfs = sqlite3_vfs_find(zOrigVfsName);
  1098    if( pOrigVfs==0 ) return SQLITE_ERROR;
  1099    assert( pOrigVfs!=&gMultiplex.sThisVfs );
  1100    gMultiplex.isInitialized = 1;
  1101    gMultiplex.pOrigVfs = pOrigVfs;
  1102    gMultiplex.sThisVfs = *pOrigVfs;
  1103    gMultiplex.sThisVfs.szOsFile += sizeof(multiplexConn);
  1104    gMultiplex.sThisVfs.zName = SQLITE_MULTIPLEX_VFS_NAME;
  1105    gMultiplex.sThisVfs.xOpen = multiplexOpen;
  1106    gMultiplex.sThisVfs.xDelete = multiplexDelete;
  1107    gMultiplex.sThisVfs.xAccess = multiplexAccess;
  1108    gMultiplex.sThisVfs.xFullPathname = multiplexFullPathname;
  1109    gMultiplex.sThisVfs.xDlOpen = multiplexDlOpen;
  1110    gMultiplex.sThisVfs.xDlError = multiplexDlError;
  1111    gMultiplex.sThisVfs.xDlSym = multiplexDlSym;
  1112    gMultiplex.sThisVfs.xDlClose = multiplexDlClose;
  1113    gMultiplex.sThisVfs.xRandomness = multiplexRandomness;
  1114    gMultiplex.sThisVfs.xSleep = multiplexSleep;
  1115    gMultiplex.sThisVfs.xCurrentTime = multiplexCurrentTime;
  1116    gMultiplex.sThisVfs.xGetLastError = multiplexGetLastError;
  1117    gMultiplex.sThisVfs.xCurrentTimeInt64 = multiplexCurrentTimeInt64;
  1118  
  1119    gMultiplex.sIoMethodsV1.iVersion = 1;
  1120    gMultiplex.sIoMethodsV1.xClose = multiplexClose;
  1121    gMultiplex.sIoMethodsV1.xRead = multiplexRead;
  1122    gMultiplex.sIoMethodsV1.xWrite = multiplexWrite;
  1123    gMultiplex.sIoMethodsV1.xTruncate = multiplexTruncate;
  1124    gMultiplex.sIoMethodsV1.xSync = multiplexSync;
  1125    gMultiplex.sIoMethodsV1.xFileSize = multiplexFileSize;
  1126    gMultiplex.sIoMethodsV1.xLock = multiplexLock;
  1127    gMultiplex.sIoMethodsV1.xUnlock = multiplexUnlock;
  1128    gMultiplex.sIoMethodsV1.xCheckReservedLock = multiplexCheckReservedLock;
  1129    gMultiplex.sIoMethodsV1.xFileControl = multiplexFileControl;
  1130    gMultiplex.sIoMethodsV1.xSectorSize = multiplexSectorSize;
  1131    gMultiplex.sIoMethodsV1.xDeviceCharacteristics =
  1132                                              multiplexDeviceCharacteristics;
  1133    gMultiplex.sIoMethodsV2 = gMultiplex.sIoMethodsV1;
  1134    gMultiplex.sIoMethodsV2.iVersion = 2;
  1135    gMultiplex.sIoMethodsV2.xShmMap = multiplexShmMap;
  1136    gMultiplex.sIoMethodsV2.xShmLock = multiplexShmLock;
  1137    gMultiplex.sIoMethodsV2.xShmBarrier = multiplexShmBarrier;
  1138    gMultiplex.sIoMethodsV2.xShmUnmap = multiplexShmUnmap;
  1139    sqlite3_vfs_register(&gMultiplex.sThisVfs, makeDefault);
  1140  
  1141    sqlite3_auto_extension((void(*)(void))multiplexFuncInit);
  1142  
  1143    return SQLITE_OK;
  1144  }
  1145  
  1146  /*
  1147  ** CAPI: Shutdown the multiplex system - sqlite3_multiplex_shutdown()
  1148  **
  1149  ** All SQLite database connections must be closed before calling this
  1150  ** routine.
  1151  **
  1152  ** THIS ROUTINE IS NOT THREADSAFE.  Call this routine exactly once while
  1153  ** shutting down in order to free all remaining multiplex groups.
  1154  */
  1155  int sqlite3_multiplex_shutdown(int eForce){
  1156    int rc = SQLITE_OK;
  1157    if( gMultiplex.isInitialized==0 ) return SQLITE_MISUSE;
  1158    gMultiplex.isInitialized = 0;
  1159    sqlite3_vfs_unregister(&gMultiplex.sThisVfs);
  1160    memset(&gMultiplex, 0, sizeof(gMultiplex));
  1161    return rc;
  1162  }
  1163  
  1164  /***************************** Test Code ***********************************/
  1165  #ifdef SQLITE_TEST
  1166  #if defined(INCLUDE_SQLITE_TCL_H)
  1167  #  include "sqlite_tcl.h"
  1168  #else
  1169  #  include "tcl.h"
  1170  #  ifndef SQLITE_TCLAPI
  1171  #    define SQLITE_TCLAPI
  1172  #  endif
  1173  #endif
  1174  extern const char *sqlite3ErrName(int);
  1175  
  1176  
  1177  /*
  1178  ** tclcmd: sqlite3_multiplex_initialize NAME MAKEDEFAULT
  1179  */
  1180  static int SQLITE_TCLAPI test_multiplex_initialize(
  1181    void * clientData,
  1182    Tcl_Interp *interp,
  1183    int objc,
  1184    Tcl_Obj *CONST objv[]
  1185  ){
  1186    const char *zName;              /* Name of new multiplex VFS */
  1187    int makeDefault;                /* True to make the new VFS the default */
  1188    int rc;                         /* Value returned by multiplex_initialize() */
  1189  
  1190    UNUSED_PARAMETER(clientData);
  1191  
  1192    /* Process arguments */
  1193    if( objc!=3 ){
  1194      Tcl_WrongNumArgs(interp, 1, objv, "NAME MAKEDEFAULT");
  1195      return TCL_ERROR;
  1196    }
  1197    zName = Tcl_GetString(objv[1]);
  1198    if( Tcl_GetBooleanFromObj(interp, objv[2], &makeDefault) ) return TCL_ERROR;
  1199    if( zName[0]=='\0' ) zName = 0;
  1200  
  1201    /* Call sqlite3_multiplex_initialize() */
  1202    rc = sqlite3_multiplex_initialize(zName, makeDefault);
  1203    Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
  1204  
  1205    return TCL_OK;
  1206  }
  1207  
  1208  /*
  1209  ** tclcmd: sqlite3_multiplex_shutdown
  1210  */
  1211  static int SQLITE_TCLAPI test_multiplex_shutdown(
  1212    void * clientData,
  1213    Tcl_Interp *interp,
  1214    int objc,
  1215    Tcl_Obj *CONST objv[]
  1216  ){
  1217    int rc;                         /* Value returned by multiplex_shutdown() */
  1218  
  1219    UNUSED_PARAMETER(clientData);
  1220  
  1221    if( objc==2 && strcmp(Tcl_GetString(objv[1]),"-force")!=0 ){
  1222      objc = 3;
  1223    }
  1224    if( (objc!=1 && objc!=2) ){
  1225      Tcl_WrongNumArgs(interp, 1, objv, "?-force?");
  1226      return TCL_ERROR;
  1227    }
  1228  
  1229    /* Call sqlite3_multiplex_shutdown() */
  1230    rc = sqlite3_multiplex_shutdown(objc==2);
  1231    Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
  1232  
  1233    return TCL_OK;
  1234  }
  1235  
  1236  /*
  1237  ** Tclcmd: test_multiplex_control HANDLE DBNAME SUB-COMMAND ?INT-VALUE?
  1238  */
  1239  static int SQLITE_TCLAPI test_multiplex_control(
  1240    ClientData cd,
  1241    Tcl_Interp *interp,
  1242    int objc,
  1243    Tcl_Obj *CONST objv[]
  1244  ){
  1245    int rc;                         /* Return code from file_control() */
  1246    int idx;                        /* Index in aSub[] */
  1247    Tcl_CmdInfo cmdInfo;            /* Command info structure for HANDLE */
  1248    sqlite3 *db;                    /* Underlying db handle for HANDLE */
  1249    int iValue = 0;
  1250    void *pArg = 0;
  1251  
  1252    struct SubCommand {
  1253      const char *zName;
  1254      int op;
  1255      int argtype;
  1256    } aSub[] = {
  1257      { "enable",       MULTIPLEX_CTRL_ENABLE,           1 },
  1258      { "chunk_size",   MULTIPLEX_CTRL_SET_CHUNK_SIZE,   1 },
  1259      { "max_chunks",   MULTIPLEX_CTRL_SET_MAX_CHUNKS,   1 },
  1260      { 0, 0, 0 }
  1261    };
  1262  
  1263    if( objc!=5 ){
  1264      Tcl_WrongNumArgs(interp, 1, objv, "HANDLE DBNAME SUB-COMMAND INT-VALUE");
  1265      return TCL_ERROR;
  1266    }
  1267  
  1268    if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
  1269      Tcl_AppendResult(interp, "expected database handle, got \"", 0);
  1270      Tcl_AppendResult(interp, Tcl_GetString(objv[1]), "\"", 0);
  1271      return TCL_ERROR;
  1272    }else{
  1273      db = *(sqlite3 **)cmdInfo.objClientData;
  1274    }
  1275  
  1276    rc = Tcl_GetIndexFromObjStruct(
  1277        interp, objv[3], aSub, sizeof(aSub[0]), "sub-command", 0, &idx
  1278    );
  1279    if( rc!=TCL_OK ) return rc;
  1280  
  1281    switch( aSub[idx].argtype ){
  1282      case 1:
  1283        if( Tcl_GetIntFromObj(interp, objv[4], &iValue) ){
  1284          return TCL_ERROR;
  1285        }
  1286        pArg = (void *)&iValue;
  1287        break;
  1288      default:
  1289        Tcl_WrongNumArgs(interp, 4, objv, "SUB-COMMAND");
  1290        return TCL_ERROR;
  1291    }
  1292  
  1293    rc = sqlite3_file_control(db, Tcl_GetString(objv[2]), aSub[idx].op, pArg);
  1294    Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
  1295    return (rc==SQLITE_OK) ? TCL_OK : TCL_ERROR;
  1296  }
  1297  
  1298  /*
  1299  ** This routine registers the custom TCL commands defined in this
  1300  ** module.  This should be the only procedure visible from outside
  1301  ** of this module.
  1302  */
  1303  int Sqlitemultiplex_Init(Tcl_Interp *interp){
  1304    static struct {
  1305       char *zName;
  1306       Tcl_ObjCmdProc *xProc;
  1307    } aCmd[] = {
  1308      { "sqlite3_multiplex_initialize", test_multiplex_initialize },
  1309      { "sqlite3_multiplex_shutdown", test_multiplex_shutdown },
  1310      { "sqlite3_multiplex_control", test_multiplex_control },
  1311    };
  1312    int i;
  1313  
  1314    for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
  1315      Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
  1316    }
  1317  
  1318    return TCL_OK;
  1319  }
  1320  #endif