000001  /*
000002  ** 2010 October 28
000003  **
000004  ** The author disclaims copyright to this source code.  In place of
000005  ** a legal notice, here is a blessing:
000006  **
000007  **    May you do good and not evil.
000008  **    May you find forgiveness for yourself and forgive others.
000009  **    May you share freely, never taking more than you give.
000010  **
000011  *************************************************************************
000012  **
000013  ** This file contains a VFS "shim" - a layer that sits in between the
000014  ** pager and the real VFS - that breaks up a very large database file
000015  ** into two or more smaller files on disk.  This is useful, for example,
000016  ** in order to support large, multi-gigabyte databases on older filesystems
000017  ** that limit the maximum file size to 2 GiB.
000018  **
000019  ** USAGE:
000020  **
000021  ** Compile this source file and link it with your application.  Then
000022  ** at start-time, invoke the following procedure:
000023  **
000024  **   int sqlite3_multiplex_initialize(
000025  **      const char *zOrigVfsName,    // The underlying real VFS
000026  **      int makeDefault              // True to make multiplex the default VFS
000027  **   );
000028  **
000029  ** The procedure call above will create and register a new VFS shim named
000030  ** "multiplex".  The multiplex VFS will use the VFS named by zOrigVfsName to
000031  ** do the actual disk I/O.  (The zOrigVfsName parameter may be NULL, in
000032  ** which case the default VFS at the moment sqlite3_multiplex_initialize()
000033  ** is called will be used as the underlying real VFS.)
000034  **
000035  ** If the makeDefault parameter is TRUE then multiplex becomes the new
000036  ** default VFS.  Otherwise, you can use the multiplex VFS by specifying
000037  ** "multiplex" as the 4th parameter to sqlite3_open_v2() or by employing
000038  ** URI filenames and adding "vfs=multiplex" as a parameter to the filename
000039  ** URI.
000040  **
000041  ** The multiplex VFS allows databases up to 32 GiB in size.  But it splits
000042  ** the files up into smaller pieces, so that they will work even on
000043  ** filesystems that do not support large files.  The default chunk size
000044  ** is 2147418112 bytes (which is 64KiB less than 2GiB) but this can be
000045  ** changed at compile-time by defining the SQLITE_MULTIPLEX_CHUNK_SIZE
000046  ** macro.  Use the "chunksize=NNNN" query parameter with a URI filename
000047  ** in order to select an alternative chunk size for individual connections
000048  ** at run-time.
000049  */
000050  #include "sqlite3.h"
000051  #include <string.h>
000052  #include <assert.h>
000053  #include <stdlib.h>
000054  #include "test_multiplex.h"
000055  
000056  #ifndef SQLITE_CORE
000057    #define SQLITE_CORE 1  /* Disable the API redefinition in sqlite3ext.h */
000058  #endif
000059  #include "sqlite3ext.h"
000060  
000061  /*
000062  ** These should be defined to be the same as the values in
000063  ** sqliteInt.h.  They are defined separately here so that
000064  ** the multiplex VFS shim can be built as a loadable
000065  ** module.
000066  */
000067  #define UNUSED_PARAMETER(x) (void)(x)
000068  #define MAX_PAGE_SIZE       0x10000
000069  #define DEFAULT_SECTOR_SIZE 0x1000
000070  
000071  /* Maximum chunk number */
000072  #define MX_CHUNK_NUMBER 299
000073  
000074  /* First chunk for rollback journal files */
000075  #define SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET 400
000076  #define SQLITE_MULTIPLEX_WAL_8_3_OFFSET 700
000077  
000078  
000079  /************************ Shim Definitions ******************************/
000080  
000081  #ifndef SQLITE_MULTIPLEX_VFS_NAME
000082  # define SQLITE_MULTIPLEX_VFS_NAME "multiplex"
000083  #endif
000084  
000085  /* This is the limit on the chunk size.  It may be changed by calling
000086  ** the xFileControl() interface.  It will be rounded up to a
000087  ** multiple of MAX_PAGE_SIZE.  We default it here to 2GiB less 64KiB.
000088  */
000089  #ifndef SQLITE_MULTIPLEX_CHUNK_SIZE
000090  # define SQLITE_MULTIPLEX_CHUNK_SIZE 2147418112
000091  #endif
000092  
000093  /* This used to be the default limit on number of chunks, but
000094  ** it is no longer enforced. There is currently no limit to the
000095  ** number of chunks.
000096  **
000097  ** May be changed by calling the xFileControl() interface.
000098  */
000099  #ifndef SQLITE_MULTIPLEX_MAX_CHUNKS
000100  # define SQLITE_MULTIPLEX_MAX_CHUNKS 12
000101  #endif
000102  
000103  /************************ Object Definitions ******************************/
000104  
000105  /* Forward declaration of all object types */
000106  typedef struct multiplexGroup multiplexGroup;
000107  typedef struct multiplexConn multiplexConn;
000108  
000109  /*
000110  ** A "multiplex group" is a collection of files that collectively
000111  ** makeup a single SQLite DB file.  This allows the size of the DB
000112  ** to exceed the limits imposed by the file system.
000113  **
000114  ** There is an instance of the following object for each defined multiplex
000115  ** group.
000116  */
000117  struct multiplexGroup {
000118    struct multiplexReal {           /* For each chunk */
000119      sqlite3_file *p;                  /* Handle for the chunk */
000120      char *z;                          /* Name of this chunk */
000121    } *aReal;                        /* list of all chunks */
000122    int nReal;                       /* Number of chunks */
000123    char *zName;                     /* Base filename of this group */
000124    int nName;                       /* Length of base filename */
000125    int flags;                       /* Flags used for original opening */
000126    unsigned int szChunk;            /* Chunk size used for this group */
000127    unsigned char bEnabled;          /* TRUE to use Multiplex VFS for this file */
000128    unsigned char bTruncate;         /* TRUE to enable truncation of databases */
000129  };
000130  
000131  /*
000132  ** An instance of the following object represents each open connection
000133  ** to a file that is multiplex'ed.  This object is a
000134  ** subclass of sqlite3_file.  The sqlite3_file object for the underlying
000135  ** VFS is appended to this structure.
000136  */
000137  struct multiplexConn {
000138    sqlite3_file base;              /* Base class - must be first */
000139    multiplexGroup *pGroup;         /* The underlying group of files */
000140  };
000141  
000142  /************************* Global Variables **********************************/
000143  /*
000144  ** All global variables used by this file are containing within the following
000145  ** gMultiplex structure.
000146  */
000147  static struct {
000148    /* The pOrigVfs is the real, original underlying VFS implementation.
000149    ** Most operations pass-through to the real VFS.  This value is read-only
000150    ** during operation.  It is only modified at start-time and thus does not
000151    ** require a mutex.
000152    */
000153    sqlite3_vfs *pOrigVfs;
000154  
000155    /* The sThisVfs is the VFS structure used by this shim.  It is initialized
000156    ** at start-time and thus does not require a mutex
000157    */
000158    sqlite3_vfs sThisVfs;
000159  
000160    /* The sIoMethods defines the methods used by sqlite3_file objects
000161    ** associated with this shim.  It is initialized at start-time and does
000162    ** not require a mutex.
000163    **
000164    ** When the underlying VFS is called to open a file, it might return
000165    ** either a version 1 or a version 2 sqlite3_file object.  This shim
000166    ** has to create a wrapper sqlite3_file of the same version.  Hence
000167    ** there are two I/O method structures, one for version 1 and the other
000168    ** for version 2.
000169    */
000170    sqlite3_io_methods sIoMethodsV1;
000171    sqlite3_io_methods sIoMethodsV2;
000172  
000173    /* True when this shim has been initialized.
000174    */
000175    int isInitialized;
000176  } gMultiplex;
000177  
000178  /************************* Utility Routines *********************************/
000179  /*
000180  ** Compute a string length that is limited to what can be stored in
000181  ** lower 30 bits of a 32-bit signed integer.
000182  **
000183  ** The value returned will never be negative.  Nor will it ever be greater
000184  ** than the actual length of the string.  For very long strings (greater
000185  ** than 1GiB) the value returned might be less than the true string length.
000186  */
000187  static int multiplexStrlen30(const char *z){
000188    const char *z2 = z;
000189    if( z==0 ) return 0;
000190    while( *z2 ){ z2++; }
000191    return 0x3fffffff & (int)(z2 - z);
000192  }
000193  
000194  /*
000195  ** Generate the file-name for chunk iChunk of the group with base name
000196  ** zBase. The file-name is written to buffer zOut before returning. Buffer
000197  ** zOut must be allocated by the caller so that it is at least (nBase+5)
000198  ** bytes in size, where nBase is the length of zBase, not including the
000199  ** nul-terminator.
000200  **
000201  ** If iChunk is 0 (or 400 - the number for the first journal file chunk),
000202  ** the output is a copy of the input string. Otherwise, if
000203  ** SQLITE_ENABLE_8_3_NAMES is not defined or the input buffer does not contain
000204  ** a "." character, then the output is a copy of the input string with the
000205  ** three-digit zero-padded decimal representation if iChunk appended to it.
000206  ** For example:
000207  **
000208  **   zBase="test.db", iChunk=4  ->  zOut="test.db004"
000209  **
000210  ** Or, if SQLITE_ENABLE_8_3_NAMES is defined and the input buffer contains
000211  ** a "." character, then everything after the "." is replaced by the
000212  ** three-digit representation of iChunk.
000213  **
000214  **   zBase="test.db", iChunk=4  ->  zOut="test.004"
000215  **
000216  ** The output buffer string is terminated by 2 0x00 bytes. This makes it safe
000217  ** to pass to sqlite3_uri_parameter() and similar.
000218  */
000219  static void multiplexFilename(
000220    const char *zBase,              /* Filename for chunk 0 */
000221    int nBase,                      /* Size of zBase in bytes (without \0) */
000222    int flags,                      /* Flags used to open file */
000223    int iChunk,                     /* Chunk to generate filename for */
000224    char *zOut                      /* Buffer to write generated name to */
000225  ){
000226    int n = nBase;
000227    memcpy(zOut, zBase, n+1);
000228    if( iChunk!=0 && iChunk<=MX_CHUNK_NUMBER ){
000229  #ifdef SQLITE_ENABLE_8_3_NAMES
000230      int i;
000231      for(i=n-1; i>0 && i>=n-4 && zOut[i]!='.'; i--){}
000232      if( i>=n-4 ) n = i+1;
000233      if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
000234        /* The extensions on overflow files for main databases are 001, 002,
000235        ** 003 and so forth.  To avoid name collisions, add 400 to the
000236        ** extensions of journal files so that they are 401, 402, 403, ....
000237        */
000238        iChunk += SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET;
000239      }else if( flags & SQLITE_OPEN_WAL ){
000240        /* To avoid name collisions, add 700 to the
000241        ** extensions of WAL files so that they are 701, 702, 703, ....
000242        */
000243        iChunk += SQLITE_MULTIPLEX_WAL_8_3_OFFSET;
000244      }
000245  #endif
000246      sqlite3_snprintf(4,&zOut[n],"%03d",iChunk);
000247      n += 3;
000248    }
000249  
000250    assert( zOut[n]=='\0' );
000251    zOut[n+1] = '\0';
000252  }
000253  
000254  /* Compute the filename for the iChunk-th chunk
000255  */
000256  static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){
000257    if( iChunk>=pGroup->nReal ){
000258      struct multiplexReal *p;
000259      p = sqlite3_realloc64(pGroup->aReal, (iChunk+1)*sizeof(*p));
000260      if( p==0 ){
000261        return SQLITE_NOMEM;
000262      }
000263      memset(&p[pGroup->nReal], 0, sizeof(p[0])*(iChunk+1-pGroup->nReal));
000264      pGroup->aReal = p;
000265      pGroup->nReal = iChunk+1;
000266    }
000267    if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){
000268      char *z;
000269      int n = pGroup->nName;
000270      z = sqlite3_malloc64( n+5 );
000271      if( z==0 ){
000272        return SQLITE_NOMEM;
000273      }
000274      multiplexFilename(pGroup->zName, pGroup->nName, pGroup->flags, iChunk, z);
000275      pGroup->aReal[iChunk].z = (char*)sqlite3_create_filename(z,"","",0,0);
000276      sqlite3_free(z);
000277      if( pGroup->aReal[iChunk].z==0 ) return SQLITE_NOMEM;
000278    }
000279    return SQLITE_OK;
000280  }
000281  
000282  /* Translate an sqlite3_file* that is really a multiplexGroup* into
000283  ** the sqlite3_file* for the underlying original VFS.
000284  **
000285  ** For chunk 0, the pGroup->flags determines whether or not a new file
000286  ** is created if it does not already exist.  For chunks 1 and higher, the
000287  ** file is created only if createFlag is 1.
000288  */
000289  static sqlite3_file *multiplexSubOpen(
000290    multiplexGroup *pGroup,    /* The multiplexor group */
000291    int iChunk,                /* Which chunk to open.  0==original file */
000292    int *rc,                   /* Result code in and out */
000293    int *pOutFlags,            /* Output flags */
000294    int createFlag             /* True to create if iChunk>0 */
000295  ){
000296    sqlite3_file *pSubOpen = 0;
000297    sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;        /* Real VFS */
000298  
000299  #ifdef SQLITE_ENABLE_8_3_NAMES
000300    /* If JOURNAL_8_3_OFFSET is set to (say) 400, then any overflow files are
000301    ** part of a database journal are named db.401, db.402, and so on. A
000302    ** database may therefore not grow to larger than 400 chunks. Attempting
000303    ** to open chunk 401 indicates the database is full. */
000304    if( iChunk>=SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET ){
000305      sqlite3_log(SQLITE_FULL, "multiplexed chunk overflow: %s", pGroup->zName);
000306      *rc = SQLITE_FULL;
000307      return 0;
000308    }
000309  #endif
000310  
000311    *rc = multiplexSubFilename(pGroup, iChunk);
000312    if( (*rc)==SQLITE_OK && (pSubOpen = pGroup->aReal[iChunk].p)==0 ){
000313      int flags, bExists;
000314      flags = pGroup->flags;
000315      if( createFlag ){
000316        flags |= SQLITE_OPEN_CREATE;
000317      }else if( iChunk==0 ){
000318        /* Fall through */
000319      }else if( pGroup->aReal[iChunk].z==0 ){
000320        return 0;
000321      }else{
000322        *rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[iChunk].z,
000323                                SQLITE_ACCESS_EXISTS, &bExists);
000324       if( *rc || !bExists ){
000325          if( *rc ){
000326            sqlite3_log(*rc, "multiplexor.xAccess failure on %s",
000327                        pGroup->aReal[iChunk].z);
000328          }
000329          return 0;
000330        }
000331        flags &= ~SQLITE_OPEN_CREATE;
000332      }
000333      pSubOpen = sqlite3_malloc64( pOrigVfs->szOsFile );
000334      if( pSubOpen==0 ){
000335        *rc = SQLITE_IOERR_NOMEM;
000336        return 0;
000337      }
000338      pGroup->aReal[iChunk].p = pSubOpen;
000339      *rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen,
000340                            flags, pOutFlags);
000341      if( (*rc)!=SQLITE_OK ){
000342        sqlite3_log(*rc, "multiplexor.xOpen failure on %s",
000343                    pGroup->aReal[iChunk].z);
000344        sqlite3_free(pSubOpen);
000345        pGroup->aReal[iChunk].p = 0;
000346        return 0;
000347      }
000348    }
000349    return pSubOpen;
000350  }
000351  
000352  /*
000353  ** Return the size, in bytes, of chunk number iChunk.  If that chunk
000354  ** does not exist, then return 0.  This function does not distinguish between
000355  ** non-existent files and zero-length files.
000356  */
000357  static sqlite3_int64 multiplexSubSize(
000358    multiplexGroup *pGroup,    /* The multiplexor group */
000359    int iChunk,                /* Which chunk to open.  0==original file */
000360    int *rc                    /* Result code in and out */
000361  ){
000362    sqlite3_file *pSub;
000363    sqlite3_int64 sz = 0;
000364  
000365    if( *rc ) return 0;
000366    pSub = multiplexSubOpen(pGroup, iChunk, rc, NULL, 0);
000367    if( pSub==0 ) return 0;
000368    *rc = pSub->pMethods->xFileSize(pSub, &sz);
000369    return sz;
000370  }  
000371  
000372  /*
000373  ** This is the implementation of the multiplex_control() SQL function.
000374  */
000375  static void multiplexControlFunc(
000376    sqlite3_context *context,
000377    int argc,
000378    sqlite3_value **argv
000379  ){
000380    int rc = SQLITE_OK;
000381    sqlite3 *db = sqlite3_context_db_handle(context);
000382    int op = 0;
000383    int iVal;
000384  
000385    if( !db || argc!=2 ){
000386      rc = SQLITE_ERROR;
000387    }else{
000388      /* extract params */
000389      op = sqlite3_value_int(argv[0]);
000390      iVal = sqlite3_value_int(argv[1]);
000391      /* map function op to file_control op */
000392      switch( op ){
000393        case 1:
000394          op = MULTIPLEX_CTRL_ENABLE;
000395          break;
000396        case 2:
000397          op = MULTIPLEX_CTRL_SET_CHUNK_SIZE;
000398          break;
000399        case 3:
000400          op = MULTIPLEX_CTRL_SET_MAX_CHUNKS;
000401          break;
000402        default:
000403          rc = SQLITE_NOTFOUND;
000404          break;
000405      }
000406    }
000407    if( rc==SQLITE_OK ){
000408      rc = sqlite3_file_control(db, 0, op, &iVal);
000409    }
000410    sqlite3_result_error_code(context, rc);
000411  }
000412  
000413  /*
000414  ** This is the entry point to register the auto-extension for the
000415  ** multiplex_control() function.
000416  */
000417  static int multiplexFuncInit(
000418    sqlite3 *db,
000419    char **pzErrMsg,
000420    const sqlite3_api_routines *pApi
000421  ){
000422    int rc;
000423    rc = sqlite3_create_function(db, "multiplex_control", 2, SQLITE_ANY,
000424        0, multiplexControlFunc, 0, 0);
000425    return rc;
000426  }
000427  
000428  /*
000429  ** Close a single sub-file in the connection group.
000430  */
000431  static void multiplexSubClose(
000432    multiplexGroup *pGroup,
000433    int iChunk,
000434    sqlite3_vfs *pOrigVfs
000435  ){
000436    sqlite3_file *pSubOpen = pGroup->aReal[iChunk].p;
000437    if( pSubOpen ){
000438      pSubOpen->pMethods->xClose(pSubOpen);
000439      if( pOrigVfs && pGroup->aReal[iChunk].z ){
000440        pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
000441      }
000442      sqlite3_free(pGroup->aReal[iChunk].p);
000443    }
000444    sqlite3_free_filename(pGroup->aReal[iChunk].z);
000445    memset(&pGroup->aReal[iChunk], 0, sizeof(pGroup->aReal[iChunk]));
000446  }
000447  
000448  /*
000449  ** Deallocate memory held by a multiplexGroup
000450  */
000451  static void multiplexFreeComponents(multiplexGroup *pGroup){
000452    int i;
000453    for(i=0; i<pGroup->nReal; i++){ multiplexSubClose(pGroup, i, 0); }
000454    sqlite3_free(pGroup->aReal);
000455    pGroup->aReal = 0;
000456    pGroup->nReal = 0;
000457  }
000458  
000459  
000460  /************************* VFS Method Wrappers *****************************/
000461  
000462  /*
000463  ** This is the xOpen method used for the "multiplex" VFS.
000464  **
000465  ** Most of the work is done by the underlying original VFS.  This method
000466  ** simply links the new file into the appropriate multiplex group if it is a
000467  ** file that needs to be tracked.
000468  */
000469  static int multiplexOpen(
000470    sqlite3_vfs *pVfs,         /* The multiplex VFS */
000471    const char *zName,         /* Name of file to be opened */
000472    sqlite3_file *pConn,       /* Fill in this file descriptor */
000473    int flags,                 /* Flags to control the opening */
000474    int *pOutFlags             /* Flags showing results of opening */
000475  ){
000476    int rc = SQLITE_OK;                  /* Result code */
000477    multiplexConn *pMultiplexOpen;       /* The new multiplex file descriptor */
000478    multiplexGroup *pGroup = 0;          /* Corresponding multiplexGroup object */
000479    sqlite3_file *pSubOpen = 0;                    /* Real file descriptor */
000480    sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
000481    int nName = 0;
000482    int sz = 0;
000483    char *zToFree = 0;
000484  
000485    UNUSED_PARAMETER(pVfs);
000486    memset(pConn, 0, pVfs->szOsFile);
000487    assert( zName || (flags & SQLITE_OPEN_DELETEONCLOSE) );
000488  
000489    /* We need to create a group structure and manage
000490    ** access to this group of files.
000491    */
000492    pMultiplexOpen = (multiplexConn*)pConn;
000493  
000494    if( rc==SQLITE_OK ){
000495      /* allocate space for group */
000496      nName = zName ? multiplexStrlen30(zName) : 0;
000497      sz = sizeof(multiplexGroup)                             /* multiplexGroup */
000498         + nName + 1;                                         /* zName */
000499      pGroup = sqlite3_malloc64( sz );
000500      if( pGroup==0 ){
000501        rc = SQLITE_NOMEM;
000502      }
000503    }
000504  
000505    if( rc==SQLITE_OK ){
000506      const char *zUri = (flags & SQLITE_OPEN_URI) ? zName : 0;
000507      /* assign pointers to extra space allocated */
000508      memset(pGroup, 0, sz);
000509      pMultiplexOpen->pGroup = pGroup;
000510      pGroup->bEnabled = (unsigned char)-1;
000511      pGroup->bTruncate = (unsigned char)sqlite3_uri_boolean(zUri, "truncate",
000512                                     (flags & SQLITE_OPEN_MAIN_DB)==0);
000513      pGroup->szChunk = (int)sqlite3_uri_int64(zUri, "chunksize",
000514                                          SQLITE_MULTIPLEX_CHUNK_SIZE);
000515      pGroup->szChunk = (pGroup->szChunk+0xffff)&~0xffff;
000516      if( zName ){
000517        char *p = (char *)&pGroup[1];
000518        pGroup->zName = p;
000519        memcpy(pGroup->zName, zName, nName+1);
000520        pGroup->nName = nName;
000521      }
000522      if( pGroup->bEnabled ){
000523        /* Make sure that the chunksize is such that the pending byte does not
000524        ** falls at the end of a chunk.  A region of up to 64K following
000525        ** the pending byte is never written, so if the pending byte occurs
000526        ** near the end of a chunk, that chunk will be too small. */
000527  #ifndef SQLITE_OMIT_WSD
000528        extern int sqlite3PendingByte;
000529  #else
000530        int sqlite3PendingByte = 0x40000000;
000531  #endif
000532        while( (sqlite3PendingByte % pGroup->szChunk)>=(pGroup->szChunk-65536) ){
000533          pGroup->szChunk += 65536;
000534        }
000535      }
000536      pGroup->flags = (flags & ~SQLITE_OPEN_URI);
000537      rc = multiplexSubFilename(pGroup, 1);
000538      if( rc==SQLITE_OK ){
000539        pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags, 0);
000540        if( pSubOpen==0 && rc==SQLITE_OK ) rc = SQLITE_CANTOPEN;
000541      }
000542      if( rc==SQLITE_OK ){
000543        sqlite3_int64 sz64;
000544  
000545        rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz64);
000546        if( rc==SQLITE_OK && zName ){
000547          int bExists;
000548          if( flags & SQLITE_OPEN_SUPER_JOURNAL ){
000549            pGroup->bEnabled = 0;
000550          }else
000551          if( sz64==0 ){
000552            if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
000553              /* If opening a main journal file and the first chunk is zero
000554              ** bytes in size, delete any subsequent chunks from the
000555              ** file-system. */
000556              int iChunk = 1;
000557              do {
000558                rc = pOrigVfs->xAccess(pOrigVfs,
000559                    pGroup->aReal[iChunk].z, SQLITE_ACCESS_EXISTS, &bExists
000560                );
000561                if( rc==SQLITE_OK && bExists ){
000562                  rc = pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
000563                  if( rc==SQLITE_OK ){
000564                    rc = multiplexSubFilename(pGroup, ++iChunk);
000565                  }
000566                }
000567              }while( rc==SQLITE_OK && bExists );
000568            }
000569          }else{
000570            /* If the first overflow file exists and if the size of the main file
000571            ** is different from the chunk size, that means the chunk size is set
000572            ** set incorrectly.  So fix it.
000573            **
000574            ** Or, if the first overflow file does not exist and the main file is
000575            ** larger than the chunk size, that means the chunk size is too small.
000576            ** But we have no way of determining the intended chunk size, so
000577            ** just disable the multiplexor all together.
000578            */
000579            rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z,
000580                SQLITE_ACCESS_EXISTS, &bExists);
000581            bExists = multiplexSubSize(pGroup, 1, &rc)>0;
000582            if( rc==SQLITE_OK && bExists && sz64==(sz64&0xffff0000) && sz64>0
000583                && sz64!=pGroup->szChunk ){
000584              pGroup->szChunk = (int)sz64;
000585            }else if( rc==SQLITE_OK && !bExists && sz64>pGroup->szChunk ){
000586              pGroup->bEnabled = 0;
000587            }
000588          }
000589        }
000590      }
000591  
000592      if( rc==SQLITE_OK ){
000593        if( pSubOpen->pMethods->iVersion==1 ){
000594          pConn->pMethods = &gMultiplex.sIoMethodsV1;
000595        }else{
000596          pConn->pMethods = &gMultiplex.sIoMethodsV2;
000597        }
000598      }else{
000599        multiplexFreeComponents(pGroup);
000600        sqlite3_free(pGroup);
000601      }
000602    }
000603    sqlite3_free(zToFree);
000604    return rc;
000605  }
000606  
000607  /*
000608  ** This is the xDelete method used for the "multiplex" VFS.
000609  ** It attempts to delete the filename specified.
000610  */
000611  static int multiplexDelete(
000612    sqlite3_vfs *pVfs,         /* The multiplex VFS */
000613    const char *zName,         /* Name of file to delete */
000614    int syncDir
000615  ){
000616    int rc;
000617    sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
000618    rc = pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
000619    if( rc==SQLITE_OK ){
000620      /* If the main chunk was deleted successfully, also delete any subsequent
000621      ** chunks - starting with the last (highest numbered).
000622      */
000623      int nName = (int)strlen(zName);
000624      char *z;
000625      z = sqlite3_malloc64(nName + 5);
000626      if( z==0 ){
000627        rc = SQLITE_IOERR_NOMEM;
000628      }else{
000629        int iChunk = 0;
000630        int bExists;
000631        do{
000632          multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, ++iChunk, z);
000633          rc = pOrigVfs->xAccess(pOrigVfs, z, SQLITE_ACCESS_EXISTS, &bExists);
000634        }while( rc==SQLITE_OK && bExists );
000635        while( rc==SQLITE_OK && iChunk>1 ){
000636          multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, --iChunk, z);
000637          rc = pOrigVfs->xDelete(pOrigVfs, z, syncDir);
000638        }
000639        if( rc==SQLITE_OK ){
000640          iChunk = 0;
000641          do{
000642            multiplexFilename(zName, nName, SQLITE_OPEN_WAL, ++iChunk, z);
000643            rc = pOrigVfs->xAccess(pOrigVfs, z, SQLITE_ACCESS_EXISTS, &bExists);
000644          }while( rc==SQLITE_OK && bExists );
000645          while( rc==SQLITE_OK && iChunk>1 ){
000646            multiplexFilename(zName, nName, SQLITE_OPEN_WAL, --iChunk, z);
000647            rc = pOrigVfs->xDelete(pOrigVfs, z, syncDir);
000648          }
000649        }
000650      }
000651      sqlite3_free(z);
000652    }
000653    return rc;
000654  }
000655  
000656  static int multiplexAccess(sqlite3_vfs *a, const char *b, int c, int *d){
000657    return gMultiplex.pOrigVfs->xAccess(gMultiplex.pOrigVfs, b, c, d);
000658  }
000659  static int multiplexFullPathname(sqlite3_vfs *a, const char *b, int c, char *d){
000660    return gMultiplex.pOrigVfs->xFullPathname(gMultiplex.pOrigVfs, b, c, d);
000661  }
000662  static void *multiplexDlOpen(sqlite3_vfs *a, const char *b){
000663    return gMultiplex.pOrigVfs->xDlOpen(gMultiplex.pOrigVfs, b);
000664  }
000665  static void multiplexDlError(sqlite3_vfs *a, int b, char *c){
000666    gMultiplex.pOrigVfs->xDlError(gMultiplex.pOrigVfs, b, c);
000667  }
000668  static void (*multiplexDlSym(sqlite3_vfs *a, void *b, const char *c))(void){
000669    return gMultiplex.pOrigVfs->xDlSym(gMultiplex.pOrigVfs, b, c);
000670  }
000671  static void multiplexDlClose(sqlite3_vfs *a, void *b){
000672    gMultiplex.pOrigVfs->xDlClose(gMultiplex.pOrigVfs, b);
000673  }
000674  static int multiplexRandomness(sqlite3_vfs *a, int b, char *c){
000675    return gMultiplex.pOrigVfs->xRandomness(gMultiplex.pOrigVfs, b, c);
000676  }
000677  static int multiplexSleep(sqlite3_vfs *a, int b){
000678    return gMultiplex.pOrigVfs->xSleep(gMultiplex.pOrigVfs, b);
000679  }
000680  static int multiplexCurrentTime(sqlite3_vfs *a, double *b){
000681    return gMultiplex.pOrigVfs->xCurrentTime(gMultiplex.pOrigVfs, b);
000682  }
000683  static int multiplexGetLastError(sqlite3_vfs *a, int b, char *c){
000684    if( gMultiplex.pOrigVfs->xGetLastError ){
000685      return gMultiplex.pOrigVfs->xGetLastError(gMultiplex.pOrigVfs, b, c);
000686    }else{
000687      return 0;
000688    }
000689  }
000690  static int multiplexCurrentTimeInt64(sqlite3_vfs *a, sqlite3_int64 *b){
000691    return gMultiplex.pOrigVfs->xCurrentTimeInt64(gMultiplex.pOrigVfs, b);
000692  }
000693  
000694  /************************ I/O Method Wrappers *******************************/
000695  
000696  /* xClose requests get passed through to the original VFS.
000697  ** We loop over all open chunk handles and close them.
000698  ** The group structure for this file is unlinked from
000699  ** our list of groups and freed.
000700  */
000701  static int multiplexClose(sqlite3_file *pConn){
000702    multiplexConn *p = (multiplexConn*)pConn;
000703    multiplexGroup *pGroup = p->pGroup;
000704    int rc = SQLITE_OK;
000705    multiplexFreeComponents(pGroup);
000706    sqlite3_free(pGroup);
000707    return rc;
000708  }
000709  
000710  /* Pass xRead requests thru to the original VFS after
000711  ** determining the correct chunk to operate on.
000712  ** Break up reads across chunk boundaries.
000713  */
000714  static int multiplexRead(
000715    sqlite3_file *pConn,
000716    void *pBuf,
000717    int iAmt,
000718    sqlite3_int64 iOfst
000719  ){
000720    multiplexConn *p = (multiplexConn*)pConn;
000721    multiplexGroup *pGroup = p->pGroup;
000722    int rc = SQLITE_OK;
000723    if( !pGroup->bEnabled ){
000724      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
000725      if( pSubOpen==0 ){
000726        rc = SQLITE_IOERR_READ;
000727      }else{
000728        rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst);
000729      }
000730    }else{
000731      while( iAmt > 0 ){
000732        int i = (int)(iOfst / pGroup->szChunk);
000733        sqlite3_file *pSubOpen;
000734        pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1);
000735        if( pSubOpen ){
000736          int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) - pGroup->szChunk;
000737          if( extra<0 ) extra = 0;
000738          iAmt -= extra;
000739          rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt,
000740                                         iOfst % pGroup->szChunk);
000741          if( rc!=SQLITE_OK ) break;
000742          pBuf = (char *)pBuf + iAmt;
000743          iOfst += iAmt;
000744          iAmt = extra;
000745        }else{
000746          rc = SQLITE_IOERR_READ;
000747          break;
000748        }
000749      }
000750    }
000751  
000752    return rc;
000753  }
000754  
000755  /* Pass xWrite requests thru to the original VFS after
000756  ** determining the correct chunk to operate on.
000757  ** Break up writes across chunk boundaries.
000758  */
000759  static int multiplexWrite(
000760    sqlite3_file *pConn,
000761    const void *pBuf,
000762    int iAmt,
000763    sqlite3_int64 iOfst
000764  ){
000765    multiplexConn *p = (multiplexConn*)pConn;
000766    multiplexGroup *pGroup = p->pGroup;
000767    int rc = SQLITE_OK;
000768    if( !pGroup->bEnabled ){
000769      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
000770      if( pSubOpen==0 ){
000771        rc = SQLITE_IOERR_WRITE;
000772      }else{
000773        rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst);
000774      }
000775    }else{
000776      while( rc==SQLITE_OK && iAmt>0 ){
000777        int i = (int)(iOfst / pGroup->szChunk);
000778        sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1);
000779        if( pSubOpen ){
000780          int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) -
000781                      pGroup->szChunk;
000782          if( extra<0 ) extra = 0;
000783          iAmt -= extra;
000784          rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt,
000785                                          iOfst % pGroup->szChunk);
000786          pBuf = (char *)pBuf + iAmt;
000787          iOfst += iAmt;
000788          iAmt = extra;
000789        }
000790      }
000791    }
000792    return rc;
000793  }
000794  
000795  /* Pass xTruncate requests thru to the original VFS after
000796  ** determining the correct chunk to operate on.  Delete any
000797  ** chunks above the truncate mark.
000798  */
000799  static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){
000800    multiplexConn *p = (multiplexConn*)pConn;
000801    multiplexGroup *pGroup = p->pGroup;
000802    int rc = SQLITE_OK;
000803    if( !pGroup->bEnabled ){
000804      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
000805      if( pSubOpen==0 ){
000806        rc = SQLITE_IOERR_TRUNCATE;
000807      }else{
000808        rc = pSubOpen->pMethods->xTruncate(pSubOpen, size);
000809      }
000810    }else{
000811      int i;
000812      int iBaseGroup = (int)(size / pGroup->szChunk);
000813      sqlite3_file *pSubOpen;
000814      sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
000815      /* delete the chunks above the truncate limit */
000816      for(i = pGroup->nReal-1; i>iBaseGroup && rc==SQLITE_OK; i--){
000817        if( pGroup->bTruncate ){
000818          multiplexSubClose(pGroup, i, pOrigVfs);
000819        }else{
000820          pSubOpen = multiplexSubOpen(pGroup, i, &rc, 0, 0);
000821          if( pSubOpen ){
000822            rc = pSubOpen->pMethods->xTruncate(pSubOpen, 0);
000823          }
000824        }
000825      }
000826      if( rc==SQLITE_OK ){
000827        pSubOpen = multiplexSubOpen(pGroup, iBaseGroup, &rc, 0, 0);
000828        if( pSubOpen ){
000829          rc = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->szChunk);
000830        }
000831      }
000832      if( rc ) rc = SQLITE_IOERR_TRUNCATE;
000833    }
000834    return rc;
000835  }
000836  
000837  /* Pass xSync requests through to the original VFS without change
000838  */
000839  static int multiplexSync(sqlite3_file *pConn, int flags){
000840    multiplexConn *p = (multiplexConn*)pConn;
000841    multiplexGroup *pGroup = p->pGroup;
000842    int rc = SQLITE_OK;
000843    int i;
000844    for(i=0; i<pGroup->nReal; i++){
000845      sqlite3_file *pSubOpen = pGroup->aReal[i].p;
000846      if( pSubOpen ){
000847        int rc2 = pSubOpen->pMethods->xSync(pSubOpen, flags);
000848        if( rc2!=SQLITE_OK ) rc = rc2;
000849      }
000850    }
000851    return rc;
000852  }
000853  
000854  /* Pass xFileSize requests through to the original VFS.
000855  ** Aggregate the size of all the chunks before returning.
000856  */
000857  static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
000858    multiplexConn *p = (multiplexConn*)pConn;
000859    multiplexGroup *pGroup = p->pGroup;
000860    int rc = SQLITE_OK;
000861    int i;
000862    if( !pGroup->bEnabled ){
000863      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
000864      if( pSubOpen==0 ){
000865        rc = SQLITE_IOERR_FSTAT;
000866      }else{
000867        rc = pSubOpen->pMethods->xFileSize(pSubOpen, pSize);
000868      }
000869    }else{
000870      *pSize = 0;
000871      for(i=0; rc==SQLITE_OK; i++){
000872        sqlite3_int64 sz = multiplexSubSize(pGroup, i, &rc);
000873        if( sz==0 ) break;
000874        *pSize = i*(sqlite3_int64)pGroup->szChunk + sz;
000875      }
000876    }
000877    return rc;
000878  }
000879  
000880  /* Pass xLock requests through to the original VFS unchanged.
000881  */
000882  static int multiplexLock(sqlite3_file *pConn, int lock){
000883    multiplexConn *p = (multiplexConn*)pConn;
000884    int rc;
000885    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
000886    if( pSubOpen ){
000887      return pSubOpen->pMethods->xLock(pSubOpen, lock);
000888    }
000889    return SQLITE_BUSY;
000890  }
000891  
000892  /* Pass xUnlock requests through to the original VFS unchanged.
000893  */
000894  static int multiplexUnlock(sqlite3_file *pConn, int lock){
000895    multiplexConn *p = (multiplexConn*)pConn;
000896    int rc;
000897    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
000898    if( pSubOpen ){
000899      return pSubOpen->pMethods->xUnlock(pSubOpen, lock);
000900    }
000901    return SQLITE_IOERR_UNLOCK;
000902  }
000903  
000904  /* Pass xCheckReservedLock requests through to the original VFS unchanged.
000905  */
000906  static int multiplexCheckReservedLock(sqlite3_file *pConn, int *pResOut){
000907    multiplexConn *p = (multiplexConn*)pConn;
000908    int rc;
000909    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
000910    if( pSubOpen ){
000911      return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut);
000912    }
000913    return SQLITE_IOERR_CHECKRESERVEDLOCK;
000914  }
000915  
000916  /* Pass xFileControl requests through to the original VFS unchanged,
000917  ** except for any MULTIPLEX_CTRL_* requests here.
000918  */
000919  static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
000920    multiplexConn *p = (multiplexConn*)pConn;
000921    multiplexGroup *pGroup = p->pGroup;
000922    int rc = SQLITE_ERROR;
000923    sqlite3_file *pSubOpen;
000924  
000925    if( !gMultiplex.isInitialized ) return SQLITE_MISUSE;
000926    switch( op ){
000927      case MULTIPLEX_CTRL_ENABLE:
000928        if( pArg ) {
000929          int bEnabled = *(int *)pArg;
000930          pGroup->bEnabled = (unsigned char)bEnabled;
000931          rc = SQLITE_OK;
000932        }
000933        break;
000934      case MULTIPLEX_CTRL_SET_CHUNK_SIZE:
000935        if( pArg ) {
000936          unsigned int szChunk = *(unsigned*)pArg;
000937          if( szChunk<1 ){
000938            rc = SQLITE_MISUSE;
000939          }else{
000940            /* Round up to nearest multiple of MAX_PAGE_SIZE. */
000941            szChunk = (szChunk + (MAX_PAGE_SIZE-1));
000942            szChunk &= ~(MAX_PAGE_SIZE-1);
000943            pGroup->szChunk = szChunk;
000944            rc = SQLITE_OK;
000945          }
000946        }
000947        break;
000948      case MULTIPLEX_CTRL_SET_MAX_CHUNKS:
000949        rc = SQLITE_OK;
000950        break;
000951      case SQLITE_FCNTL_SIZE_HINT:
000952      case SQLITE_FCNTL_CHUNK_SIZE:
000953        /* no-op these */
000954        rc = SQLITE_OK;
000955        break;
000956      case SQLITE_FCNTL_PRAGMA: {
000957        char **aFcntl = (char**)pArg;
000958        /*
000959        ** EVIDENCE-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA
000960        ** file control is an array of pointers to strings (char**) in which the
000961        ** second element of the array is the name of the pragma and the third
000962        ** element is the argument to the pragma or NULL if the pragma has no
000963        ** argument.
000964        */
000965        if( aFcntl[1] && sqlite3_strnicmp(aFcntl[1],"multiplex_",10)==0 ){
000966          sqlite3_int64 sz = 0;
000967          (void)multiplexFileSize(pConn, &sz);
000968          /*
000969          ** PRAGMA multiplex_truncate=BOOLEAN;
000970          ** PRAGMA multiplex_truncate;
000971          **
000972          ** Turn the multiplexor truncate feature on or off.  Return either
000973          ** "on" or "off" to indicate the new setting.  If the BOOLEAN argument
000974          ** is omitted, just return the current value for the truncate setting.
000975          */
000976          if( sqlite3_stricmp(aFcntl[1],"multiplex_truncate")==0 ){
000977            if( aFcntl[2] && aFcntl[2][0] ){
000978              if( sqlite3_stricmp(aFcntl[2], "on")==0
000979               || sqlite3_stricmp(aFcntl[2], "1")==0 ){
000980                pGroup->bTruncate = 1;
000981              }else
000982              if( sqlite3_stricmp(aFcntl[2], "off")==0
000983               || sqlite3_stricmp(aFcntl[2], "0")==0 ){
000984                pGroup->bTruncate = 0;
000985              }
000986            }
000987            /* EVIDENCE-OF: R-27806-26076 The handler for an SQLITE_FCNTL_PRAGMA
000988            ** file control can optionally make the first element of the char**
000989            ** argument point to a string obtained from sqlite3_mprintf() or the
000990            ** equivalent and that string will become the result of the pragma
000991            ** or the error message if the pragma fails.
000992            */
000993            aFcntl[0] = sqlite3_mprintf(pGroup->bTruncate ? "on" : "off");
000994            rc = SQLITE_OK;
000995            break;
000996          }
000997          /*
000998          ** PRAGMA multiplex_enabled;
000999          **
001000          ** Return 0 or 1 depending on whether the multiplexor is enabled or
001001          ** disabled, respectively.
001002          */
001003          if( sqlite3_stricmp(aFcntl[1],"multiplex_enabled")==0 ){
001004            aFcntl[0] = sqlite3_mprintf("%d", pGroup->bEnabled!=0);
001005            rc = SQLITE_OK;
001006            break;
001007          }
001008          /*
001009          ** PRAGMA multiplex_chunksize;
001010          **
001011          ** Return the chunksize for the multiplexor, or no-op if the
001012          ** multiplexor is not active.
001013          */
001014          if( sqlite3_stricmp(aFcntl[1],"multiplex_chunksize")==0
001015           && pGroup->bEnabled
001016          ){
001017            aFcntl[0] = sqlite3_mprintf("%u", pGroup->szChunk);
001018            rc = SQLITE_OK;
001019            break;
001020          }
001021          /*
001022          ** PRAGMA multiplex_filecount;
001023          **
001024          ** Return the number of disk files currently in use by the
001025          ** multiplexor.  This should be the total database size size
001026          ** divided by the chunksize and rounded up.
001027          */
001028          if( sqlite3_stricmp(aFcntl[1],"multiplex_filecount")==0 ){
001029            int n = 0;
001030            int ii;
001031            for(ii=0; ii<pGroup->nReal; ii++){
001032              if( pGroup->aReal[ii].p!=0 ) n++;
001033            }
001034            aFcntl[0] = sqlite3_mprintf("%d", n);
001035            rc = SQLITE_OK;
001036            break;
001037          }
001038        }
001039        /* If the multiplexor does not handle the pragma, pass it through
001040        ** into the default case. */
001041      }
001042      default:
001043        pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
001044        if( pSubOpen ){
001045          rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
001046          if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
001047           *(char**)pArg = sqlite3_mprintf("multiplex/%z", *(char**)pArg);
001048          }
001049        }
001050        break;
001051    }
001052    return rc;
001053  }
001054  
001055  /* Pass xSectorSize requests through to the original VFS unchanged.
001056  */
001057  static int multiplexSectorSize(sqlite3_file *pConn){
001058    multiplexConn *p = (multiplexConn*)pConn;
001059    int rc;
001060    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
001061    if( pSubOpen && pSubOpen->pMethods->xSectorSize ){
001062      return pSubOpen->pMethods->xSectorSize(pSubOpen);
001063    }
001064    return DEFAULT_SECTOR_SIZE;
001065  }
001066  
001067  /* Pass xDeviceCharacteristics requests through to the original VFS unchanged.
001068  */
001069  static int multiplexDeviceCharacteristics(sqlite3_file *pConn){
001070    multiplexConn *p = (multiplexConn*)pConn;
001071    int rc;
001072    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
001073    if( pSubOpen ){
001074      return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen);
001075    }
001076    return 0;
001077  }
001078  
001079  /* Pass xShmMap requests through to the original VFS unchanged.
001080  */
001081  static int multiplexShmMap(
001082    sqlite3_file *pConn,            /* Handle open on database file */
001083    int iRegion,                    /* Region to retrieve */
001084    int szRegion,                   /* Size of regions */
001085    int bExtend,                    /* True to extend file if necessary */
001086    void volatile **pp              /* OUT: Mapped memory */
001087  ){
001088    multiplexConn *p = (multiplexConn*)pConn;
001089    int rc;
001090    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
001091    if( pSubOpen ){
001092      return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend,pp);
001093    }
001094    return SQLITE_IOERR;
001095  }
001096  
001097  /* Pass xShmLock requests through to the original VFS unchanged.
001098  */
001099  static int multiplexShmLock(
001100    sqlite3_file *pConn,       /* Database file holding the shared memory */
001101    int ofst,                  /* First lock to acquire or release */
001102    int n,                     /* Number of locks to acquire or release */
001103    int flags                  /* What to do with the lock */
001104  ){
001105    multiplexConn *p = (multiplexConn*)pConn;
001106    int rc;
001107    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
001108    if( pSubOpen ){
001109      return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags);
001110    }
001111    return SQLITE_BUSY;
001112  }
001113  
001114  /* Pass xShmBarrier requests through to the original VFS unchanged.
001115  */
001116  static void multiplexShmBarrier(sqlite3_file *pConn){
001117    multiplexConn *p = (multiplexConn*)pConn;
001118    int rc;
001119    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
001120    if( pSubOpen ){
001121      pSubOpen->pMethods->xShmBarrier(pSubOpen);
001122    }
001123  }
001124  
001125  /* Pass xShmUnmap requests through to the original VFS unchanged.
001126  */
001127  static int multiplexShmUnmap(sqlite3_file *pConn, int deleteFlag){
001128    multiplexConn *p = (multiplexConn*)pConn;
001129    int rc;
001130    sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
001131    if( pSubOpen ){
001132      return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag);
001133    }
001134    return SQLITE_OK;
001135  }
001136  
001137  /************************** Public Interfaces *****************************/
001138  /*
001139  ** CAPI: Initialize the multiplex VFS shim - sqlite3_multiplex_initialize()
001140  **
001141  ** Use the VFS named zOrigVfsName as the VFS that does the actual work.
001142  ** Use the default if zOrigVfsName==NULL.
001143  **
001144  ** The multiplex VFS shim is named "multiplex".  It will become the default
001145  ** VFS if makeDefault is non-zero.
001146  **
001147  ** THIS ROUTINE IS NOT THREADSAFE.  Call this routine exactly once
001148  ** during start-up.
001149  */
001150  int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){
001151    sqlite3_vfs *pOrigVfs;
001152    if( gMultiplex.isInitialized ) return SQLITE_MISUSE;
001153    pOrigVfs = sqlite3_vfs_find(zOrigVfsName);
001154    if( pOrigVfs==0 ) return SQLITE_ERROR;
001155    assert( pOrigVfs!=&gMultiplex.sThisVfs );
001156    gMultiplex.isInitialized = 1;
001157    gMultiplex.pOrigVfs = pOrigVfs;
001158    gMultiplex.sThisVfs = *pOrigVfs;
001159    gMultiplex.sThisVfs.szOsFile += sizeof(multiplexConn);
001160    gMultiplex.sThisVfs.zName = SQLITE_MULTIPLEX_VFS_NAME;
001161    gMultiplex.sThisVfs.xOpen = multiplexOpen;
001162    gMultiplex.sThisVfs.xDelete = multiplexDelete;
001163    gMultiplex.sThisVfs.xAccess = multiplexAccess;
001164    gMultiplex.sThisVfs.xFullPathname = multiplexFullPathname;
001165    gMultiplex.sThisVfs.xDlOpen = multiplexDlOpen;
001166    gMultiplex.sThisVfs.xDlError = multiplexDlError;
001167    gMultiplex.sThisVfs.xDlSym = multiplexDlSym;
001168    gMultiplex.sThisVfs.xDlClose = multiplexDlClose;
001169    gMultiplex.sThisVfs.xRandomness = multiplexRandomness;
001170    gMultiplex.sThisVfs.xSleep = multiplexSleep;
001171    gMultiplex.sThisVfs.xCurrentTime = multiplexCurrentTime;
001172    gMultiplex.sThisVfs.xGetLastError = multiplexGetLastError;
001173    gMultiplex.sThisVfs.xCurrentTimeInt64 = multiplexCurrentTimeInt64;
001174  
001175    gMultiplex.sIoMethodsV1.iVersion = 1;
001176    gMultiplex.sIoMethodsV1.xClose = multiplexClose;
001177    gMultiplex.sIoMethodsV1.xRead = multiplexRead;
001178    gMultiplex.sIoMethodsV1.xWrite = multiplexWrite;
001179    gMultiplex.sIoMethodsV1.xTruncate = multiplexTruncate;
001180    gMultiplex.sIoMethodsV1.xSync = multiplexSync;
001181    gMultiplex.sIoMethodsV1.xFileSize = multiplexFileSize;
001182    gMultiplex.sIoMethodsV1.xLock = multiplexLock;
001183    gMultiplex.sIoMethodsV1.xUnlock = multiplexUnlock;
001184    gMultiplex.sIoMethodsV1.xCheckReservedLock = multiplexCheckReservedLock;
001185    gMultiplex.sIoMethodsV1.xFileControl = multiplexFileControl;
001186    gMultiplex.sIoMethodsV1.xSectorSize = multiplexSectorSize;
001187    gMultiplex.sIoMethodsV1.xDeviceCharacteristics =
001188                                              multiplexDeviceCharacteristics;
001189    gMultiplex.sIoMethodsV2 = gMultiplex.sIoMethodsV1;
001190    gMultiplex.sIoMethodsV2.iVersion = 2;
001191    gMultiplex.sIoMethodsV2.xShmMap = multiplexShmMap;
001192    gMultiplex.sIoMethodsV2.xShmLock = multiplexShmLock;
001193    gMultiplex.sIoMethodsV2.xShmBarrier = multiplexShmBarrier;
001194    gMultiplex.sIoMethodsV2.xShmUnmap = multiplexShmUnmap;
001195    sqlite3_vfs_register(&gMultiplex.sThisVfs, makeDefault);
001196  
001197    sqlite3_auto_extension((void(*)(void))multiplexFuncInit);
001198  
001199    return SQLITE_OK;
001200  }
001201  
001202  /*
001203  ** CAPI: Shutdown the multiplex system - sqlite3_multiplex_shutdown()
001204  **
001205  ** All SQLite database connections must be closed before calling this
001206  ** routine.
001207  **
001208  ** THIS ROUTINE IS NOT THREADSAFE.  Call this routine exactly once while
001209  ** shutting down in order to free all remaining multiplex groups.
001210  */
001211  int sqlite3_multiplex_shutdown(int eForce){
001212    int rc = SQLITE_OK;
001213    if( gMultiplex.isInitialized==0 ) return SQLITE_MISUSE;
001214    gMultiplex.isInitialized = 0;
001215    sqlite3_vfs_unregister(&gMultiplex.sThisVfs);
001216    memset(&gMultiplex, 0, sizeof(gMultiplex));
001217    return rc;
001218  }
001219  
001220  /***************************** Test Code ***********************************/
001221  #ifdef SQLITE_TEST
001222  #if defined(INCLUDE_SQLITE_TCL_H)
001223  #  include "sqlite_tcl.h"
001224  #else
001225  #  include "tcl.h"
001226  #  ifndef SQLITE_TCLAPI
001227  #    define SQLITE_TCLAPI
001228  #  endif
001229  #endif
001230  extern const char *sqlite3ErrName(int);
001231  
001232  
001233  /*
001234  ** tclcmd: sqlite3_multiplex_initialize NAME MAKEDEFAULT
001235  */
001236  static int SQLITE_TCLAPI test_multiplex_initialize(
001237    void * clientData,
001238    Tcl_Interp *interp,
001239    int objc,
001240    Tcl_Obj *CONST objv[]
001241  ){
001242    const char *zName;              /* Name of new multiplex VFS */
001243    int makeDefault;                /* True to make the new VFS the default */
001244    int rc;                         /* Value returned by multiplex_initialize() */
001245  
001246    UNUSED_PARAMETER(clientData);
001247  
001248    /* Process arguments */
001249    if( objc!=3 ){
001250      Tcl_WrongNumArgs(interp, 1, objv, "NAME MAKEDEFAULT");
001251      return TCL_ERROR;
001252    }
001253    zName = Tcl_GetString(objv[1]);
001254    if( Tcl_GetBooleanFromObj(interp, objv[2], &makeDefault) ) return TCL_ERROR;
001255    if( zName[0]=='\0' ) zName = 0;
001256  
001257    /* Call sqlite3_multiplex_initialize() */
001258    rc = sqlite3_multiplex_initialize(zName, makeDefault);
001259    Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
001260  
001261    return TCL_OK;
001262  }
001263  
001264  /*
001265  ** tclcmd: sqlite3_multiplex_shutdown
001266  */
001267  static int SQLITE_TCLAPI test_multiplex_shutdown(
001268    void * clientData,
001269    Tcl_Interp *interp,
001270    int objc,
001271    Tcl_Obj *CONST objv[]
001272  ){
001273    int rc;                         /* Value returned by multiplex_shutdown() */
001274  
001275    UNUSED_PARAMETER(clientData);
001276  
001277    if( objc==2 && strcmp(Tcl_GetString(objv[1]),"-force")!=0 ){
001278      objc = 3;
001279    }
001280    if( (objc!=1 && objc!=2) ){
001281      Tcl_WrongNumArgs(interp, 1, objv, "?-force?");
001282      return TCL_ERROR;
001283    }
001284  
001285    /* Call sqlite3_multiplex_shutdown() */
001286    rc = sqlite3_multiplex_shutdown(objc==2);
001287    Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
001288  
001289    return TCL_OK;
001290  }
001291  
001292  /*
001293  ** Tclcmd: test_multiplex_control HANDLE DBNAME SUB-COMMAND ?INT-VALUE?
001294  */
001295  static int SQLITE_TCLAPI test_multiplex_control(
001296    ClientData cd,
001297    Tcl_Interp *interp,
001298    int objc,
001299    Tcl_Obj *CONST objv[]
001300  ){
001301    int rc;                         /* Return code from file_control() */
001302    int idx;                        /* Index in aSub[] */
001303    Tcl_CmdInfo cmdInfo;            /* Command info structure for HANDLE */
001304    sqlite3 *db;                    /* Underlying db handle for HANDLE */
001305    int iValue = 0;
001306    void *pArg = 0;
001307  
001308    struct SubCommand {
001309      const char *zName;
001310      int op;
001311      int argtype;
001312    } aSub[] = {
001313      { "enable",       MULTIPLEX_CTRL_ENABLE,           1 },
001314      { "chunk_size",   MULTIPLEX_CTRL_SET_CHUNK_SIZE,   1 },
001315      { "max_chunks",   MULTIPLEX_CTRL_SET_MAX_CHUNKS,   1 },
001316      { 0, 0, 0 }
001317    };
001318  
001319    if( objc!=5 ){
001320      Tcl_WrongNumArgs(interp, 1, objv, "HANDLE DBNAME SUB-COMMAND INT-VALUE");
001321      return TCL_ERROR;
001322    }
001323  
001324    if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
001325      Tcl_AppendResult(interp, "expected database handle, got \"", 0);
001326      Tcl_AppendResult(interp, Tcl_GetString(objv[1]), "\"", 0);
001327      return TCL_ERROR;
001328    }else{
001329      db = *(sqlite3 **)cmdInfo.objClientData;
001330    }
001331  
001332    rc = Tcl_GetIndexFromObjStruct(
001333        interp, objv[3], aSub, sizeof(aSub[0]), "sub-command", 0, &idx
001334    );
001335    if( rc!=TCL_OK ) return rc;
001336  
001337    switch( aSub[idx].argtype ){
001338      case 1:
001339        if( Tcl_GetIntFromObj(interp, objv[4], &iValue) ){
001340          return TCL_ERROR;
001341        }
001342        pArg = (void *)&iValue;
001343        break;
001344      default:
001345        Tcl_WrongNumArgs(interp, 4, objv, "SUB-COMMAND");
001346        return TCL_ERROR;
001347    }
001348  
001349    rc = sqlite3_file_control(db, Tcl_GetString(objv[2]), aSub[idx].op, pArg);
001350    Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
001351    return (rc==SQLITE_OK) ? TCL_OK : TCL_ERROR;
001352  }
001353  
001354  /*
001355  ** This routine registers the custom TCL commands defined in this
001356  ** module.  This should be the only procedure visible from outside
001357  ** of this module.
001358  */
001359  int Sqlitemultiplex_Init(Tcl_Interp *interp){
001360    static struct {
001361       char *zName;
001362       Tcl_ObjCmdProc *xProc;
001363    } aCmd[] = {
001364      { "sqlite3_multiplex_initialize", test_multiplex_initialize },
001365      { "sqlite3_multiplex_shutdown", test_multiplex_shutdown },
001366      { "sqlite3_multiplex_control", test_multiplex_control },
001367    };
001368    int i;
001369  
001370    for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
001371      Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
001372    }
001373  
001374    return TCL_OK;
001375  }
001376  #endif