xref: /sqlite-3.40.0/src/test_multiplex.c (revision 42829635)
1 /*
2 ** 2010 October 28
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 *************************************************************************
12 **
13 ** This file contains a VFS "shim" - a layer that sits in between the
14 ** pager and the real VFS - that breaks up a very large database file
15 ** into two or more smaller files on disk.  This is useful, for example,
16 ** in order to support large, multi-gigabyte databases on older filesystems
17 ** that limit the maximum file size to 2 GiB.
18 **
19 ** USAGE:
20 **
21 ** Compile this source file and link it with your application.  Then
22 ** at start-time, invoke the following procedure:
23 **
24 **   int sqlite3_multiplex_initialize(
25 **      const char *zOrigVfsName,    // The underlying real VFS
26 **      int makeDefault              // True to make multiplex the default VFS
27 **   );
28 **
29 ** The procedure call above will create and register a new VFS shim named
30 ** "multiplex".  The multiplex VFS will use the VFS named by zOrigVfsName to
31 ** do the actual disk I/O.  (The zOrigVfsName parameter may be NULL, in
32 ** which case the default VFS at the moment sqlite3_multiplex_initialize()
33 ** is called will be used as the underlying real VFS.)
34 **
35 ** If the makeDefault parameter is TRUE then multiplex becomes the new
36 ** default VFS.  Otherwise, you can use the multiplex VFS by specifying
37 ** "multiplex" as the 4th parameter to sqlite3_open_v2() or by employing
38 ** URI filenames and adding "vfs=multiplex" as a parameter to the filename
39 ** URI.
40 **
41 ** The multiplex VFS allows databases up to 32 GiB in size.  But it splits
42 ** the files up into smaller pieces, so that they will work even on
43 ** filesystems that do not support large files.  The default chunk size
44 ** is 2147418112 bytes (which is 64KiB less than 2GiB) but this can be
45 ** changed at compile-time by defining the SQLITE_MULTIPLEX_CHUNK_SIZE
46 ** macro.  Use the "chunksize=NNNN" query parameter with a URI filename
47 ** in order to select an alternative chunk size for individual connections
48 ** at run-time.
49 */
50 #include "sqlite3.h"
51 #include <string.h>
52 #include <assert.h>
53 #include <stdlib.h>
54 #include "test_multiplex.h"
55 
56 #ifndef SQLITE_CORE
57   #define SQLITE_CORE 1  /* Disable the API redefinition in sqlite3ext.h */
58 #endif
59 #include "sqlite3ext.h"
60 
61 /*
62 ** These should be defined to be the same as the values in
63 ** sqliteInt.h.  They are defined seperately here so that
64 ** the multiplex VFS shim can be built as a loadable
65 ** module.
66 */
67 #define UNUSED_PARAMETER(x) (void)(x)
68 #define MAX_PAGE_SIZE       0x10000
69 #define DEFAULT_SECTOR_SIZE 0x1000
70 
71 /*
72 ** For a build without mutexes, no-op the mutex calls.
73 */
74 #if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE==0
75 #define sqlite3_mutex_alloc(X)    ((sqlite3_mutex*)8)
76 #define sqlite3_mutex_free(X)
77 #define sqlite3_mutex_enter(X)
78 #define sqlite3_mutex_try(X)      SQLITE_OK
79 #define sqlite3_mutex_leave(X)
80 #define sqlite3_mutex_held(X)     ((void)(X),1)
81 #define sqlite3_mutex_notheld(X)  ((void)(X),1)
82 #endif /* SQLITE_THREADSAFE==0 */
83 
84 /* First chunk for rollback journal files */
85 #define SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET 400
86 
87 
88 /************************ Shim Definitions ******************************/
89 
90 #ifndef SQLITE_MULTIPLEX_VFS_NAME
91 # define SQLITE_MULTIPLEX_VFS_NAME "multiplex"
92 #endif
93 
94 /* This is the limit on the chunk size.  It may be changed by calling
95 ** the xFileControl() interface.  It will be rounded up to a
96 ** multiple of MAX_PAGE_SIZE.  We default it here to 2GiB less 64KiB.
97 */
98 #ifndef SQLITE_MULTIPLEX_CHUNK_SIZE
99 # define SQLITE_MULTIPLEX_CHUNK_SIZE 2147418112
100 #endif
101 
102 /* This used to be the default limit on number of chunks, but
103 ** it is no longer enforced. There is currently no limit to the
104 ** number of chunks.
105 **
106 ** May be changed by calling the xFileControl() interface.
107 */
108 #ifndef SQLITE_MULTIPLEX_MAX_CHUNKS
109 # define SQLITE_MULTIPLEX_MAX_CHUNKS 12
110 #endif
111 
112 /************************ Object Definitions ******************************/
113 
114 /* Forward declaration of all object types */
115 typedef struct multiplexGroup multiplexGroup;
116 typedef struct multiplexConn multiplexConn;
117 
118 /*
119 ** A "multiplex group" is a collection of files that collectively
120 ** makeup a single SQLite DB file.  This allows the size of the DB
121 ** to exceed the limits imposed by the file system.
122 **
123 ** There is an instance of the following object for each defined multiplex
124 ** group.
125 */
126 struct multiplexGroup {
127   struct multiplexReal {           /* For each chunk */
128     sqlite3_file *p;                  /* Handle for the chunk */
129     char *z;                          /* Name of this chunk */
130   } *aReal;                        /* list of all chunks */
131   int nReal;                       /* Number of chunks */
132   char *zName;                     /* Base filename of this group */
133   int nName;                       /* Length of base filename */
134   int flags;                       /* Flags used for original opening */
135   unsigned int szChunk;            /* Chunk size used for this group */
136   unsigned char bEnabled;          /* TRUE to use Multiplex VFS for this file */
137   unsigned char bTruncate;         /* TRUE to enable truncation of databases */
138   multiplexGroup *pNext, *pPrev;   /* Doubly linked list of all group objects */
139 };
140 
141 /*
142 ** An instance of the following object represents each open connection
143 ** to a file that is multiplex'ed.  This object is a
144 ** subclass of sqlite3_file.  The sqlite3_file object for the underlying
145 ** VFS is appended to this structure.
146 */
147 struct multiplexConn {
148   sqlite3_file base;              /* Base class - must be first */
149   multiplexGroup *pGroup;         /* The underlying group of files */
150 };
151 
152 /************************* Global Variables **********************************/
153 /*
154 ** All global variables used by this file are containing within the following
155 ** gMultiplex structure.
156 */
157 static struct {
158   /* The pOrigVfs is the real, original underlying VFS implementation.
159   ** Most operations pass-through to the real VFS.  This value is read-only
160   ** during operation.  It is only modified at start-time and thus does not
161   ** require a mutex.
162   */
163   sqlite3_vfs *pOrigVfs;
164 
165   /* The sThisVfs is the VFS structure used by this shim.  It is initialized
166   ** at start-time and thus does not require a mutex
167   */
168   sqlite3_vfs sThisVfs;
169 
170   /* The sIoMethods defines the methods used by sqlite3_file objects
171   ** associated with this shim.  It is initialized at start-time and does
172   ** not require a mutex.
173   **
174   ** When the underlying VFS is called to open a file, it might return
175   ** either a version 1 or a version 2 sqlite3_file object.  This shim
176   ** has to create a wrapper sqlite3_file of the same version.  Hence
177   ** there are two I/O method structures, one for version 1 and the other
178   ** for version 2.
179   */
180   sqlite3_io_methods sIoMethodsV1;
181   sqlite3_io_methods sIoMethodsV2;
182 
183   /* True when this shim has been initialized.
184   */
185   int isInitialized;
186 
187   /* For run-time access any of the other global data structures in this
188   ** shim, the following mutex must be held.
189   */
190   sqlite3_mutex *pMutex;
191 
192   /* List of multiplexGroup objects.
193   */
194   multiplexGroup *pGroups;
195 } gMultiplex;
196 
197 /************************* Utility Routines *********************************/
198 /*
199 ** Acquire and release the mutex used to serialize access to the
200 ** list of multiplexGroups.
201 */
202 static void multiplexEnter(void){ sqlite3_mutex_enter(gMultiplex.pMutex); }
203 static void multiplexLeave(void){ sqlite3_mutex_leave(gMultiplex.pMutex); }
204 
205 /*
206 ** Compute a string length that is limited to what can be stored in
207 ** lower 30 bits of a 32-bit signed integer.
208 **
209 ** The value returned will never be negative.  Nor will it ever be greater
210 ** than the actual length of the string.  For very long strings (greater
211 ** than 1GiB) the value returned might be less than the true string length.
212 */
213 static int multiplexStrlen30(const char *z){
214   const char *z2 = z;
215   if( z==0 ) return 0;
216   while( *z2 ){ z2++; }
217   return 0x3fffffff & (int)(z2 - z);
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+5)
224 ** bytes in size, where nBase is the length of zBase, not including the
225 ** nul-terminator.
226 **
227 ** If iChunk is 0 (or 400 - the number for the first journal file chunk),
228 ** the output is a copy of the input string. Otherwise, if
229 ** SQLITE_ENABLE_8_3_NAMES is not defined or the input buffer does not contain
230 ** a "." character, then the output is a copy of the input string with the
231 ** three-digit zero-padded decimal representation if iChunk appended to it.
232 ** For example:
233 **
234 **   zBase="test.db", iChunk=4  ->  zOut="test.db004"
235 **
236 ** Or, if SQLITE_ENABLE_8_3_NAMES is defined and the input buffer contains
237 ** a "." character, then everything after the "." is replaced by the
238 ** three-digit representation of iChunk.
239 **
240 **   zBase="test.db", iChunk=4  ->  zOut="test.004"
241 **
242 ** The output buffer string is terminated by 2 0x00 bytes. This makes it safe
243 ** to pass to sqlite3_uri_parameter() and similar.
244 */
245 static void multiplexFilename(
246   const char *zBase,              /* Filename for chunk 0 */
247   int nBase,                      /* Size of zBase in bytes (without \0) */
248   int flags,                      /* Flags used to open file */
249   int iChunk,                     /* Chunk to generate filename for */
250   char *zOut                      /* Buffer to write generated name to */
251 ){
252   int n = nBase;
253   memcpy(zOut, zBase, n+1);
254   if( iChunk!=0 && iChunk!=SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET ){
255 #ifdef SQLITE_ENABLE_8_3_NAMES
256     int i;
257     for(i=n-1; i>0 && i>=n-4 && zOut[i]!='.'; i--){}
258     if( i>=n-4 ) n = i+1;
259     if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
260       /* The extensions on overflow files for main databases are 001, 002,
261        ** 003 and so forth.  To avoid name collisions, add 400 to the
262        ** extensions of journal files so that they are 401, 402, 403, ....
263        */
264       iChunk += SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET;
265     }
266 #endif
267     sqlite3_snprintf(4,&zOut[n],"%03d",iChunk);
268     n += 3;
269   }
270 
271   assert( zOut[n]=='\0' );
272   zOut[n+1] = '\0';
273 }
274 
275 /* Compute the filename for the iChunk-th chunk
276 */
277 static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){
278   if( iChunk>=pGroup->nReal ){
279     struct multiplexReal *p;
280     p = sqlite3_realloc(pGroup->aReal, (iChunk+1)*sizeof(*p));
281     if( p==0 ){
282       return SQLITE_NOMEM;
283     }
284     memset(&p[pGroup->nReal], 0, sizeof(p[0])*(iChunk+1-pGroup->nReal));
285     pGroup->aReal = p;
286     pGroup->nReal = iChunk+1;
287   }
288   if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){
289     char *z;
290     int n = pGroup->nName;
291     pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+5 );
292     if( z==0 ){
293       return SQLITE_NOMEM;
294     }
295     multiplexFilename(pGroup->zName, pGroup->nName, pGroup->flags, iChunk, z);
296   }
297   return SQLITE_OK;
298 }
299 
300 /* Translate an sqlite3_file* that is really a multiplexGroup* into
301 ** the sqlite3_file* for the underlying original VFS.
302 **
303 ** For chunk 0, the pGroup->flags determines whether or not a new file
304 ** is created if it does not already exist.  For chunks 1 and higher, the
305 ** file is created only if createFlag is 1.
306 */
307 static sqlite3_file *multiplexSubOpen(
308   multiplexGroup *pGroup,    /* The multiplexor group */
309   int iChunk,                /* Which chunk to open.  0==original file */
310   int *rc,                   /* Result code in and out */
311   int *pOutFlags,            /* Output flags */
312   int createFlag             /* True to create if iChunk>0 */
313 ){
314   sqlite3_file *pSubOpen = 0;
315   sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;        /* Real VFS */
316 
317 #ifdef SQLITE_ENABLE_8_3_NAMES
318   /* If JOURNAL_8_3_OFFSET is set to (say) 400, then any overflow files are
319   ** part of a database journal are named db.401, db.402, and so on. A
320   ** database may therefore not grow to larger than 400 chunks. Attempting
321   ** to open chunk 401 indicates the database is full. */
322   if( iChunk>=SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET ){
323     *rc = SQLITE_FULL;
324     return 0;
325   }
326 #endif
327 
328   *rc = multiplexSubFilename(pGroup, iChunk);
329   if( (*rc)==SQLITE_OK && (pSubOpen = pGroup->aReal[iChunk].p)==0 ){
330     int flags, bExists;
331     flags = pGroup->flags;
332     if( createFlag ){
333       flags |= SQLITE_OPEN_CREATE;
334     }else if( iChunk==0 ){
335       /* Fall through */
336     }else if( pGroup->aReal[iChunk].z==0 ){
337       return 0;
338     }else{
339       *rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[iChunk].z,
340                               SQLITE_ACCESS_EXISTS, &bExists);
341       if( *rc || !bExists ) return 0;
342       flags &= ~SQLITE_OPEN_CREATE;
343     }
344     pSubOpen = sqlite3_malloc( pOrigVfs->szOsFile );
345     if( pSubOpen==0 ){
346       *rc = SQLITE_IOERR_NOMEM;
347       return 0;
348     }
349     pGroup->aReal[iChunk].p = pSubOpen;
350     *rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen,
351                           flags, pOutFlags);
352     if( (*rc)!=SQLITE_OK ){
353       sqlite3_free(pSubOpen);
354       pGroup->aReal[iChunk].p = 0;
355       return 0;
356     }
357   }
358   return pSubOpen;
359 }
360 
361 /*
362 ** Return the size, in bytes, of chunk number iChunk.  If that chunk
363 ** does not exist, then return 0.  This function does not distingish between
364 ** non-existant files and zero-length files.
365 */
366 static sqlite3_int64 multiplexSubSize(
367   multiplexGroup *pGroup,    /* The multiplexor group */
368   int iChunk,                /* Which chunk to open.  0==original file */
369   int *rc                    /* Result code in and out */
370 ){
371   sqlite3_file *pSub;
372   sqlite3_int64 sz = 0;
373 
374   if( *rc ) return 0;
375   pSub = multiplexSubOpen(pGroup, iChunk, rc, NULL, 0);
376   if( pSub==0 ) return 0;
377   *rc = pSub->pMethods->xFileSize(pSub, &sz);
378   return sz;
379 }
380 
381 /*
382 ** This is the implementation of the multiplex_control() SQL function.
383 */
384 static void multiplexControlFunc(
385   sqlite3_context *context,
386   int argc,
387   sqlite3_value **argv
388 ){
389   int rc = SQLITE_OK;
390   sqlite3 *db = sqlite3_context_db_handle(context);
391   int op;
392   int iVal;
393 
394   if( !db || argc!=2 ){
395     rc = SQLITE_ERROR;
396   }else{
397     /* extract params */
398     op = sqlite3_value_int(argv[0]);
399     iVal = sqlite3_value_int(argv[1]);
400     /* map function op to file_control op */
401     switch( op ){
402       case 1:
403         op = MULTIPLEX_CTRL_ENABLE;
404         break;
405       case 2:
406         op = MULTIPLEX_CTRL_SET_CHUNK_SIZE;
407         break;
408       case 3:
409         op = MULTIPLEX_CTRL_SET_MAX_CHUNKS;
410         break;
411       default:
412         rc = SQLITE_NOTFOUND;
413         break;
414     }
415   }
416   if( rc==SQLITE_OK ){
417     rc = sqlite3_file_control(db, 0, op, &iVal);
418   }
419   sqlite3_result_error_code(context, rc);
420 }
421 
422 /*
423 ** This is the entry point to register the auto-extension for the
424 ** multiplex_control() function.
425 */
426 static int multiplexFuncInit(
427   sqlite3 *db,
428   char **pzErrMsg,
429   const sqlite3_api_routines *pApi
430 ){
431   int rc;
432   rc = sqlite3_create_function(db, "multiplex_control", 2, SQLITE_ANY,
433       0, multiplexControlFunc, 0, 0);
434   return rc;
435 }
436 
437 /*
438 ** Close a single sub-file in the connection group.
439 */
440 static void multiplexSubClose(
441   multiplexGroup *pGroup,
442   int iChunk,
443   sqlite3_vfs *pOrigVfs
444 ){
445   sqlite3_file *pSubOpen = pGroup->aReal[iChunk].p;
446   if( pSubOpen ){
447     pSubOpen->pMethods->xClose(pSubOpen);
448     if( pOrigVfs && pGroup->aReal[iChunk].z ){
449       pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
450     }
451     sqlite3_free(pGroup->aReal[iChunk].p);
452   }
453   sqlite3_free(pGroup->aReal[iChunk].z);
454   memset(&pGroup->aReal[iChunk], 0, sizeof(pGroup->aReal[iChunk]));
455 }
456 
457 /*
458 ** Deallocate memory held by a multiplexGroup
459 */
460 static void multiplexFreeComponents(multiplexGroup *pGroup){
461   int i;
462   for(i=0; i<pGroup->nReal; i++){ multiplexSubClose(pGroup, i, 0); }
463   sqlite3_free(pGroup->aReal);
464   pGroup->aReal = 0;
465   pGroup->nReal = 0;
466 }
467 
468 
469 /************************* VFS Method Wrappers *****************************/
470 
471 /*
472 ** This is the xOpen method used for the "multiplex" VFS.
473 **
474 ** Most of the work is done by the underlying original VFS.  This method
475 ** simply links the new file into the appropriate multiplex group if it is a
476 ** file that needs to be tracked.
477 */
478 static int multiplexOpen(
479   sqlite3_vfs *pVfs,         /* The multiplex VFS */
480   const char *zName,         /* Name of file to be opened */
481   sqlite3_file *pConn,       /* Fill in this file descriptor */
482   int flags,                 /* Flags to control the opening */
483   int *pOutFlags             /* Flags showing results of opening */
484 ){
485   int rc = SQLITE_OK;                  /* Result code */
486   multiplexConn *pMultiplexOpen;       /* The new multiplex file descriptor */
487   multiplexGroup *pGroup;              /* Corresponding multiplexGroup object */
488   sqlite3_file *pSubOpen = 0;                    /* Real file descriptor */
489   sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
490   int nName;
491   int sz;
492   char *zToFree = 0;
493 
494   UNUSED_PARAMETER(pVfs);
495   memset(pConn, 0, pVfs->szOsFile);
496   assert( zName || (flags & SQLITE_OPEN_DELETEONCLOSE) );
497 
498   /* We need to create a group structure and manage
499   ** access to this group of files.
500   */
501   multiplexEnter();
502   pMultiplexOpen = (multiplexConn*)pConn;
503 
504   if( rc==SQLITE_OK ){
505     /* allocate space for group */
506     nName = zName ? multiplexStrlen30(zName) : 0;
507     sz = sizeof(multiplexGroup)                             /* multiplexGroup */
508        + nName + 1;                                         /* zName */
509     pGroup = sqlite3_malloc( sz );
510     if( pGroup==0 ){
511       rc = SQLITE_NOMEM;
512     }
513   }
514 
515   if( rc==SQLITE_OK ){
516     const char *zUri = (flags & SQLITE_OPEN_URI) ? zName : 0;
517     /* assign pointers to extra space allocated */
518     memset(pGroup, 0, sz);
519     pMultiplexOpen->pGroup = pGroup;
520     pGroup->bEnabled = -1;
521     pGroup->bTruncate = sqlite3_uri_boolean(zUri, "truncate",
522                                    (flags & SQLITE_OPEN_MAIN_DB)==0);
523     pGroup->szChunk = sqlite3_uri_int64(zUri, "chunksize",
524                                         SQLITE_MULTIPLEX_CHUNK_SIZE);
525     pGroup->szChunk = (pGroup->szChunk+0xffff)&~0xffff;
526     if( zName ){
527       char *p = (char *)&pGroup[1];
528       pGroup->zName = p;
529       memcpy(pGroup->zName, zName, nName+1);
530       pGroup->nName = nName;
531     }
532     if( pGroup->bEnabled ){
533       /* Make sure that the chunksize is such that the pending byte does not
534       ** falls at the end of a chunk.  A region of up to 64K following
535       ** the pending byte is never written, so if the pending byte occurs
536       ** near the end of a chunk, that chunk will be too small. */
537 #ifndef SQLITE_OMIT_WSD
538       extern int sqlite3PendingByte;
539 #else
540       int sqlite3PendingByte = 0x40000000;
541 #endif
542       while( (sqlite3PendingByte % pGroup->szChunk)>=(pGroup->szChunk-65536) ){
543         pGroup->szChunk += 65536;
544       }
545     }
546     pGroup->flags = flags;
547     rc = multiplexSubFilename(pGroup, 1);
548     if( rc==SQLITE_OK ){
549       pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags, 0);
550       if( pSubOpen==0 && rc==SQLITE_OK ) rc = SQLITE_CANTOPEN;
551     }
552     if( rc==SQLITE_OK ){
553       sqlite3_int64 sz;
554 
555       rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
556       if( rc==SQLITE_OK && zName ){
557         int bExists;
558         if( sz==0 ){
559           if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
560             /* If opening a main journal file and the first chunk is zero
561             ** bytes in size, delete any subsequent chunks from the
562             ** file-system. */
563             int iChunk = 1;
564             do {
565               rc = pOrigVfs->xAccess(pOrigVfs,
566                   pGroup->aReal[iChunk].z, SQLITE_ACCESS_EXISTS, &bExists
567               );
568               if( rc==SQLITE_OK && bExists ){
569                 rc = pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
570                 if( rc==SQLITE_OK ){
571                   rc = multiplexSubFilename(pGroup, ++iChunk);
572                 }
573               }
574             }while( rc==SQLITE_OK && bExists );
575           }
576         }else{
577           /* If the first overflow file exists and if the size of the main file
578           ** is different from the chunk size, that means the chunk size is set
579           ** set incorrectly.  So fix it.
580           **
581           ** Or, if the first overflow file does not exist and the main file is
582           ** larger than the chunk size, that means the chunk size is too small.
583           ** But we have no way of determining the intended chunk size, so
584           ** just disable the multiplexor all togethre.
585           */
586           rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z,
587               SQLITE_ACCESS_EXISTS, &bExists);
588           bExists = multiplexSubSize(pGroup, 1, &rc)>0;
589           if( rc==SQLITE_OK && bExists  && sz==(sz&0xffff0000) && sz>0
590               && sz!=pGroup->szChunk ){
591             pGroup->szChunk = sz;
592           }else if( rc==SQLITE_OK && !bExists && sz>pGroup->szChunk ){
593             pGroup->bEnabled = 0;
594           }
595         }
596       }
597     }
598 
599     if( rc==SQLITE_OK ){
600       if( pSubOpen->pMethods->iVersion==1 ){
601         pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1;
602       }else{
603         pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV2;
604       }
605       /* place this group at the head of our list */
606       pGroup->pNext = gMultiplex.pGroups;
607       if( gMultiplex.pGroups ) gMultiplex.pGroups->pPrev = pGroup;
608       gMultiplex.pGroups = pGroup;
609     }else{
610       multiplexFreeComponents(pGroup);
611       sqlite3_free(pGroup);
612     }
613   }
614   multiplexLeave();
615   sqlite3_free(zToFree);
616   return rc;
617 }
618 
619 /*
620 ** This is the xDelete method used for the "multiplex" VFS.
621 ** It attempts to delete the filename specified.
622 */
623 static int multiplexDelete(
624   sqlite3_vfs *pVfs,         /* The multiplex VFS */
625   const char *zName,         /* Name of file to delete */
626   int syncDir
627 ){
628   int rc;
629   sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
630   rc = pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
631   if( rc==SQLITE_OK ){
632     /* If the main chunk was deleted successfully, also delete any subsequent
633     ** chunks - starting with the last (highest numbered).
634     */
635     int nName = strlen(zName);
636     char *z;
637     z = sqlite3_malloc(nName + 5);
638     if( z==0 ){
639       rc = SQLITE_IOERR_NOMEM;
640     }else{
641       int iChunk = 0;
642       int bExists;
643       do{
644         multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, ++iChunk, z);
645         rc = pOrigVfs->xAccess(pOrigVfs, z, SQLITE_ACCESS_EXISTS, &bExists);
646       }while( rc==SQLITE_OK && bExists );
647       while( rc==SQLITE_OK && iChunk>1 ){
648         multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, --iChunk, z);
649         rc = pOrigVfs->xDelete(pOrigVfs, z, syncDir);
650       }
651     }
652     sqlite3_free(z);
653   }
654   return rc;
655 }
656 
657 static int multiplexAccess(sqlite3_vfs *a, const char *b, int c, int *d){
658   return gMultiplex.pOrigVfs->xAccess(gMultiplex.pOrigVfs, b, c, d);
659 }
660 static int multiplexFullPathname(sqlite3_vfs *a, const char *b, int c, char *d){
661   return gMultiplex.pOrigVfs->xFullPathname(gMultiplex.pOrigVfs, b, c, d);
662 }
663 static void *multiplexDlOpen(sqlite3_vfs *a, const char *b){
664   return gMultiplex.pOrigVfs->xDlOpen(gMultiplex.pOrigVfs, b);
665 }
666 static void multiplexDlError(sqlite3_vfs *a, int b, char *c){
667   gMultiplex.pOrigVfs->xDlError(gMultiplex.pOrigVfs, b, c);
668 }
669 static void (*multiplexDlSym(sqlite3_vfs *a, void *b, const char *c))(void){
670   return gMultiplex.pOrigVfs->xDlSym(gMultiplex.pOrigVfs, b, c);
671 }
672 static void multiplexDlClose(sqlite3_vfs *a, void *b){
673   gMultiplex.pOrigVfs->xDlClose(gMultiplex.pOrigVfs, b);
674 }
675 static int multiplexRandomness(sqlite3_vfs *a, int b, char *c){
676   return gMultiplex.pOrigVfs->xRandomness(gMultiplex.pOrigVfs, b, c);
677 }
678 static int multiplexSleep(sqlite3_vfs *a, int b){
679   return gMultiplex.pOrigVfs->xSleep(gMultiplex.pOrigVfs, b);
680 }
681 static int multiplexCurrentTime(sqlite3_vfs *a, double *b){
682   return gMultiplex.pOrigVfs->xCurrentTime(gMultiplex.pOrigVfs, b);
683 }
684 static int multiplexGetLastError(sqlite3_vfs *a, int b, char *c){
685   return gMultiplex.pOrigVfs->xGetLastError(gMultiplex.pOrigVfs, b, c);
686 }
687 static int multiplexCurrentTimeInt64(sqlite3_vfs *a, sqlite3_int64 *b){
688   return gMultiplex.pOrigVfs->xCurrentTimeInt64(gMultiplex.pOrigVfs, b);
689 }
690 
691 /************************ I/O Method Wrappers *******************************/
692 
693 /* xClose requests get passed through to the original VFS.
694 ** We loop over all open chunk handles and close them.
695 ** The group structure for this file is unlinked from
696 ** our list of groups and freed.
697 */
698 static int multiplexClose(sqlite3_file *pConn){
699   multiplexConn *p = (multiplexConn*)pConn;
700   multiplexGroup *pGroup = p->pGroup;
701   int rc = SQLITE_OK;
702   multiplexEnter();
703   multiplexFreeComponents(pGroup);
704   /* remove from linked list */
705   if( pGroup->pNext ) pGroup->pNext->pPrev = pGroup->pPrev;
706   if( pGroup->pPrev ){
707     pGroup->pPrev->pNext = pGroup->pNext;
708   }else{
709     gMultiplex.pGroups = pGroup->pNext;
710   }
711   sqlite3_free(pGroup);
712   multiplexLeave();
713   return rc;
714 }
715 
716 /* Pass xRead requests thru to the original VFS after
717 ** determining the correct chunk to operate on.
718 ** Break up reads across chunk boundaries.
719 */
720 static int multiplexRead(
721   sqlite3_file *pConn,
722   void *pBuf,
723   int iAmt,
724   sqlite3_int64 iOfst
725 ){
726   multiplexConn *p = (multiplexConn*)pConn;
727   multiplexGroup *pGroup = p->pGroup;
728   int rc = SQLITE_OK;
729   multiplexEnter();
730   if( !pGroup->bEnabled ){
731     sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
732     if( pSubOpen==0 ){
733       rc = SQLITE_IOERR_READ;
734     }else{
735       rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst);
736     }
737   }else{
738     while( iAmt > 0 ){
739       int i = (int)(iOfst / pGroup->szChunk);
740       sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1);
741       if( pSubOpen ){
742         int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) - pGroup->szChunk;
743         if( extra<0 ) extra = 0;
744         iAmt -= extra;
745         rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt,
746                                        iOfst % pGroup->szChunk);
747         if( rc!=SQLITE_OK ) break;
748         pBuf = (char *)pBuf + iAmt;
749         iOfst += iAmt;
750         iAmt = extra;
751       }else{
752         rc = SQLITE_IOERR_READ;
753         break;
754       }
755     }
756   }
757   multiplexLeave();
758   return rc;
759 }
760 
761 /* Pass xWrite requests thru to the original VFS after
762 ** determining the correct chunk to operate on.
763 ** Break up writes across chunk boundaries.
764 */
765 static int multiplexWrite(
766   sqlite3_file *pConn,
767   const void *pBuf,
768   int iAmt,
769   sqlite3_int64 iOfst
770 ){
771   multiplexConn *p = (multiplexConn*)pConn;
772   multiplexGroup *pGroup = p->pGroup;
773   int rc = SQLITE_OK;
774   multiplexEnter();
775   if( !pGroup->bEnabled ){
776     sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
777     if( pSubOpen==0 ){
778       rc = SQLITE_IOERR_WRITE;
779     }else{
780       rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst);
781     }
782   }else{
783     while( rc==SQLITE_OK && iAmt>0 ){
784       int i = (int)(iOfst / pGroup->szChunk);
785       sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1);
786       if( pSubOpen ){
787         int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) -
788                     pGroup->szChunk;
789         if( extra<0 ) extra = 0;
790         iAmt -= extra;
791         rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt,
792                                         iOfst % pGroup->szChunk);
793         pBuf = (char *)pBuf + iAmt;
794         iOfst += iAmt;
795         iAmt = extra;
796       }
797     }
798   }
799   multiplexLeave();
800   return rc;
801 }
802 
803 /* Pass xTruncate requests thru to the original VFS after
804 ** determining the correct chunk to operate on.  Delete any
805 ** chunks above the truncate mark.
806 */
807 static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){
808   multiplexConn *p = (multiplexConn*)pConn;
809   multiplexGroup *pGroup = p->pGroup;
810   int rc = SQLITE_OK;
811   multiplexEnter();
812   if( !pGroup->bEnabled ){
813     sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
814     if( pSubOpen==0 ){
815       rc = SQLITE_IOERR_TRUNCATE;
816     }else{
817       rc = pSubOpen->pMethods->xTruncate(pSubOpen, size);
818     }
819   }else{
820     int i;
821     int iBaseGroup = (int)(size / pGroup->szChunk);
822     sqlite3_file *pSubOpen;
823     sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
824     /* delete the chunks above the truncate limit */
825     for(i = pGroup->nReal-1; i>iBaseGroup && rc==SQLITE_OK; i--){
826       if( pGroup->bTruncate ){
827         multiplexSubClose(pGroup, i, pOrigVfs);
828       }else{
829         pSubOpen = multiplexSubOpen(pGroup, i, &rc, 0, 0);
830         if( pSubOpen ){
831           rc = pSubOpen->pMethods->xTruncate(pSubOpen, 0);
832         }
833       }
834     }
835     if( rc==SQLITE_OK ){
836       pSubOpen = multiplexSubOpen(pGroup, iBaseGroup, &rc, 0, 0);
837       if( pSubOpen ){
838         rc = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->szChunk);
839       }
840     }
841     if( rc ) rc = SQLITE_IOERR_TRUNCATE;
842   }
843   multiplexLeave();
844   return rc;
845 }
846 
847 /* Pass xSync requests through to the original VFS without change
848 */
849 static int multiplexSync(sqlite3_file *pConn, int flags){
850   multiplexConn *p = (multiplexConn*)pConn;
851   multiplexGroup *pGroup = p->pGroup;
852   int rc = SQLITE_OK;
853   int i;
854   multiplexEnter();
855   for(i=0; i<pGroup->nReal; i++){
856     sqlite3_file *pSubOpen = pGroup->aReal[i].p;
857     if( pSubOpen ){
858       int rc2 = pSubOpen->pMethods->xSync(pSubOpen, flags);
859       if( rc2!=SQLITE_OK ) rc = rc2;
860     }
861   }
862   multiplexLeave();
863   return rc;
864 }
865 
866 /* Pass xFileSize requests through to the original VFS.
867 ** Aggregate the size of all the chunks before returning.
868 */
869 static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
870   multiplexConn *p = (multiplexConn*)pConn;
871   multiplexGroup *pGroup = p->pGroup;
872   int rc = SQLITE_OK;
873   int i;
874   multiplexEnter();
875   if( !pGroup->bEnabled ){
876     sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
877     if( pSubOpen==0 ){
878       rc = SQLITE_IOERR_FSTAT;
879     }else{
880       rc = pSubOpen->pMethods->xFileSize(pSubOpen, pSize);
881     }
882   }else{
883     *pSize = 0;
884     for(i=0; rc==SQLITE_OK; i++){
885       sqlite3_int64 sz = multiplexSubSize(pGroup, i, &rc);
886       if( sz==0 ) break;
887       *pSize = i*(sqlite3_int64)pGroup->szChunk + sz;
888     }
889   }
890   multiplexLeave();
891   return rc;
892 }
893 
894 /* Pass xLock requests through to the original VFS unchanged.
895 */
896 static int multiplexLock(sqlite3_file *pConn, int lock){
897   multiplexConn *p = (multiplexConn*)pConn;
898   int rc;
899   sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
900   if( pSubOpen ){
901     return pSubOpen->pMethods->xLock(pSubOpen, lock);
902   }
903   return SQLITE_BUSY;
904 }
905 
906 /* Pass xUnlock requests through to the original VFS unchanged.
907 */
908 static int multiplexUnlock(sqlite3_file *pConn, int lock){
909   multiplexConn *p = (multiplexConn*)pConn;
910   int rc;
911   sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
912   if( pSubOpen ){
913     return pSubOpen->pMethods->xUnlock(pSubOpen, lock);
914   }
915   return SQLITE_IOERR_UNLOCK;
916 }
917 
918 /* Pass xCheckReservedLock requests through to the original VFS unchanged.
919 */
920 static int multiplexCheckReservedLock(sqlite3_file *pConn, int *pResOut){
921   multiplexConn *p = (multiplexConn*)pConn;
922   int rc;
923   sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
924   if( pSubOpen ){
925     return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut);
926   }
927   return SQLITE_IOERR_CHECKRESERVEDLOCK;
928 }
929 
930 /* Pass xFileControl requests through to the original VFS unchanged,
931 ** except for any MULTIPLEX_CTRL_* requests here.
932 */
933 static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
934   multiplexConn *p = (multiplexConn*)pConn;
935   multiplexGroup *pGroup = p->pGroup;
936   int rc = SQLITE_ERROR;
937   sqlite3_file *pSubOpen;
938 
939   if( !gMultiplex.isInitialized ) return SQLITE_MISUSE;
940   switch( op ){
941     case MULTIPLEX_CTRL_ENABLE:
942       if( pArg ) {
943         int bEnabled = *(int *)pArg;
944         pGroup->bEnabled = bEnabled;
945         rc = SQLITE_OK;
946       }
947       break;
948     case MULTIPLEX_CTRL_SET_CHUNK_SIZE:
949       if( pArg ) {
950         unsigned int szChunk = *(unsigned*)pArg;
951         if( szChunk<1 ){
952           rc = SQLITE_MISUSE;
953         }else{
954           /* Round up to nearest multiple of MAX_PAGE_SIZE. */
955           szChunk = (szChunk + (MAX_PAGE_SIZE-1));
956           szChunk &= ~(MAX_PAGE_SIZE-1);
957           pGroup->szChunk = szChunk;
958           rc = SQLITE_OK;
959         }
960       }
961       break;
962     case MULTIPLEX_CTRL_SET_MAX_CHUNKS:
963       rc = SQLITE_OK;
964       break;
965     case SQLITE_FCNTL_SIZE_HINT:
966     case SQLITE_FCNTL_CHUNK_SIZE:
967       /* no-op these */
968       rc = SQLITE_OK;
969       break;
970     default:
971       pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
972       if( pSubOpen ){
973         rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
974         if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
975          *(char**)pArg = sqlite3_mprintf("multiplex/%z", *(char**)pArg);
976         }
977       }
978       break;
979   }
980   return rc;
981 }
982 
983 /* Pass xSectorSize requests through to the original VFS unchanged.
984 */
985 static int multiplexSectorSize(sqlite3_file *pConn){
986   multiplexConn *p = (multiplexConn*)pConn;
987   int rc;
988   sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
989   if( pSubOpen && pSubOpen->pMethods->xSectorSize ){
990     return pSubOpen->pMethods->xSectorSize(pSubOpen);
991   }
992   return DEFAULT_SECTOR_SIZE;
993 }
994 
995 /* Pass xDeviceCharacteristics requests through to the original VFS unchanged.
996 */
997 static int multiplexDeviceCharacteristics(sqlite3_file *pConn){
998   multiplexConn *p = (multiplexConn*)pConn;
999   int rc;
1000   sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
1001   if( pSubOpen ){
1002     return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen);
1003   }
1004   return 0;
1005 }
1006 
1007 /* Pass xShmMap requests through to the original VFS unchanged.
1008 */
1009 static int multiplexShmMap(
1010   sqlite3_file *pConn,            /* Handle open on database file */
1011   int iRegion,                    /* Region to retrieve */
1012   int szRegion,                   /* Size of regions */
1013   int bExtend,                    /* True to extend file if necessary */
1014   void volatile **pp              /* OUT: Mapped memory */
1015 ){
1016   multiplexConn *p = (multiplexConn*)pConn;
1017   int rc;
1018   sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
1019   if( pSubOpen ){
1020     return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend,pp);
1021   }
1022   return SQLITE_IOERR;
1023 }
1024 
1025 /* Pass xShmLock requests through to the original VFS unchanged.
1026 */
1027 static int multiplexShmLock(
1028   sqlite3_file *pConn,       /* Database file holding the shared memory */
1029   int ofst,                  /* First lock to acquire or release */
1030   int n,                     /* Number of locks to acquire or release */
1031   int flags                  /* What to do with the lock */
1032 ){
1033   multiplexConn *p = (multiplexConn*)pConn;
1034   int rc;
1035   sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
1036   if( pSubOpen ){
1037     return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags);
1038   }
1039   return SQLITE_BUSY;
1040 }
1041 
1042 /* Pass xShmBarrier requests through to the original VFS unchanged.
1043 */
1044 static void multiplexShmBarrier(sqlite3_file *pConn){
1045   multiplexConn *p = (multiplexConn*)pConn;
1046   int rc;
1047   sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
1048   if( pSubOpen ){
1049     pSubOpen->pMethods->xShmBarrier(pSubOpen);
1050   }
1051 }
1052 
1053 /* Pass xShmUnmap requests through to the original VFS unchanged.
1054 */
1055 static int multiplexShmUnmap(sqlite3_file *pConn, int deleteFlag){
1056   multiplexConn *p = (multiplexConn*)pConn;
1057   int rc;
1058   sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
1059   if( pSubOpen ){
1060     return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag);
1061   }
1062   return SQLITE_OK;
1063 }
1064 
1065 /************************** Public Interfaces *****************************/
1066 /*
1067 ** CAPI: Initialize the multiplex VFS shim - sqlite3_multiplex_initialize()
1068 **
1069 ** Use the VFS named zOrigVfsName as the VFS that does the actual work.
1070 ** Use the default if zOrigVfsName==NULL.
1071 **
1072 ** The multiplex VFS shim is named "multiplex".  It will become the default
1073 ** VFS if makeDefault is non-zero.
1074 **
1075 ** THIS ROUTINE IS NOT THREADSAFE.  Call this routine exactly once
1076 ** during start-up.
1077 */
1078 int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){
1079   sqlite3_vfs *pOrigVfs;
1080   if( gMultiplex.isInitialized ) return SQLITE_MISUSE;
1081   pOrigVfs = sqlite3_vfs_find(zOrigVfsName);
1082   if( pOrigVfs==0 ) return SQLITE_ERROR;
1083   assert( pOrigVfs!=&gMultiplex.sThisVfs );
1084   gMultiplex.pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
1085   if( !gMultiplex.pMutex ){
1086     return SQLITE_NOMEM;
1087   }
1088   gMultiplex.pGroups = NULL;
1089   gMultiplex.isInitialized = 1;
1090   gMultiplex.pOrigVfs = pOrigVfs;
1091   gMultiplex.sThisVfs = *pOrigVfs;
1092   gMultiplex.sThisVfs.szOsFile += sizeof(multiplexConn);
1093   gMultiplex.sThisVfs.zName = SQLITE_MULTIPLEX_VFS_NAME;
1094   gMultiplex.sThisVfs.xOpen = multiplexOpen;
1095   gMultiplex.sThisVfs.xDelete = multiplexDelete;
1096   gMultiplex.sThisVfs.xAccess = multiplexAccess;
1097   gMultiplex.sThisVfs.xFullPathname = multiplexFullPathname;
1098   gMultiplex.sThisVfs.xDlOpen = multiplexDlOpen;
1099   gMultiplex.sThisVfs.xDlError = multiplexDlError;
1100   gMultiplex.sThisVfs.xDlSym = multiplexDlSym;
1101   gMultiplex.sThisVfs.xDlClose = multiplexDlClose;
1102   gMultiplex.sThisVfs.xRandomness = multiplexRandomness;
1103   gMultiplex.sThisVfs.xSleep = multiplexSleep;
1104   gMultiplex.sThisVfs.xCurrentTime = multiplexCurrentTime;
1105   gMultiplex.sThisVfs.xGetLastError = multiplexGetLastError;
1106   gMultiplex.sThisVfs.xCurrentTimeInt64 = multiplexCurrentTimeInt64;
1107 
1108   gMultiplex.sIoMethodsV1.iVersion = 1;
1109   gMultiplex.sIoMethodsV1.xClose = multiplexClose;
1110   gMultiplex.sIoMethodsV1.xRead = multiplexRead;
1111   gMultiplex.sIoMethodsV1.xWrite = multiplexWrite;
1112   gMultiplex.sIoMethodsV1.xTruncate = multiplexTruncate;
1113   gMultiplex.sIoMethodsV1.xSync = multiplexSync;
1114   gMultiplex.sIoMethodsV1.xFileSize = multiplexFileSize;
1115   gMultiplex.sIoMethodsV1.xLock = multiplexLock;
1116   gMultiplex.sIoMethodsV1.xUnlock = multiplexUnlock;
1117   gMultiplex.sIoMethodsV1.xCheckReservedLock = multiplexCheckReservedLock;
1118   gMultiplex.sIoMethodsV1.xFileControl = multiplexFileControl;
1119   gMultiplex.sIoMethodsV1.xSectorSize = multiplexSectorSize;
1120   gMultiplex.sIoMethodsV1.xDeviceCharacteristics =
1121                                             multiplexDeviceCharacteristics;
1122   gMultiplex.sIoMethodsV2 = gMultiplex.sIoMethodsV1;
1123   gMultiplex.sIoMethodsV2.iVersion = 2;
1124   gMultiplex.sIoMethodsV2.xShmMap = multiplexShmMap;
1125   gMultiplex.sIoMethodsV2.xShmLock = multiplexShmLock;
1126   gMultiplex.sIoMethodsV2.xShmBarrier = multiplexShmBarrier;
1127   gMultiplex.sIoMethodsV2.xShmUnmap = multiplexShmUnmap;
1128   sqlite3_vfs_register(&gMultiplex.sThisVfs, makeDefault);
1129 
1130   sqlite3_auto_extension((void*)multiplexFuncInit);
1131 
1132   return SQLITE_OK;
1133 }
1134 
1135 /*
1136 ** CAPI: Shutdown the multiplex system - sqlite3_multiplex_shutdown()
1137 **
1138 ** All SQLite database connections must be closed before calling this
1139 ** routine.
1140 **
1141 ** THIS ROUTINE IS NOT THREADSAFE.  Call this routine exactly once while
1142 ** shutting down in order to free all remaining multiplex groups.
1143 */
1144 int sqlite3_multiplex_shutdown(void){
1145   if( gMultiplex.isInitialized==0 ) return SQLITE_MISUSE;
1146   if( gMultiplex.pGroups ) return SQLITE_MISUSE;
1147   gMultiplex.isInitialized = 0;
1148   sqlite3_mutex_free(gMultiplex.pMutex);
1149   sqlite3_vfs_unregister(&gMultiplex.sThisVfs);
1150   memset(&gMultiplex, 0, sizeof(gMultiplex));
1151   return SQLITE_OK;
1152 }
1153 
1154 /***************************** Test Code ***********************************/
1155 #ifdef SQLITE_TEST
1156 #include <tcl.h>
1157 extern const char *sqlite3TestErrorName(int);
1158 
1159 
1160 /*
1161 ** tclcmd: sqlite3_multiplex_initialize NAME MAKEDEFAULT
1162 */
1163 static int test_multiplex_initialize(
1164   void * clientData,
1165   Tcl_Interp *interp,
1166   int objc,
1167   Tcl_Obj *CONST objv[]
1168 ){
1169   const char *zName;              /* Name of new multiplex VFS */
1170   int makeDefault;                /* True to make the new VFS the default */
1171   int rc;                         /* Value returned by multiplex_initialize() */
1172 
1173   UNUSED_PARAMETER(clientData);
1174 
1175   /* Process arguments */
1176   if( objc!=3 ){
1177     Tcl_WrongNumArgs(interp, 1, objv, "NAME MAKEDEFAULT");
1178     return TCL_ERROR;
1179   }
1180   zName = Tcl_GetString(objv[1]);
1181   if( Tcl_GetBooleanFromObj(interp, objv[2], &makeDefault) ) return TCL_ERROR;
1182   if( zName[0]=='\0' ) zName = 0;
1183 
1184   /* Call sqlite3_multiplex_initialize() */
1185   rc = sqlite3_multiplex_initialize(zName, makeDefault);
1186   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
1187 
1188   return TCL_OK;
1189 }
1190 
1191 /*
1192 ** tclcmd: sqlite3_multiplex_shutdown
1193 */
1194 static int test_multiplex_shutdown(
1195   void * clientData,
1196   Tcl_Interp *interp,
1197   int objc,
1198   Tcl_Obj *CONST objv[]
1199 ){
1200   int rc;                         /* Value returned by multiplex_shutdown() */
1201 
1202   UNUSED_PARAMETER(clientData);
1203 
1204   if( objc!=1 ){
1205     Tcl_WrongNumArgs(interp, 1, objv, "");
1206     return TCL_ERROR;
1207   }
1208 
1209   /* Call sqlite3_multiplex_shutdown() */
1210   rc = sqlite3_multiplex_shutdown();
1211   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
1212 
1213   return TCL_OK;
1214 }
1215 
1216 /*
1217 ** tclcmd:  sqlite3_multiplex_dump
1218 */
1219 static int test_multiplex_dump(
1220   void * clientData,
1221   Tcl_Interp *interp,
1222   int objc,
1223   Tcl_Obj *CONST objv[]
1224 ){
1225   Tcl_Obj *pResult;
1226   Tcl_Obj *pGroupTerm;
1227   multiplexGroup *pGroup;
1228   int i;
1229   int nChunks = 0;
1230 
1231   UNUSED_PARAMETER(clientData);
1232   UNUSED_PARAMETER(objc);
1233   UNUSED_PARAMETER(objv);
1234 
1235   pResult = Tcl_NewObj();
1236   multiplexEnter();
1237   for(pGroup=gMultiplex.pGroups; pGroup; pGroup=pGroup->pNext){
1238     pGroupTerm = Tcl_NewObj();
1239 
1240     if( pGroup->zName ){
1241       pGroup->zName[pGroup->nName] = '\0';
1242       Tcl_ListObjAppendElement(interp, pGroupTerm,
1243           Tcl_NewStringObj(pGroup->zName, -1));
1244     }else{
1245       Tcl_ListObjAppendElement(interp, pGroupTerm, Tcl_NewObj());
1246     }
1247     Tcl_ListObjAppendElement(interp, pGroupTerm,
1248           Tcl_NewIntObj(pGroup->nName));
1249     Tcl_ListObjAppendElement(interp, pGroupTerm,
1250           Tcl_NewIntObj(pGroup->flags));
1251 
1252     /* count number of chunks with open handles */
1253     for(i=0; i<pGroup->nReal; i++){
1254       if( pGroup->aReal[i].p!=0 ) nChunks++;
1255     }
1256     Tcl_ListObjAppendElement(interp, pGroupTerm,
1257           Tcl_NewIntObj(nChunks));
1258 
1259     Tcl_ListObjAppendElement(interp, pGroupTerm,
1260           Tcl_NewIntObj(pGroup->szChunk));
1261     Tcl_ListObjAppendElement(interp, pGroupTerm,
1262           Tcl_NewIntObj(pGroup->nReal));
1263 
1264     Tcl_ListObjAppendElement(interp, pResult, pGroupTerm);
1265   }
1266   multiplexLeave();
1267   Tcl_SetObjResult(interp, pResult);
1268   return TCL_OK;
1269 }
1270 
1271 /*
1272 ** Tclcmd: test_multiplex_control HANDLE DBNAME SUB-COMMAND ?INT-VALUE?
1273 */
1274 static int test_multiplex_control(
1275   ClientData cd,
1276   Tcl_Interp *interp,
1277   int objc,
1278   Tcl_Obj *CONST objv[]
1279 ){
1280   int rc;                         /* Return code from file_control() */
1281   int idx;                        /* Index in aSub[] */
1282   Tcl_CmdInfo cmdInfo;            /* Command info structure for HANDLE */
1283   sqlite3 *db;                    /* Underlying db handle for HANDLE */
1284   int iValue = 0;
1285   void *pArg = 0;
1286 
1287   struct SubCommand {
1288     const char *zName;
1289     int op;
1290     int argtype;
1291   } aSub[] = {
1292     { "enable",       MULTIPLEX_CTRL_ENABLE,           1 },
1293     { "chunk_size",   MULTIPLEX_CTRL_SET_CHUNK_SIZE,   1 },
1294     { "max_chunks",   MULTIPLEX_CTRL_SET_MAX_CHUNKS,   1 },
1295     { 0, 0, 0 }
1296   };
1297 
1298   if( objc!=5 ){
1299     Tcl_WrongNumArgs(interp, 1, objv, "HANDLE DBNAME SUB-COMMAND INT-VALUE");
1300     return TCL_ERROR;
1301   }
1302 
1303   if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
1304     Tcl_AppendResult(interp, "expected database handle, got \"", 0);
1305     Tcl_AppendResult(interp, Tcl_GetString(objv[1]), "\"", 0);
1306     return TCL_ERROR;
1307   }else{
1308     db = *(sqlite3 **)cmdInfo.objClientData;
1309   }
1310 
1311   rc = Tcl_GetIndexFromObjStruct(
1312       interp, objv[3], aSub, sizeof(aSub[0]), "sub-command", 0, &idx
1313   );
1314   if( rc!=TCL_OK ) return rc;
1315 
1316   switch( aSub[idx].argtype ){
1317     case 1:
1318       if( Tcl_GetIntFromObj(interp, objv[4], &iValue) ){
1319         return TCL_ERROR;
1320       }
1321       pArg = (void *)&iValue;
1322       break;
1323     default:
1324       Tcl_WrongNumArgs(interp, 4, objv, "SUB-COMMAND");
1325       return TCL_ERROR;
1326   }
1327 
1328   rc = sqlite3_file_control(db, Tcl_GetString(objv[2]), aSub[idx].op, pArg);
1329   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
1330   return (rc==SQLITE_OK) ? TCL_OK : TCL_ERROR;
1331 }
1332 
1333 /*
1334 ** This routine registers the custom TCL commands defined in this
1335 ** module.  This should be the only procedure visible from outside
1336 ** of this module.
1337 */
1338 int Sqlitemultiplex_Init(Tcl_Interp *interp){
1339   static struct {
1340      char *zName;
1341      Tcl_ObjCmdProc *xProc;
1342   } aCmd[] = {
1343     { "sqlite3_multiplex_initialize", test_multiplex_initialize },
1344     { "sqlite3_multiplex_shutdown", test_multiplex_shutdown },
1345     { "sqlite3_multiplex_dump", test_multiplex_dump },
1346     { "sqlite3_multiplex_control", test_multiplex_control },
1347   };
1348   int i;
1349 
1350   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
1351     Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
1352   }
1353 
1354   return TCL_OK;
1355 }
1356 #endif
1357