/*****************************************************************************
** The low-level storage engine
*/
-typedef struct KVStorage KVStorage;
-struct KVStorage {
- char *zDir;
- char zKey[50];
-};
-
-static KVStorage *kvstorageOpen(void);
-static void kvstorageClose(KVStorage*);
-static int kvstorageWrite(KVStorage*, const char *zKey, const char *zData);
-static int kvstorageDelete(KVStorage*, const char *zKey);
-static int kvstorageRead(KVStorage*, const char *zKey, char *zBuf, int nBuf);
+#define KVSTORAGE_KEY_SZ 24
+static int kvstorageWrite(const char*, const char *zKey, const char *zData);
+static int kvstorageDelete(const char*, const char *zKey);
+static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf);
/*
-** Forward declaration of objects used by this utility
+** Forward declaration of objects used by this VFS implementation
*/
-typedef struct KVVfsVfs KVVfsVfs;
typedef struct KVVfsFile KVVfsFile;
-
-/* All information about the database */
-struct KVVfsVfs {
- sqlite3_vfs base; /* VFS methods */
- KVStorage *pStore; /* Single command KV storage object */
- KVVfsFile *pFiles; /* List of open KVVfsFile objects */
-};
-
/* A single open file. There are only two files represented by this
** VFS - the database and the rollback journal.
*/
struct KVVfsFile {
sqlite3_file base; /* IO methods */
- KVVfsVfs *pVfs; /* The VFS to which this file belongs */
- KVVfsFile *pNext; /* Next in list of all files */
+ const char *zClass; /* Storage class */
int isJournal; /* True if this is a journal file */
unsigned int nJrnl; /* Space allocated for aJrnl[] */
char *aJrnl; /* Journal content */
static int kvvfsDeviceCharacteristics(sqlite3_file*);
/*
-** Methods for KVVfsVfs
+** Methods for sqlite3_vfs
*/
static int kvvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
static int kvvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);
static int kvvfsCurrentTime(sqlite3_vfs*, double*);
static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
-static KVVfsVfs kvvfs_vfs = {
- {
- 1, /* iVersion */
- sizeof(KVVfsFile), /* szOsFile */
- 1024, /* mxPathname */
- 0, /* pNext */
- "kvvfs", /* zName */
- 0, /* pAppData */
- kvvfsOpen, /* xOpen */
- kvvfsDelete, /* xDelete */
- kvvfsAccess, /* xAccess */
- kvvfsFullPathname, /* xFullPathname */
- kvvfsDlOpen, /* xDlOpen */
- 0, /* xDlError */
- 0, /* xDlSym */
- 0, /* xDlClose */
- kvvfsRandomness, /* xRandomness */
- kvvfsSleep, /* xSleep */
- kvvfsCurrentTime, /* xCurrentTime */
- 0, /* xGetLastError */
- kvvfsCurrentTimeInt64 /* xCurrentTimeInt64 */
- },
- 0,
- 0
+static sqlite3_vfs kvvfs_vfs = {
+ 1, /* iVersion */
+ sizeof(KVVfsFile), /* szOsFile */
+ 1024, /* mxPathname */
+ 0, /* pNext */
+ "kvvfs", /* zName */
+ 0, /* pAppData */
+ kvvfsOpen, /* xOpen */
+ kvvfsDelete, /* xDelete */
+ kvvfsAccess, /* xAccess */
+ kvvfsFullPathname, /* xFullPathname */
+ kvvfsDlOpen, /* xDlOpen */
+ 0, /* xDlError */
+ 0, /* xDlSym */
+ 0, /* xDlClose */
+ kvvfsRandomness, /* xRandomness */
+ kvvfsSleep, /* xSleep */
+ kvvfsCurrentTime, /* xCurrentTime */
+ 0, /* xGetLastError */
+ kvvfsCurrentTimeInt64 /* xCurrentTimeInt64 */
};
/* Methods for sqlite3_file objects referencing a database file
/****** Storage subsystem **************************************************/
-/* Allocate a new storage subsystem.
-** Return NULL if OOM
-*/
-static KVStorage *kvstorageOpen(void){
- KVStorage *pStore;
- pStore = sqlite3_malloc64( sizeof(*pStore) );
- if( pStore==0 ) return 0;
- memset(pStore, 0, sizeof(*pStore));
- return pStore;
-}
-
-/* Free all resources associated with the storage subsystem */
-static void kvstorageClose(KVStorage *pStore){
- sqlite3_free(pStore);
-}
/* Expand the key name with an appropriate prefix and put the result
** in pStore->zKey[]
*/
-static void kvstorageMakeKey(KVStorage *pStore, const char *zKey){
- sqlite3_snprintf(sizeof(pStore->zKey), pStore->zKey, "kvvfs-%s", zKey);
+static void kvstorageMakeKey(
+ const char *zClass,
+ const char *zKeyIn,
+ char *zKeyOut
+){
+ sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "%s-%s", zClass, zKeyIn);
}
/* Write content into a key. zKey is of limited size. zData should be
** Return the number of errors.
*/
static int kvstorageWrite(
- KVStorage *pStore,
+ const char *zClass,
const char *zKey,
const char *zData
){
FILE *fd;
- kvstorageMakeKey(pStore, zKey);
- fd = fopen(pStore->zKey, "wb");
+ char zXKey[KVSTORAGE_KEY_SZ];
+ kvstorageMakeKey(zClass, zKey, zXKey);
+ fd = fopen(zXKey, "wb");
if( fd ){
- KVVFS_TRACE(("KVVFS-WRITE %-10s (%d) %.50s%s\n", pStore->zKey,
+ KVVFS_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey,
(int)strlen(zData), zData,
strlen(zData)>50 ? "..." : ""));
fputs(zData, fd);
/* Delete a key
*/
-static int kvstorageDelete(KVStorage *pStore, const char *zKey){
- kvstorageMakeKey(pStore, zKey);
- unlink(pStore->zKey);
- KVVFS_TRACE(("KVVFS-DELETE %-10s\n", pStore->zKey));
+static int kvstorageDelete(const char *zClass, const char *zKey){
+ char zXKey[KVSTORAGE_KEY_SZ];
+ kvstorageMakeKey(zClass, zKey, zXKey);
+ unlink(zXKey);
+ KVVFS_TRACE(("KVVFS-DELETE %-15s\n", zXKey));
return 0;
}
** actually reading it.
*/
static int kvstorageRead(
- KVStorage *pStore,
+ const char *zClass,
const char *zKey,
char *zBuf,
int nBuf
){
FILE *fd;
struct stat buf;
- kvstorageMakeKey(pStore, zKey);
- if( access(pStore->zKey, R_OK)!=0
- || stat(pStore->zKey, &buf)!=0
+ char zXKey[KVSTORAGE_KEY_SZ];
+ kvstorageMakeKey(zClass, zKey, zXKey);
+ if( access(zXKey, R_OK)!=0
+ || stat(zXKey, &buf)!=0
|| !S_ISREG(buf.st_mode)
){
- KVVFS_TRACE(("KVVFS-READ %-10s (-1)\n", pStore->zKey));
+ KVVFS_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
return -1;
}
if( nBuf<0 ){
return (int)buf.st_size;
}else if( nBuf==1 ){
zBuf[0] = 0;
- KVVFS_TRACE(("KVVFS-READ %-10s (%d)\n", pStore->zKey,
+ KVVFS_TRACE(("KVVFS-READ %-15s (%d)\n", zXKey,
(int)buf.st_size));
return (int)buf.st_size;
}
- if( nBuf-1 > buf.st_size ){
+ if( nBuf > buf.st_size + 1 ){
nBuf = buf.st_size + 1;
}
- fd = fopen(pStore->zKey, "rb");
+ fd = fopen(zXKey, "rb");
if( fd==0 ){
- KVVFS_TRACE(("KVVFS-READ %-10s (-1)\n", pStore->zKey));
+ KVVFS_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
return -1;
}else{
sqlite3_int64 n = fread(zBuf, 1, nBuf-1, fd);
fclose(fd);
zBuf[n] = 0;
- KVVFS_TRACE(("KVVFS-READ %-10s (%lld) %.50s%s\n", pStore->zKey,
+ KVVFS_TRACE(("KVVFS-READ %-15s (%lld) %.50s%s\n", zXKey,
n, zBuf, n>50 ? "..." : ""));
return (int)n;
}
static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){
char zData[50];
zData[0] = 0;
- kvstorageRead(pFile->pVfs->pStore, "sz", zData, sizeof(zData)-1);
+ kvstorageRead(pFile->zClass, "sz", zData, sizeof(zData)-1);
return strtoll(zData, 0, 0);
}
static void kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){
char zData[50];
sqlite3_snprintf(sizeof(zData), zData, "%lld", sz);
- kvstorageWrite(pFile->pVfs->pStore, "sz", zData);
+ kvstorageWrite(pFile->zClass, "sz", zData);
}
-/****** VFS methods ********************************************************/
+/****** sqlite3_io_methods methods ******************************************/
/*
** Close an kvvfs-file.
*/
static int kvvfsClose(sqlite3_file *pProtoFile){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
- KVVfsVfs *pVfs = pFile->pVfs;
-
- KVVFS_LOG(("xClose %s\n", pFile->isJournal ? "journal" : "db"));
- if( pVfs->pFiles==pFile ){
- pVfs->pFiles = pFile->pNext;
- if( pVfs->pFiles==0 ){
- kvstorageClose(pVfs->pStore);
- pVfs->pStore = 0;
- }
- }else{
- KVVfsFile *pX = pVfs->pFiles;
- while( 1 ){
- assert( pX );
- if( pX->pNext==pFile ){
- pX->pNext = pFile->pNext;
- break;
- }
- pX = pX->pNext;
- }
- }
+
+ KVVFS_LOG(("xClose %s %s\n", pFile->zClass,
+ pFile->isJournal ? "journal" : "db"));
sqlite3_free(pFile->aJrnl);
return SQLITE_OK;
}
){
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
assert( pFile->isJournal );
- KVVFS_LOG(("xRead('journal',%d,%lld)\n", iAmt, iOfst));
+ KVVFS_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
if( pFile->aJrnl==0 ){
- int szTxt = kvstorageRead(pFile->pVfs->pStore, "jrnl", 0, 0);
+ int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, -1);
char *aTxt;
if( szTxt<=4 ){
return SQLITE_IOERR;
}
aTxt = sqlite3_malloc64( szTxt+1 );
if( aTxt==0 ) return SQLITE_NOMEM;
- kvstorageRead(pFile->pVfs->pStore, "jrnl", aTxt, szTxt+1);
+ kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1);
kvvfsDecodeJournal(pFile, aTxt, szTxt);
sqlite3_free(aTxt);
if( pFile->aJrnl==0 ) return SQLITE_IOERR;
char aData[131073];
assert( iOfst>=0 );
assert( iAmt>=0 );
- KVVFS_LOG(("xRead('db',%d,%lld)\n", iAmt, iOfst));
+ KVVFS_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
if( iOfst+iAmt>=512 ){
if( (iOfst % iAmt)!=0 ){
return SQLITE_IOERR_READ;
pgno = 1;
}
sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
- got = kvstorageRead(pFile->pVfs->pStore, zKey, aData, sizeof(aData)-1);
+ got = kvstorageRead(pFile->zClass, zKey, aData, sizeof(aData)-1);
if( got<0 ){
n = 0;
}else{
){
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
sqlite3_int64 iEnd = iOfst+iAmt;
- KVVFS_LOG(("xWrite('journal',%d,%lld)\n", iAmt, iOfst));
+ KVVFS_LOG(("xWrite('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
if( iEnd>=0x10000000 ) return SQLITE_FULL;
if( pFile->aJrnl==0 || pFile->nJrnl<iEnd ){
char *aNew = sqlite3_realloc(pFile->aJrnl, iEnd);
unsigned int pgno;
char zKey[30];
char aData[131073];
- KVVFS_LOG(("xWrite('db',%d,%lld)\n", iAmt, iOfst));
+ KVVFS_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
assert( iAmt>=512 && iAmt<=65536 );
assert( (iAmt & (iAmt-1))==0 );
pgno = 1 + iOfst/iAmt;
sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
kvvfsEncode(zBuf, iAmt, aData);
- kvstorageWrite(pFile->pVfs->pStore, zKey, aData);
+ kvstorageWrite(pFile->zClass, zKey, aData);
if( iOfst+iAmt > pFile->szDb ){
pFile->szDb = iOfst + iAmt;
}
*/
static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
- KVVFS_LOG(("xTruncate('journal',%lld)\n", size));
+ KVVFS_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size));
assert( size==0 );
- kvstorageDelete(pFile->pVfs->pStore, "jrnl");
+ kvstorageDelete(pFile->zClass, "jrnl");
sqlite3_free(pFile->aJrnl);
pFile->aJrnl = 0;
pFile->nJrnl = 0;
){
char zKey[50];
unsigned int pgno, pgnoMax;
- KVVFS_LOG(("xTruncate('db',%lld)\n", size));
+ KVVFS_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size));
pgno = 1 + size/pFile->szPage;
pgnoMax = 2 + pFile->szDb/pFile->szPage;
while( pgno<=pgnoMax ){
sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
- kvstorageDelete(pFile->pVfs->pStore, zKey);
+ kvstorageDelete(pFile->zClass, zKey);
pgno++;
}
pFile->szDb = size;
int i, n;
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
char *zOut;
- KVVFS_LOG(("xSync('journal')\n"));
+ KVVFS_LOG(("xSync('%s-journal')\n", pFile->zClass));
if( pFile->nJrnl<=0 ){
return kvvfsTruncateJrnl(pProtoFile, 0);
}
}while( n>0 );
zOut[i++] = ' ';
kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]);
- kvstorageWrite(pFile->pVfs->pStore, "jrnl", zOut);
+ kvstorageWrite(pFile->zClass, "jrnl", zOut);
sqlite3_free(zOut);
return SQLITE_OK;
}
static int kvvfsSyncDb(sqlite3_file *pProtoFile, int flags){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
- KVVFS_LOG(("xSync('db')\n"));
+ KVVFS_LOG(("xSync('%s-db')\n", pFile->zClass));
if( pFile->szDb>0 ){
kvvfsWriteFileSize(pFile, pFile->szDb);
}
*/
static int kvvfsFileSizeJrnl(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
- KVVFS_LOG(("xFileSize('journal')\n"));
+ KVVFS_LOG(("xFileSize('%s-journal')\n", pFile->zClass));
*pSize = pFile->nJrnl;
return SQLITE_OK;
}
static int kvvfsFileSizeDb(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
- KVVFS_LOG(("xFileSize('db')\n"));
+ KVVFS_LOG(("xFileSize('%s-db')\n", pFile->zClass));
if( pFile->szDb>=0 ){
*pSize = pFile->szDb;
}else{
static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
assert( !pFile->isJournal );
- KVVFS_LOG(("xLock(%d)\n", eLock));
+ KVVFS_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock));
if( eLock!=SQLITE_LOCK_NONE ){
pFile->szDb = kvvfsReadFileSize(pFile);
static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
assert( !pFile->isJournal );
- KVVFS_LOG(("xUnlock(%d)\n", eLock));
+ KVVFS_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock));
if( eLock==SQLITE_LOCK_NONE ){
pFile->szDb = -1;
}
return 0;
}
+/****** sqlite3_vfs methods *************************************************/
/*
** Open an kvvfs file handle.
int *pOutFlags
){
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
- KVVfsVfs *pVfs = (KVVfsVfs*)pProtoVfs;
KVVFS_LOG(("xOpen(\"%s\")\n", zName));
- pFile->aJrnl = 0;
- pFile->nJrnl = 0;
- if( sqlite3_strglob("*-journal", zName)==0 ){
+ if( strcmp(zName, "local")==0
+ || strcmp(zName, "session")==0
+ ){
+ pFile->isJournal = 0;
+ pFile->base.pMethods = &kvvfs_db_io_methods;
+ }else
+ if( strcmp(zName, "local-journal")==0
+ || strcmp(zName, "session-journal")==0
+ ){
pFile->isJournal = 1;
pFile->base.pMethods = &kvvfs_jrnl_io_methods;
}else{
- pFile->isJournal = 0;
- pFile->base.pMethods = &kvvfs_db_io_methods;
+ return SQLITE_CANTOPEN;
}
+ pFile->zClass = zName[0]=='s' ? "kvvfs-ses" : "kvvfs-loc";
+ pFile->aJrnl = 0;
+ pFile->nJrnl = 0;
pFile->szPage = -1;
pFile->szDb = -1;
- pFile->pVfs = pVfs;
- if( pVfs->pFiles==0 ){
- pVfs->pStore = kvstorageOpen();
- }
- pFile->pNext = pVfs->pFiles;
- pVfs->pFiles = pFile;
return SQLITE_OK;
}
** returning.
*/
static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
- KVVfsVfs *p = (KVVfsVfs*)pVfs;
- if( sqlite3_strglob("*-journal",zPath)==0 ){
- kvstorageDelete(p->pStore, "jrnl");
+ if( strcmp(zPath, "local-journal")==0 ){
+ kvstorageDelete("kvvfs-loc", "jrnl");
+ }else
+ if( strcmp(zPath, "session-journal")==0 ){
+ kvstorageDelete("kvvfs-ses", "jrnl");
}
return SQLITE_OK;
}
int flags,
int *pResOut
){
- KVVfsVfs *pVfs = (KVVfsVfs*)pProtoVfs;
KVVFS_LOG(("xAccess(\"%s\")\n", zPath));
- if( sqlite3_strglob("*-journal", zPath)==0 ){
- *pResOut = kvstorageRead(pVfs->pStore, "jrnl", 0, 0)>0;
- }else if( sqlite3_strglob("*-wal", zPath)==0 ){
+ if( strcmp(zPath, "local-journal")==0 ){
+ *pResOut = kvstorageRead("kvvfs-loc", "jrnl", 0, -1)>0;
+ }else
+ if( strcmp(zPath, "session-journal")==0 ){
+ *pResOut = kvstorageRead("kvvfs-ses", "jrnl", 0, -1)>0;
+ }else
+ if( strcmp(zPath, "local")==0 ){
+ *pResOut = kvstorageRead("kvvfs-loc", "sz", 0, -1)>0;
+ }else
+ if( strcmp(zPath, "session")==0 ){
+ *pResOut = kvstorageRead("kvvfs-ses", "sz", 0, -1)>0;
+ }else
+ {
*pResOut = 0;
- }else{
- *pResOut = 1;
}
KVVFS_LOG(("xAccess returns %d\n",*pResOut));
return SQLITE_OK;
const sqlite3_api_routines *pApi
){
SQLITE_EXTENSION_INIT2(pApi);
- sqlite3_vfs_register(&kvvfs_vfs.base, 1);
+ sqlite3_vfs_register(&kvvfs_vfs, 1);
return SQLITE_OK_LOAD_PERMANENTLY;
}