mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-15 11:41:13 +03:00
Merge the multiplexer enhancements back into the trunk.
FossilOrigin-Name: 2c125710cbf04198464d436b16e5ef37c5b219cf
This commit is contained in:
15
manifest
15
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Add\sa\sscript\sthat\swill\sbreak\sthe\samalgamation\ssource\sfile\sup\sinto\s4\sor\s5\nsmaller\ssource\sfiles,\seach\s32K\slines\sor\sfewer,\sand\sa\ssingle\s"sqlite3-all.c"\nsource\sfile\sthat\s#includes\sthe\sothers.
|
C Merge\sthe\smultiplexer\senhancements\sback\sinto\sthe\strunk.
|
||||||
D 2011-04-01T18:12:58.662
|
D 2011-04-01T18:39:24.584
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
|
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@@ -209,7 +209,8 @@ F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
|
|||||||
F src/test_journal.c 785edd54f963aefb3c1628124170a56697c68c70
|
F src/test_journal.c 785edd54f963aefb3c1628124170a56697c68c70
|
||||||
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
|
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
|
||||||
F src/test_malloc.c fd6188b1501c0010fb4241ddc9f0d5ac402c688d
|
F src/test_malloc.c fd6188b1501c0010fb4241ddc9f0d5ac402c688d
|
||||||
F src/test_multiplex.c 655cb3b663f87db7d3d2427ea127c9daacae4abc
|
F src/test_multiplex.c fdabd793ee7a9642c5a8a470def2347144c46d05
|
||||||
|
F src/test_multiplex.h e99c571bc4968b7a9363b661481f3934bfead61d
|
||||||
F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e
|
F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e
|
||||||
F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
|
F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
|
||||||
F src/test_osinst.c f408c6a181f2fb04c56273afd5c3e1e82f60392c
|
F src/test_osinst.c f408c6a181f2fb04c56273afd5c3e1e82f60392c
|
||||||
@@ -579,7 +580,7 @@ F test/misc5.test 45b2e3ed5f79af2b4f38ae362eaf4c49674575bd
|
|||||||
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
||||||
F test/misc7.test 29032efcd3d826fbd409e2a7af873e7939f4a4e3
|
F test/misc7.test 29032efcd3d826fbd409e2a7af873e7939f4a4e3
|
||||||
F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
|
F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
|
||||||
F test/multiplex.test 92a4839213fd8cba8b59f86d42b7a1da1857db39
|
F test/multiplex.test a88f3e2c16e567e72be7296195c59fbdd6a8d3d4
|
||||||
F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41
|
F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41
|
||||||
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||||
F test/nan.test a44e04df1486fcfb02d32468cbcd3c8e1e433723
|
F test/nan.test a44e04df1486fcfb02d32468cbcd3c8e1e433723
|
||||||
@@ -922,7 +923,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
|||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
|
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
|
||||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||||
P 9415201c8a0b9b640f5997c5348c5df812e88230
|
P 5d34e64d4d2398aa9a54fd0a4f1de37ced7ea5dd 718f1ad7df9115871ba6159012d3183183fc40a1
|
||||||
R c3ff07e6303499e88c2cf0a9abaa71e9
|
R 3be437ca6e714e1f6c593836a791944c
|
||||||
U drh
|
U drh
|
||||||
Z 975ba0a508eed8e252cfd7014026f442
|
Z e8e2d5336305d42bc1912c6d6b830ecf
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
5d34e64d4d2398aa9a54fd0a4f1de37ced7ea5dd
|
2c125710cbf04198464d436b16e5ef37c5b219cf
|
||||||
@@ -22,7 +22,22 @@
|
|||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "sqliteInt.h"
|
#include "test_multiplex.h"
|
||||||
|
|
||||||
|
#ifndef SQLITE_CORE
|
||||||
|
#define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */
|
||||||
|
#endif
|
||||||
|
#include "sqlite3ext.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** These should be defined to be the same as the values in
|
||||||
|
** sqliteInt.h. They are defined seperately here so that
|
||||||
|
** the multiplex VFS shim can be built as a loadable
|
||||||
|
** module.
|
||||||
|
*/
|
||||||
|
#define UNUSED_PARAMETER(x) (void)(x)
|
||||||
|
#define MAX_PAGE_SIZE 0x10000
|
||||||
|
#define DEFAULT_SECTOR_SIZE 0x1000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** For a build without mutexes, no-op the mutex calls.
|
** For a build without mutexes, no-op the mutex calls.
|
||||||
@@ -40,14 +55,18 @@
|
|||||||
|
|
||||||
/************************ Shim Definitions ******************************/
|
/************************ Shim Definitions ******************************/
|
||||||
|
|
||||||
|
#define SQLITE_MULTIPLEX_VFS_NAME "multiplex"
|
||||||
|
|
||||||
/* This is the limit on the chunk size. It may be changed by calling
|
/* This is the limit on the chunk size. It may be changed by calling
|
||||||
** the sqlite3_multiplex_set() interface.
|
** the xFileControl() interface. It will be rounded up to a
|
||||||
|
** multiple of MAX_PAGE_SIZE. We default it here to 1GB.
|
||||||
*/
|
*/
|
||||||
#define SQLITE_MULTIPLEX_CHUNK_SIZE 0x40000000
|
#define SQLITE_MULTIPLEX_CHUNK_SIZE (MAX_PAGE_SIZE*16384)
|
||||||
|
|
||||||
/* Default limit on number of chunks. Care should be taken
|
/* Default limit on number of chunks. Care should be taken
|
||||||
** so that values for chunks numbers fit in the SQLITE_MULTIPLEX_EXT_FMT
|
** so that values for chunks numbers fit in the SQLITE_MULTIPLEX_EXT_FMT
|
||||||
** format specifier. It may be changed by calling
|
** format specifier. It may be changed by calling
|
||||||
** the sqlite3_multiplex_set() interface.
|
** the xFileControl() interface.
|
||||||
*/
|
*/
|
||||||
#define SQLITE_MULTIPLEX_MAX_CHUNKS 32
|
#define SQLITE_MULTIPLEX_MAX_CHUNKS 32
|
||||||
|
|
||||||
@@ -82,6 +101,9 @@ struct multiplexGroup {
|
|||||||
char *zName; /* Base filename of this group */
|
char *zName; /* Base filename of this group */
|
||||||
int nName; /* Length of base filename */
|
int nName; /* Length of base filename */
|
||||||
int flags; /* Flags used for original opening */
|
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 */
|
multiplexGroup *pNext, *pPrev; /* Doubly linked list of all group objects */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -140,11 +162,6 @@ static struct {
|
|||||||
*/
|
*/
|
||||||
multiplexGroup *pGroups;
|
multiplexGroup *pGroups;
|
||||||
|
|
||||||
/* Chunk params.
|
|
||||||
*/
|
|
||||||
int nChunkSize;
|
|
||||||
int nMaxChunks;
|
|
||||||
|
|
||||||
/* Storage for temp file names. Allocated during
|
/* Storage for temp file names. Allocated during
|
||||||
** initialization to the max pathname of the underlying VFS.
|
** initialization to the max pathname of the underlying VFS.
|
||||||
*/
|
*/
|
||||||
@@ -160,13 +177,28 @@ static struct {
|
|||||||
static void multiplexEnter(void){ sqlite3_mutex_enter(gMultiplex.pMutex); }
|
static void multiplexEnter(void){ sqlite3_mutex_enter(gMultiplex.pMutex); }
|
||||||
static void multiplexLeave(void){ sqlite3_mutex_leave(gMultiplex.pMutex); }
|
static void multiplexLeave(void){ sqlite3_mutex_leave(gMultiplex.pMutex); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Compute a string length that is limited to what can be stored in
|
||||||
|
** lower 30 bits of a 32-bit signed integer.
|
||||||
|
**
|
||||||
|
** The value returned will never be negative. Nor will it ever be greater
|
||||||
|
** than the actual length of the string. For very long strings (greater
|
||||||
|
** than 1GiB) the value returned might be less than the true string length.
|
||||||
|
*/
|
||||||
|
int multiplexStrlen30(const char *z){
|
||||||
|
const char *z2 = z;
|
||||||
|
if( z==0 ) return 0;
|
||||||
|
while( *z2 ){ z2++; }
|
||||||
|
return 0x3fffffff & (int)(z2 - z);
|
||||||
|
}
|
||||||
|
|
||||||
/* Translate an sqlite3_file* that is really a multiplexGroup* into
|
/* Translate an sqlite3_file* that is really a multiplexGroup* into
|
||||||
** the sqlite3_file* for the underlying original VFS.
|
** the sqlite3_file* for the underlying original VFS.
|
||||||
*/
|
*/
|
||||||
static sqlite3_file *multiplexSubOpen(multiplexConn *pConn, int iChunk, int *rc, int *pOutFlags){
|
static sqlite3_file *multiplexSubOpen(multiplexConn *pConn, int iChunk, int *rc, int *pOutFlags){
|
||||||
multiplexGroup *pGroup = pConn->pGroup;
|
multiplexGroup *pGroup = pConn->pGroup;
|
||||||
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
|
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
|
||||||
if( iChunk<gMultiplex.nMaxChunks ){
|
if( iChunk<pGroup->nMaxChunks ){
|
||||||
sqlite3_file *pSubOpen = pGroup->pReal[iChunk]; /* Real file descriptor */
|
sqlite3_file *pSubOpen = pGroup->pReal[iChunk]; /* Real file descriptor */
|
||||||
if( !pGroup->bOpen[iChunk] ){
|
if( !pGroup->bOpen[iChunk] ){
|
||||||
memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
|
memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
|
||||||
@@ -191,6 +223,62 @@ static sqlite3_file *multiplexSubOpen(multiplexConn *pConn, int iChunk, int *rc,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This is the implementation of the multiplex_control() SQL function.
|
||||||
|
*/
|
||||||
|
static void multiplexControlFunc(
|
||||||
|
sqlite3_context *context,
|
||||||
|
int argc,
|
||||||
|
sqlite3_value **argv
|
||||||
|
){
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||||
|
int op;
|
||||||
|
int iVal;
|
||||||
|
|
||||||
|
if( !db || argc!=2 ){
|
||||||
|
rc = SQLITE_ERROR;
|
||||||
|
}else{
|
||||||
|
/* extract params */
|
||||||
|
op = sqlite3_value_int(argv[0]);
|
||||||
|
iVal = sqlite3_value_int(argv[1]);
|
||||||
|
/* map function op to file_control op */
|
||||||
|
switch( op ){
|
||||||
|
case 1:
|
||||||
|
op = MULTIPLEX_CTRL_ENABLE;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
op = MULTIPLEX_CTRL_SET_CHUNK_SIZE;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
op = MULTIPLEX_CTRL_SET_MAX_CHUNKS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rc = SQLITE_NOTFOUND;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = sqlite3_file_control(db, 0, op, &iVal);
|
||||||
|
}
|
||||||
|
sqlite3_result_error_code(context, rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This is the entry point to register the auto-extension for the
|
||||||
|
** multiplex_control() function.
|
||||||
|
*/
|
||||||
|
static int multiplexFuncInit(
|
||||||
|
sqlite3 *db,
|
||||||
|
char **pzErrMsg,
|
||||||
|
const sqlite3_api_routines *pApi
|
||||||
|
){
|
||||||
|
int rc;
|
||||||
|
rc = sqlite3_create_function(db, "multiplex_control", 2, SQLITE_ANY,
|
||||||
|
0, multiplexControlFunc, 0, 0);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/************************* VFS Method Wrappers *****************************/
|
/************************* VFS Method Wrappers *****************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -212,7 +300,7 @@ static int multiplexOpen(
|
|||||||
multiplexGroup *pGroup; /* Corresponding multiplexGroup object */
|
multiplexGroup *pGroup; /* Corresponding multiplexGroup object */
|
||||||
sqlite3_file *pSubOpen; /* Real file descriptor */
|
sqlite3_file *pSubOpen; /* Real file descriptor */
|
||||||
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
|
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
|
||||||
int nName = sqlite3Strlen30(zName);
|
int nName = multiplexStrlen30(zName);
|
||||||
int i;
|
int i;
|
||||||
int sz;
|
int sz;
|
||||||
|
|
||||||
@@ -225,9 +313,9 @@ static int multiplexOpen(
|
|||||||
pMultiplexOpen = (multiplexConn*)pConn;
|
pMultiplexOpen = (multiplexConn*)pConn;
|
||||||
/* allocate space for group */
|
/* allocate space for group */
|
||||||
sz = sizeof(multiplexGroup) /* multiplexGroup */
|
sz = sizeof(multiplexGroup) /* multiplexGroup */
|
||||||
+ (sizeof(sqlite3_file *)*gMultiplex.nMaxChunks) /* pReal[] */
|
+ (sizeof(sqlite3_file *)*SQLITE_MULTIPLEX_MAX_CHUNKS) /* pReal[] */
|
||||||
+ (pOrigVfs->szOsFile*gMultiplex.nMaxChunks) /* *pReal */
|
+ (pOrigVfs->szOsFile*SQLITE_MULTIPLEX_MAX_CHUNKS) /* *pReal */
|
||||||
+ gMultiplex.nMaxChunks /* bOpen[] */
|
+ SQLITE_MULTIPLEX_MAX_CHUNKS /* bOpen[] */
|
||||||
+ nName + 1; /* zName */
|
+ nName + 1; /* zName */
|
||||||
#ifndef SQLITE_MULTIPLEX_EXT_OVWR
|
#ifndef SQLITE_MULTIPLEX_EXT_OVWR
|
||||||
sz += SQLITE_MULTIPLEX_EXT_SZ;
|
sz += SQLITE_MULTIPLEX_EXT_SZ;
|
||||||
@@ -244,14 +332,18 @@ static int multiplexOpen(
|
|||||||
char *p = (char *)&pGroup[1];
|
char *p = (char *)&pGroup[1];
|
||||||
pMultiplexOpen->pGroup = pGroup;
|
pMultiplexOpen->pGroup = pGroup;
|
||||||
memset(pGroup, 0, sz);
|
memset(pGroup, 0, sz);
|
||||||
|
pGroup->bEnabled = -1;
|
||||||
|
pGroup->nChunkSize = SQLITE_MULTIPLEX_CHUNK_SIZE;
|
||||||
|
pGroup->nMaxChunks = SQLITE_MULTIPLEX_MAX_CHUNKS;
|
||||||
pGroup->pReal = (sqlite3_file **)p;
|
pGroup->pReal = (sqlite3_file **)p;
|
||||||
p += (sizeof(sqlite3_file *)*gMultiplex.nMaxChunks);
|
p += (sizeof(sqlite3_file *)*pGroup->nMaxChunks);
|
||||||
for(i=0; i<gMultiplex.nMaxChunks; i++){
|
for(i=0; i<pGroup->nMaxChunks; i++){
|
||||||
pGroup->pReal[i] = (sqlite3_file *)p;
|
pGroup->pReal[i] = (sqlite3_file *)p;
|
||||||
p += pOrigVfs->szOsFile;
|
p += pOrigVfs->szOsFile;
|
||||||
}
|
}
|
||||||
|
/* bOpen[] vals should all be zero from memset above */
|
||||||
pGroup->bOpen = p;
|
pGroup->bOpen = p;
|
||||||
p += gMultiplex.nMaxChunks;
|
p += pGroup->nMaxChunks;
|
||||||
pGroup->zName = p;
|
pGroup->zName = p;
|
||||||
/* save off base filename, name length, and original open flags */
|
/* save off base filename, name length, and original open flags */
|
||||||
memcpy(pGroup->zName, zName, nName+1);
|
memcpy(pGroup->zName, zName, nName+1);
|
||||||
@@ -259,6 +351,14 @@ static int multiplexOpen(
|
|||||||
pGroup->flags = flags;
|
pGroup->flags = flags;
|
||||||
pSubOpen = multiplexSubOpen(pMultiplexOpen, 0, &rc, pOutFlags);
|
pSubOpen = multiplexSubOpen(pMultiplexOpen, 0, &rc, pOutFlags);
|
||||||
if( pSubOpen ){
|
if( pSubOpen ){
|
||||||
|
/* if this file is already larger than chunk size, disable
|
||||||
|
** the multiplex feature.
|
||||||
|
*/
|
||||||
|
sqlite3_int64 sz;
|
||||||
|
int rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
|
||||||
|
if( (rc2==SQLITE_OK) && (sz>pGroup->nChunkSize) ){
|
||||||
|
pGroup->bEnabled = 0;
|
||||||
|
}
|
||||||
if( pSubOpen->pMethods->iVersion==1 ){
|
if( pSubOpen->pMethods->iVersion==1 ){
|
||||||
pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1;
|
pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1;
|
||||||
}else{
|
}else{
|
||||||
@@ -288,24 +388,29 @@ static int multiplexDelete(
|
|||||||
){
|
){
|
||||||
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
|
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
int nName = sqlite3Strlen30(zName);
|
int nName = multiplexStrlen30(zName);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
UNUSED_PARAMETER(pVfs);
|
UNUSED_PARAMETER(pVfs);
|
||||||
|
|
||||||
multiplexEnter();
|
multiplexEnter();
|
||||||
memcpy(gMultiplex.zName, zName, nName+1);
|
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 rc2;
|
||||||
int exists = 0;
|
int exists = 0;
|
||||||
if( i ){
|
if( i ){
|
||||||
#ifdef SQLITE_MULTIPLEX_EXT_OVWR
|
#ifdef SQLITE_MULTIPLEX_EXT_OVWR
|
||||||
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, gMultiplex.zName+nName-SQLITE_MULTIPLEX_EXT_SZ, SQLITE_MULTIPLEX_EXT_FMT, i);
|
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
|
||||||
|
gMultiplex.zName+nName-SQLITE_MULTIPLEX_EXT_SZ,
|
||||||
|
SQLITE_MULTIPLEX_EXT_FMT, i);
|
||||||
#else
|
#else
|
||||||
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, gMultiplex.zName+nName, SQLITE_MULTIPLEX_EXT_FMT, i);
|
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
|
||||||
|
gMultiplex.zName+nName,
|
||||||
|
SQLITE_MULTIPLEX_EXT_FMT, i);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName, SQLITE_ACCESS_EXISTS, &exists);
|
rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName,
|
||||||
|
SQLITE_ACCESS_EXISTS, &exists);
|
||||||
if( rc2==SQLITE_OK && exists){
|
if( rc2==SQLITE_OK && exists){
|
||||||
/* if it exists, delete it */
|
/* if it exists, delete it */
|
||||||
rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, syncDir);
|
rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, syncDir);
|
||||||
@@ -367,7 +472,7 @@ static int multiplexClose(sqlite3_file *pConn){
|
|||||||
int i;
|
int i;
|
||||||
multiplexEnter();
|
multiplexEnter();
|
||||||
/* close any open handles */
|
/* close any open handles */
|
||||||
for(i=0; i<gMultiplex.nMaxChunks; i++){
|
for(i=0; i<pGroup->nMaxChunks; i++){
|
||||||
if( pGroup->bOpen[i] ){
|
if( pGroup->bOpen[i] ){
|
||||||
sqlite3_file *pSubOpen = pGroup->pReal[i];
|
sqlite3_file *pSubOpen = pGroup->pReal[i];
|
||||||
int rc2 = pSubOpen->pMethods->xClose(pSubOpen);
|
int rc2 = pSubOpen->pMethods->xClose(pSubOpen);
|
||||||
@@ -398,16 +503,21 @@ static int multiplexRead(
|
|||||||
sqlite3_int64 iOfst
|
sqlite3_int64 iOfst
|
||||||
){
|
){
|
||||||
multiplexConn *p = (multiplexConn*)pConn;
|
multiplexConn *p = (multiplexConn*)pConn;
|
||||||
|
multiplexGroup *pGroup = p->pGroup;
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
multiplexEnter();
|
multiplexEnter();
|
||||||
|
if( !pGroup->bEnabled ){
|
||||||
|
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
|
||||||
|
rc = ( !pSubOpen ) ? SQLITE_IOERR_READ : pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst);
|
||||||
|
}else{
|
||||||
while( iAmt > 0 ){
|
while( iAmt > 0 ){
|
||||||
int i = (int)(iOfst/gMultiplex.nChunkSize);
|
int i = (int)(iOfst / pGroup->nChunkSize);
|
||||||
sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
|
sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
|
||||||
if( pSubOpen ){
|
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;
|
if( extra<0 ) extra = 0;
|
||||||
iAmt -= extra;
|
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;
|
if( rc!=SQLITE_OK ) break;
|
||||||
pBuf = (char *)pBuf + iAmt;
|
pBuf = (char *)pBuf + iAmt;
|
||||||
iOfst += iAmt;
|
iOfst += iAmt;
|
||||||
@@ -417,6 +527,7 @@ static int multiplexRead(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
multiplexLeave();
|
multiplexLeave();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -432,16 +543,21 @@ static int multiplexWrite(
|
|||||||
sqlite3_int64 iOfst
|
sqlite3_int64 iOfst
|
||||||
){
|
){
|
||||||
multiplexConn *p = (multiplexConn*)pConn;
|
multiplexConn *p = (multiplexConn*)pConn;
|
||||||
|
multiplexGroup *pGroup = p->pGroup;
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
multiplexEnter();
|
multiplexEnter();
|
||||||
|
if( !pGroup->bEnabled ){
|
||||||
|
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
|
||||||
|
rc = ( !pSubOpen ) ? SQLITE_IOERR_WRITE : pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst);
|
||||||
|
}else{
|
||||||
while( iAmt > 0 ){
|
while( iAmt > 0 ){
|
||||||
int i = (int)(iOfst/gMultiplex.nChunkSize);
|
int i = (int)(iOfst / pGroup->nChunkSize);
|
||||||
sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
|
sqlite3_file *pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
|
||||||
if( pSubOpen ){
|
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;
|
if( extra<0 ) extra = 0;
|
||||||
iAmt -= extra;
|
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;
|
if( rc!=SQLITE_OK ) break;
|
||||||
pBuf = (char *)pBuf + iAmt;
|
pBuf = (char *)pBuf + iAmt;
|
||||||
iOfst += iAmt;
|
iOfst += iAmt;
|
||||||
@@ -451,6 +567,7 @@ static int multiplexWrite(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
multiplexLeave();
|
multiplexLeave();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -463,14 +580,18 @@ static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){
|
|||||||
multiplexConn *p = (multiplexConn*)pConn;
|
multiplexConn *p = (multiplexConn*)pConn;
|
||||||
multiplexGroup *pGroup = p->pGroup;
|
multiplexGroup *pGroup = p->pGroup;
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
|
multiplexEnter();
|
||||||
|
if( !pGroup->bEnabled ){
|
||||||
|
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
|
||||||
|
rc = ( !pSubOpen ) ? SQLITE_IOERR_TRUNCATE : pSubOpen->pMethods->xTruncate(pSubOpen, size);
|
||||||
|
}else{
|
||||||
int rc2;
|
int rc2;
|
||||||
int i;
|
int i;
|
||||||
sqlite3_file *pSubOpen;
|
sqlite3_file *pSubOpen;
|
||||||
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
|
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
|
||||||
multiplexEnter();
|
|
||||||
memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
|
memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
|
||||||
/* delete the chunks above the truncate limit */
|
/* 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 */
|
/* close any open chunks before deleting them */
|
||||||
if( pGroup->bOpen[i] ){
|
if( pGroup->bOpen[i] ){
|
||||||
pSubOpen = pGroup->pReal[i];
|
pSubOpen = pGroup->pReal[i];
|
||||||
@@ -479,20 +600,25 @@ static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){
|
|||||||
pGroup->bOpen[i] = 0;
|
pGroup->bOpen[i] = 0;
|
||||||
}
|
}
|
||||||
#ifdef SQLITE_MULTIPLEX_EXT_OVWR
|
#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);
|
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
|
||||||
|
gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ,
|
||||||
|
SQLITE_MULTIPLEX_EXT_FMT, i);
|
||||||
#else
|
#else
|
||||||
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, gMultiplex.zName+pGroup->nName, SQLITE_MULTIPLEX_EXT_FMT, i);
|
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
|
||||||
|
gMultiplex.zName+pGroup->nName,
|
||||||
|
SQLITE_MULTIPLEX_EXT_FMT, i);
|
||||||
#endif
|
#endif
|
||||||
rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, 0);
|
rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, 0);
|
||||||
if( rc2!=SQLITE_OK ) rc = SQLITE_IOERR_TRUNCATE;
|
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 ){
|
if( pSubOpen ){
|
||||||
rc2 = pSubOpen->pMethods->xTruncate(pSubOpen, size%gMultiplex.nChunkSize);
|
rc2 = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->nChunkSize);
|
||||||
if( rc2!=SQLITE_OK ) rc = rc2;
|
if( rc2!=SQLITE_OK ) rc = rc2;
|
||||||
}else{
|
}else{
|
||||||
rc = SQLITE_IOERR_TRUNCATE;
|
rc = SQLITE_IOERR_TRUNCATE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
multiplexLeave();
|
multiplexLeave();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -505,7 +631,7 @@ static int multiplexSync(sqlite3_file *pConn, int flags){
|
|||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
int i;
|
int i;
|
||||||
multiplexEnter();
|
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 we don't have it open, we don't need to sync it */
|
||||||
if( pGroup->bOpen[i] ){
|
if( pGroup->bOpen[i] ){
|
||||||
sqlite3_file *pSubOpen = pGroup->pReal[i];
|
sqlite3_file *pSubOpen = pGroup->pReal[i];
|
||||||
@@ -527,8 +653,12 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
|
|||||||
int rc2;
|
int rc2;
|
||||||
int i;
|
int i;
|
||||||
multiplexEnter();
|
multiplexEnter();
|
||||||
|
if( !pGroup->bEnabled ){
|
||||||
|
sqlite3_file *pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
|
||||||
|
rc = ( !pSubOpen ) ? SQLITE_IOERR_FSTAT : pSubOpen->pMethods->xFileSize(pSubOpen, pSize);
|
||||||
|
}else{
|
||||||
*pSize = 0;
|
*pSize = 0;
|
||||||
for(i=0; i<gMultiplex.nMaxChunks; i++){
|
for(i=0; i<pGroup->nMaxChunks; i++){
|
||||||
sqlite3_file *pSubOpen = NULL;
|
sqlite3_file *pSubOpen = NULL;
|
||||||
/* if not opened already, check to see if the chunk exists */
|
/* if not opened already, check to see if the chunk exists */
|
||||||
if( pGroup->bOpen[i] ){
|
if( pGroup->bOpen[i] ){
|
||||||
@@ -539,12 +669,17 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
|
|||||||
memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
|
memcpy(gMultiplex.zName, pGroup->zName, pGroup->nName+1);
|
||||||
if( i ){
|
if( i ){
|
||||||
#ifdef SQLITE_MULTIPLEX_EXT_OVWR
|
#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);
|
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
|
||||||
|
gMultiplex.zName+pGroup->nName-SQLITE_MULTIPLEX_EXT_SZ,
|
||||||
|
SQLITE_MULTIPLEX_EXT_FMT, i);
|
||||||
#else
|
#else
|
||||||
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1, gMultiplex.zName+pGroup->nName, SQLITE_MULTIPLEX_EXT_FMT, i);
|
sqlite3_snprintf(SQLITE_MULTIPLEX_EXT_SZ+1,
|
||||||
|
gMultiplex.zName+pGroup->nName,
|
||||||
|
SQLITE_MULTIPLEX_EXT_FMT, i);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName, SQLITE_ACCESS_EXISTS, &exists);
|
rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName,
|
||||||
|
SQLITE_ACCESS_EXISTS, &exists);
|
||||||
if( rc2==SQLITE_OK && exists){
|
if( rc2==SQLITE_OK && exists){
|
||||||
/* if it exists, open it */
|
/* if it exists, open it */
|
||||||
pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
|
pSubOpen = multiplexSubOpen(p, i, &rc, NULL);
|
||||||
@@ -559,7 +694,7 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
|
|||||||
if( rc2!=SQLITE_OK ){
|
if( rc2!=SQLITE_OK ){
|
||||||
rc = rc2;
|
rc = rc2;
|
||||||
}else{
|
}else{
|
||||||
if( sz>gMultiplex.nChunkSize ){
|
if( sz>pGroup->nChunkSize ){
|
||||||
rc = SQLITE_IOERR_FSTAT;
|
rc = SQLITE_IOERR_FSTAT;
|
||||||
}
|
}
|
||||||
*pSize += sz;
|
*pSize += sz;
|
||||||
@@ -568,6 +703,7 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
multiplexLeave();
|
multiplexLeave();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -608,18 +744,62 @@ static int multiplexCheckReservedLock(sqlite3_file *pConn, int *pResOut){
|
|||||||
return SQLITE_IOERR_CHECKRESERVEDLOCK;
|
return SQLITE_IOERR_CHECKRESERVEDLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pass xFileControl requests through to the original VFS unchanged.
|
/* Pass xFileControl requests through to the original VFS unchanged,
|
||||||
|
** except for any MULTIPLEX_CTRL_* requests here.
|
||||||
*/
|
*/
|
||||||
static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
|
static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
|
||||||
multiplexConn *p = (multiplexConn*)pConn;
|
multiplexConn *p = (multiplexConn*)pConn;
|
||||||
int rc;
|
multiplexGroup *pGroup = p->pGroup;
|
||||||
|
int rc = SQLITE_ERROR;
|
||||||
sqlite3_file *pSubOpen;
|
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<1 ){
|
||||||
|
rc = SQLITE_MISUSE;
|
||||||
|
}else{
|
||||||
|
/* Round up to nearest multiple of MAX_PAGE_SIZE. */
|
||||||
|
nChunkSize = (nChunkSize + (MAX_PAGE_SIZE-1));
|
||||||
|
nChunkSize &= ~(MAX_PAGE_SIZE-1);
|
||||||
|
pGroup->nChunkSize = nChunkSize;
|
||||||
|
rc = SQLITE_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SQLITE_FCNTL_SIZE_HINT:
|
||||||
|
case SQLITE_FCNTL_CHUNK_SIZE:
|
||||||
|
/* no-op these */
|
||||||
|
rc = SQLITE_OK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
|
pSubOpen = multiplexSubOpen(p, 0, &rc, NULL);
|
||||||
if( pSubOpen ){
|
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.
|
/* Pass xSectorSize requests through to the original VFS unchanged.
|
||||||
@@ -631,7 +811,7 @@ static int multiplexSectorSize(sqlite3_file *pConn){
|
|||||||
if( pSubOpen ){
|
if( pSubOpen ){
|
||||||
return pSubOpen->pMethods->xSectorSize(pSubOpen);
|
return pSubOpen->pMethods->xSectorSize(pSubOpen);
|
||||||
}
|
}
|
||||||
return SQLITE_DEFAULT_SECTOR_SIZE;
|
return DEFAULT_SECTOR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pass xDeviceCharacteristics requests through to the original VFS unchanged.
|
/* Pass xDeviceCharacteristics requests through to the original VFS unchanged.
|
||||||
@@ -706,9 +886,10 @@ static int multiplexShmUnmap(sqlite3_file *pConn, int deleteFlag){
|
|||||||
|
|
||||||
/************************** Public Interfaces *****************************/
|
/************************** Public Interfaces *****************************/
|
||||||
/*
|
/*
|
||||||
** Initialize the multiplex VFS shim. Use the VFS named zOrigVfsName
|
** CAPI: Initialize the multiplex VFS shim - sqlite3_multiplex_initialize()
|
||||||
** as the VFS that does the actual work. Use the default if
|
**
|
||||||
** zOrigVfsName==NULL.
|
** Use the VFS named zOrigVfsName as the VFS that does the actual work.
|
||||||
|
** Use the default if zOrigVfsName==NULL.
|
||||||
**
|
**
|
||||||
** The multiplex VFS shim is named "multiplex". It will become the default
|
** The multiplex VFS shim is named "multiplex". It will become the default
|
||||||
** VFS if makeDefault is non-zero.
|
** VFS if makeDefault is non-zero.
|
||||||
@@ -731,14 +912,12 @@ int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){
|
|||||||
sqlite3_mutex_free(gMultiplex.pMutex);
|
sqlite3_mutex_free(gMultiplex.pMutex);
|
||||||
return SQLITE_NOMEM;
|
return SQLITE_NOMEM;
|
||||||
}
|
}
|
||||||
gMultiplex.nChunkSize = SQLITE_MULTIPLEX_CHUNK_SIZE;
|
|
||||||
gMultiplex.nMaxChunks = SQLITE_MULTIPLEX_MAX_CHUNKS;
|
|
||||||
gMultiplex.pGroups = NULL;
|
gMultiplex.pGroups = NULL;
|
||||||
gMultiplex.isInitialized = 1;
|
gMultiplex.isInitialized = 1;
|
||||||
gMultiplex.pOrigVfs = pOrigVfs;
|
gMultiplex.pOrigVfs = pOrigVfs;
|
||||||
gMultiplex.sThisVfs = *pOrigVfs;
|
gMultiplex.sThisVfs = *pOrigVfs;
|
||||||
gMultiplex.sThisVfs.szOsFile += sizeof(multiplexConn);
|
gMultiplex.sThisVfs.szOsFile += sizeof(multiplexConn);
|
||||||
gMultiplex.sThisVfs.zName = "multiplex";
|
gMultiplex.sThisVfs.zName = SQLITE_MULTIPLEX_VFS_NAME;
|
||||||
gMultiplex.sThisVfs.xOpen = multiplexOpen;
|
gMultiplex.sThisVfs.xOpen = multiplexOpen;
|
||||||
gMultiplex.sThisVfs.xDelete = multiplexDelete;
|
gMultiplex.sThisVfs.xDelete = multiplexDelete;
|
||||||
gMultiplex.sThisVfs.xAccess = multiplexAccess;
|
gMultiplex.sThisVfs.xAccess = multiplexAccess;
|
||||||
@@ -773,11 +952,14 @@ int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){
|
|||||||
gMultiplex.sIoMethodsV2.xShmBarrier = multiplexShmBarrier;
|
gMultiplex.sIoMethodsV2.xShmBarrier = multiplexShmBarrier;
|
||||||
gMultiplex.sIoMethodsV2.xShmUnmap = multiplexShmUnmap;
|
gMultiplex.sIoMethodsV2.xShmUnmap = multiplexShmUnmap;
|
||||||
sqlite3_vfs_register(&gMultiplex.sThisVfs, makeDefault);
|
sqlite3_vfs_register(&gMultiplex.sThisVfs, makeDefault);
|
||||||
|
|
||||||
|
sqlite3_auto_extension((void*)multiplexFuncInit);
|
||||||
|
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Shutdown the multiplex system.
|
** CAPI: Shutdown the multiplex system - sqlite3_multiplex_shutdown()
|
||||||
**
|
**
|
||||||
** All SQLite database connections must be closed before calling this
|
** All SQLite database connections must be closed before calling this
|
||||||
** routine.
|
** routine.
|
||||||
@@ -796,31 +978,9 @@ int sqlite3_multiplex_shutdown(void){
|
|||||||
return SQLITE_OK;
|
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 ***********************************/
|
/***************************** Test Code ***********************************/
|
||||||
#ifdef SQLITE_TEST
|
#ifdef SQLITE_TEST
|
||||||
#include <tcl.h>
|
#include <tcl.h>
|
||||||
|
|
||||||
extern const char *sqlite3TestErrorName(int);
|
extern const char *sqlite3TestErrorName(int);
|
||||||
|
|
||||||
|
|
||||||
@@ -880,36 +1040,6 @@ static int test_multiplex_shutdown(
|
|||||||
return TCL_OK;
|
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
|
** tclcmd: sqlite3_multiplex_dump
|
||||||
*/
|
*/
|
||||||
@@ -943,16 +1073,16 @@ static int test_multiplex_dump(
|
|||||||
Tcl_NewIntObj(pGroup->flags));
|
Tcl_NewIntObj(pGroup->flags));
|
||||||
|
|
||||||
/* count number of chunks with open handles */
|
/* 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++;
|
if( pGroup->bOpen[i] ) nChunks++;
|
||||||
}
|
}
|
||||||
Tcl_ListObjAppendElement(interp, pGroupTerm,
|
Tcl_ListObjAppendElement(interp, pGroupTerm,
|
||||||
Tcl_NewIntObj(nChunks));
|
Tcl_NewIntObj(nChunks));
|
||||||
|
|
||||||
Tcl_ListObjAppendElement(interp, pGroupTerm,
|
Tcl_ListObjAppendElement(interp, pGroupTerm,
|
||||||
Tcl_NewIntObj(gMultiplex.nChunkSize));
|
Tcl_NewIntObj(pGroup->nChunkSize));
|
||||||
Tcl_ListObjAppendElement(interp, pGroupTerm,
|
Tcl_ListObjAppendElement(interp, pGroupTerm,
|
||||||
Tcl_NewIntObj(gMultiplex.nMaxChunks));
|
Tcl_NewIntObj(pGroup->nMaxChunks));
|
||||||
|
|
||||||
Tcl_ListObjAppendElement(interp, pResult, pGroupTerm);
|
Tcl_ListObjAppendElement(interp, pResult, pGroupTerm);
|
||||||
}
|
}
|
||||||
@@ -961,6 +1091,68 @@ static int test_multiplex_dump(
|
|||||||
return TCL_OK;
|
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!=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( 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
|
** This routine registers the custom TCL commands defined in this
|
||||||
** module. This should be the only procedure visible from outside
|
** module. This should be the only procedure visible from outside
|
||||||
@@ -973,8 +1165,8 @@ int Sqlitemultiplex_Init(Tcl_Interp *interp){
|
|||||||
} aCmd[] = {
|
} aCmd[] = {
|
||||||
{ "sqlite3_multiplex_initialize", test_multiplex_initialize },
|
{ "sqlite3_multiplex_initialize", test_multiplex_initialize },
|
||||||
{ "sqlite3_multiplex_shutdown", test_multiplex_shutdown },
|
{ "sqlite3_multiplex_shutdown", test_multiplex_shutdown },
|
||||||
{ "sqlite3_multiplex_set", test_multiplex_set },
|
|
||||||
{ "sqlite3_multiplex_dump", test_multiplex_dump },
|
{ "sqlite3_multiplex_dump", test_multiplex_dump },
|
||||||
|
{ "sqlite3_multiplex_control", test_multiplex_control },
|
||||||
};
|
};
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|||||||
91
src/test_multiplex.h
Normal file
91
src/test_multiplex.h
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
** 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. The chunk size should be
|
||||||
|
** a multiple of SQLITE_MAX_PAGE_SIZE, and will be rounded up
|
||||||
|
** if not.
|
||||||
|
**
|
||||||
|
** 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
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Initialize the multiplex VFS shim - sqlite3_multiplex_initialize()
|
||||||
|
**
|
||||||
|
** Use the VFS named zOrigVfsName as the VFS that does the actual work.
|
||||||
|
** Use the default if zOrigVfsName==NULL.
|
||||||
|
**
|
||||||
|
** The multiplex VFS shim is named "multiplex". It will become the default
|
||||||
|
** VFS if makeDefault is non-zero.
|
||||||
|
**
|
||||||
|
** An auto-extension is registered which will make the function
|
||||||
|
** multiplex_control() available to database connections. This
|
||||||
|
** function gives access to the xFileControl interface of the
|
||||||
|
** multiplex VFS shim.
|
||||||
|
**
|
||||||
|
** SELECT multiplex_control(<op>,<val>);
|
||||||
|
**
|
||||||
|
** <op>=1 MULTIPLEX_CTRL_ENABLE
|
||||||
|
** <val>=0 disable
|
||||||
|
** <val>=1 enable
|
||||||
|
**
|
||||||
|
** <op>=2 MULTIPLEX_CTRL_SET_CHUNK_SIZE
|
||||||
|
** <val> int, chunk size
|
||||||
|
**
|
||||||
|
** <op>=3 MULTIPLEX_CTRL_SET_MAX_CHUNKS
|
||||||
|
** <val> int, max chunks
|
||||||
|
**
|
||||||
|
** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once
|
||||||
|
** during start-up.
|
||||||
|
*/
|
||||||
|
extern int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Shutdown the multiplex system - sqlite3_multiplex_shutdown()
|
||||||
|
**
|
||||||
|
** All SQLite database connections must be closed before calling this
|
||||||
|
** routine.
|
||||||
|
**
|
||||||
|
** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while
|
||||||
|
** shutting down in order to free all remaining multiplex groups.
|
||||||
|
*/
|
||||||
|
extern int sqlite3_multiplex_shutdown(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -14,7 +14,7 @@ set testdir [file dirname $argv0]
|
|||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
source $testdir/malloc_common.tcl
|
source $testdir/malloc_common.tcl
|
||||||
|
|
||||||
set g_chunk_size 2147483648
|
set g_chunk_size [ expr ($::SQLITE_MAX_PAGE_SIZE*16384) ]
|
||||||
set g_max_chunks 32
|
set g_max_chunks 32
|
||||||
|
|
||||||
# This handles appending the chunk number
|
# This handles appending the chunk number
|
||||||
@@ -32,13 +32,17 @@ proc multiplex_name {name chunk} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# This saves off the parameters and calls the
|
# This saves off the parameters and calls the
|
||||||
# underlying sqlite3_multiplex_set() API.
|
# underlying sqlite3_multiplex_control() API.
|
||||||
proc multiplex_set {chunk_size max_chunks} {
|
proc multiplex_set {db name chunk_size max_chunks} {
|
||||||
global g_chunk_size
|
global g_chunk_size
|
||||||
global g_max_chunks
|
global g_max_chunks
|
||||||
set g_chunk_size $chunk_size
|
set g_chunk_size [ expr (($chunk_size+($::SQLITE_MAX_PAGE_SIZE-1)) & ~($::SQLITE_MAX_PAGE_SIZE-1)) ]
|
||||||
set g_max_chunks $max_chunks
|
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
|
# This attempts to delete the base file and
|
||||||
@@ -70,14 +74,51 @@ do_test multiplex-1.6 { sqlite3_multiplex_shutdown } {SQLITE_OK}
|
|||||||
do_test multiplex-1.7 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
|
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.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}
|
|
||||||
do_test multiplex-1.11 { sqlite3_multiplex_shutdown } {SQLITE_OK}
|
|
||||||
|
|
||||||
|
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.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.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.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.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}
|
||||||
|
|
||||||
|
do_test multiplex-1.11.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
|
||||||
|
do_test multiplex-1.11.2 { sqlite3 db test.db } {}
|
||||||
|
do_test multiplex-1.11.3 { sqlite3_multiplex_control db main enable 0 } {SQLITE_OK}
|
||||||
|
do_test multiplex-1.11.4 { sqlite3_multiplex_control db main enable 1 } {SQLITE_OK}
|
||||||
|
do_test multiplex-1.11.5 { sqlite3_multiplex_control db main enable -1 } {SQLITE_OK}
|
||||||
|
do_test multiplex-1.11.6 { db close } {}
|
||||||
|
do_test multiplex-1.11.7 { sqlite3_multiplex_shutdown } {SQLITE_OK}
|
||||||
|
|
||||||
|
do_test multiplex-1.12.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
|
||||||
|
do_test multiplex-1.12.2 { sqlite3 db test.db } {}
|
||||||
|
do_test multiplex-1.12.3 { lindex [ catchsql { SELECT multiplex_control(1, 0); } ] 0 } {0}
|
||||||
|
do_test multiplex-1.12.4 { lindex [ catchsql { SELECT multiplex_control(1, 1); } ] 0 } {0}
|
||||||
|
do_test multiplex-1.12.5 { lindex [ catchsql { SELECT multiplex_control(1, -1); } ] 0 } {0}
|
||||||
|
do_test multiplex-1.12.6 { db close } {}
|
||||||
|
do_test multiplex-1.12.7 { sqlite3_multiplex_shutdown } {SQLITE_OK}
|
||||||
|
|
||||||
|
do_test multiplex-1.13.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
|
||||||
|
do_test multiplex-1.13.2 { sqlite3 db test.db } {}
|
||||||
|
do_test multiplex-1.13.3 { lindex [ catchsql { SELECT multiplex_control(-1, 0); } ] 0 } {1}
|
||||||
|
do_test multiplex-1.13.4 { lindex [ catchsql { SELECT multiplex_control(4, 1); } ] 0 } {1}
|
||||||
|
do_test multiplex-1.13.6 { db close } {}
|
||||||
|
do_test multiplex-1.13.7 { sqlite3_multiplex_shutdown } {SQLITE_OK}
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
# Some simple warm-body tests with a single database file in rollback
|
# Some simple warm-body tests with a single database file in rollback
|
||||||
@@ -98,9 +139,12 @@ do_test multiplex-1.11 { sqlite3_multiplex_shutdown } {SQLITE_OK}
|
|||||||
#
|
#
|
||||||
# multiplex-2.6.*: More reading/writing with varying small chunk sizes, as
|
# multiplex-2.6.*: More reading/writing with varying small chunk sizes, as
|
||||||
# well as varying journal mode.
|
# well as varying journal mode.
|
||||||
|
#
|
||||||
|
# multiplex-2.7.*: Disable/enable tests.
|
||||||
|
#
|
||||||
|
|
||||||
sqlite3_multiplex_initialize "" 1
|
sqlite3_multiplex_initialize "" 1
|
||||||
multiplex_set 32768 16
|
multiplex_set db main 32768 16
|
||||||
|
|
||||||
do_test multiplex-2.1.2 {
|
do_test multiplex-2.1.2 {
|
||||||
sqlite3 db test.db
|
sqlite3 db test.db
|
||||||
@@ -130,6 +174,7 @@ do_test multiplex-2.3.1 {
|
|||||||
db2 close
|
db2 close
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
|
|
||||||
do_test multiplex-2.4.1 {
|
do_test multiplex-2.4.1 {
|
||||||
sqlite3_multiplex_shutdown
|
sqlite3_multiplex_shutdown
|
||||||
} {SQLITE_MISUSE}
|
} {SQLITE_MISUSE}
|
||||||
@@ -146,11 +191,11 @@ do_test multiplex-2.4.99 {
|
|||||||
do_test multiplex-2.5.1 {
|
do_test multiplex-2.5.1 {
|
||||||
multiplex_delete test.db
|
multiplex_delete test.db
|
||||||
sqlite3_multiplex_initialize "" 1
|
sqlite3_multiplex_initialize "" 1
|
||||||
multiplex_set 4096 16
|
sqlite3 db test.db
|
||||||
|
multiplex_set db main 4096 16
|
||||||
} {SQLITE_OK}
|
} {SQLITE_OK}
|
||||||
|
|
||||||
do_test multiplex-2.5.2 {
|
do_test multiplex-2.5.2 {
|
||||||
sqlite3 db test.db
|
|
||||||
execsql {
|
execsql {
|
||||||
PRAGMA page_size = 1024;
|
PRAGMA page_size = 1024;
|
||||||
PRAGMA journal_mode = delete;
|
PRAGMA journal_mode = delete;
|
||||||
@@ -165,7 +210,9 @@ do_test multiplex-2.5.3 {
|
|||||||
INSERT INTO t1 VALUES(2, randomblob(4000));
|
INSERT INTO t1 VALUES(2, randomblob(4000));
|
||||||
INSERT INTO t1 VALUES(3, 'three');
|
INSERT INTO t1 VALUES(3, 'three');
|
||||||
INSERT INTO t1 VALUES(4, randomblob(4000));
|
INSERT INTO t1 VALUES(4, randomblob(4000));
|
||||||
INSERT INTO t1 VALUES(5, 'five')
|
INSERT INTO t1 VALUES(5, 'five');
|
||||||
|
INSERT INTO t1 VALUES(6, randomblob($g_chunk_size));
|
||||||
|
INSERT INTO t1 VALUES(7, randomblob($g_chunk_size));
|
||||||
}
|
}
|
||||||
} {}
|
} {}
|
||||||
|
|
||||||
@@ -205,11 +252,11 @@ foreach jmode $all_journal_modes {
|
|||||||
do_test multiplex-2.6.1.$sz.$jmode {
|
do_test multiplex-2.6.1.$sz.$jmode {
|
||||||
multiplex_delete test.db
|
multiplex_delete test.db
|
||||||
sqlite3_multiplex_initialize "" 1
|
sqlite3_multiplex_initialize "" 1
|
||||||
multiplex_set $sz 32
|
sqlite3 db test.db
|
||||||
|
multiplex_set db main $sz 32
|
||||||
} {SQLITE_OK}
|
} {SQLITE_OK}
|
||||||
|
|
||||||
do_test multiplex-2.6.2.$sz.$jmode {
|
do_test multiplex-2.6.2.$sz.$jmode {
|
||||||
sqlite3 db test.db
|
|
||||||
db eval {
|
db eval {
|
||||||
PRAGMA page_size = 1024;
|
PRAGMA page_size = 1024;
|
||||||
PRAGMA auto_vacuum = off;
|
PRAGMA auto_vacuum = off;
|
||||||
@@ -243,6 +290,31 @@ foreach jmode $all_journal_modes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_test multiplex-2.7.1 { multiplex_delete test.db } {}
|
||||||
|
do_test multiplex-2.7.2 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
|
||||||
|
do_test multiplex-2.7.3 { sqlite3 db test.db } {}
|
||||||
|
do_test multiplex-2.7.4 { lindex [ catchsql { SELECT multiplex_control(2, 65536); } ] 0 } {0}
|
||||||
|
do_test multiplex-2.7.5 { lindex [ catchsql { SELECT multiplex_control(1, 0); } ] 0 } {0}
|
||||||
|
do_test multiplex-2.7.6 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||||
|
INSERT INTO t1 VALUES(1, randomblob(1000));
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
# verify only one file, and file size is less than chunks size
|
||||||
|
do_test multiplex-2.7.7 { expr ([file size [multiplex_name test.db 0]] < 65536) } {1}
|
||||||
|
do_test multiplex-2.7.8 { file exists [multiplex_name test.db 1] } {0}
|
||||||
|
do_test multiplex-2.7.9 {
|
||||||
|
execsql {
|
||||||
|
INSERT INTO t1 VALUES(2, randomblob(65536));
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
# verify only one file, and file size exceeds chunks size
|
||||||
|
do_test multiplex-2.7.10 { expr ([file size [multiplex_name test.db 0]] > 65536) } {1}
|
||||||
|
do_test multiplex-2.7.11 { file exists [multiplex_name test.db 1] } {0}
|
||||||
|
do_test multiplex-2.7.12 { db close } {}
|
||||||
|
do_test multiplex-2.7.13 { sqlite3_multiplex_shutdown } {SQLITE_OK}
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
# Try some tests with more than one connection to a database file. Still
|
# Try some tests with more than one connection to a database file. Still
|
||||||
# in rollback mode.
|
# in rollback mode.
|
||||||
@@ -255,10 +327,10 @@ foreach jmode $all_journal_modes {
|
|||||||
do_test multiplex-3.1.1 {
|
do_test multiplex-3.1.1 {
|
||||||
multiplex_delete test.db
|
multiplex_delete test.db
|
||||||
sqlite3_multiplex_initialize "" 1
|
sqlite3_multiplex_initialize "" 1
|
||||||
multiplex_set 32768 16
|
sqlite3 db test.db
|
||||||
|
multiplex_set db main 32768 16
|
||||||
} {SQLITE_OK}
|
} {SQLITE_OK}
|
||||||
do_test multiplex-3.1.2 {
|
do_test multiplex-3.1.2 {
|
||||||
sqlite3 db test.db
|
|
||||||
execsql {
|
execsql {
|
||||||
PRAGMA page_size = 1024;
|
PRAGMA page_size = 1024;
|
||||||
PRAGMA journal_mode = delete;
|
PRAGMA journal_mode = delete;
|
||||||
@@ -341,7 +413,7 @@ do_test multiplex-3.2.X {
|
|||||||
#
|
#
|
||||||
|
|
||||||
sqlite3_multiplex_initialize "" 1
|
sqlite3_multiplex_initialize "" 1
|
||||||
multiplex_set 32768 16
|
multiplex_set db main 32768 16
|
||||||
|
|
||||||
# Return a list of all currently defined multiplexs.
|
# Return a list of all currently defined multiplexs.
|
||||||
proc multiplex_list {} {
|
proc multiplex_list {} {
|
||||||
@@ -403,7 +475,7 @@ do_test multiplex-4.1.12 {
|
|||||||
#
|
#
|
||||||
|
|
||||||
sqlite3_multiplex_initialize "" 1
|
sqlite3_multiplex_initialize "" 1
|
||||||
multiplex_set 32768 16
|
multiplex_set db main 32768 16
|
||||||
|
|
||||||
do_faultsim_test multiplex-5.1 -prep {
|
do_faultsim_test multiplex-5.1 -prep {
|
||||||
catch {db close}
|
catch {db close}
|
||||||
@@ -448,7 +520,7 @@ do_faultsim_test multiplex-5.5 -prep {
|
|||||||
catch { sqlite3_multiplex_shutdown }
|
catch { sqlite3_multiplex_shutdown }
|
||||||
} -body {
|
} -body {
|
||||||
sqlite3_multiplex_initialize "" 1
|
sqlite3_multiplex_initialize "" 1
|
||||||
multiplex_set 32768 16
|
multiplex_set db main 32768 16
|
||||||
}
|
}
|
||||||
|
|
||||||
# test that mismatch filesize is detected
|
# test that mismatch filesize is detected
|
||||||
@@ -473,20 +545,20 @@ if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} {
|
|||||||
do_test multiplex-5.6.2.$jmode {
|
do_test multiplex-5.6.2.$jmode {
|
||||||
execsql {
|
execsql {
|
||||||
CREATE TABLE t1(a, b);
|
CREATE TABLE t1(a, b);
|
||||||
INSERT INTO t1 VALUES(1, randomblob(1100));
|
INSERT INTO t1 VALUES(1, randomblob(15000));
|
||||||
INSERT INTO t1 VALUES(2, randomblob(1100));
|
INSERT INTO t1 VALUES(2, randomblob(15000));
|
||||||
INSERT INTO t1 VALUES(3, randomblob(1100));
|
INSERT INTO t1 VALUES(3, randomblob(15000));
|
||||||
INSERT INTO t1 VALUES(4, randomblob(1100));
|
INSERT INTO t1 VALUES(4, randomblob(15000));
|
||||||
INSERT INTO t1 VALUES(5, randomblob(1100));
|
INSERT INTO t1 VALUES(5, randomblob(15000));
|
||||||
}
|
}
|
||||||
db close
|
db close
|
||||||
sqlite3_multiplex_initialize "" 1
|
sqlite3_multiplex_initialize "" 1
|
||||||
multiplex_set 4096 16
|
|
||||||
sqlite3 db test.db
|
sqlite3 db test.db
|
||||||
} {}
|
multiplex_set db main 4096 16
|
||||||
|
} {SQLITE_OK}
|
||||||
do_test multiplex-5.6.3.$jmode {
|
do_test multiplex-5.6.3.$jmode {
|
||||||
catchsql {
|
catchsql {
|
||||||
INSERT INTO t1 VALUES(6, randomblob(1100));
|
INSERT INTO t1 VALUES(6, randomblob(15000));
|
||||||
}
|
}
|
||||||
} {1 {disk I/O error}}
|
} {1 {disk I/O error}}
|
||||||
do_test multiplex-5.6.4.$jmode {
|
do_test multiplex-5.6.4.$jmode {
|
||||||
|
|||||||
Reference in New Issue
Block a user