** group.
*/
struct multiplexGroup {
- sqlite3_file **pReal; /* Handles to each chunk */
- char *bOpen; /* array of bools - 0 if chunk not opened */
+ struct multiplexReal { /* For each chunk */
+ sqlite3_file *p; /* Handle for the chunk */
+ char *z; /* Name of this chunk */
+ } *aReal; /* list of all chunks */
+ int nReal; /* Number of chunks */
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 */
};
/* List of multiplexGroup objects.
*/
multiplexGroup *pGroups;
-
- /* Storage for temp file names. Allocated during
- ** initialization to the max pathname of the underlying VFS.
- */
- char *zName;
-
} gMultiplex;
/************************* Utility Routines *********************************/
return rc;
}
+/* 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));
+ if( p==0 ){
+ return SQLITE_NOMEM;
+ }
+ memset(&p[pGroup->nReal], 0, sizeof(p[0])*(iChunk+1-pGroup->nReal));
+ pGroup->aReal = p;
+ pGroup->nReal = iChunk+1;
+ }
+ if( pGroup->aReal[iChunk].z==0 ){
+ char *z;
+ int n = pGroup->nName;
+ pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+3 );
+ if( z==0 ){
+ return SQLITE_NOMEM;
+ }
+ memcpy(z, pGroup->zName, n+1);
+ if( iChunk>0 ){
+#ifdef SQLITE_ENABLE_8_3_NAMES
+ if( n>3 && z[n-3]=='.' ){
+ n--;
+ }else if( n>4 && z[n-4]=='.' ){
+ n -= 2;
+ }
+#endif
+ sqlite3_snprintf(3,&z[n],"%02d",iChunk);
+ }
+ }
+ return SQLITE_OK;
+}
+
/* Translate an sqlite3_file* that is really a multiplexGroup* into
** the sqlite3_file* for the underlying original VFS.
*/
static sqlite3_file *multiplexSubOpen(
- multiplexConn *pConn,
+ multiplexGroup *pGroup,
int iChunk,
int *rc,
int *pOutFlags
){
- multiplexGroup *pGroup = pConn->pGroup;
+ sqlite3_file *pSubOpen = 0;
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
- 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);
- if( iChunk ){
-#ifdef SQLITE_MULTIPLEX_EXT_OVWR
- sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
- gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ,
- SQLITE_MULTIPLEX_EXT_FMT, iChunk);
-#else
- sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
- gMultiplex.zName+pGroup->nName,
- SQLITE_MULTIPLEX_EXT_FMT, iChunk);
-#endif
- }
- *rc = pOrigVfs->xOpen(pOrigVfs, gMultiplex.zName, pSubOpen,
- pGroup->flags, pOutFlags);
- if( *rc==SQLITE_OK ){
- pGroup->bOpen[iChunk] = -1;
- return pSubOpen;
- }
- return NULL;
+ *rc = multiplexSubFilename(pGroup, iChunk);
+ if( (*rc)==SQLITE_OK && (pSubOpen = pGroup->aReal[iChunk].p)==0 ){
+ pSubOpen = sqlite3_malloc( pOrigVfs->szOsFile );
+ if( pSubOpen==0 ){
+ *rc = SQLITE_NOMEM;
+ return 0;
+ }
+ pGroup->aReal[iChunk].p = pSubOpen;
+ *rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen,
+ pGroup->flags, pOutFlags);
+ if( *rc!=SQLITE_OK ){
+ sqlite3_free(pSubOpen);
+ pGroup->aReal[iChunk].p = 0;
+ return 0;
}
- *rc = SQLITE_OK;
- return pSubOpen;
}
- *rc = SQLITE_FULL;
- return NULL;
+ return pSubOpen;
}
/*
return rc;
}
+/*
+** Close a single sub-file in the connection group.
+*/
+static void multiplexSubClose(
+ multiplexGroup *pGroup,
+ int iChunk,
+ sqlite3_vfs *pOrigVfs
+){
+ sqlite3_file *pSubOpen = pGroup->aReal[iChunk].p;
+ if( pSubOpen ){
+ if( pOrigVfs ) pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
+ pSubOpen->pMethods->xClose(pSubOpen);
+ sqlite3_free(pGroup->aReal[iChunk].p);
+ }
+ sqlite3_free(pGroup->aReal[iChunk].z);
+ memset(&pGroup->aReal[iChunk], 0, sizeof(pGroup->aReal[iChunk]));
+}
+
+/*
+** Deallocate memory held by a multiplexGroup
+*/
+static void multiplexFreeComponents(multiplexGroup *pGroup){
+ int i;
+ for(i=0; i<pGroup->nReal; i++){ multiplexSubClose(pGroup, i, 0); }
+ sqlite3_free(pGroup->aReal);
+ pGroup->aReal = 0;
+ pGroup->nReal = 0;
+}
+
+
/************************* VFS Method Wrappers *****************************/
/*
sqlite3_file *pSubOpen; /* Real file descriptor */
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
int nName;
- int i;
int sz;
+ char *zToFree = 0;
UNUSED_PARAMETER(pVfs);
+ memset(pConn, 0, pVfs->szOsFile);
/* We need to create a group structure and manage
** access to this group of files.
** it.
*/
if( !zName ){
- rc = multiplexGetTempname(pOrigVfs, pOrigVfs->mxPathname, gMultiplex.zName);
- zName = gMultiplex.zName;
+ zName = zToFree = sqlite3_malloc( pOrigVfs->mxPathname + 10 );
+ if( zName==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = multiplexGetTempname(pOrigVfs, pOrigVfs->mxPathname, zToFree);
+ }
}
if( rc==SQLITE_OK ){
/* allocate space for group */
nName = multiplexStrlen30(zName);
sz = sizeof(multiplexGroup) /* multiplexGroup */
- + (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;
- assert(nName+SQLITE_MULTIPLEX_EXT_SZ < pOrigVfs->mxPathname);
-#else
- assert(nName >= SQLITE_MULTIPLEX_EXT_SZ);
- assert(nName < pOrigVfs->mxPathname);
-#endif
+ + nName + 1; /* zName */
pGroup = sqlite3_malloc( sz );
if( pGroup==0 ){
- rc=SQLITE_NOMEM;
+ rc = SQLITE_NOMEM;
}
}
memset(pGroup, 0, sz);
pGroup->bEnabled = -1;
pGroup->nChunkSize = SQLITE_MULTIPLEX_CHUNK_SIZE;
- zChunkSize = sqlite3_uri_parameter(zName, "chunksize");
- if( zChunkSize ){
- int n = atoi(zChunkSize);
- if( n>0 ) pGroup->nChunkSize = (n+0xffff)&~0xffff;
- }
- pGroup->nMaxChunks = SQLITE_MULTIPLEX_MAX_CHUNKS;
- pGroup->pReal = (sqlite3_file **)p;
- p += (sizeof(sqlite3_file *)*pGroup->nMaxChunks);
- for(i=0; i<pGroup->nMaxChunks; i++){
- pGroup->pReal[i] = (sqlite3_file *)p;
- p += pOrigVfs->szOsFile;
+ if( flags & SQLITE_OPEN_URI ){
+ zChunkSize = sqlite3_uri_parameter(zName, "chunksize");
+ if( zChunkSize ){
+ int n = atoi(zChunkSize);
+ if( n>0 ) pGroup->nChunkSize = (n+0xffff)&~0xffff;
+ }
}
- /* bOpen[] vals should all be zero from memset above */
- pGroup->bOpen = p;
- p += pGroup->nMaxChunks;
pGroup->zName = p;
/* save off base filename, name length, and original open flags */
memcpy(pGroup->zName, zName, nName+1);
pGroup->nName = nName;
pGroup->flags = flags;
- pSubOpen = multiplexSubOpen(pMultiplexOpen, 0, &rc, pOutFlags);
+ pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags);
if( pSubOpen ){
/* if this file is already larger than chunk size, disable
** the multiplex feature.
if( gMultiplex.pGroups ) gMultiplex.pGroups->pPrev = pGroup;
gMultiplex.pGroups = pGroup;
}else{
+ multiplexFreeComponents(pGroup);
sqlite3_free(pGroup);
}
}
multiplexLeave();
+ sqlite3_free(zToFree);
return rc;
}
/*
** This is the xDelete method used for the "multiplex" VFS.
-** It attempts to delete the filename specified, as well
-** as additional files with the SQLITE_MULTIPLEX_EXT_FMT extension.
+** It attempts to delete the filename specified.
*/
static int multiplexDelete(
sqlite3_vfs *pVfs, /* The multiplex VFS */
int syncDir
){
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
- int rc = SQLITE_OK;
- int nName = multiplexStrlen30(zName);
- int i;
-
- UNUSED_PARAMETER(pVfs);
-
- multiplexEnter();
- memcpy(gMultiplex.zName, zName, nName+1);
- for(i=0; i<SQLITE_MULTIPLEX_MAX_CHUNKS; i++){
- int rc2;
- int exists = 0;
- if( i ){
-#ifdef SQLITE_MULTIPLEX_EXT_OVWR
- sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
- gMultiplex.zName+nName-SQLITE_MULTIPLEX_EXT_SZ,
- SQLITE_MULTIPLEX_EXT_FMT, i);
-#else
- sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
- gMultiplex.zName+nName,
- SQLITE_MULTIPLEX_EXT_FMT, i);
-#endif
- }
- rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName,
- SQLITE_ACCESS_EXISTS, &exists);
- if( rc2==SQLITE_OK && exists ){
- /* if it exists, delete it */
- rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, syncDir);
- if( rc2!=SQLITE_OK ) rc = rc2;
- }else{
- /* stop at first "gap" */
- break;
- }
- }
- multiplexLeave();
- return rc;
+ return pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
}
static int multiplexAccess(sqlite3_vfs *a, const char *b, int c, int *d){
multiplexConn *p = (multiplexConn*)pConn;
multiplexGroup *pGroup = p->pGroup;
int rc = SQLITE_OK;
- int i;
multiplexEnter();
- /* close any open handles */
- for(i=0; i<pGroup->nMaxChunks; i++){
- if( pGroup->bOpen[i] ){
- sqlite3_file *pSubOpen = pGroup->pReal[i];
- int rc2 = pSubOpen->pMethods->xClose(pSubOpen);
- if( rc2!=SQLITE_OK ) rc = rc2;
- pGroup->bOpen[i] = 0;
- }
- }
+ multiplexFreeComponents(pGroup);
/* remove from linked list */
if( pGroup->pNext ) pGroup->pNext->pPrev = pGroup->pPrev;
if( pGroup->pPrev ){
int rc = SQLITE_OK;
multiplexEnter();
if( !pGroup->bEnabled ){
- sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
- if( !pSubOpen ){
+ sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
+ if( pSubOpen==0 ){
rc = SQLITE_IOERR_READ;
}else{
rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst);
}else{
while( iAmt > 0 ){
int i = (int)(iOfst / pGroup->nChunkSize);
- sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
if( pSubOpen ){
int extra = ((int)(iOfst % pGroup->nChunkSize) + iAmt) -
pGroup->nChunkSize;
int rc = SQLITE_OK;
multiplexEnter();
if( !pGroup->bEnabled ){
- sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
if( pSubOpen==0 ){
rc = SQLITE_IOERR_WRITE;
}else{
}else{
while( iAmt > 0 ){
int i = (int)(iOfst / pGroup->nChunkSize);
- sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
if( pSubOpen ){
int extra = ((int)(iOfst % pGroup->nChunkSize) + iAmt) -
pGroup->nChunkSize;
int rc = SQLITE_OK;
multiplexEnter();
if( !pGroup->bEnabled ){
- sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
if( pSubOpen==0 ){
rc = SQLITE_IOERR_TRUNCATE;
}else{
int i;
sqlite3_file *pSubOpen;
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
- memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
/* delete the chunks above the truncate limit */
- 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];
- rc2 = pSubOpen->pMethods->xClose(pSubOpen);
- if( rc2!=SQLITE_OK ) rc = SQLITE_IOERR_TRUNCATE;
- pGroup->bOpen[i] = 0;
- }
-#ifdef SQLITE_MULTIPLEX_EXT_OVWR
- sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
- gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ,
- SQLITE_MULTIPLEX_EXT_FMT, i);
-#else
- sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
- gMultiplex.zName+pGroup->nName,
- SQLITE_MULTIPLEX_EXT_FMT, i);
-#endif
- rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, 0);
- if( rc2!=SQLITE_OK ) rc = SQLITE_IOERR_TRUNCATE;
+ for(i=(int)(size / pGroup->nChunkSize)+1; i<pGroup->nReal; i++){
+ multiplexSubClose(pGroup, i, pOrigVfs);
}
- pSubOpen = multiplexSubOpen(p, (int)(size/pGroup->nChunkSize), &rc2, NULL);
+ pSubOpen = multiplexSubOpen(pGroup, (int)(size/pGroup->nChunkSize), &rc2,0);
if( pSubOpen ){
rc2 = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->nChunkSize);
if( rc2!=SQLITE_OK ) rc = rc2;
int rc = SQLITE_OK;
int i;
multiplexEnter();
- 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];
+ for(i=0; i<pGroup->nReal; i++){
+ sqlite3_file *pSubOpen = pGroup->aReal[i].p;
+ if( pSubOpen ){
int rc2 = pSubOpen->pMethods->xSync(pSubOpen, flags);
if( rc2!=SQLITE_OK ) rc = rc2;
}
int i;
multiplexEnter();
if( !pGroup->bEnabled ){
- sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
if( pSubOpen==0 ){
rc = SQLITE_IOERR_FSTAT;
}else{
}
}else{
*pSize = 0;
- 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] ){
- pSubOpen = pGroup->pReal[i];
+ for(i=0; 1; i++){
+ sqlite3_file *pSubOpen = 0;
+ sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;
+ int exists = 0;
+ rc = multiplexSubFilename(pGroup, i);
+ if( rc ) break;
+ rc2 = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[i].z,
+ SQLITE_ACCESS_EXISTS, &exists);
+ if( rc2==SQLITE_OK && exists){
+ /* if it exists, open it */
+ pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
}else{
- sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
- int exists = 0;
- memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
- if( i ){
-#ifdef SQLITE_MULTIPLEX_EXT_OVWR
- sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
- gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ,
- SQLITE_MULTIPLEX_EXT_FMT, i);
-#else
- sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
- gMultiplex.zName+pGroup->nName,
- SQLITE_MULTIPLEX_EXT_FMT, i);
-#endif
- }
- 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);
- }else{
- /* stop at first "gap" */
- break;
- }
+ /* stop at first "gap" */
+ break;
}
if( pSubOpen ){
sqlite3_int64 sz;
static int multiplexLock(sqlite3_file *pConn, int lock){
multiplexConn *p = (multiplexConn*)pConn;
int rc;
- sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){
return pSubOpen->pMethods->xLock(pSubOpen, lock);
}
static int multiplexUnlock(sqlite3_file *pConn, int lock){
multiplexConn *p = (multiplexConn*)pConn;
int rc;
- sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){
return pSubOpen->pMethods->xUnlock(pSubOpen, lock);
}
static int multiplexCheckReservedLock(sqlite3_file *pConn, int *pResOut){
multiplexConn *p = (multiplexConn*)pConn;
int rc;
- sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){
return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut);
}
}
break;
case MULTIPLEX_CTRL_SET_MAX_CHUNKS:
- if( pArg ) {
- int nMaxChunks = *(int *)pArg;
- if(( nMaxChunks<1 ) || ( nMaxChunks>SQLITE_MULTIPLEX_MAX_CHUNKS )){
- rc = SQLITE_MISUSE;
- }else{
- pGroup->nMaxChunks = nMaxChunks;
- rc = SQLITE_OK;
- }
- }
+ rc = SQLITE_OK;
break;
case SQLITE_FCNTL_SIZE_HINT:
case SQLITE_FCNTL_CHUNK_SIZE:
rc = SQLITE_OK;
break;
default:
- pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
+ pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
if( pSubOpen ){
rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
}
static int multiplexSectorSize(sqlite3_file *pConn){
multiplexConn *p = (multiplexConn*)pConn;
int rc;
- sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){
return pSubOpen->pMethods->xSectorSize(pSubOpen);
}
static int multiplexDeviceCharacteristics(sqlite3_file *pConn){
multiplexConn *p = (multiplexConn*)pConn;
int rc;
- sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){
return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen);
}
){
multiplexConn *p = (multiplexConn*)pConn;
int rc;
- sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){
return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend,pp);
}
){
multiplexConn *p = (multiplexConn*)pConn;
int rc;
- sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){
return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags);
}
static void multiplexShmBarrier(sqlite3_file *pConn){
multiplexConn *p = (multiplexConn*)pConn;
int rc;
- sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){
pSubOpen->pMethods->xShmBarrier(pSubOpen);
}
static int multiplexShmUnmap(sqlite3_file *pConn, int deleteFlag){
multiplexConn *p = (multiplexConn*)pConn;
int rc;
- sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
+ sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
if( pSubOpen ){
return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag);
}
if( !gMultiplex.pMutex ){
return SQLITE_NOMEM;
}
- gMultiplex.zName = sqlite3_malloc(pOrigVfs->mxPathname);
- if( !gMultiplex.zName ){
- sqlite3_mutex_free(gMultiplex.pMutex);
- return SQLITE_NOMEM;
- }
gMultiplex.pGroups = NULL;
gMultiplex.isInitialized = 1;
gMultiplex.pOrigVfs = pOrigVfs;
if( gMultiplex.isInitialized==0 ) return SQLITE_MISUSE;
if( gMultiplex.pGroups ) return SQLITE_MISUSE;
gMultiplex.isInitialized = 0;
- sqlite3_free(gMultiplex.zName);
sqlite3_mutex_free(gMultiplex.pMutex);
sqlite3_vfs_unregister(&gMultiplex.sThisVfs);
memset(&gMultiplex, 0, sizeof(gMultiplex));
Tcl_NewIntObj(pGroup->flags));
/* count number of chunks with open handles */
- for(i=0; i<pGroup->nMaxChunks; i++){
- if( pGroup->bOpen[i] ) nChunks++;
+ for(i=0; i<pGroup->nReal; i++){
+ if( pGroup->aReal[i].p!=0 ) nChunks++;
}
Tcl_ListObjAppendElement(interp, pGroupTerm,
Tcl_NewIntObj(nChunks));
Tcl_ListObjAppendElement(interp, pGroupTerm,
Tcl_NewIntObj(pGroup->nChunkSize));
Tcl_ListObjAppendElement(interp, pGroupTerm,
- Tcl_NewIntObj(pGroup->nMaxChunks));
+ Tcl_NewIntObj(pGroup->nReal));
Tcl_ListObjAppendElement(interp, pResult, pGroupTerm);
}
# and files with the chunk extension.
proc multiplex_delete {name} {
global g_max_chunks
+ forcedelete $name
for {set i 0} {$i<$g_max_chunks} {incr i} {
forcedelete [multiplex_name $name $i]
forcedelete [multiplex_name $name-journal $i]
do_test multiplex-1.9.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
do_test multiplex-1.9.2 { sqlite3 db test.db } {}
do_test multiplex-1.9.3 { multiplex_set db main 32768 16 } {SQLITE_OK}
-do_test multiplex-1.9.4 { multiplex_set db main 32768 -1 } {SQLITE_MISUSE}
+do_test multiplex-1.9.4 { multiplex_set db main 32768 -1 } {SQLITE_OK}
do_test multiplex-1.9.5 { multiplex_set db main -1 16 } {SQLITE_MISUSE}
do_test multiplex-1.9.6 { multiplex_set db main 31 16 } {SQLITE_OK}
-do_test multiplex-1.9.7 { multiplex_set db main 32768 100 } {SQLITE_MISUSE}
+do_test multiplex-1.9.7 { multiplex_set db main 32768 100 } {SQLITE_OK}
do_test multiplex-1.9.8 { multiplex_set db main 1073741824 1 } {SQLITE_OK}
do_test multiplex-1.9.9 { db close } {}
do_test multiplex-1.9.10 { sqlite3_multiplex_shutdown } {SQLITE_OK}
do_test multiplex-1.10.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
do_test multiplex-1.10.2 { sqlite3 db test.db } {}
do_test multiplex-1.10.3 { lindex [ catchsql { SELECT multiplex_control(2, 32768); } ] 0 } {0}
-do_test multiplex-1.10.4 { lindex [ catchsql { SELECT multiplex_control(3, -1); } ] 0 } {1}
+do_test multiplex-1.10.4 { lindex [ catchsql { SELECT multiplex_control(3, -1); } ] 0 } {0}
do_test multiplex-1.10.5 { lindex [ catchsql { SELECT multiplex_control(2, -1); } ] 0 } {1}
do_test multiplex-1.10.6 { lindex [ catchsql { SELECT multiplex_control(2, 31); } ] 0 } {0}
-do_test multiplex-1.10.7 { lindex [ catchsql { SELECT multiplex_control(3, 100); } ] 0 } {1}
+do_test multiplex-1.10.7 { lindex [ catchsql { SELECT multiplex_control(3, 100); } ] 0 } {0}
do_test multiplex-1.10.8 { lindex [ catchsql { SELECT multiplex_control(2, 1073741824); } ] 0 } {0}
do_test multiplex-1.10.9 { db close } {}
do_test multiplex-1.10.10 { sqlite3_multiplex_shutdown } {SQLITE_OK}
sqlite3_multiplex_initialize "" 1
multiplex_set db main 32768 16
+file delete -force test.x
do_test multiplex-2.1.2 {
- sqlite3 db test.db
+ sqlite3 db test.x
execsql {
PRAGMA page_size=1024;
PRAGMA auto_vacuum=OFF;
INSERT INTO t1 VALUES(2, randomblob(1100));
}
} {}
-do_test multiplex-2.1.3 { file size [multiplex_name test.db 0] } {4096}
+do_test multiplex-2.1.3 { file size [multiplex_name test.x 0] } {4096}
do_test multiplex-2.1.4 {
execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
} {}
do_test multiplex-2.2.1 {
execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
} {}
-do_test multiplex-2.2.3 { file size [multiplex_name test.db 0] } {6144}
+do_test multiplex-2.2.3 { file size [multiplex_name test.x 0] } {6144}
do_test multiplex-2.3.1 {
- sqlite3 db2 test2.db
+ sqlite3 db2 test2.x
db2 close
} {}
do_test multiplex-2.4.2 {
execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
} {}
-do_test multiplex-2.4.4 { file size [multiplex_name test.db 0] } {7168}
+do_test multiplex-2.4.4 { file size [multiplex_name test.x 0] } {7168}
do_test multiplex-2.4.99 {
db close
sqlite3_multiplex_shutdown
do_test multiplex-2.5.1 {
- multiplex_delete test.db
+ multiplex_delete test.x
sqlite3_multiplex_initialize "" 1
- sqlite3 db test.db
+ sqlite3 db test.x
multiplex_set db main 4096 16
} {SQLITE_OK}
db eval {SELECT a,length(b) FROM t1 WHERE a=4}
} {4 4000}
-do_test multiplex-2.5.9 { file size [multiplex_name test.db 0] } [list $g_chunk_size]
-do_test multiplex-2.5.10 { file size [multiplex_name test.db 1] } [list $g_chunk_size]
+do_test multiplex-2.5.9 { file size [multiplex_name test.x 0] } [list $g_chunk_size]
+do_test multiplex-2.5.10 { file size [multiplex_name test.x 1] } [list $g_chunk_size]
do_test multiplex-2.5.99 {
db close
multiplex_set db main 32768 16
}
-# test that mismatch filesize is detected
-#
-# Do not run this test if $::G(perm:presql) is set. If it is set, then the
-# expected IO error will occur within the Tcl [sqlite3] wrapper, not within
-# the first SQL statement executed below. This breaks the test case.
-#
-if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} {
- set all_journal_modes {delete persist truncate memory off}
- foreach jmode $all_journal_modes {
- do_test multiplex-5.6.1.$jmode {
- sqlite3_multiplex_shutdown
- multiplex_delete test.db
- sqlite3 db test.db
- db eval {
- PRAGMA page_size = 1024;
- PRAGMA auto_vacuum = off;
- }
- db eval "PRAGMA journal_mode = $jmode;"
- } $jmode
- do_test multiplex-5.6.2.$jmode {
- execsql {
- CREATE TABLE t1(a, b);
- INSERT INTO t1 VALUES(1, randomblob(15000));
- INSERT INTO t1 VALUES(2, randomblob(15000));
- INSERT INTO t1 VALUES(3, randomblob(15000));
- INSERT INTO t1 VALUES(4, randomblob(15000));
- INSERT INTO t1 VALUES(5, randomblob(15000));
- }
- db close
- sqlite3_multiplex_initialize "" 1
- sqlite3 db test.db
- multiplex_set db main 4096 16
- } {SQLITE_OK}
- do_test multiplex-5.6.3.$jmode {
- catchsql {
- INSERT INTO t1 VALUES(6, randomblob(15000));
- }
- } {1 {disk I/O error}}
- do_test multiplex-5.6.4.$jmode {
- db close
- } {}
- }
-}
-
#-------------------------------------------------------------------------
# Test that you can vacuum a multiplex'ed DB.
sqlite3_multiplex_shutdown
do_test multiplex-6.0.0 {
multiplex_delete test.db
+ multiplex_delete test.x
sqlite3_multiplex_initialize "" 1
- sqlite3 db test.db
+ sqlite3 db test.x
multiplex_set db main 4096 16
} {SQLITE_OK}
INSERT INTO t1 VALUES(2, randomblob($g_chunk_size));
}
} {}
-do_test multiplex-6.2.1 { file size [multiplex_name test.db 0] } [list $g_chunk_size]
-do_test multiplex-6.2.2 { file size [multiplex_name test.db 1] } [list $g_chunk_size]
+do_test multiplex-6.2.1 { file size [multiplex_name test.x 0] } [list $g_chunk_size]
+do_test multiplex-6.2.2 { file size [multiplex_name test.x 1] } [list $g_chunk_size]
do_test multiplex-6.3.0 {
execsql { VACUUM }
do_test multiplex-6.99 {
db close
- multiplex_delete test.db
+ multiplex_delete test.x
sqlite3_multiplex_shutdown
} {SQLITE_OK}