/ Check-in [1ffa542b]
Login

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

Overview
Comment:When the multiplexor opens an auxiliary file, it now persists the name of that file until it is closed, as it should. Remove the limit on the number of auxiliary files used by the multiplexor.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1ffa542bf913200a18ef77447aec4fc3ca1ed618
User & Date: drh 2011-07-20 16:35:31
Context
2011-07-20
17:13
All the SQLITE_OPEN_URI flag to propagate down into the VFS. check-in: 29866f95 user: drh tags: trunk
16:35
When the multiplexor opens an auxiliary file, it now persists the name of that file until it is closed, as it should. Remove the limit on the number of auxiliary files used by the multiplexor. check-in: 1ffa542b user: drh tags: trunk
2011-07-19
18:29
Formatting changes on the multiplexor code - make sure no lines exceed 80 characters. No logical changes. check-in: ed5f0aad user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/test_multiplex.c.

   122    122   ** makeup a single SQLite DB file.  This allows the size of the DB
   123    123   ** to exceed the limits imposed by the file system.
   124    124   **
   125    125   ** There is an instance of the following object for each defined multiplex
   126    126   ** group.
   127    127   */
   128    128   struct multiplexGroup {
   129         -  sqlite3_file **pReal;            /* Handles to each chunk */
   130         -  char *bOpen;                     /* array of bools - 0 if chunk not opened */
          129  +  struct multiplexReal {           /* For each chunk */
          130  +    sqlite3_file *p;                  /* Handle for the chunk */
          131  +    char *z;                          /* Name of this chunk */
          132  +  } *aReal;                        /* list of all chunks */
          133  +  int nReal;                       /* Number of chunks */
   131    134     char *zName;                     /* Base filename of this group */
   132    135     int nName;                       /* Length of base filename */
   133    136     int flags;                       /* Flags used for original opening */
   134    137     int nChunkSize;                  /* Chunk size used for this group */
   135         -  int nMaxChunks;                  /* Max number of chunks for this group */
   136    138     int bEnabled;                    /* TRUE to use Multiplex VFS for this file */
   137    139     multiplexGroup *pNext, *pPrev;   /* Doubly linked list of all group objects */
   138    140   };
   139    141   
   140    142   /*
   141    143   ** An instance of the following object represents each open connection
   142    144   ** to a file that is multiplex'ed.  This object is a 
................................................................................
   187    189     ** shim, the following mutex must be held.
   188    190     */
   189    191     sqlite3_mutex *pMutex;
   190    192   
   191    193     /* List of multiplexGroup objects.
   192    194     */
   193    195     multiplexGroup *pGroups;
   194         -
   195         -  /* Storage for temp file names.  Allocated during 
   196         -  ** initialization to the max pathname of the underlying VFS.
   197         -  */
   198         -  char *zName;
   199         -
   200    196   } gMultiplex;
   201    197   
   202    198   /************************* Utility Routines *********************************/
   203    199   /*
   204    200   ** Acquire and release the mutex used to serialize access to the
   205    201   ** list of multiplexGroups.
   206    202   */
................................................................................
   282    278           rc = SQLITE_ERROR;
   283    279         }
   284    280       }
   285    281     }
   286    282   
   287    283     return rc;
   288    284   }
          285  +
          286  +/* Compute the filename for the iChunk-th chunk
          287  +*/
          288  +static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){
          289  +  if( iChunk>=pGroup->nReal ){
          290  +    struct multiplexReal *p;
          291  +    p = sqlite3_realloc(pGroup->aReal, (iChunk+1)*sizeof(*p));
          292  +    if( p==0 ){
          293  +      return SQLITE_NOMEM;
          294  +    }
          295  +    memset(&p[pGroup->nReal], 0, sizeof(p[0])*(iChunk+1-pGroup->nReal));
          296  +    pGroup->aReal = p;
          297  +    pGroup->nReal = iChunk+1;
          298  +  }
          299  +  if( pGroup->aReal[iChunk].z==0 ){
          300  +    char *z;
          301  +    int n = pGroup->nName;
          302  +    pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+3 );
          303  +    if( z==0 ){
          304  +      return SQLITE_NOMEM;
          305  +    }
          306  +    memcpy(z, pGroup->zName, n+1);
          307  +    if( iChunk>0 ){
          308  +#ifdef SQLITE_ENABLE_8_3_NAMES
          309  +      if( n>3 && z[n-3]=='.' ){
          310  +        n--;
          311  +      }else if( n>4 && z[n-4]=='.' ){
          312  +        n -= 2;
          313  +      }
          314  +#endif
          315  +      sqlite3_snprintf(3,&z[n],"%02d",iChunk);
          316  +    }
          317  +  }
          318  +  return SQLITE_OK;
          319  +}
   289    320   
   290    321   /* Translate an sqlite3_file* that is really a multiplexGroup* into
   291    322   ** the sqlite3_file* for the underlying original VFS.
   292    323   */
   293    324   static sqlite3_file *multiplexSubOpen(
   294         -  multiplexConn *pConn,
          325  +  multiplexGroup *pGroup,
   295    326     int iChunk,
   296    327     int *rc,
   297    328     int *pOutFlags
   298    329   ){
   299         -  multiplexGroup *pGroup = pConn->pGroup;
          330  +  sqlite3_file *pSubOpen = 0;
   300    331     sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;        /* Real VFS */
   301         -  if( iChunk<pGroup->nMaxChunks ){
   302         -    sqlite3_file *pSubOpen = pGroup->pReal[iChunk];   /* Real file descriptor */
   303         -    if( !pGroup->bOpen[iChunk] ){
   304         -      memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
   305         -      if( iChunk ){
   306         -#ifdef SQLITE_MULTIPLEX_EXT_OVWR
   307         -        sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
   308         -             gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ,
   309         -             SQLITE_MULTIPLEX_EXT_FMT, iChunk);
   310         -#else
   311         -        sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
   312         -             gMultiplex.zName+pGroup->nName,
   313         -             SQLITE_MULTIPLEX_EXT_FMT, iChunk);
   314         -#endif
   315         -      }
   316         -      *rc = pOrigVfs->xOpen(pOrigVfs, gMultiplex.zName, pSubOpen,
   317         -                            pGroup->flags, pOutFlags);
   318         -      if( *rc==SQLITE_OK ){
   319         -        pGroup->bOpen[iChunk] = -1;
   320         -        return pSubOpen;
   321         -      }
   322         -      return NULL;
   323         -    }
   324         -    *rc = SQLITE_OK;
   325         -    return pSubOpen;
   326         -  }
   327         -  *rc = SQLITE_FULL;
   328         -  return NULL;
          332  +  *rc = multiplexSubFilename(pGroup, iChunk);
          333  +  if( (*rc)==SQLITE_OK && (pSubOpen = pGroup->aReal[iChunk].p)==0 ){
          334  +    pSubOpen = sqlite3_malloc( pOrigVfs->szOsFile );
          335  +    if( pSubOpen==0 ){
          336  +      *rc = SQLITE_NOMEM;
          337  +      return 0;
          338  +    }
          339  +    pGroup->aReal[iChunk].p = pSubOpen;
          340  +    *rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen,
          341  +                          pGroup->flags, pOutFlags);
          342  +    if( *rc!=SQLITE_OK ){
          343  +      sqlite3_free(pSubOpen);
          344  +      pGroup->aReal[iChunk].p = 0;
          345  +      return 0;
          346  +    }
          347  +  }
          348  +  return pSubOpen;
   329    349   }
   330    350   
   331    351   /*
   332    352   ** This is the implementation of the multiplex_control() SQL function.
   333    353   */
   334    354   static void multiplexControlFunc(
   335    355     sqlite3_context *context,
................................................................................
   379    399     const sqlite3_api_routines *pApi
   380    400   ){
   381    401     int rc;
   382    402     rc = sqlite3_create_function(db, "multiplex_control", 2, SQLITE_ANY, 
   383    403         0, multiplexControlFunc, 0, 0);
   384    404     return rc;
   385    405   }
          406  +
          407  +/*
          408  +** Close a single sub-file in the connection group.
          409  +*/
          410  +static void multiplexSubClose(
          411  +  multiplexGroup *pGroup,
          412  +  int iChunk,
          413  +  sqlite3_vfs *pOrigVfs
          414  +){
          415  +  sqlite3_file *pSubOpen = pGroup->aReal[iChunk].p;
          416  +  if( pSubOpen ){
          417  +    if( pOrigVfs ) pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
          418  +    pSubOpen->pMethods->xClose(pSubOpen);
          419  +    sqlite3_free(pGroup->aReal[iChunk].p);
          420  +  }
          421  +  sqlite3_free(pGroup->aReal[iChunk].z);
          422  +  memset(&pGroup->aReal[iChunk], 0, sizeof(pGroup->aReal[iChunk]));
          423  +}
          424  +
          425  +/*
          426  +** Deallocate memory held by a multiplexGroup
          427  +*/
          428  +static void multiplexFreeComponents(multiplexGroup *pGroup){
          429  +  int i;
          430  +  for(i=0; i<pGroup->nReal; i++){ multiplexSubClose(pGroup, i, 0); }
          431  +  sqlite3_free(pGroup->aReal);
          432  +  pGroup->aReal = 0;
          433  +  pGroup->nReal = 0;
          434  +}
          435  +
   386    436   
   387    437   /************************* VFS Method Wrappers *****************************/
   388    438   
   389    439   /*
   390    440   ** This is the xOpen method used for the "multiplex" VFS.
   391    441   **
   392    442   ** Most of the work is done by the underlying original VFS.  This method
................................................................................
   402    452   ){
   403    453     int rc = SQLITE_OK;                  /* Result code */
   404    454     multiplexConn *pMultiplexOpen;       /* The new multiplex file descriptor */
   405    455     multiplexGroup *pGroup;              /* Corresponding multiplexGroup object */
   406    456     sqlite3_file *pSubOpen;                        /* Real file descriptor */
   407    457     sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
   408    458     int nName;
   409         -  int i;
   410    459     int sz;
          460  +  char *zToFree = 0;
   411    461   
   412    462     UNUSED_PARAMETER(pVfs);
          463  +  memset(pConn, 0, pVfs->szOsFile);
   413    464   
   414    465     /* We need to create a group structure and manage
   415    466     ** access to this group of files.
   416    467     */
   417    468     multiplexEnter();
   418    469     pMultiplexOpen = (multiplexConn*)pConn;
   419    470   
   420    471     /* If the second argument to this function is NULL, generate a 
   421    472     ** temporary file name to use.  This will be handled by the
   422    473     ** original xOpen method.  We just need to allocate space for
   423    474     ** it.
   424    475     */
   425    476     if( !zName ){
   426         -    rc = multiplexGetTempname(pOrigVfs, pOrigVfs->mxPathname, gMultiplex.zName);
   427         -    zName = gMultiplex.zName;
          477  +    zName = zToFree = sqlite3_malloc( pOrigVfs->mxPathname + 10 );
          478  +    if( zName==0 ){
          479  +      rc = SQLITE_NOMEM;
          480  +    }else{
          481  +      rc = multiplexGetTempname(pOrigVfs, pOrigVfs->mxPathname, zToFree);
          482  +    }
   428    483     }
   429    484   
   430    485     if( rc==SQLITE_OK ){
   431    486       /* allocate space for group */
   432    487       nName = multiplexStrlen30(zName);
   433    488       sz = sizeof(multiplexGroup)                             /* multiplexGroup */
   434         -       + (sizeof(sqlite3_file *)*SQLITE_MULTIPLEX_MAX_CHUNKS)  /* pReal[] */
   435         -       + (pOrigVfs->szOsFile*SQLITE_MULTIPLEX_MAX_CHUNKS)      /* *pReal */
   436         -       + SQLITE_MULTIPLEX_MAX_CHUNKS                           /* bOpen[] */
   437         -       + nName + 1;                                            /* zName */
   438         -#ifndef SQLITE_MULTIPLEX_EXT_OVWR
   439         -    sz += SQLITE_MULTIPLEX_EXT_SZ;
   440         -    assert(nName+SQLITE_MULTIPLEX_EXT_SZ < pOrigVfs->mxPathname);
   441         -#else
   442         -    assert(nName >= SQLITE_MULTIPLEX_EXT_SZ);
   443         -    assert(nName < pOrigVfs->mxPathname);
   444         -#endif
          489  +       + nName + 1;                                         /* zName */
   445    490       pGroup = sqlite3_malloc( sz );
   446    491       if( pGroup==0 ){
   447         -      rc=SQLITE_NOMEM;
          492  +      rc = SQLITE_NOMEM;
   448    493       }
   449    494     }
   450    495   
   451    496     if( rc==SQLITE_OK ){
   452    497       const char *zChunkSize;
   453    498       /* assign pointers to extra space allocated */
   454    499       char *p = (char *)&pGroup[1];
   455    500       pMultiplexOpen->pGroup = pGroup;
   456    501       memset(pGroup, 0, sz);
   457    502       pGroup->bEnabled = -1;
   458    503       pGroup->nChunkSize = SQLITE_MULTIPLEX_CHUNK_SIZE;
   459         -    zChunkSize = sqlite3_uri_parameter(zName, "chunksize");
   460         -    if( zChunkSize ){
   461         -      int n = atoi(zChunkSize);
   462         -      if( n>0 ) pGroup->nChunkSize = (n+0xffff)&~0xffff;
          504  +    if( flags & SQLITE_OPEN_URI ){
          505  +      zChunkSize = sqlite3_uri_parameter(zName, "chunksize");
          506  +      if( zChunkSize ){
          507  +        int n = atoi(zChunkSize);
          508  +        if( n>0 ) pGroup->nChunkSize = (n+0xffff)&~0xffff;
          509  +      }
   463    510       }
   464         -    pGroup->nMaxChunks = SQLITE_MULTIPLEX_MAX_CHUNKS;
   465         -    pGroup->pReal = (sqlite3_file **)p;
   466         -    p += (sizeof(sqlite3_file *)*pGroup->nMaxChunks);
   467         -    for(i=0; i<pGroup->nMaxChunks; i++){
   468         -      pGroup->pReal[i] = (sqlite3_file *)p;
   469         -      p += pOrigVfs->szOsFile;
   470         -    }
   471         -    /* bOpen[] vals should all be zero from memset above */
   472         -    pGroup->bOpen = p;
   473         -    p += pGroup->nMaxChunks;
   474    511       pGroup->zName = p;
   475    512       /* save off base filename, name length, and original open flags  */
   476    513       memcpy(pGroup->zName, zName, nName+1);
   477    514       pGroup->nName = nName;
   478    515       pGroup->flags = flags;
   479         -    pSubOpen = multiplexSubOpen(pMultiplexOpen, 0, &rc, pOutFlags);
          516  +    pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags);
   480    517       if( pSubOpen ){
   481    518         /* if this file is already larger than chunk size, disable 
   482    519         ** the multiplex feature.
   483    520         */
   484    521         sqlite3_int64 sz;
   485    522         int rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
   486    523         if( (rc2==SQLITE_OK) && (sz>pGroup->nChunkSize) ){
................................................................................
   492    529           pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV2;
   493    530         }
   494    531         /* place this group at the head of our list */
   495    532         pGroup->pNext = gMultiplex.pGroups;
   496    533         if( gMultiplex.pGroups ) gMultiplex.pGroups->pPrev = pGroup;
   497    534         gMultiplex.pGroups = pGroup;
   498    535       }else{
          536  +      multiplexFreeComponents(pGroup);
   499    537         sqlite3_free(pGroup);
   500    538       }
   501    539     }
   502    540     multiplexLeave();
          541  +  sqlite3_free(zToFree);
   503    542     return rc;
   504    543   }
   505    544   
   506    545   /*
   507    546   ** This is the xDelete method used for the "multiplex" VFS.
   508         -** It attempts to delete the filename specified, as well
   509         -** as additional files with the SQLITE_MULTIPLEX_EXT_FMT extension.
          547  +** It attempts to delete the filename specified.
   510    548   */
   511    549   static int multiplexDelete(
   512    550     sqlite3_vfs *pVfs,         /* The multiplex VFS */
   513    551     const char *zName,         /* Name of file to delete */
   514    552     int syncDir
   515    553   ){
   516    554     sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
   517         -  int rc = SQLITE_OK;
   518         -  int nName = multiplexStrlen30(zName);
   519         -  int i;
   520         -
   521         -  UNUSED_PARAMETER(pVfs);
   522         -
   523         -  multiplexEnter();
   524         -  memcpy(gMultiplex.zName, zName, nName+1);
   525         -  for(i=0; i<SQLITE_MULTIPLEX_MAX_CHUNKS; i++){
   526         -    int rc2;
   527         -    int exists = 0;
   528         -    if( i ){
   529         -#ifdef SQLITE_MULTIPLEX_EXT_OVWR
   530         -        sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, 
   531         -            gMultiplex.zName+nName-SQLITE_MULTIPLEX_EXT_SZ, 
   532         -            SQLITE_MULTIPLEX_EXT_FMT, i);
   533         -#else
   534         -        sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, 
   535         -            gMultiplex.zName+nName, 
   536         -            SQLITE_MULTIPLEX_EXT_FMT, i);
   537         -#endif
   538         -    }
   539         -    rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName, 
   540         -        SQLITE_ACCESS_EXISTS, &exists);
   541         -    if( rc2==SQLITE_OK && exists ){
   542         -      /* if it exists, delete it */
   543         -      rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, syncDir);
   544         -      if( rc2!=SQLITE_OK ) rc = rc2;
   545         -    }else{
   546         -      /* stop at first "gap" */
   547         -      break;
   548         -    }
   549         -  }
   550         -  multiplexLeave();
   551         -  return rc;
          555  +  return pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
   552    556   }
   553    557   
   554    558   static int multiplexAccess(sqlite3_vfs *a, const char *b, int c, int *d){
   555    559     return gMultiplex.pOrigVfs->xAccess(gMultiplex.pOrigVfs, b, c, d);
   556    560   }
   557    561   static int multiplexFullPathname(sqlite3_vfs *a, const char *b, int c, char *d){
   558    562     return gMultiplex.pOrigVfs->xFullPathname(gMultiplex.pOrigVfs, b, c, d);
................................................................................
   592    596   ** The group structure for this file is unlinked from 
   593    597   ** our list of groups and freed.
   594    598   */
   595    599   static int multiplexClose(sqlite3_file *pConn){
   596    600     multiplexConn *p = (multiplexConn*)pConn;
   597    601     multiplexGroup *pGroup = p->pGroup;
   598    602     int rc = SQLITE_OK;
   599         -  int i;
   600    603     multiplexEnter();
   601         -  /* close any open handles */
   602         -  for(i=0; i<pGroup->nMaxChunks; i++){
   603         -    if( pGroup->bOpen[i] ){
   604         -      sqlite3_file *pSubOpen = pGroup->pReal[i];
   605         -      int rc2 = pSubOpen->pMethods->xClose(pSubOpen);
   606         -      if( rc2!=SQLITE_OK ) rc = rc2;
   607         -      pGroup->bOpen[i] = 0;
   608         -    }
   609         -  }
          604  +  multiplexFreeComponents(pGroup);
   610    605     /* remove from linked list */
   611    606     if( pGroup->pNext ) pGroup->pNext->pPrev = pGroup->pPrev;
   612    607     if( pGroup->pPrev ){
   613    608       pGroup->pPrev->pNext = pGroup->pNext;
   614    609     }else{
   615    610       gMultiplex.pGroups = pGroup->pNext;
   616    611     }
................................................................................
   630    625     sqlite3_int64 iOfst
   631    626   ){
   632    627     multiplexConn *p = (multiplexConn*)pConn;
   633    628     multiplexGroup *pGroup = p->pGroup;
   634    629     int rc = SQLITE_OK;
   635    630     multiplexEnter();
   636    631     if( !pGroup->bEnabled ){
   637         -    sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
   638         -    if( !pSubOpen ){
          632  +    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
          633  +    if( pSubOpen==0 ){
   639    634         rc = SQLITE_IOERR_READ;
   640    635       }else{
   641    636         rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst);
   642    637       }
   643    638     }else{
   644    639       while( iAmt > 0 ){
   645    640         int i = (int)(iOfst / pGroup->nChunkSize);
   646         -      sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
          641  +      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
   647    642         if( pSubOpen ){
   648    643           int extra = ((int)(iOfst % pGroup->nChunkSize) + iAmt) -
   649    644                                                           pGroup->nChunkSize;
   650    645           if( extra<0 ) extra = 0;
   651    646           iAmt -= extra;
   652    647           rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt,
   653    648                                          iOfst % pGroup->nChunkSize);
................................................................................
   676    671     sqlite3_int64 iOfst
   677    672   ){
   678    673     multiplexConn *p = (multiplexConn*)pConn;
   679    674     multiplexGroup *pGroup = p->pGroup;
   680    675     int rc = SQLITE_OK;
   681    676     multiplexEnter();
   682    677     if( !pGroup->bEnabled ){
   683         -    sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
          678  +    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
   684    679       if( pSubOpen==0 ){
   685    680         rc = SQLITE_IOERR_WRITE;
   686    681       }else{
   687    682         rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst);
   688    683       }
   689    684     }else{
   690    685       while( iAmt > 0 ){
   691    686         int i = (int)(iOfst / pGroup->nChunkSize);
   692         -      sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
          687  +      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
   693    688         if( pSubOpen ){
   694    689           int extra = ((int)(iOfst % pGroup->nChunkSize) + iAmt) -
   695    690                       pGroup->nChunkSize;
   696    691           if( extra<0 ) extra = 0;
   697    692           iAmt -= extra;
   698    693           rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt,
   699    694                                           iOfst % pGroup->nChunkSize);
................................................................................
   717    712   */
   718    713   static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){
   719    714     multiplexConn *p = (multiplexConn*)pConn;
   720    715     multiplexGroup *pGroup = p->pGroup;
   721    716     int rc = SQLITE_OK;
   722    717     multiplexEnter();
   723    718     if( !pGroup->bEnabled ){
   724         -    sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
          719  +    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
   725    720       if( pSubOpen==0 ){
   726    721         rc = SQLITE_IOERR_TRUNCATE;
   727    722       }else{
   728    723         rc = pSubOpen->pMethods->xTruncate(pSubOpen, size);
   729    724       }
   730    725     }else{
   731    726       int rc2;
   732    727       int i;
   733    728       sqlite3_file *pSubOpen;
   734    729       sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
   735         -    memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
   736    730       /* delete the chunks above the truncate limit */
   737         -    for(i=(int)(size / pGroup->nChunkSize)+1; i<pGroup->nMaxChunks; i++){
   738         -      /* close any open chunks before deleting them */
   739         -      if( pGroup->bOpen[i] ){
   740         -        pSubOpen = pGroup->pReal[i];
   741         -        rc2 = pSubOpen->pMethods->xClose(pSubOpen);
   742         -        if( rc2!=SQLITE_OK ) rc = SQLITE_IOERR_TRUNCATE;
   743         -        pGroup->bOpen[i] = 0;
   744         -      }
   745         -#ifdef SQLITE_MULTIPLEX_EXT_OVWR
   746         -      sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, 
   747         -          gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ, 
   748         -          SQLITE_MULTIPLEX_EXT_FMT, i);
   749         -#else
   750         -      sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, 
   751         -          gMultiplex.zName+pGroup->nName, 
   752         -          SQLITE_MULTIPLEX_EXT_FMT, i);
   753         -#endif
   754         -      rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, 0);
   755         -      if( rc2!=SQLITE_OK ) rc = SQLITE_IOERR_TRUNCATE;
          731  +    for(i=(int)(size / pGroup->nChunkSize)+1; i<pGroup->nReal; i++){
          732  +      multiplexSubClose(pGroup, i, pOrigVfs);
   756    733       }
   757         -    pSubOpen = multiplexSubOpen(p, (int)(size/pGroup->nChunkSize), &rc2, NULL);
          734  +    pSubOpen = multiplexSubOpen(pGroup, (int)(size/pGroup->nChunkSize), &rc2,0);
   758    735       if( pSubOpen ){
   759    736         rc2 = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->nChunkSize);
   760    737         if( rc2!=SQLITE_OK ) rc = rc2;
   761    738       }else{
   762    739         rc = SQLITE_IOERR_TRUNCATE;
   763    740       }
   764    741     }
................................................................................
   770    747   */
   771    748   static int multiplexSync(sqlite3_file *pConn, int flags){
   772    749     multiplexConn *p = (multiplexConn*)pConn;
   773    750     multiplexGroup *pGroup = p->pGroup;
   774    751     int rc = SQLITE_OK;
   775    752     int i;
   776    753     multiplexEnter();
   777         -  for(i=0; i<pGroup->nMaxChunks; i++){
   778         -    /* if we don't have it open, we don't need to sync it */
   779         -    if( pGroup->bOpen[i] ){
   780         -      sqlite3_file *pSubOpen = pGroup->pReal[i];
          754  +  for(i=0; i<pGroup->nReal; i++){
          755  +    sqlite3_file *pSubOpen = pGroup->aReal[i].p;
          756  +    if( pSubOpen ){
   781    757         int rc2 = pSubOpen->pMethods->xSync(pSubOpen, flags);
   782    758         if( rc2!=SQLITE_OK ) rc = rc2;
   783    759       }
   784    760     }
   785    761     multiplexLeave();
   786    762     return rc;
   787    763   }
................................................................................
   793    769     multiplexConn *p = (multiplexConn*)pConn;
   794    770     multiplexGroup *pGroup = p->pGroup;
   795    771     int rc = SQLITE_OK;
   796    772     int rc2;
   797    773     int i;
   798    774     multiplexEnter();
   799    775     if( !pGroup->bEnabled ){
   800         -    sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
          776  +    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
   801    777       if( pSubOpen==0 ){
   802    778         rc = SQLITE_IOERR_FSTAT;
   803    779       }else{
   804    780         rc = pSubOpen->pMethods->xFileSize(pSubOpen, pSize);
   805    781       }
   806    782     }else{
   807    783       *pSize = 0;
   808         -    for(i=0; i<pGroup->nMaxChunks; i++){
   809         -      sqlite3_file *pSubOpen = NULL;
   810         -      /* if not opened already, check to see if the chunk exists */
   811         -      if( pGroup->bOpen[i] ){
   812         -        pSubOpen = pGroup->pReal[i];
   813         -      }else{
   814         -        sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
   815         -        int exists = 0;
   816         -        memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
   817         -        if( i ){
   818         -#ifdef SQLITE_MULTIPLEX_EXT_OVWR
   819         -          sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, 
   820         -              gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ, 
   821         -              SQLITE_MULTIPLEX_EXT_FMT, i);
   822         -#else
   823         -          sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, 
   824         -              gMultiplex.zName+pGroup->nName, 
   825         -              SQLITE_MULTIPLEX_EXT_FMT, i);
   826         -#endif
   827         -        }
   828         -        rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName, 
   829         -            SQLITE_ACCESS_EXISTS, &exists);
   830         -        if( rc2==SQLITE_OK && exists){
   831         -          /* if it exists, open it */
   832         -          pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
   833         -        }else{
   834         -          /* stop at first "gap" */
   835         -          break;
   836         -        }
          784  +    for(i=0; 1; i++){
          785  +      sqlite3_file *pSubOpen = 0;
          786  +      sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;
          787  +      int exists = 0;
          788  +      rc = multiplexSubFilename(pGroup, i);
          789  +      if( rc ) break;
          790  +      rc2 = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[i].z,
          791  +          SQLITE_ACCESS_EXISTS, &exists);
          792  +      if( rc2==SQLITE_OK && exists){
          793  +        /* if it exists, open it */
          794  +        pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
          795  +      }else{
          796  +        /* stop at first "gap" */
          797  +        break;
   837    798         }
   838    799         if( pSubOpen ){
   839    800           sqlite3_int64 sz;
   840    801           rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
   841    802           if( rc2!=SQLITE_OK ){
   842    803             rc = rc2;
   843    804           }else{
................................................................................
   856    817   }
   857    818   
   858    819   /* Pass xLock requests through to the original VFS unchanged.
   859    820   */
   860    821   static int multiplexLock(sqlite3_file *pConn, int lock){
   861    822     multiplexConn *p = (multiplexConn*)pConn;
   862    823     int rc;
   863         -  sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
          824  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
   864    825     if( pSubOpen ){
   865    826       return pSubOpen->pMethods->xLock(pSubOpen, lock);
   866    827     }
   867    828     return SQLITE_BUSY;
   868    829   }
   869    830   
   870    831   /* Pass xUnlock requests through to the original VFS unchanged.
   871    832   */
   872    833   static int multiplexUnlock(sqlite3_file *pConn, int lock){
   873    834     multiplexConn *p = (multiplexConn*)pConn;
   874    835     int rc;
   875         -  sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
          836  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
   876    837     if( pSubOpen ){
   877    838       return pSubOpen->pMethods->xUnlock(pSubOpen, lock);
   878    839     }
   879    840     return SQLITE_IOERR_UNLOCK;
   880    841   }
   881    842   
   882    843   /* Pass xCheckReservedLock requests through to the original VFS unchanged.
   883    844   */
   884    845   static int multiplexCheckReservedLock(sqlite3_file *pConn, int *pResOut){
   885    846     multiplexConn *p = (multiplexConn*)pConn;
   886    847     int rc;
   887         -  sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
          848  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
   888    849     if( pSubOpen ){
   889    850       return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut);
   890    851     }
   891    852     return SQLITE_IOERR_CHECKRESERVEDLOCK;
   892    853   }
   893    854   
   894    855   /* Pass xFileControl requests through to the original VFS unchanged,
................................................................................
   920    881             nChunkSize &= ~(MAX_PAGE_SIZE-1);
   921    882             pGroup->nChunkSize = nChunkSize;
   922    883             rc = SQLITE_OK;
   923    884           }
   924    885         }
   925    886         break;
   926    887       case MULTIPLEX_CTRL_SET_MAX_CHUNKS:
   927         -      if( pArg ) {
   928         -        int nMaxChunks = *(int *)pArg;
   929         -        if(( nMaxChunks<1 ) || ( nMaxChunks>SQLITE_MULTIPLEX_MAX_CHUNKS )){
   930         -          rc = SQLITE_MISUSE;
   931         -        }else{
   932         -          pGroup->nMaxChunks = nMaxChunks;
   933         -          rc = SQLITE_OK;
   934         -        }
   935         -      }
          888  +      rc = SQLITE_OK;
   936    889         break;
   937    890       case SQLITE_FCNTL_SIZE_HINT:
   938    891       case SQLITE_FCNTL_CHUNK_SIZE:
   939    892         /* no-op these */
   940    893         rc = SQLITE_OK;
   941    894         break;
   942    895       default:
   943         -      pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
          896  +      pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
   944    897         if( pSubOpen ){
   945    898           rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
   946    899         }
   947    900         break;
   948    901     }
   949    902     return rc;
   950    903   }
   951    904   
   952    905   /* Pass xSectorSize requests through to the original VFS unchanged.
   953    906   */
   954    907   static int multiplexSectorSize(sqlite3_file *pConn){
   955    908     multiplexConn *p = (multiplexConn*)pConn;
   956    909     int rc;
   957         -  sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
          910  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
   958    911     if( pSubOpen ){
   959    912       return pSubOpen->pMethods->xSectorSize(pSubOpen);
   960    913     }
   961    914     return DEFAULT_SECTOR_SIZE;
   962    915   }
   963    916   
   964    917   /* Pass xDeviceCharacteristics requests through to the original VFS unchanged.
   965    918   */
   966    919   static int multiplexDeviceCharacteristics(sqlite3_file *pConn){
   967    920     multiplexConn *p = (multiplexConn*)pConn;
   968    921     int rc;
   969         -  sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
          922  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
   970    923     if( pSubOpen ){
   971    924       return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen);
   972    925     }
   973    926     return 0;
   974    927   }
   975    928   
   976    929   /* Pass xShmMap requests through to the original VFS unchanged.
................................................................................
   980    933     int iRegion,                    /* Region to retrieve */
   981    934     int szRegion,                   /* Size of regions */
   982    935     int bExtend,                    /* True to extend file if necessary */
   983    936     void volatile **pp              /* OUT: Mapped memory */
   984    937   ){
   985    938     multiplexConn *p = (multiplexConn*)pConn;
   986    939     int rc;
   987         -  sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
          940  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
   988    941     if( pSubOpen ){
   989    942       return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend,pp);
   990    943     }
   991    944     return SQLITE_IOERR;
   992    945   }
   993    946   
   994    947   /* Pass xShmLock requests through to the original VFS unchanged.
................................................................................
   997    950     sqlite3_file *pConn,       /* Database file holding the shared memory */
   998    951     int ofst,                  /* First lock to acquire or release */
   999    952     int n,                     /* Number of locks to acquire or release */
  1000    953     int flags                  /* What to do with the lock */
  1001    954   ){
  1002    955     multiplexConn *p = (multiplexConn*)pConn;
  1003    956     int rc;
  1004         -  sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
          957  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
  1005    958     if( pSubOpen ){
  1006    959       return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags);
  1007    960     }
  1008    961     return SQLITE_BUSY;
  1009    962   }
  1010    963   
  1011    964   /* Pass xShmBarrier requests through to the original VFS unchanged.
  1012    965   */
  1013    966   static void multiplexShmBarrier(sqlite3_file *pConn){
  1014    967     multiplexConn *p = (multiplexConn*)pConn;
  1015    968     int rc;
  1016         -  sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
          969  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
  1017    970     if( pSubOpen ){
  1018    971       pSubOpen->pMethods->xShmBarrier(pSubOpen);
  1019    972     }
  1020    973   }
  1021    974   
  1022    975   /* Pass xShmUnmap requests through to the original VFS unchanged.
  1023    976   */
  1024    977   static int multiplexShmUnmap(sqlite3_file *pConn, int deleteFlag){
  1025    978     multiplexConn *p = (multiplexConn*)pConn;
  1026    979     int rc;
  1027         -  sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
          980  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
  1028    981     if( pSubOpen ){
  1029    982       return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag);
  1030    983     }
  1031    984     return SQLITE_OK;
  1032    985   }
  1033    986   
  1034    987   /************************** Public Interfaces *****************************/
................................................................................
  1050   1003     pOrigVfs = sqlite3_vfs_find(zOrigVfsName);
  1051   1004     if( pOrigVfs==0 ) return SQLITE_ERROR;
  1052   1005     assert( pOrigVfs!=&gMultiplex.sThisVfs );
  1053   1006     gMultiplex.pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
  1054   1007     if( !gMultiplex.pMutex ){
  1055   1008       return SQLITE_NOMEM;
  1056   1009     }
  1057         -  gMultiplex.zName = sqlite3_malloc(pOrigVfs->mxPathname);
  1058         -  if( !gMultiplex.zName ){
  1059         -    sqlite3_mutex_free(gMultiplex.pMutex);
  1060         -    return SQLITE_NOMEM;
  1061         -  }
  1062   1010     gMultiplex.pGroups = NULL;
  1063   1011     gMultiplex.isInitialized = 1;
  1064   1012     gMultiplex.pOrigVfs = pOrigVfs;
  1065   1013     gMultiplex.sThisVfs = *pOrigVfs;
  1066   1014     gMultiplex.sThisVfs.szOsFile += sizeof(multiplexConn);
  1067   1015     gMultiplex.sThisVfs.zName = SQLITE_MULTIPLEX_VFS_NAME;
  1068   1016     gMultiplex.sThisVfs.xOpen = multiplexOpen;
................................................................................
  1115   1063   ** THIS ROUTINE IS NOT THREADSAFE.  Call this routine exactly once while
  1116   1064   ** shutting down in order to free all remaining multiplex groups.
  1117   1065   */
  1118   1066   int sqlite3_multiplex_shutdown(void){
  1119   1067     if( gMultiplex.isInitialized==0 ) return SQLITE_MISUSE;
  1120   1068     if( gMultiplex.pGroups ) return SQLITE_MISUSE;
  1121   1069     gMultiplex.isInitialized = 0;
  1122         -  sqlite3_free(gMultiplex.zName);
  1123   1070     sqlite3_mutex_free(gMultiplex.pMutex);
  1124   1071     sqlite3_vfs_unregister(&gMultiplex.sThisVfs);
  1125   1072     memset(&gMultiplex, 0, sizeof(gMultiplex));
  1126   1073     return SQLITE_OK;
  1127   1074   }
  1128   1075   
  1129   1076   /***************************** Test Code ***********************************/
................................................................................
  1217   1164             Tcl_NewStringObj(pGroup->zName, -1));
  1218   1165       Tcl_ListObjAppendElement(interp, pGroupTerm,
  1219   1166             Tcl_NewIntObj(pGroup->nName));
  1220   1167       Tcl_ListObjAppendElement(interp, pGroupTerm,
  1221   1168             Tcl_NewIntObj(pGroup->flags));
  1222   1169   
  1223   1170       /* count number of chunks with open handles */
  1224         -    for(i=0; i<pGroup->nMaxChunks; i++){
  1225         -      if( pGroup->bOpen[i] ) nChunks++;
         1171  +    for(i=0; i<pGroup->nReal; i++){
         1172  +      if( pGroup->aReal[i].p!=0 ) nChunks++;
  1226   1173       }
  1227   1174       Tcl_ListObjAppendElement(interp, pGroupTerm,
  1228   1175             Tcl_NewIntObj(nChunks));
  1229   1176   
  1230   1177       Tcl_ListObjAppendElement(interp, pGroupTerm,
  1231   1178             Tcl_NewIntObj(pGroup->nChunkSize));
  1232   1179       Tcl_ListObjAppendElement(interp, pGroupTerm,
  1233         -          Tcl_NewIntObj(pGroup->nMaxChunks));
         1180  +          Tcl_NewIntObj(pGroup->nReal));
  1234   1181   
  1235   1182       Tcl_ListObjAppendElement(interp, pResult, pGroupTerm);
  1236   1183     }
  1237   1184     multiplexLeave();
  1238   1185     Tcl_SetObjResult(interp, pResult);
  1239   1186     return TCL_OK;
  1240   1187   }

Changes to test/multiplex.test.

    45     45     list $msg
    46     46   }
    47     47   
    48     48   # This attempts to delete the base file and 
    49     49   # and files with the chunk extension.
    50     50   proc multiplex_delete {name} {
    51     51     global g_max_chunks
           52  +  forcedelete $name
    52     53     for {set i 0} {$i<$g_max_chunks} {incr i} {
    53     54       forcedelete [multiplex_name $name $i]
    54     55       forcedelete [multiplex_name $name-journal $i]
    55     56       forcedelete [multiplex_name $name-wal $i]
    56     57     }
    57     58   }
    58     59   
................................................................................
    74     75   do_test multiplex-1.7 { sqlite3_multiplex_initialize "" 1 }        {SQLITE_OK}
    75     76   do_test multiplex-1.8 { sqlite3_multiplex_shutdown }               {SQLITE_OK}
    76     77   
    77     78   
    78     79   do_test multiplex-1.9.1  { sqlite3_multiplex_initialize "" 1 }     {SQLITE_OK}
    79     80   do_test multiplex-1.9.2  { sqlite3 db test.db }                    {}
    80     81   do_test multiplex-1.9.3  { multiplex_set db main 32768 16 }        {SQLITE_OK}
    81         -do_test multiplex-1.9.4  { multiplex_set db main 32768 -1 }        {SQLITE_MISUSE}
           82  +do_test multiplex-1.9.4  { multiplex_set db main 32768 -1 }        {SQLITE_OK}
    82     83   do_test multiplex-1.9.5  { multiplex_set db main -1 16 }           {SQLITE_MISUSE}
    83     84   do_test multiplex-1.9.6  { multiplex_set db main 31 16 }           {SQLITE_OK}
    84         -do_test multiplex-1.9.7  { multiplex_set db main 32768 100 }       {SQLITE_MISUSE}
           85  +do_test multiplex-1.9.7  { multiplex_set db main 32768 100 }       {SQLITE_OK}
    85     86   do_test multiplex-1.9.8  { multiplex_set db main 1073741824 1 }    {SQLITE_OK}
    86     87   do_test multiplex-1.9.9  { db close }                              {}
    87     88   do_test multiplex-1.9.10 { sqlite3_multiplex_shutdown }            {SQLITE_OK}
    88     89   
    89     90   do_test multiplex-1.10.1  { sqlite3_multiplex_initialize "" 1 }                                  {SQLITE_OK}
    90     91   do_test multiplex-1.10.2  { sqlite3 db test.db }                                                 {}
    91     92   do_test multiplex-1.10.3  { lindex [ catchsql { SELECT multiplex_control(2, 32768); } ] 0 }      {0}
    92         -do_test multiplex-1.10.4  { lindex [ catchsql { SELECT multiplex_control(3, -1); } ] 0 }         {1}
           93  +do_test multiplex-1.10.4  { lindex [ catchsql { SELECT multiplex_control(3, -1); } ] 0 }         {0}
    93     94   do_test multiplex-1.10.5  { lindex [ catchsql { SELECT multiplex_control(2, -1); } ] 0 }         {1}
    94     95   do_test multiplex-1.10.6  { lindex [ catchsql { SELECT multiplex_control(2, 31); } ] 0 }         {0}
    95         -do_test multiplex-1.10.7  { lindex [ catchsql { SELECT multiplex_control(3, 100); } ] 0 }        {1}
           96  +do_test multiplex-1.10.7  { lindex [ catchsql { SELECT multiplex_control(3, 100); } ] 0 }        {0}
    96     97   do_test multiplex-1.10.8  { lindex [ catchsql { SELECT multiplex_control(2, 1073741824); } ] 0 } {0}
    97     98   do_test multiplex-1.10.9  { db close }                                                           {}
    98     99   do_test multiplex-1.10.10 { sqlite3_multiplex_shutdown }                                         {SQLITE_OK}
    99    100   
   100    101   do_test multiplex-1.11.1  { sqlite3_multiplex_initialize "" 1 }               {SQLITE_OK}
   101    102   do_test multiplex-1.11.2  { sqlite3 db test.db }                              {}
   102    103   do_test multiplex-1.11.3  { sqlite3_multiplex_control db main enable 0  }     {SQLITE_OK}
................................................................................
   142    143   #
   143    144   #   multiplex-2.7.*: Disable/enable tests.
   144    145   #
   145    146   
   146    147   sqlite3_multiplex_initialize "" 1
   147    148   multiplex_set db main 32768 16
   148    149   
          150  +file delete -force test.x
   149    151   do_test multiplex-2.1.2 {
   150         -  sqlite3 db test.db
          152  +  sqlite3 db test.x
   151    153     execsql {
   152    154       PRAGMA page_size=1024;
   153    155       PRAGMA auto_vacuum=OFF;
   154    156       PRAGMA journal_mode=DELETE;
   155    157     }
   156    158     execsql {
   157    159       CREATE TABLE t1(a, b);
   158    160       INSERT INTO t1 VALUES(1, randomblob(1100));
   159    161       INSERT INTO t1 VALUES(2, randomblob(1100));
   160    162     }
   161    163   } {}
   162         -do_test multiplex-2.1.3 { file size [multiplex_name test.db 0] } {4096}
          164  +do_test multiplex-2.1.3 { file size [multiplex_name test.x 0] } {4096}
   163    165   do_test multiplex-2.1.4 {
   164    166     execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
   165    167   } {}
   166    168   
   167    169   do_test multiplex-2.2.1 {
   168    170     execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
   169    171   } {}
   170         -do_test multiplex-2.2.3 { file size [multiplex_name test.db 0] } {6144}
          172  +do_test multiplex-2.2.3 { file size [multiplex_name test.x 0] } {6144}
   171    173   
   172    174   do_test multiplex-2.3.1 {
   173         -  sqlite3 db2 test2.db
          175  +  sqlite3 db2 test2.x
   174    176     db2 close
   175    177   } {}
   176    178   
   177    179   
   178    180   do_test multiplex-2.4.1 {
   179    181     sqlite3_multiplex_shutdown
   180    182   } {SQLITE_MISUSE}
   181    183   do_test multiplex-2.4.2 {
   182    184     execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
   183    185   } {}
   184         -do_test multiplex-2.4.4 { file size [multiplex_name test.db 0] } {7168}
          186  +do_test multiplex-2.4.4 { file size [multiplex_name test.x 0] } {7168}
   185    187   do_test multiplex-2.4.99 {
   186    188     db close
   187    189     sqlite3_multiplex_shutdown
   188    190   } {SQLITE_OK}
   189    191   
   190    192   
   191    193   do_test multiplex-2.5.1 {
   192         -  multiplex_delete test.db
          194  +  multiplex_delete test.x
   193    195     sqlite3_multiplex_initialize "" 1
   194         -  sqlite3 db test.db
          196  +  sqlite3 db test.x
   195    197     multiplex_set db main 4096 16
   196    198   } {SQLITE_OK}
   197    199   
   198    200   do_test multiplex-2.5.2 {
   199    201     execsql {
   200    202       PRAGMA page_size = 1024;
   201    203       PRAGMA journal_mode = delete;
................................................................................
   232    234     db eval {SELECT a,length(b) FROM t1 WHERE a=2}
   233    235   } {2 4000}
   234    236   
   235    237   do_test multiplex-2.5.8 {
   236    238     db eval {SELECT a,length(b) FROM t1 WHERE a=4}
   237    239   } {4 4000}
   238    240   
   239         -do_test multiplex-2.5.9 { file size [multiplex_name test.db 0] } [list $g_chunk_size]
   240         -do_test multiplex-2.5.10 { file size [multiplex_name test.db 1] } [list $g_chunk_size]
          241  +do_test multiplex-2.5.9 { file size [multiplex_name test.x 0] } [list $g_chunk_size]
          242  +do_test multiplex-2.5.10 { file size [multiplex_name test.x 1] } [list $g_chunk_size]
   241    243   
   242    244   do_test multiplex-2.5.99 {
   243    245     db close
   244    246     sqlite3_multiplex_shutdown
   245    247   } {SQLITE_OK}
   246    248   
   247    249   
................................................................................
   519    521   do_faultsim_test multiplex-5.5 -prep {
   520    522     catch { sqlite3_multiplex_shutdown }
   521    523   } -body {
   522    524     sqlite3_multiplex_initialize "" 1
   523    525     multiplex_set db main 32768 16
   524    526   }
   525    527   
   526         -# test that mismatch filesize is detected
   527         -#
   528         -# Do not run this test if $::G(perm:presql) is set. If it is set, then the
   529         -# expected IO error will occur within the Tcl [sqlite3] wrapper, not within
   530         -# the first SQL statement executed below. This breaks the test case.
   531         -#
   532         -if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} {
   533         -  set all_journal_modes {delete persist truncate memory off}
   534         -  foreach jmode $all_journal_modes {
   535         -    do_test multiplex-5.6.1.$jmode {
   536         -      sqlite3_multiplex_shutdown
   537         -      multiplex_delete test.db
   538         -      sqlite3 db test.db
   539         -      db eval {
   540         -        PRAGMA page_size = 1024;
   541         -        PRAGMA auto_vacuum = off;
   542         -      }
   543         -      db eval "PRAGMA journal_mode = $jmode;"
   544         -    } $jmode
   545         -    do_test multiplex-5.6.2.$jmode {
   546         -      execsql {
   547         -        CREATE TABLE t1(a, b);
   548         -        INSERT INTO t1 VALUES(1, randomblob(15000));
   549         -        INSERT INTO t1 VALUES(2, randomblob(15000));
   550         -        INSERT INTO t1 VALUES(3, randomblob(15000));
   551         -        INSERT INTO t1 VALUES(4, randomblob(15000));
   552         -        INSERT INTO t1 VALUES(5, randomblob(15000));
   553         -      }
   554         -      db close
   555         -      sqlite3_multiplex_initialize "" 1
   556         -      sqlite3 db test.db
   557         -      multiplex_set db main 4096 16
   558         -    } {SQLITE_OK}
   559         -    do_test multiplex-5.6.3.$jmode {
   560         -      catchsql {
   561         -        INSERT INTO t1 VALUES(6, randomblob(15000));
   562         -      }
   563         -    } {1 {disk I/O error}}
   564         -    do_test multiplex-5.6.4.$jmode {
   565         -      db close
   566         -    } {}
   567         -  }
   568         -}
   569         -
   570    528   #-------------------------------------------------------------------------
   571    529   # Test that you can vacuum a multiplex'ed DB.  
   572    530   
   573    531   ifcapable vacuum {
   574    532   
   575    533   sqlite3_multiplex_shutdown
   576    534   do_test multiplex-6.0.0 {
   577    535     multiplex_delete test.db
          536  +  multiplex_delete test.x
   578    537     sqlite3_multiplex_initialize "" 1
   579         -  sqlite3 db test.db
          538  +  sqlite3 db test.x
   580    539     multiplex_set db main 4096 16
   581    540   } {SQLITE_OK}
   582    541   
   583    542   do_test multiplex-6.1.0 {
   584    543     execsql {
   585    544       PRAGMA page_size=1024;
   586    545       PRAGMA journal_mode=DELETE;
................................................................................
   588    547     }
   589    548     execsql {
   590    549       CREATE TABLE t1(a, b);
   591    550       INSERT INTO t1 VALUES(1, randomblob($g_chunk_size));
   592    551       INSERT INTO t1 VALUES(2, randomblob($g_chunk_size));
   593    552     }
   594    553   } {}
   595         -do_test multiplex-6.2.1 { file size [multiplex_name test.db 0] } [list $g_chunk_size]
   596         -do_test multiplex-6.2.2 { file size [multiplex_name test.db 1] } [list $g_chunk_size]
          554  +do_test multiplex-6.2.1 { file size [multiplex_name test.x 0] } [list $g_chunk_size]
          555  +do_test multiplex-6.2.2 { file size [multiplex_name test.x 1] } [list $g_chunk_size]
   597    556   
   598    557   do_test multiplex-6.3.0 {
   599    558     execsql { VACUUM }
   600    559   } {}
   601    560   
   602    561   do_test multiplex-6.99 {
   603    562     db close
   604         -  multiplex_delete test.db
          563  +  multiplex_delete test.x
   605    564     sqlite3_multiplex_shutdown
   606    565   } {SQLITE_OK}
   607    566   
   608    567   }
   609    568   
   610    569   
   611    570   catch { sqlite3_multiplex_shutdown }
   612    571   finish_test