SQLite

Check-in [3af1feaa35]
Login

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

Overview
Comment:When deleting a file with the multiplexor VFS, also delete any overflow files that exist.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | nx-devkit
Files: files | file ages | folders
SHA1: 3af1feaa35d3fb2e7be550cd32a727001b874938
User & Date: dan 2011-12-15 17:00:10.854
Context
2011-12-16
00:33
Make sure the antipenultimate character of master-journal filenames is a "9" in order to avoid collisions with other files in 8+3 filename mode. Also, limit the number of attempts at finding a unique master-journal filename. (check-in: 34a0483605 user: drh tags: nx-devkit)
2011-12-15
17:00
When deleting a file with the multiplexor VFS, also delete any overflow files that exist. (check-in: 3af1feaa35 user: dan tags: nx-devkit)
13:29
Make sure the chunksize in test_multiplex does not cause the pending byte to fall near the end of a chunk. Adjust the chunksize upward as necessary to prevent this. (check-in: e05f8a2998 user: drh tags: nx-devkit)
Changes
Side-by-Side Diff Ignore Whitespace Patch
Changes to src/test_multiplex.c.
211
212
213
214
215
216
217

































218
219
220
221
222
223
224
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







*/
static int multiplexStrlen30(const char *z){
  const char *z2 = z;
  if( z==0 ) return 0;
  while( *z2 ){ z2++; }
  return 0x3fffffff & (int)(z2 - z);
}

/*
** Generate the file-name for chunk iChunk of the group with base name
** zBase. The file-name is written to buffer zOut before returning. Buffer
** zOut must be allocated by the caller so that it is at least (nBase+4)
** bytes in size, where nBase is the length of zBase, not including the
** nul-terminator.
*/
static void multiplexFilename(
  const char *zBase,              /* Filename for chunk 0 */
  int nBase,                      /* Size of zBase in bytes (without \0) */
  int flags,                      /* Flags used to open file */
  int iChunk,                     /* Chunk to generate filename for */
  char *zOut                      /* Buffer to write generated name to */
){
  memcpy(zOut, zBase, nBase+1);
  if( iChunk!=0 && iChunk!=SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET ){
    int n = nBase;
#ifdef SQLITE_ENABLE_8_3_NAMES
    int i;
    for(i=n-1; i>0 && i>=n-4 && zOut[i]!='.'; i--){}
    if( i>=n-4 ) n = i+1;
    if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
      /* The extensions on overflow files for main databases are 001, 002,
       ** 003 and so forth.  To avoid name collisions, add 400 to the 
       ** extensions of journal files so that they are 401, 402, 403, ....
       */
      iChunk += SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET;
    }
#endif
    sqlite3_snprintf(4,&zOut[n],"%03d",iChunk);
  }
}

/* Compute the filename for the iChunk-th chunk
*/
static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){
  if( iChunk>=pGroup->nReal ){
    struct multiplexReal *p;
    p = sqlite3_realloc(pGroup->aReal, (iChunk+1)*sizeof(*p));
232
233
234
235
236
237
238
239

240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
265
266
267
268
269
270
271

272















273
274
275
276
277
278
279







-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







  if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){
    char *z;
    int n = pGroup->nName;
    pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+4 );
    if( z==0 ){
      return SQLITE_NOMEM;
    }
    memcpy(z, pGroup->zName, n+1);
    multiplexFilename(pGroup->zName, pGroup->nName, pGroup->flags, iChunk, z);
    if( iChunk>0 ){
#ifdef SQLITE_ENABLE_8_3_NAMES
      int i;
      for(i=n-1; i>0 && i>=n-4 && z[i]!='.'; i--){}
      if( i>=n-4 ) n = i+1;
      if( pGroup->flags & (SQLITE_OPEN_MAIN_JOURNAL|SQLITE_OPEN_TEMP_JOURNAL) ){
        /* The extensions on overflow files for main databases are 001, 002,
        ** 003 and so forth.  To avoid name collisions, add 400 to the 
        ** extensions of journal files so that they are 401, 402, 403, ....
        */
        iChunk += SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET;
      }
#endif
      sqlite3_snprintf(4,&z[n],"%03d",iChunk);
    }
  }
  return SQLITE_OK;
}

/* Translate an sqlite3_file* that is really a multiplexGroup* into
** the sqlite3_file* for the underlying original VFS.
*/
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503





































504
505
506
507
508
509
510
497
498
499
500
501
502
503


















504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







      assert( pSubOpen || rc!=SQLITE_OK );
    }
    if( rc==SQLITE_OK ){
      sqlite3_int64 sz;

      rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
      if( rc==SQLITE_OK && zName ){
        int exists;

        /* If the first overflow file exists and if the size of the main file
        ** is different from the chunk size, that means the chunk size is set
        ** set incorrectly.  So fix it.
        **
        ** Or, if the first overflow file does not exist and the main file is
        ** larger than the chunk size, that means the chunk size is too small.
        ** But we have no way of determining the intended chunk size, so 
        ** just disable the multiplexor all togethre.
        */
        rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z,
            SQLITE_ACCESS_EXISTS, &exists);
        if( rc==SQLITE_OK && exists && sz==(sz&0xffff0000) && sz>0
            && sz!=pGroup->szChunk ){
          pGroup->szChunk = sz;
        }else if( rc==SQLITE_OK && !exists && sz>pGroup->szChunk ){
          pGroup->bEnabled = 0;
        int bExists;
        if( sz==0 ){
          if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
            /* If opening a main journal file and the first chunk is zero
            ** bytes in size, delete any subsequent chunks from the 
            ** file-system. */
            int iChunk = 1;
            do {
              rc = pOrigVfs->xAccess(pOrigVfs, 
                  pGroup->aReal[iChunk].z, SQLITE_ACCESS_EXISTS, &bExists
              );
              if( rc==SQLITE_OK && bExists ){
                rc = pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
                if( rc==SQLITE_OK ){
                  rc = multiplexSubFilename(pGroup, ++iChunk);
                }
              }
            }while( rc==SQLITE_OK && bExists );
          }
        }else{
          /* If the first overflow file exists and if the size of the main file
           ** is different from the chunk size, that means the chunk size is set
           ** set incorrectly.  So fix it.
           **
           ** Or, if the first overflow file does not exist and the main file is
           ** larger than the chunk size, that means the chunk size is too small.
           ** But we have no way of determining the intended chunk size, so 
           ** just disable the multiplexor all togethre.
           */
          rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z,
              SQLITE_ACCESS_EXISTS, &bExists);
          if( rc==SQLITE_OK && bExists && sz==(sz&0xffff0000) && sz>0
              && sz!=pGroup->szChunk ){
            pGroup->szChunk = sz;
          }else if( rc==SQLITE_OK && !bExists && sz>pGroup->szChunk ){
            pGroup->bEnabled = 0;
          }
        }
      }
    }

    if( rc==SQLITE_OK ){
      if( pSubOpen->pMethods->iVersion==1 ){
        pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1;
530
531
532
533
534
535
536

537
538

























539
540
541
542
543
544
545
567
568
569
570
571
572
573
574
575

576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607







+

-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







** It attempts to delete the filename specified.
*/
static int multiplexDelete(
  sqlite3_vfs *pVfs,         /* The multiplex VFS */
  const char *zName,         /* Name of file to delete */
  int syncDir
){
  int rc;
  sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
  return pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
  rc = pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
  if( rc==SQLITE_OK ){
    /* If the main chunk was deleted successfully, also delete any subsequent
    ** chunks - starting with the last (highest numbered). 
    */
    int nName = strlen(zName);
    char *z;
    z = sqlite3_malloc(nName + 4);
    if( z==0 ){
      rc = SQLITE_IOERR_NOMEM;
    }else{
      int iChunk = 0;
      int bExists;
      do{
        multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, ++iChunk, z);
        rc = pOrigVfs->xAccess(pOrigVfs, z, SQLITE_ACCESS_EXISTS, &bExists);
      }while( rc==SQLITE_OK && bExists );
      while( rc==SQLITE_OK && iChunk>1 ){
        multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, --iChunk, z);
        rc = pOrigVfs->xDelete(pOrigVfs, z, syncDir);
      }
    }
    sqlite3_free(z);
  }
  return rc;
}

static int multiplexAccess(sqlite3_vfs *a, const char *b, int c, int *d){
  return gMultiplex.pOrigVfs->xAccess(gMultiplex.pOrigVfs, b, c, d);
}
static int multiplexFullPathname(sqlite3_vfs *a, const char *b, int c, char *d){
  return gMultiplex.pOrigVfs->xFullPathname(gMultiplex.pOrigVfs, b, c, d);