/ Check-in [cf3bccc2]
Login

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

Overview
Comment:Merge the nx-devkit changes into trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: cf3bccc2e944cd2dd3efb8554682994a06115f16
User & Date: drh 2011-12-16 13:42:03
References
2011-12-19
11:16
Fix a couple of test cases to account for the master-journal name related change in [cf3bccc2]. check-in: 21b76af6 user: dan tags: trunk
Context
2011-12-16
15:11
Improved logging of master-journal name conflicts. check-in: b1005ef4 user: drh tags: trunk
13:42
Merge the nx-devkit changes into trunk. check-in: cf3bccc2 user: drh tags: trunk
05:50
Tweaks to the way multiplexSubOpen() works, for backwards compatibility. check-in: bb403388 user: drh tags: nx-devkit
2011-12-15
17:44
Add stdio support to the quota VFS. check-in: 322bd15f user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/test_multiplex.c.

   129    129       char *z;                          /* Name of this chunk */
   130    130     } *aReal;                        /* list of all chunks */
   131    131     int nReal;                       /* Number of chunks */
   132    132     char *zName;                     /* Base filename of this group */
   133    133     int nName;                       /* Length of base filename */
   134    134     int flags;                       /* Flags used for original opening */
   135    135     unsigned int szChunk;            /* Chunk size used for this group */
   136         -  int bEnabled;                    /* TRUE to use Multiplex VFS for this file */
          136  +  unsigned char bEnabled;          /* TRUE to use Multiplex VFS for this file */
          137  +  unsigned char bTruncate;         /* TRUE to enable truncation of databases */
   137    138     multiplexGroup *pNext, *pPrev;   /* Doubly linked list of all group objects */
   138    139   };
   139    140   
   140    141   /*
   141    142   ** An instance of the following object represents each open connection
   142    143   ** to a file that is multiplex'ed.  This object is a 
   143    144   ** subclass of sqlite3_file.  The sqlite3_file object for the underlying
................................................................................
   211    212   */
   212    213   static int multiplexStrlen30(const char *z){
   213    214     const char *z2 = z;
   214    215     if( z==0 ) return 0;
   215    216     while( *z2 ){ z2++; }
   216    217     return 0x3fffffff & (int)(z2 - z);
   217    218   }
          219  +
          220  +/*
          221  +** Generate the file-name for chunk iChunk of the group with base name
          222  +** zBase. The file-name is written to buffer zOut before returning. Buffer
          223  +** zOut must be allocated by the caller so that it is at least (nBase+4)
          224  +** bytes in size, where nBase is the length of zBase, not including the
          225  +** nul-terminator.
          226  +*/
          227  +static void multiplexFilename(
          228  +  const char *zBase,              /* Filename for chunk 0 */
          229  +  int nBase,                      /* Size of zBase in bytes (without \0) */
          230  +  int flags,                      /* Flags used to open file */
          231  +  int iChunk,                     /* Chunk to generate filename for */
          232  +  char *zOut                      /* Buffer to write generated name to */
          233  +){
          234  +  memcpy(zOut, zBase, nBase+1);
          235  +  if( iChunk!=0 && iChunk!=SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET ){
          236  +    int n = nBase;
          237  +#ifdef SQLITE_ENABLE_8_3_NAMES
          238  +    int i;
          239  +    for(i=n-1; i>0 && i>=n-4 && zOut[i]!='.'; i--){}
          240  +    if( i>=n-4 ) n = i+1;
          241  +    if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
          242  +      /* The extensions on overflow files for main databases are 001, 002,
          243  +       ** 003 and so forth.  To avoid name collisions, add 400 to the 
          244  +       ** extensions of journal files so that they are 401, 402, 403, ....
          245  +       */
          246  +      iChunk += SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET;
          247  +    }
          248  +#endif
          249  +    sqlite3_snprintf(4,&zOut[n],"%03d",iChunk);
          250  +  }
          251  +}
   218    252   
   219    253   /* Compute the filename for the iChunk-th chunk
   220    254   */
   221    255   static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){
   222    256     if( iChunk>=pGroup->nReal ){
   223    257       struct multiplexReal *p;
   224    258       p = sqlite3_realloc(pGroup->aReal, (iChunk+1)*sizeof(*p));
................................................................................
   232    266     if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){
   233    267       char *z;
   234    268       int n = pGroup->nName;
   235    269       pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+4 );
   236    270       if( z==0 ){
   237    271         return SQLITE_NOMEM;
   238    272       }
   239         -    memcpy(z, pGroup->zName, n+1);
   240         -    if( iChunk>0 ){
   241         -#ifdef SQLITE_ENABLE_8_3_NAMES
   242         -      int i;
   243         -      for(i=n-1; i>0 && i>=n-4 && z[i]!='.'; i--){}
   244         -      if( i>=n-4 ) n = i+1;
   245         -      if( pGroup->flags & (SQLITE_OPEN_MAIN_JOURNAL|SQLITE_OPEN_TEMP_JOURNAL) ){
   246         -        /* The extensions on overflow files for main databases are 001, 002,
   247         -        ** 003 and so forth.  To avoid name collisions, add 400 to the 
   248         -        ** extensions of journal files so that they are 401, 402, 403, ....
   249         -        */
   250         -        iChunk += SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET;
   251         -      }
   252         -#endif
   253         -      sqlite3_snprintf(4,&z[n],"%03d",iChunk);
   254         -    }
          273  +    multiplexFilename(pGroup->zName, pGroup->nName, pGroup->flags, iChunk, z);
   255    274     }
   256    275     return SQLITE_OK;
   257    276   }
   258    277   
   259    278   /* Translate an sqlite3_file* that is really a multiplexGroup* into
   260    279   ** the sqlite3_file* for the underlying original VFS.
          280  +**
          281  +** For chunk 0, the pGroup->flags determines whether or not a new file
          282  +** is created if it does not already exist.  For chunks 1 and higher, the
          283  +** file is created only if createFlag is 1.
   261    284   */
   262    285   static sqlite3_file *multiplexSubOpen(
   263         -  multiplexGroup *pGroup,
   264         -  int iChunk,
   265         -  int *rc,
   266         -  int *pOutFlags
          286  +  multiplexGroup *pGroup,    /* The multiplexor group */
          287  +  int iChunk,                /* Which chunk to open.  0==original file */
          288  +  int *rc,                   /* Result code in and out */
          289  +  int *pOutFlags,            /* Output flags */
          290  +  int createFlag             /* True to create if iChunk>0 */
   267    291   ){
   268    292     sqlite3_file *pSubOpen = 0;
   269    293     sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;        /* Real VFS */
   270    294   
   271    295   #ifdef SQLITE_ENABLE_8_3_NAMES
   272    296     /* If JOURNAL_8_3_OFFSET is set to (say) 400, then any overflow files are 
   273    297     ** part of a database journal are named db.401, db.402, and so on. A 
................................................................................
   277    301       *rc = SQLITE_FULL;
   278    302       return 0;
   279    303     }
   280    304   #endif
   281    305   
   282    306     *rc = multiplexSubFilename(pGroup, iChunk);
   283    307     if( (*rc)==SQLITE_OK && (pSubOpen = pGroup->aReal[iChunk].p)==0 ){
          308  +    int flags, bExists;
          309  +    createFlag = (pGroup->flags & SQLITE_OPEN_CREATE)!=0;
          310  +    flags = pGroup->flags;
          311  +    if( createFlag ){
          312  +      flags |= SQLITE_OPEN_CREATE;
          313  +    }else if( iChunk==0 ){
          314  +      /* Fall through */
          315  +    }else if( pGroup->aReal[iChunk].z==0 ){
          316  +      return 0;
          317  +    }else{
          318  +      *rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[iChunk].z,
          319  +                              SQLITE_ACCESS_EXISTS, &bExists);
          320  +      if( *rc || !bExists ) return 0;
          321  +      flags &= ~SQLITE_OPEN_CREATE;
          322  +    }
   284    323       pSubOpen = sqlite3_malloc( pOrigVfs->szOsFile );
   285    324       if( pSubOpen==0 ){
   286         -      *rc = SQLITE_NOMEM;
          325  +      *rc = SQLITE_IOERR_NOMEM;
   287    326         return 0;
   288    327       }
   289    328       pGroup->aReal[iChunk].p = pSubOpen;
   290    329       *rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen,
   291         -                          pGroup->flags, pOutFlags);
   292         -    if( *rc!=SQLITE_OK ){
          330  +                          flags, pOutFlags);
          331  +    if( (*rc)!=SQLITE_OK ){
   293    332         sqlite3_free(pSubOpen);
   294    333         pGroup->aReal[iChunk].p = 0;
   295    334         return 0;
   296    335       }
   297    336     }
   298    337     return pSubOpen;
   299    338   }
   300    339   
          340  +/*
          341  +** Return the size, in bytes, of chunk number iChunk.  If that chunk
          342  +** does not exist, then return 0.  This function does not distingish between
          343  +** non-existant files and zero-length files.
          344  +*/
          345  +static sqlite3_int64 multiplexSubSize(
          346  +  multiplexGroup *pGroup,    /* The multiplexor group */
          347  +  int iChunk,                /* Which chunk to open.  0==original file */
          348  +  int *rc                    /* Result code in and out */
          349  +){
          350  +  sqlite3_file *pSub;
          351  +  sqlite3_int64 sz = 0;
          352  +
          353  +  pSub = multiplexSubOpen(pGroup, iChunk, rc, NULL, 0);
          354  +  if( pSub==0 ) return 0;
          355  +  *rc = pSub->pMethods->xFileSize(pSub, &sz);
          356  +  return sz;
          357  +}    
          358  +
   301    359   /*
   302    360   ** This is the implementation of the multiplex_control() SQL function.
   303    361   */
   304    362   static void multiplexControlFunc(
   305    363     sqlite3_context *context,
   306    364     int argc,
   307    365     sqlite3_value **argv
................................................................................
   361    419     multiplexGroup *pGroup,
   362    420     int iChunk,
   363    421     sqlite3_vfs *pOrigVfs
   364    422   ){
   365    423     sqlite3_file *pSubOpen = pGroup->aReal[iChunk].p;
   366    424     if( pSubOpen ){
   367    425       pSubOpen->pMethods->xClose(pSubOpen);
   368         -    if( pOrigVfs ) pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
          426  +    if( pOrigVfs && pGroup->aReal[iChunk].z ){
          427  +      pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
          428  +    }
   369    429       sqlite3_free(pGroup->aReal[iChunk].p);
   370    430     }
   371    431     sqlite3_free(pGroup->aReal[iChunk].z);
   372    432     memset(&pGroup->aReal[iChunk], 0, sizeof(pGroup->aReal[iChunk]));
   373    433   }
   374    434   
   375    435   /*
................................................................................
   431    491     }
   432    492   
   433    493     if( rc==SQLITE_OK ){
   434    494       /* assign pointers to extra space allocated */
   435    495       memset(pGroup, 0, sz);
   436    496       pMultiplexOpen->pGroup = pGroup;
   437    497       pGroup->bEnabled = -1;
          498  +    pGroup->bTruncate = (flags & SQLITE_OPEN_MAIN_DB)==0;
   438    499       pGroup->szChunk = SQLITE_MULTIPLEX_CHUNK_SIZE;
   439    500   
   440    501       if( zName ){
   441    502         char *p = (char *)&pGroup[1];
   442    503         if( flags & SQLITE_OPEN_URI ){
   443    504           const char *zChunkSize;
   444    505           zChunkSize = sqlite3_uri_parameter(zName, "chunksize");
................................................................................
   451    512             if( n>0 ){
   452    513               pGroup->szChunk = (n+0xffff)&~0xffff;
   453    514             }else{
   454    515               /* A zero or negative chunksize disabled the multiplexor */
   455    516               pGroup->bEnabled = 0;
   456    517             }
   457    518           }
          519  +        if( sqlite3_uri_parameter(zName, "truncate") ) pGroup->bTruncate = 1;
   458    520         }
   459    521         pGroup->zName = p;
   460    522         memcpy(pGroup->zName, zName, nName+1);
   461    523         pGroup->nName = nName;
          524  +    }
          525  +    if( pGroup->bEnabled ){
          526  +      /* Make sure that the chunksize is not such that the pending byte
          527  +      ** falls at the end of a chunk.  A region of up to 64K following
          528  +      ** the pending byte is never written, so if the pending byte occurs
          529  +      ** near the end of a chunk, that chunk will be too small. */
          530  +      extern int sqlite3PendingByte;
          531  +      while( (sqlite3PendingByte % pGroup->szChunk)>=(pGroup->szChunk-65536) ){
          532  +        pGroup->szChunk += 65536;
          533  +      }
   462    534       }
   463    535       pGroup->flags = flags;
   464    536       rc = multiplexSubFilename(pGroup, 1);
   465    537       if( rc==SQLITE_OK ){
   466         -      pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags);
          538  +      pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags, 0);
          539  +      if( pSubOpen==0 && rc==SQLITE_OK ) rc = SQLITE_CANTOPEN;
   467    540       }
   468         -    if( pSubOpen ){
   469         -      int exists, rc2, rc3;
          541  +    if( rc==SQLITE_OK ){
   470    542         sqlite3_int64 sz;
   471    543   
   472         -      rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
   473         -      if( rc2==SQLITE_OK && zName ){
   474         -        /* If the first overflow file exists and if the size of the main file
   475         -        ** is different from the chunk size, that means the chunk size is set
   476         -        ** set incorrectly.  So fix it.
   477         -        **
   478         -        ** Or, if the first overflow file does not exist and the main file is
   479         -        ** larger than the chunk size, that means the chunk size is too small.
   480         -        ** But we have no way of determining the intended chunk size, so 
   481         -        ** just disable the multiplexor all togethre.
   482         -        */
   483         -        rc3 = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z,
   484         -            SQLITE_ACCESS_EXISTS, &exists);
   485         -        if( rc3==SQLITE_OK && exists && sz==(sz&0xffff0000) && sz>0
   486         -            && sz!=pGroup->szChunk ){
   487         -          pGroup->szChunk = sz;
   488         -        }else if( rc3==SQLITE_OK && !exists && sz>pGroup->szChunk ){
   489         -          pGroup->bEnabled = 0;
          544  +      rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
          545  +      if( rc==SQLITE_OK && zName ){
          546  +        int bExists;
          547  +        if( sz==0 ){
          548  +          if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
          549  +            /* If opening a main journal file and the first chunk is zero
          550  +            ** bytes in size, delete any subsequent chunks from the 
          551  +            ** file-system. */
          552  +            int iChunk = 1;
          553  +            do {
          554  +              rc = pOrigVfs->xAccess(pOrigVfs, 
          555  +                  pGroup->aReal[iChunk].z, SQLITE_ACCESS_EXISTS, &bExists
          556  +              );
          557  +              if( rc==SQLITE_OK && bExists ){
          558  +                rc = pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
          559  +                if( rc==SQLITE_OK ){
          560  +                  rc = multiplexSubFilename(pGroup, ++iChunk);
          561  +                }
          562  +              }
          563  +            }while( rc==SQLITE_OK && bExists );
          564  +          }
          565  +        }else{
          566  +          /* If the first overflow file exists and if the size of the main file
          567  +          ** is different from the chunk size, that means the chunk size is set
          568  +          ** set incorrectly.  So fix it.
          569  +          **
          570  +          ** Or, if the first overflow file does not exist and the main file is
          571  +          ** larger than the chunk size, that means the chunk size is too small.
          572  +          ** But we have no way of determining the intended chunk size, so 
          573  +          ** just disable the multiplexor all togethre.
          574  +          */
          575  +          rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z,
          576  +              SQLITE_ACCESS_EXISTS, &bExists);
          577  +          bExists = multiplexSubSize(pGroup, 1, &rc)>0;
          578  +          if( rc==SQLITE_OK && bExists  && sz==(sz&0xffff0000) && sz>0
          579  +              && sz!=pGroup->szChunk ){
          580  +            pGroup->szChunk = sz;
          581  +          }else if( rc==SQLITE_OK && !bExists && sz>pGroup->szChunk ){
          582  +            pGroup->bEnabled = 0;
          583  +          }
   490    584           }
   491    585         }
          586  +    }
   492    587   
          588  +    if( rc==SQLITE_OK ){
   493    589         if( pSubOpen->pMethods->iVersion==1 ){
   494    590           pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1;
   495    591         }else{
   496    592           pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV2;
   497    593         }
   498    594         /* place this group at the head of our list */
   499    595         pGroup->pNext = gMultiplex.pGroups;
................................................................................
   514    610   ** It attempts to delete the filename specified.
   515    611   */
   516    612   static int multiplexDelete(
   517    613     sqlite3_vfs *pVfs,         /* The multiplex VFS */
   518    614     const char *zName,         /* Name of file to delete */
   519    615     int syncDir
   520    616   ){
          617  +  int rc;
   521    618     sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
   522         -  return pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
          619  +  rc = pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
          620  +  if( rc==SQLITE_OK ){
          621  +    /* If the main chunk was deleted successfully, also delete any subsequent
          622  +    ** chunks - starting with the last (highest numbered). 
          623  +    */
          624  +    int nName = strlen(zName);
          625  +    char *z;
          626  +    z = sqlite3_malloc(nName + 4);
          627  +    if( z==0 ){
          628  +      rc = SQLITE_IOERR_NOMEM;
          629  +    }else{
          630  +      int iChunk = 0;
          631  +      int bExists;
          632  +      do{
          633  +        multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, ++iChunk, z);
          634  +        rc = pOrigVfs->xAccess(pOrigVfs, z, SQLITE_ACCESS_EXISTS, &bExists);
          635  +      }while( rc==SQLITE_OK && bExists );
          636  +      while( rc==SQLITE_OK && iChunk>1 ){
          637  +        multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, --iChunk, z);
          638  +        rc = pOrigVfs->xDelete(pOrigVfs, z, syncDir);
          639  +      }
          640  +    }
          641  +    sqlite3_free(z);
          642  +  }
          643  +  return rc;
   523    644   }
   524    645   
   525    646   static int multiplexAccess(sqlite3_vfs *a, const char *b, int c, int *d){
   526    647     return gMultiplex.pOrigVfs->xAccess(gMultiplex.pOrigVfs, b, c, d);
   527    648   }
   528    649   static int multiplexFullPathname(sqlite3_vfs *a, const char *b, int c, char *d){
   529    650     return gMultiplex.pOrigVfs->xFullPathname(gMultiplex.pOrigVfs, b, c, d);
................................................................................
   592    713     sqlite3_int64 iOfst
   593    714   ){
   594    715     multiplexConn *p = (multiplexConn*)pConn;
   595    716     multiplexGroup *pGroup = p->pGroup;
   596    717     int rc = SQLITE_OK;
   597    718     multiplexEnter();
   598    719     if( !pGroup->bEnabled ){
   599         -    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
          720  +    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
   600    721       if( pSubOpen==0 ){
   601    722         rc = SQLITE_IOERR_READ;
   602    723       }else{
   603    724         rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst);
   604    725       }
   605    726     }else{
   606    727       while( iAmt > 0 ){
   607    728         int i = (int)(iOfst / pGroup->szChunk);
   608         -      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
          729  +      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1);
   609    730         if( pSubOpen ){
   610    731           int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) - pGroup->szChunk;
   611    732           if( extra<0 ) extra = 0;
   612    733           iAmt -= extra;
   613    734           rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt,
   614    735                                          iOfst % pGroup->szChunk);
   615    736           if( rc!=SQLITE_OK ) break;
................................................................................
   637    758     sqlite3_int64 iOfst
   638    759   ){
   639    760     multiplexConn *p = (multiplexConn*)pConn;
   640    761     multiplexGroup *pGroup = p->pGroup;
   641    762     int rc = SQLITE_OK;
   642    763     multiplexEnter();
   643    764     if( !pGroup->bEnabled ){
   644         -    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
          765  +    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
   645    766       if( pSubOpen==0 ){
   646    767         rc = SQLITE_IOERR_WRITE;
   647    768       }else{
   648    769         rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst);
   649    770       }
   650    771     }else{
   651    772       while( rc==SQLITE_OK && iAmt>0 ){
   652    773         int i = (int)(iOfst / pGroup->szChunk);
   653         -      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
          774  +      sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1);
   654    775         if( pSubOpen ){
   655    776           int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) -
   656    777                       pGroup->szChunk;
   657    778           if( extra<0 ) extra = 0;
   658    779           iAmt -= extra;
   659    780           rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt,
   660    781                                           iOfst % pGroup->szChunk);
................................................................................
   674    795   */
   675    796   static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){
   676    797     multiplexConn *p = (multiplexConn*)pConn;
   677    798     multiplexGroup *pGroup = p->pGroup;
   678    799     int rc = SQLITE_OK;
   679    800     multiplexEnter();
   680    801     if( !pGroup->bEnabled ){
   681         -    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
          802  +    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
   682    803       if( pSubOpen==0 ){
   683    804         rc = SQLITE_IOERR_TRUNCATE;
   684    805       }else{
   685    806         rc = pSubOpen->pMethods->xTruncate(pSubOpen, size);
   686    807       }
   687         -  }else if( (pGroup->flags & SQLITE_OPEN_MAIN_DB)==0 ){
   688         -    int rc2;
          808  +  }else{
   689    809       int i;
          810  +    int iBaseGroup = (int)(size / pGroup->szChunk);
   690    811       sqlite3_file *pSubOpen;
   691    812       sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
   692    813       /* delete the chunks above the truncate limit */
   693         -    for(i=(int)(size / pGroup->szChunk)+1; i<pGroup->nReal; i++){
   694         -      multiplexSubClose(pGroup, i, pOrigVfs);
          814  +    for(i = pGroup->nReal-1; i>iBaseGroup && rc==SQLITE_OK; i--){
          815  +      if( pGroup->bTruncate ){
          816  +        multiplexSubClose(pGroup, i, pOrigVfs);
          817  +      }else{
          818  +        pSubOpen = multiplexSubOpen(pGroup, i, &rc, 0, 0);
          819  +        if( pSubOpen ){
          820  +          rc = pSubOpen->pMethods->xTruncate(pSubOpen, 0);
          821  +        }
          822  +      }
   695    823       }
   696         -    pSubOpen = multiplexSubOpen(pGroup, (int)(size/pGroup->szChunk), &rc2,0);
   697         -    if( pSubOpen ){
   698         -      rc2 = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->szChunk);
   699         -      if( rc2!=SQLITE_OK ) rc = rc2;
   700         -    }else{
   701         -      rc = SQLITE_IOERR_TRUNCATE;
          824  +    if( rc==SQLITE_OK ){
          825  +      pSubOpen = multiplexSubOpen(pGroup, iBaseGroup, &rc, 0, 0);
          826  +      if( pSubOpen ){
          827  +        rc = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->szChunk);
          828  +      }
   702    829       }
          830  +    if( rc ) rc = SQLITE_IOERR_TRUNCATE;
   703    831     }
   704    832     multiplexLeave();
   705    833     return rc;
   706    834   }
   707    835   
   708    836   /* Pass xSync requests through to the original VFS without change
   709    837   */
................................................................................
   730    858   static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
   731    859     multiplexConn *p = (multiplexConn*)pConn;
   732    860     multiplexGroup *pGroup = p->pGroup;
   733    861     int rc = SQLITE_OK;
   734    862     int i;
   735    863     multiplexEnter();
   736    864     if( !pGroup->bEnabled ){
   737         -    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
          865  +    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
   738    866       if( pSubOpen==0 ){
   739    867         rc = SQLITE_IOERR_FSTAT;
   740    868       }else{
   741    869         rc = pSubOpen->pMethods->xFileSize(pSubOpen, pSize);
   742    870       }
   743    871     }else{
   744         -    sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;
   745    872       *pSize = 0;
   746    873       for(i=0; rc==SQLITE_OK; i++){
   747         -      sqlite3_file *pSubOpen = 0;
   748         -      int exists = 0;
   749         -      rc = multiplexSubFilename(pGroup, i);
   750         -      if( rc!=SQLITE_OK ) break;
   751         -      if( pGroup->nReal>i && pGroup->aReal[i].p!=0 ){
   752         -        exists = 1;
   753         -      }else if( (pGroup->flags & SQLITE_OPEN_DELETEONCLOSE)==0 ){
   754         -        const char *zReal = pGroup->aReal[i].z;
   755         -        rc = pOrigVfs->xAccess(pOrigVfs, zReal, SQLITE_ACCESS_EXISTS, &exists);
   756         -      }
   757         -      if( exists==0 ){
   758         -        /* stop at first "gap" or IO error. */
   759         -        break;
   760         -      }
   761         -      if( rc==SQLITE_OK ){
   762         -        pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
   763         -      }
   764         -      assert( pSubOpen || rc!=SQLITE_OK );
   765         -      if( rc==SQLITE_OK ){
   766         -        sqlite3_int64 sz = 0;
   767         -        rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
   768         -        if( rc==SQLITE_OK && sz>pGroup->szChunk ){
   769         -          rc = SQLITE_IOERR_FSTAT;
   770         -        }
   771         -        *pSize += sz;
   772         -      }
          874  +      sqlite3_int64 sz = multiplexSubSize(pGroup, i, &rc);
          875  +      if( sz==0 ) break;
          876  +      *pSize = i*(sqlite3_int64)pGroup->szChunk + sz;
   773    877       }
   774    878     }
   775    879     multiplexLeave();
   776    880     return rc;
   777    881   }
   778    882   
   779    883   /* Pass xLock requests through to the original VFS unchanged.
   780    884   */
   781    885   static int multiplexLock(sqlite3_file *pConn, int lock){
   782    886     multiplexConn *p = (multiplexConn*)pConn;
   783    887     int rc;
   784         -  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
          888  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
   785    889     if( pSubOpen ){
   786    890       return pSubOpen->pMethods->xLock(pSubOpen, lock);
   787    891     }
   788    892     return SQLITE_BUSY;
   789    893   }
   790    894   
   791    895   /* Pass xUnlock requests through to the original VFS unchanged.
   792    896   */
   793    897   static int multiplexUnlock(sqlite3_file *pConn, int lock){
   794    898     multiplexConn *p = (multiplexConn*)pConn;
   795    899     int rc;
   796         -  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
          900  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
   797    901     if( pSubOpen ){
   798    902       return pSubOpen->pMethods->xUnlock(pSubOpen, lock);
   799    903     }
   800    904     return SQLITE_IOERR_UNLOCK;
   801    905   }
   802    906   
   803    907   /* Pass xCheckReservedLock requests through to the original VFS unchanged.
   804    908   */
   805    909   static int multiplexCheckReservedLock(sqlite3_file *pConn, int *pResOut){
   806    910     multiplexConn *p = (multiplexConn*)pConn;
   807    911     int rc;
   808         -  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
          912  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
   809    913     if( pSubOpen ){
   810    914       return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut);
   811    915     }
   812    916     return SQLITE_IOERR_CHECKRESERVEDLOCK;
   813    917   }
   814    918   
   815    919   /* Pass xFileControl requests through to the original VFS unchanged,
................................................................................
   849    953         break;
   850    954       case SQLITE_FCNTL_SIZE_HINT:
   851    955       case SQLITE_FCNTL_CHUNK_SIZE:
   852    956         /* no-op these */
   853    957         rc = SQLITE_OK;
   854    958         break;
   855    959       default:
   856         -      pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
          960  +      pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
   857    961         if( pSubOpen ){
   858    962           rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
   859    963           if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
   860    964            *(char**)pArg = sqlite3_mprintf("multiplex/%z", *(char**)pArg);
   861    965           }
   862    966         }
   863    967         break;
................................................................................
   866    970   }
   867    971   
   868    972   /* Pass xSectorSize requests through to the original VFS unchanged.
   869    973   */
   870    974   static int multiplexSectorSize(sqlite3_file *pConn){
   871    975     multiplexConn *p = (multiplexConn*)pConn;
   872    976     int rc;
   873         -  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
          977  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
   874    978     if( pSubOpen && pSubOpen->pMethods->xSectorSize ){
   875    979       return pSubOpen->pMethods->xSectorSize(pSubOpen);
   876    980     }
   877    981     return DEFAULT_SECTOR_SIZE;
   878    982   }
   879    983   
   880    984   /* Pass xDeviceCharacteristics requests through to the original VFS unchanged.
   881    985   */
   882    986   static int multiplexDeviceCharacteristics(sqlite3_file *pConn){
   883    987     multiplexConn *p = (multiplexConn*)pConn;
   884    988     int rc;
   885         -  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
          989  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
   886    990     if( pSubOpen ){
   887    991       return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen);
   888    992     }
   889    993     return 0;
   890    994   }
   891    995   
   892    996   /* Pass xShmMap requests through to the original VFS unchanged.
................................................................................
   896   1000     int iRegion,                    /* Region to retrieve */
   897   1001     int szRegion,                   /* Size of regions */
   898   1002     int bExtend,                    /* True to extend file if necessary */
   899   1003     void volatile **pp              /* OUT: Mapped memory */
   900   1004   ){
   901   1005     multiplexConn *p = (multiplexConn*)pConn;
   902   1006     int rc;
   903         -  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
         1007  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
   904   1008     if( pSubOpen ){
   905   1009       return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend,pp);
   906   1010     }
   907   1011     return SQLITE_IOERR;
   908   1012   }
   909   1013   
   910   1014   /* Pass xShmLock requests through to the original VFS unchanged.
................................................................................
   913   1017     sqlite3_file *pConn,       /* Database file holding the shared memory */
   914   1018     int ofst,                  /* First lock to acquire or release */
   915   1019     int n,                     /* Number of locks to acquire or release */
   916   1020     int flags                  /* What to do with the lock */
   917   1021   ){
   918   1022     multiplexConn *p = (multiplexConn*)pConn;
   919   1023     int rc;
   920         -  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
         1024  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
   921   1025     if( pSubOpen ){
   922   1026       return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags);
   923   1027     }
   924   1028     return SQLITE_BUSY;
   925   1029   }
   926   1030   
   927   1031   /* Pass xShmBarrier requests through to the original VFS unchanged.
   928   1032   */
   929   1033   static void multiplexShmBarrier(sqlite3_file *pConn){
   930   1034     multiplexConn *p = (multiplexConn*)pConn;
   931   1035     int rc;
   932         -  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
         1036  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
   933   1037     if( pSubOpen ){
   934   1038       pSubOpen->pMethods->xShmBarrier(pSubOpen);
   935   1039     }
   936   1040   }
   937   1041   
   938   1042   /* Pass xShmUnmap requests through to the original VFS unchanged.
   939   1043   */
   940   1044   static int multiplexShmUnmap(sqlite3_file *pConn, int deleteFlag){
   941   1045     multiplexConn *p = (multiplexConn*)pConn;
   942   1046     int rc;
   943         -  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
         1047  +  sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
   944   1048     if( pSubOpen ){
   945   1049       return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag);
   946   1050     }
   947   1051     return SQLITE_OK;
   948   1052   }
   949   1053   
   950   1054   /************************** Public Interfaces *****************************/

Changes to src/util.c.

  1165   1165   ** do the suffix shortening regardless of URI parameter.
  1166   1166   **
  1167   1167   ** Examples:
  1168   1168   **
  1169   1169   **     test.db-journal    =>   test.nal
  1170   1170   **     test.db-wal        =>   test.wal
  1171   1171   **     test.db-shm        =>   test.shm
         1172  +**     test.db-mj7f3319fa =>   test.9fa
  1172   1173   */
  1173   1174   void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
  1174   1175   #if SQLITE_ENABLE_8_3_NAMES<2
  1175   1176     const char *zOk;
  1176   1177     zOk = sqlite3_uri_parameter(zBaseFilename, "8_3_names");
  1177   1178     if( zOk && sqlite3GetBoolean(zOk) )
  1178   1179   #endif

Changes to src/vdbeaux.c.

  1829   1829       sqlite3_vfs *pVfs = db->pVfs;
  1830   1830       int needSync = 0;
  1831   1831       char *zMaster = 0;   /* File-name for the master journal */
  1832   1832       char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
  1833   1833       sqlite3_file *pMaster = 0;
  1834   1834       i64 offset = 0;
  1835   1835       int res;
         1836  +    int retryCount = 0;
         1837  +    int nMainFile;
  1836   1838   
  1837   1839       /* Select a master journal file name */
         1840  +    nMainFile = sqlite3Strlen30(zMainFile);
         1841  +    zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XX", zMainFile);
         1842  +    if( zMaster==0 ) return SQLITE_NOMEM;
  1838   1843       do {
  1839   1844         u32 iRandom;
  1840         -      sqlite3DbFree(db, zMaster);
         1845  +      if( retryCount++>100 ){
         1846  +        sqlite3_log(SQLITE_FULL, "cannot find unique master-journal");
         1847  +        sqlite3OsDelete(pVfs, zMaster, 0);
         1848  +        break;
         1849  +      }
  1841   1850         sqlite3_randomness(sizeof(iRandom), &iRandom);
  1842         -      zMaster = sqlite3MPrintf(db, "%s-mj%08X", zMainFile, iRandom&0x7fffffff);
  1843         -      if( !zMaster ){
  1844         -        return SQLITE_NOMEM;
  1845         -      }
         1851  +      sqlite3_snprintf(13, &zMaster[nMainFile], "-mj%06X9%02X",
         1852  +                               (iRandom>>8)&0xffffff, iRandom&0xff);
         1853  +      /* The antipenultimate character of the master journal name must
         1854  +      ** be "9" to avoid name collisions when using 8+3 filenames. */
         1855  +      assert( zMaster[sqlite3Strlen30(zMaster)-3]=='9' );
  1846   1856         sqlite3FileSuffix3(zMainFile, zMaster);
  1847   1857         rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
  1848   1858       }while( rc==SQLITE_OK && res );
  1849   1859       if( rc==SQLITE_OK ){
  1850   1860         /* Open the master journal. */
  1851   1861         rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster, 
  1852   1862             SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|