]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
In-progress changes - do not use; Removed prefix support; Added file control interfac...
authorshaneh <shaneh@noemail.net>
Tue, 29 Mar 2011 05:06:46 +0000 (05:06 +0000)
committershaneh <shaneh@noemail.net>
Tue, 29 Mar 2011 05:06:46 +0000 (05:06 +0000)
added app-def function for same;

FossilOrigin-Name: bc02d0c193225bd49a8d8a3295aeac752d3c2e30

manifest
manifest.uuid
src/test_multiplex.c
src/test_multiplex.h [new file with mode: 0644]
test/multiplex.test

index 5ec64793db79bc90f5b2eb57b33da139f1bbd112..f83b7c380fe220e068b9fc59830c77c58c53c376 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Allow\smultiplex\sfile\snames\sto\sbe\spreceeded\sby\sprefix\sof\sthe\sform\s":multiplex:chunksize:maxchunks:"\s\nStill\swork\sto\sbe\sdone,\sthough\sit\scompiles\sand\sprefixes\sare\signored.
-D 2011-03-15T04:45:48.735
+C In-progress\schanges\s-\sdo\snot\suse;\sRemoved\sprefix\ssupport;\sAdded\sfile\scontrol\sinterface\sto\senable/disable\sand\sadjust\schunk\ssize;\nadded\sapp-def\sfunction\sfor\ssame;
+D 2011-03-29T05:06:46.821
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -209,7 +209,8 @@ F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
 F src/test_journal.c 785edd54f963aefb3c1628124170a56697c68c70
 F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
 F src/test_malloc.c fd6188b1501c0010fb4241ddc9f0d5ac402c688d
-F src/test_multiplex.c cf01141845d29639de2b6cdd6d7ef9dc0bce2888
+F src/test_multiplex.c 234f4b371d1a2ba88041e17c21e13f5273dd1b50
+F src/test_multiplex.h 22238a3286817918f1975a7c523827ea45d9fbb4
 F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e
 F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
 F src/test_osinst.c f408c6a181f2fb04c56273afd5c3e1e82f60392c
@@ -575,7 +576,7 @@ F test/misc5.test 45b2e3ed5f79af2b4f38ae362eaf4c49674575bd
 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
 F test/misc7.test 29032efcd3d826fbd409e2a7af873e7939f4a4e3
 F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
-F test/multiplex.test 92a4839213fd8cba8b59f86d42b7a1da1857db39
+F test/multiplex.test b813d11f2cd6a15c64d85b97c0c009afc2168226
 F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41
 F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
 F test/nan.test a44e04df1486fcfb02d32468cbcd3c8e1e433723
@@ -913,10 +914,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P def98fd23e42bda13547e38ab13fed0e6554ce99
-R 324244b8e2a2e32cd06c5dbee5aab290
-T *branch * experimental
-T *sym-experimental *
-T -sym-trunk *
+P cfa4a2f7ea948be0925227efca82baea509249c9
+R cd848b3ee75fe87902bd71c01c78919c
 U shaneh
-Z b5732ca362c3f4ec7a64142aa2707561
+Z 7951456e7d17419744e4f948b8232fcd
index ad05a9f286d0a81d6706fd81f091d41451bf7377..9ab9b53bfec4dce69cf3805f279aeef250832ecf 100644 (file)
@@ -1 +1 @@
-cfa4a2f7ea948be0925227efca82baea509249c9
\ No newline at end of file
+bc02d0c193225bd49a8d8a3295aeac752d3c2e30
\ No newline at end of file
index 694f7b4cb6b37f14e2ed478039039a7e4e52389d..3855050eddf4357a9bac3fc95efca35692a2d0c2 100644 (file)
 #include <string.h>
 #include <assert.h>
 #include "sqliteInt.h"
+#include "test_multiplex.h"
+
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
 
 /*
 ** For a build without mutexes, no-op the mutex calls.
 #define SQLITE_MULTIPLEX_VFS_NAME "multiplex"
 
 /* This is the limit on the chunk size.  It may be changed by calling
-** the sqlite3_multiplex_set() interface.
+** the xFileControl() interface.
 */
 #define SQLITE_MULTIPLEX_CHUNK_SIZE 0x40000000
 /* Default limit on number of chunks.  Care should be taken
 ** so that values for chunks numbers fit in the SQLITE_MULTIPLEX_EXT_FMT
 ** format specifier. It may be changed by calling
-** the sqlite3_multiplex_set() interface.
+** the xFileControl() interface.
 */
 #define SQLITE_MULTIPLEX_MAX_CHUNKS 32
 
@@ -84,6 +88,9 @@ struct multiplexGroup {
   char *zName;                     /* Base filename of this group */
   int nName;                       /* Length of base filename */
   int flags;                       /* Flags used for original opening */
+  int nChunkSize;                  /* Chunk size used for this group */
+  int nMaxChunks;                  /* Max number of chunks for this group */
+  int bEnabled;                    /* TRUE to use Multiplex VFS for this file */
   multiplexGroup *pNext, *pPrev;   /* Doubly linked list of all group objects */
 };
 
@@ -142,11 +149,6 @@ static struct {
   */
   multiplexGroup *pGroups;
 
-  /* Chunk params.
-  */
-  int nChunkSize;
-  int nMaxChunks;
-
   /* Storage for temp file names.  Allocated during 
   ** initialization to the max pathname of the underlying VFS.
   */
@@ -168,7 +170,7 @@ static void multiplexLeave(void){ sqlite3_mutex_leave(gMultiplex.pMutex); }
 static sqlite3_file *multiplexSubOpen(multiplexConn *pConn, int iChunk, int *rc, int *pOutFlags){
   multiplexGroup *pGroup = pConn->pGroup;
   sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;        /* Real VFS */
-  if( iChunk<gMultiplex.nMaxChunks ){
+  if( iChunk<pGroup->nMaxChunks ){
     sqlite3_file *pSubOpen = pGroup->pReal[iChunk];    /* Real file descriptor */
     if( !pGroup->bOpen[iChunk] ){
       memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
@@ -193,51 +195,34 @@ static sqlite3_file *multiplexSubOpen(multiplexConn *pConn, int iChunk, int *rc,
   return NULL;
 }
 
-/*
-** If the given filename begins with a valid multiplex prefix, return
-** a pointer to the first character past the prefix.  Otherwise
-** return NULL pointer.  If optional chunk size and max chunk
-** values found, return them in int pointers.
-*/
-static const char *multiplexParsePrefix(const char *zName, int *pChunkSize, int *pMaxChunks){
-  int i;
-  int nChunkSize = 0;
-  int nMaxChunks = 0;
-  int lenPrefix = sqlite3Strlen30(SQLITE_MULTIPLEX_VFS_NAME)+2;
-  if( strncmp(zName, ":"SQLITE_MULTIPLEX_VFS_NAME":", lenPrefix)!=0 ) return 0;
-  /* if :multiplex: followed by ':' terminated string of digits, use
-  ** that value for the chunk size. */
-  for(i=lenPrefix; sqlite3Isdigit(zName[i]); i++){ }
-  if ( zName[i]==':' ){
-    if( pChunkSize ){
-      if( sqlite3GetInt32(&zName[lenPrefix], &nChunkSize) ){
-         *pChunkSize = nChunkSize;
-      }
-    }
-    lenPrefix = i+1;
-    /* if chunksize followed by ':' terminated string of digits, use
-    ** that value for the max chunks. */
-    for(i=lenPrefix; sqlite3Isdigit(zName[i]); i++){ }
-    if ( zName[i]==':' ) {
-      if( pMaxChunks ){
-        if( sqlite3GetInt32(&zName[lenPrefix], &nMaxChunks) ){
-           *pMaxChunks = nMaxChunks;
-        }
-      }
-      lenPrefix = i+1;
-    }
+static void multiplexControlFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  extern const char *sqlite3TestErrorName(int);
+  extern int multiplexFileControl(sqlite3_file *, int, void *);
+  sqlite3_file *db = (sqlite3_file *)sqlite3_user_data(context);
+  int op = sqlite3_value_int(argv[0]);
+  int iVal = sqlite3_value_int(argv[1]);
+  int rc = multiplexFileControl(db, op, &iVal);
+  if( rc== 0 ){
+    sqlite3_result_text(context, (char *)sqlite3TestErrorName(rc), -1, SQLITE_TRANSIENT);
   }
-  return &zName[lenPrefix];
+  sqlite3_result_text(context, (char *)sqlite3TestErrorName(rc), -1, SQLITE_TRANSIENT);
 }
 
 /*
-** If the given filename that may or may not begin with a CEROD prefix, return
-** a pointer to the first character of the filename past the prefix.
+** This is the entry point to register the extension for the multiplex_control() function.
 */
-static const char *multiplexRootFilename(const char *zName){
-  const char *zRoot = multiplexParsePrefix(zName, NULL, NULL);
-  if( zRoot==0 ) zRoot = zName;
-  return zRoot;
+static int multiplexFuncInit(
+  sqlite3 *db, 
+  char **pzErrMsg, 
+  const sqlite3_api_routines *pApi
+){
+  sqlite3_create_function(db, "multiplex_control", 2, SQLITE_ANY, 
+    db, multiplexControlFunc, 0, 0);
+  return 0;
 }
 
 /************************* VFS Method Wrappers *****************************/
@@ -274,9 +259,9 @@ static int multiplexOpen(
   pMultiplexOpen = (multiplexConn*)pConn;
   /* allocate space for group */
   sz = sizeof(multiplexGroup)                         /* multiplexGroup */
-     + (sizeof(sqlite3_file *)*gMultiplex.nMaxChunks) /* pReal[] */
-     + (pOrigVfs->szOsFile*gMultiplex.nMaxChunks)     /* *pReal */
-     + gMultiplex.nMaxChunks                          /* bOpen[] */
+     + (sizeof(sqlite3_file *)*SQLITE_MULTIPLEX_MAX_CHUNKS)    /* pReal[] */
+     + (pOrigVfs->szOsFile*SQLITE_MULTIPLEX_MAX_CHUNKS)        /* *pReal */
+     + SQLITE_MULTIPLEX_MAX_CHUNKS                             /* bOpen[] */
      + nName + 1;                                     /* zName */
 #ifndef SQLITE_MULTIPLEX_EXT_OVWR
   sz += SQLITE_MULTIPLEX_EXT_SZ;
@@ -293,14 +278,17 @@ static int multiplexOpen(
     char *p = (char *)&pGroup[1];
     pMultiplexOpen->pGroup = pGroup;
     memset(pGroup, 0, sz);
+    pGroup->nChunkSize = SQLITE_MULTIPLEX_CHUNK_SIZE;
+    pGroup->nMaxChunks = SQLITE_MULTIPLEX_MAX_CHUNKS;
     pGroup->pReal = (sqlite3_file **)p;
-    p += (sizeof(sqlite3_file *)*gMultiplex.nMaxChunks);
-    for(i=0; i<gMultiplex.nMaxChunks; i++){
+    p += (sizeof(sqlite3_file *)*pGroup->nMaxChunks);
+    for(i=0; i<pGroup->nMaxChunks; i++){
       pGroup->pReal[i] = (sqlite3_file *)p;
       p += pOrigVfs->szOsFile;
     }
+    /* bOpen[] vals should all be zero from memset above */
     pGroup->bOpen = p;
-    p += gMultiplex.nMaxChunks;
+    p += pGroup->nMaxChunks;
     pGroup->zName = p;
     /* save off base filename, name length, and original open flags  */
     memcpy(pGroup->zName, zName, nName+1);
@@ -344,7 +332,7 @@ static int multiplexDelete(
 
   multiplexEnter();
   memcpy(gMultiplex.zName, zName, nName+1);
-  for(i=0; i<gMultiplex.nMaxChunks; i++){
+  for(i=0; i<SQLITE_MULTIPLEX_MAX_CHUNKS; i++){
     int rc2;
     int exists = 0;
     if( i ){
@@ -354,10 +342,10 @@ static int multiplexDelete(
         sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, gMultiplex.zName+nName, SQLITE_MULTIPLEX_EXT_FMT, i);
 #endif
     }
-    rc2 = pOrigVfs->xAccess(pOrigVfs, multiplexRootFilename(gMultiplex.zName), SQLITE_ACCESS_EXISTS, &exists);
+    rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName, SQLITE_ACCESS_EXISTS, &exists);
     if( rc2==SQLITE_OK && exists){
       /* if it exists, delete it */
-      rc2 = pOrigVfs->xDelete(pOrigVfs, multiplexRootFilename(gMultiplex.zName), syncDir);
+      rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, syncDir);
       if( rc2!=SQLITE_OK ) rc = rc2;
     }else{
       /* stop at first "gap" */
@@ -368,19 +356,11 @@ static int multiplexDelete(
   return rc;
 }
 
-static int multiplexAccess(sqlite3_vfs *pVfs, const char *zName,int flgs,int *pOut){
-  return gMultiplex.pOrigVfs->xAccess(gMultiplex.pOrigVfs, multiplexRootFilename(zName), flgs, pOut);
+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 *pVfs, const char *zName, int nOut, char *zOut){
-  int n;
-  const char *zBase;
-  zBase = multiplexParsePrefix(zName, NULL, NULL);
-  if( zBase==0 ){
-    return gMultiplex.pOrigVfs->xFullPathname(gMultiplex.pOrigVfs, zName, nOut, zOut);
-  }
-  n = (int)(zBase - zName);
-  memcpy(zOut, zName, n);
-  return gMultiplex.pOrigVfs->xFullPathname(gMultiplex.pOrigVfs, zBase, nOut - n, &zOut[n]);
+static int multiplexFullPathname(sqlite3_vfs *a, const char *b, int c, char *d){
+  return gMultiplex.pOrigVfs->xFullPathname(gMultiplex.pOrigVfs, b, c, d);
 }
 static void *multiplexDlOpen(sqlite3_vfs *a, const char *b){
   return gMultiplex.pOrigVfs->xDlOpen(gMultiplex.pOrigVfs, b);
@@ -424,7 +404,7 @@ static int multiplexClose(sqlite3_file *pConn){
   int i;
   multiplexEnter();
   /* close any open handles */
-  for(i=0; i<gMultiplex.nMaxChunks; i++){
+  for(i=0; i<pGroup->nMaxChunks; i++){
     if( pGroup->bOpen[i] ){
       sqlite3_file *pSubOpen = pGroup->pReal[i];
       int rc2 = pSubOpen->pMethods->xClose(pSubOpen);
@@ -455,16 +435,17 @@ static int multiplexRead(
   sqlite3_int64 iOfst
 ){
   multiplexConn *p = (multiplexConn*)pConn;
+  multiplexGroup *pGroup = p->pGroup;
   int rc = SQLITE_OK;
   multiplexEnter();
   while( iAmt > 0 ){
-    int i = (int)(iOfst/gMultiplex.nChunkSize);
+    int i = (int)(iOfst / pGroup->nChunkSize);
     sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
     if( pSubOpen ){
-      int extra = ((int)(iOfst % gMultiplex.nChunkSize) + iAmt) - gMultiplex.nChunkSize;
+      int extra = ((int)(iOfst % pGroup->nChunkSize) + iAmt) - pGroup->nChunkSize;
       if( extra<0 ) extra = 0;
       iAmt -= extra;
-      rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst%gMultiplex.nChunkSize);
+      rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst % pGroup->nChunkSize);
       if( rc!=SQLITE_OK ) break;
       pBuf = (char *)pBuf + iAmt;
       iOfst += iAmt;
@@ -489,16 +470,17 @@ static int multiplexWrite(
   sqlite3_int64 iOfst
 ){
   multiplexConn *p = (multiplexConn*)pConn;
+  multiplexGroup *pGroup = p->pGroup;
   int rc = SQLITE_OK;
   multiplexEnter();
   while( iAmt > 0 ){
-    int i = (int)(iOfst/gMultiplex.nChunkSize);
+    int i = (int)(iOfst / pGroup->nChunkSize);
     sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
     if( pSubOpen ){
-      int extra = ((int)(iOfst % gMultiplex.nChunkSize) + iAmt) - gMultiplex.nChunkSize;
+      int extra = ((int)(iOfst % pGroup->nChunkSize) + iAmt) - pGroup->nChunkSize;
       if( extra<0 ) extra = 0;
       iAmt -= extra;
-      rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst%gMultiplex.nChunkSize);
+      rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst % pGroup->nChunkSize);
       if( rc!=SQLITE_OK ) break;
       pBuf = (char *)pBuf + iAmt;
       iOfst += iAmt;
@@ -527,7 +509,7 @@ static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){
   multiplexEnter();
   memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
   /* delete the chunks above the truncate limit */
-  for(i=(int)(size/gMultiplex.nChunkSize)+1; i<gMultiplex.nMaxChunks; i++){
+  for(i=(int)(size / pGroup->nChunkSize)+1; i<pGroup->nMaxChunks; i++){
     /* close any open chunks before deleting them */
     if( pGroup->bOpen[i] ){
       pSubOpen = pGroup->pReal[i];
@@ -540,12 +522,12 @@ static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){
 #else
     sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, gMultiplex.zName+pGroup->nName, SQLITE_MULTIPLEX_EXT_FMT, i);
 #endif
-    rc2 = pOrigVfs->xDelete(pOrigVfs, multiplexRootFilename(gMultiplex.zName), 0);
+    rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, 0);
     if( rc2!=SQLITE_OK ) rc = SQLITE_IOERR_TRUNCATE;
   }
-  pSubOpen = multiplexSubOpen(p, (int)(size/gMultiplex.nChunkSize), &rc2, NULL);
+  pSubOpen = multiplexSubOpen(p, (int)(size / pGroup->nChunkSize), &rc2, NULL);
   if( pSubOpen ){
-    rc2 = pSubOpen->pMethods->xTruncate(pSubOpen, size%gMultiplex.nChunkSize);
+    rc2 = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->nChunkSize);
     if( rc2!=SQLITE_OK ) rc = rc2;
   }else{
     rc = SQLITE_IOERR_TRUNCATE;
@@ -562,7 +544,7 @@ static int multiplexSync(sqlite3_file *pConn, int flags){
   int rc = SQLITE_OK;
   int i;
   multiplexEnter();
-  for(i=0; i<gMultiplex.nMaxChunks; i++){
+  for(i=0; i<pGroup->nMaxChunks; i++){
     /* if we don't have it open, we don't need to sync it */
     if( pGroup->bOpen[i] ){
       sqlite3_file *pSubOpen = pGroup->pReal[i];
@@ -585,7 +567,7 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
   int i;
   multiplexEnter();
   *pSize = 0;
-  for(i=0; i<gMultiplex.nMaxChunks; i++){
+  for(i=0; i<pGroup->nMaxChunks; i++){
     sqlite3_file *pSubOpen = NULL;
     /* if not opened already, check to see if the chunk exists */
     if( pGroup->bOpen[i] ){
@@ -601,7 +583,7 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
         sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, gMultiplex.zName+pGroup->nName, SQLITE_MULTIPLEX_EXT_FMT, i);
 #endif
       }
-      rc2 = pOrigVfs->xAccess(pOrigVfs, multiplexRootFilename(gMultiplex.zName), SQLITE_ACCESS_EXISTS, &exists);
+      rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName, SQLITE_ACCESS_EXISTS, &exists);
       if( rc2==SQLITE_OK && exists){
         /* if it exists, open it */
         pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
@@ -616,7 +598,7 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
       if( rc2!=SQLITE_OK ){
         rc = rc2;
       }else{
-        if( sz>gMultiplex.nChunkSize ){
+        if( sz>pGroup->nChunkSize ){
           rc = SQLITE_IOERR_FSTAT;
         }
         *pSize += sz;
@@ -669,14 +651,49 @@ static int multiplexCheckReservedLock(sqlite3_file *pConn, int *pResOut){
 */
 static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
   multiplexConn *p = (multiplexConn*)pConn;
-  int rc;
+  multiplexGroup *pGroup = p->pGroup;
+  int rc = SQLITE_ERROR;
   sqlite3_file *pSubOpen;
-  if ( op==SQLITE_FCNTL_SIZE_HINT || op==SQLITE_FCNTL_CHUNK_SIZE ) return SQLITE_OK;
+
+  if( !gMultiplex.isInitialized ) return SQLITE_MISUSE;
+  switch( op ){
+    case MULTIPLEX_CTRL_ENABLE:
+      if( pArg ) {
+        int bEnabled = *(int *)pArg;
+        pGroup->bEnabled = bEnabled;
+        rc = SQLITE_OK;
+      }
+      break;
+    case MULTIPLEX_CTRL_SET_CHUNK_SIZE:
+      if( pArg ) {
+        int nChunkSize = *(int *)pArg;
+        if( nChunkSize<32 ){ 
+          rc = SQLITE_MISUSE;
+        }else{
+          pGroup->nChunkSize = nChunkSize;
+          rc = SQLITE_OK;
+        }
+      }
+      break;
+    case MULTIPLEX_CTRL_SET_MAX_CHUNKS:
+      if( pArg ) {
+        int nMaxChunks = *(int *)pArg;
+        if(( nMaxChunks<1 ) || ( nMaxChunks>99 )){
+          rc = SQLITE_MISUSE;
+        }else{
+          pGroup->nMaxChunks = nMaxChunks;
+          rc = SQLITE_OK;
+        }
+      }
+      break;
+    default:
   pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
   if( pSubOpen ){
-    return pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
+        rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
   }
-  return SQLITE_ERROR;
+      break;
+  }
+  return rc;
 }
 
 /* Pass xSectorSize requests through to the original VFS unchanged.
@@ -788,8 +805,6 @@ int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){
     sqlite3_mutex_free(gMultiplex.pMutex);
     return SQLITE_NOMEM;
   }
-  gMultiplex.nChunkSize = SQLITE_MULTIPLEX_CHUNK_SIZE;
-  gMultiplex.nMaxChunks = SQLITE_MULTIPLEX_MAX_CHUNKS;
   gMultiplex.pGroups = NULL;
   gMultiplex.isInitialized = 1;
   gMultiplex.pOrigVfs = pOrigVfs;
@@ -830,6 +845,9 @@ int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){
   gMultiplex.sIoMethodsV2.xShmBarrier = multiplexShmBarrier;
   gMultiplex.sIoMethodsV2.xShmUnmap = multiplexShmUnmap;
   sqlite3_vfs_register(&gMultiplex.sThisVfs, makeDefault);
+
+  sqlite3_auto_extension((void*)multiplexFuncInit);
+
   return SQLITE_OK;
 }
 
@@ -853,33 +871,10 @@ int sqlite3_multiplex_shutdown(void){
   return SQLITE_OK;
 }
 
-/*
-** Adjust chunking params.  VFS should be initialized first.
-** No files should be open.  Re-intializing will reset these
-** to the default.
-*/
-int sqlite3_multiplex_set(
-  int nChunkSize,                 /* Max chunk size */
-  int nMaxChunks                  /* Max number of chunks */
-){
-  if( !gMultiplex.isInitialized ) return SQLITE_MISUSE;
-  if( gMultiplex.pGroups ) return SQLITE_MISUSE;
-  if( nChunkSize<32 ) return SQLITE_MISUSE;
-  if( nMaxChunks<1 ) return SQLITE_MISUSE;
-  if( nMaxChunks>99 ) return SQLITE_MISUSE;
-  multiplexEnter();
-  gMultiplex.nChunkSize = nChunkSize;
-  gMultiplex.nMaxChunks = nMaxChunks;
-  multiplexLeave();
-  return SQLITE_OK;
-}
-
 /***************************** Test Code ***********************************/
 #ifdef SQLITE_TEST
 #include <tcl.h>
 
-extern const char *sqlite3TestErrorName(int);
-
 
 /*
 ** tclcmd: sqlite3_multiplex_initialize NAME MAKEDEFAULT
@@ -937,36 +932,6 @@ static int test_multiplex_shutdown(
   return TCL_OK;
 }
 
-/*
-** tclcmd: sqlite3_multiplex_set CHUNK_SIZE MAX_CHUNKS
-*/
-static int test_multiplex_set(
-  void * clientData,
-  Tcl_Interp *interp,
-  int objc,
-  Tcl_Obj *CONST objv[]
-){
-  int nChunkSize;                 /* Max chunk size */
-  int nMaxChunks;                 /* Max number of chunks */
-  int rc;                         /* Value returned by sqlite3_multiplex_set() */
-
-  UNUSED_PARAMETER(clientData);
-
-  /* Process arguments */
-  if( objc!=3 ){
-    Tcl_WrongNumArgs(interp, 1, objv, "CHUNK_SIZE MAX_CHUNKS");
-    return TCL_ERROR;
-  }
-  if( Tcl_GetIntFromObj(interp, objv[1], &nChunkSize) ) return TCL_ERROR;
-  if( Tcl_GetIntFromObj(interp, objv[2], &nMaxChunks) ) return TCL_ERROR;
-
-  /* Invoke sqlite3_multiplex_set() */
-  rc = sqlite3_multiplex_set(nChunkSize, nMaxChunks);
-
-  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
-  return TCL_OK;
-}
-
 /*
 ** tclcmd:  sqlite3_multiplex_dump
 */
@@ -1000,16 +965,16 @@ static int test_multiplex_dump(
           Tcl_NewIntObj(pGroup->flags));
 
     /* count number of chunks with open handles */
-    for(i=0; i<gMultiplex.nMaxChunks; i++){
+    for(i=0; i<pGroup->nMaxChunks; i++){
       if( pGroup->bOpen[i] ) nChunks++;
     }
     Tcl_ListObjAppendElement(interp, pGroupTerm,
           Tcl_NewIntObj(nChunks));
 
     Tcl_ListObjAppendElement(interp, pGroupTerm,
-          Tcl_NewIntObj(gMultiplex.nChunkSize));
+          Tcl_NewIntObj(pGroup->nChunkSize));
     Tcl_ListObjAppendElement(interp, pGroupTerm,
-          Tcl_NewIntObj(gMultiplex.nMaxChunks));
+          Tcl_NewIntObj(pGroup->nMaxChunks));
 
     Tcl_ListObjAppendElement(interp, pResult, pGroupTerm);
   }
@@ -1018,6 +983,72 @@ static int test_multiplex_dump(
   return TCL_OK;
 }
 
+/*
+** Tclcmd: test_multiplex_control HANDLE DBNAME SUB-COMMAND ?INT-VALUE?
+*/
+static int test_multiplex_control(
+  ClientData cd,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  int rc;                         /* Return code from file_control() */
+  int idx;                        /* Index in aSub[] */
+  Tcl_CmdInfo cmdInfo;            /* Command info structure for HANDLE */
+  sqlite3 *db;                    /* Underlying db handle for HANDLE */
+  int iValue = 0;
+  void *pArg = 0;
+
+  struct SubCommand {
+    const char *zName;
+    int op;
+    int argtype;
+  } aSub[] = {
+    { "enable",       MULTIPLEX_CTRL_ENABLE,           1 },
+    { "chunk_size",   MULTIPLEX_CTRL_SET_CHUNK_SIZE,   1 },
+    { "max_chunks",   MULTIPLEX_CTRL_SET_MAX_CHUNKS,   1 },
+    { 0, 0, 0 }
+  };
+
+  if( objc!=4 && objc!=5 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "HANDLE DBNAME SUB-COMMAND ?INT-VALUE?");
+    return TCL_ERROR;
+  }
+
+  if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
+    Tcl_AppendResult(interp, "expected database handle, got \"", 0);
+    Tcl_AppendResult(interp, Tcl_GetString(objv[1]), "\"", 0);
+    return TCL_ERROR;
+  }else{
+    db = *(sqlite3 **)cmdInfo.objClientData;
+  }
+
+  rc = Tcl_GetIndexFromObjStruct(
+      interp, objv[3], aSub, sizeof(aSub[0]), "sub-command", 0, &idx
+  );
+  if( rc!=TCL_OK ) return rc;
+
+  switch( aSub[idx].argtype ){
+    case 1:
+      if( objc!=5 ){
+        Tcl_WrongNumArgs(interp, 4, objv, "INT-VALUE");
+        return TCL_ERROR;
+      }
+      if( Tcl_GetIntFromObj(interp, objv[4], &iValue) ){
+        return TCL_ERROR;
+      }
+      pArg = (void *)&iValue;
+      break;
+    default:
+      Tcl_WrongNumArgs(interp, 4, objv, "SUB-COMMAND");
+      return TCL_ERROR;
+  }
+
+  rc = sqlite3_file_control(db, Tcl_GetString(objv[2]), aSub[idx].op, pArg);
+  Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
+  return (rc==SQLITE_OK) ? TCL_OK : TCL_ERROR;
+}
+
 /*
 ** This routine registers the custom TCL commands defined in this
 ** module.  This should be the only procedure visible from outside
@@ -1030,8 +1061,8 @@ int Sqlitemultiplex_Init(Tcl_Interp *interp){
   } aCmd[] = {
     { "sqlite3_multiplex_initialize", test_multiplex_initialize },
     { "sqlite3_multiplex_shutdown", test_multiplex_shutdown },
-    { "sqlite3_multiplex_set", test_multiplex_set },
     { "sqlite3_multiplex_dump", test_multiplex_dump },
+    { "sqlite3_multiplex_control", test_multiplex_control },
   };
   int i;
 
diff --git a/src/test_multiplex.h b/src/test_multiplex.h
new file mode 100644 (file)
index 0000000..cc56ee9
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+** 2011 March 18
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file contains a VFS "shim" - a layer that sits in between the
+** pager and the real VFS.
+**
+** This particular shim enforces a multiplex system on DB files.  
+** This shim shards/partitions a single DB file into smaller 
+** "chunks" such that the total DB file size may exceed the maximum
+** file size of the underlying file system.
+**
+*/
+
+#ifndef _TEST_MULTIPLEX_H
+#define _TEST_MULTIPLEX_H
+
+/*
+** CAPI: File-control Operations Supported by Multiplex VFS
+**
+** Values interpreted by the xFileControl method of a Multiplex VFS db file-handle.
+**
+** MULTIPLEX_CTRL_ENABLE:
+**   This file control is used to enable or disable the multiplex
+**   shim.
+**
+** MULTIPLEX_CTRL_SET_CHUNK_SIZE:
+**   This file control is used to set the maximum allowed chunk 
+**   size for a multiplex file set.
+**
+** MULTIPLEX_CTRL_SET_MAX_CHUNKS:
+**   This file control is used to set the maximum number of chunks
+**   allowed to be used for a mutliplex file set.
+*/
+#define MULTIPLEX_CTRL_ENABLE          214014
+#define MULTIPLEX_CTRL_SET_CHUNK_SIZE  214015
+#define MULTIPLEX_CTRL_SET_MAX_CHUNKS  214016
+
+
+#endif
index 742ca5079e230b61916c5b5740b86c17d503090f..582f71eabefcc450d5d9196a990be697a56ea557 100644 (file)
@@ -32,13 +32,17 @@ proc multiplex_name {name chunk} {
 }
 
 # This saves off the parameters and calls the 
-# underlying sqlite3_multiplex_set() API.
-proc multiplex_set {chunk_size max_chunks} {
+# underlying sqlite3_multiplex_control() API.
+proc multiplex_set {db name chunk_size max_chunks} {
   global g_chunk_size
   global g_max_chunks
   set g_chunk_size $chunk_size
   set g_max_chunks $max_chunks
-  sqlite3_multiplex_set $chunk_size $max_chunks
+  set rc [catch {sqlite3_multiplex_control $db $name chunk_size $chunk_size} msg]
+  if { $rc==0 } { 
+    set rc [catch {sqlite3_multiplex_control $db $name max_chunks $max_chunks} msg]
+  }
+  list $msg
 }
 
 # This attempts to delete the base file and 
@@ -71,14 +75,15 @@ do_test multiplex-1.7 { sqlite3_multiplex_initialize "" 1 }        {SQLITE_OK}
 do_test multiplex-1.8 { sqlite3_multiplex_shutdown }               {SQLITE_OK}
 
 do_test multiplex-1.9  { sqlite3_multiplex_initialize "" 1 }       {SQLITE_OK}
-do_test multiplex-1.10.1 { multiplex_set 32768 16 }                {SQLITE_OK}
-do_test multiplex-1.10.2 { multiplex_set 32768 -1 }                {SQLITE_MISUSE}
-do_test multiplex-1.10.3 { multiplex_set -1 16 }                   {SQLITE_MISUSE}
-do_test multiplex-1.10.4 { multiplex_set 31 16 }                   {SQLITE_MISUSE}
-do_test multiplex-1.10.5 { multiplex_set 32768 100 }               {SQLITE_MISUSE}
+sqlite3 db test.db
+do_test multiplex-1.10.1 { multiplex_set db main 32768 16 }        {SQLITE_OK}
+do_test multiplex-1.10.2 { multiplex_set db main 32768 -1 }        {SQLITE_MISUSE}
+do_test multiplex-1.10.3 { multiplex_set db main -1 16 }           {SQLITE_MISUSE}
+do_test multiplex-1.10.4 { multiplex_set db main 31 16 }           {SQLITE_MISUSE}
+do_test multiplex-1.10.5 { multiplex_set db main 32768 100 }       {SQLITE_MISUSE}
+db close
 do_test multiplex-1.11 { sqlite3_multiplex_shutdown }              {SQLITE_OK}
 
-
 #-------------------------------------------------------------------------
 # Some simple warm-body tests with a single database file in rollback 
 # mode:
@@ -89,7 +94,7 @@ do_test multiplex-1.11 { sqlite3_multiplex_shutdown }              {SQLITE_OK}
 #
 #   multiplex-2.3.*: Open and close a second db.
 #
-#   multiplex-2.4.*: Try to shutdown the multiplex system before closing the db
+#   multiplex-2.4.*: Try to shutdown the multiplex system befor e closing the db
 #                file. Check that this fails and the multiplex system still works
 #                afterwards. Then close the database and successfully shut
 #                down the multiplex system.
@@ -100,7 +105,7 @@ do_test multiplex-1.11 { sqlite3_multiplex_shutdown }              {SQLITE_OK}
 #                well as varying journal mode.
 
 sqlite3_multiplex_initialize "" 1
-multiplex_set 32768 16
+multiplex_set db main 32768 16
 
 do_test multiplex-2.1.2 {
   sqlite3 db test.db
@@ -130,6 +135,7 @@ do_test multiplex-2.3.1 {
   db2 close
 } {}
 
+
 do_test multiplex-2.4.1 {
   sqlite3_multiplex_shutdown
 } {SQLITE_MISUSE}
@@ -146,11 +152,11 @@ do_test multiplex-2.4.99 {
 do_test multiplex-2.5.1 {
   multiplex_delete test.db
   sqlite3_multiplex_initialize "" 1
-  multiplex_set 4096 16
+  sqlite3 db test.db
+  multiplex_set db main 4096 16
 } {SQLITE_OK}
 
 do_test multiplex-2.5.2 {
-  sqlite3 db test.db
   execsql {
     PRAGMA page_size = 1024;
     PRAGMA journal_mode = delete;
@@ -197,6 +203,9 @@ do_test multiplex-2.5.99 {
   sqlite3_multiplex_shutdown
 } {SQLITE_OK}
 
+return
+
+# TBD fix the below
 
 set all_journal_modes {delete persist truncate memory off}
 foreach jmode $all_journal_modes {
@@ -205,7 +214,7 @@ foreach jmode $all_journal_modes {
     do_test multiplex-2.6.1.$sz.$jmode {
       multiplex_delete test.db
       sqlite3_multiplex_initialize "" 1
-      multiplex_set $sz 32
+      multiplex_set db main $sz 32
     } {SQLITE_OK}
 
     do_test multiplex-2.6.2.$sz.$jmode {
@@ -255,7 +264,7 @@ foreach jmode $all_journal_modes {
 do_test multiplex-3.1.1 {
   multiplex_delete test.db
   sqlite3_multiplex_initialize "" 1
-  multiplex_set 32768 16
+  multiplex_set db main 32768 16
 } {SQLITE_OK}
 do_test multiplex-3.1.2 {
   sqlite3 db test.db
@@ -341,7 +350,7 @@ do_test multiplex-3.2.X {
 #
 
 sqlite3_multiplex_initialize "" 1
-multiplex_set 32768 16
+multiplex_set db main 32768 16
 
 # Return a list of all currently defined multiplexs.
 proc multiplex_list {} {
@@ -403,7 +412,7 @@ do_test multiplex-4.1.12 {
 #
 
 sqlite3_multiplex_initialize "" 1
-multiplex_set 32768 16
+multiplex_set db main 32768 16
 
 do_faultsim_test multiplex-5.1 -prep {
   catch {db close}
@@ -448,7 +457,7 @@ do_faultsim_test multiplex-5.5 -prep {
   catch { sqlite3_multiplex_shutdown }
 } -body {
   sqlite3_multiplex_initialize "" 1
-  multiplex_set 32768 16
+  multiplex_set db main 32768 16
 }
 
 # test that mismatch filesize is detected
@@ -481,7 +490,7 @@ if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} {
       }
       db close
       sqlite3_multiplex_initialize "" 1
-      multiplex_set 4096 16
+      multiplex_set db main 4096 16
       sqlite3 db test.db
     } {}
     do_test multiplex-5.6.3.$jmode {