** Key/Value storage engine where both keys and values must be pure
** text.
*/
-#include "sqlite3.h"
+#include <sqlite3ext.h>
+SQLITE_EXTENSION_INIT1
#include <string.h>
#include <assert.h>
#include <stdio.h>
-#include <stat/types.h>
+#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <assert.h>
+#include <stdlib.h>
+
+/*****************************************************************************
+** Debugging logic
+*/
+#if 1
+#define KVVFS_TRACE(X) printf X;
+#else
+#define KVVFS_TRACE(X)
+#endif
/*****************************************************************************
static void kvstorageClose(KVStorage*);
static int kvstorageWrite(KVStorage*, const char *zKey, const char *zData);
static int kvstorageDelete(KVStorage*, const char *zKey);
-static int kvstorageSize(KVStorage*, const char *zKey);
static int kvstorageRead(KVStorage*, const char *zKey, char *zBuf, int nBuf);
static int kvvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
static int kvvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
static void *kvvfsDlOpen(sqlite3_vfs*, const char *zFilename);
-static void kvvfsDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
-static void (*kvvfsDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
-static void kvvfsDlClose(sqlite3_vfs*, void*);
static int kvvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int kvvfsSleep(sqlite3_vfs*, int microseconds);
static int kvvfsCurrentTime(sqlite3_vfs*, double*);
-static int kvvfsGetLastError(sqlite3_vfs*, int, char *);
static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
static KVVfsVfs kvvfs_vfs = {
kvvfsSleep, /* xSleep */
kvvfsCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
- kvvfsCurrentTimeInt64, /* xCurrentTimeInt64 */
+ kvvfsCurrentTimeInt64 /* xCurrentTimeInt64 */
},
0,
0
kvvfsCheckReservedLock, /* xCheckReservedLock */
kvvfsFileControl, /* xFileControl */
kvvfsSectorSize, /* xSectorSize */
- kvvfsDeviceCharacteristics /* xDeviceCharacteristics */
+ kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
0, /* xShmMap */
0, /* xShmLock */
0, /* xShmBarrier */
FILE *fd;
kvstorageMakeKey(pStore, zKey);
fd = fopen(pStore->zKey, "wb");
- if( fd==0 ) return 1;
if( fd ){
+ KVVFS_TRACE(("KVVFS-WRITE %-12s (%d) %.30s\n", pStore->zKey,
+ (int)strlen(zData), zData));
fputs(zData, fd);
fclose(fd);
+ return 0;
+ }else{
+ return 1;
}
- return 0;
}
/* Delete a key
static int kvstorageDelete(KVStorage *pStore, const char *zKey){
kvstorageMakeKey(pStore, zKey);
unlink(pStore->zKey);
+ KVVFS_TRACE(("KVVFS-DELETE %-12s\n", pStore->zKey));
return 0;
}
|| stat(pStore->zKey, &buf)!=0
|| !S_ISREG(buf.st_mode)
){
+ KVVFS_TRACE(("KVVFS-READ %-12s (-1)\n", pStore->zKey));
return -1;
}
if( nBuf<0 ){
return (int)buf.st_size;
}else if( nBuf==1 ){
zBuf[0] = 0;
+ KVVFS_TRACE(("KVVFS-READ %-12s (%d)\n", pStore->zKey,
+ (int)buf.st_size));
return (int)buf.st_size;
}
if( nBuf-1 > buf.st_size ){
nBuf = buf.st_size + 1;
}
fd = fopen(pStore->zKey, "rb");
- if( fd==0 ) return -1;
- fread(zBuf, nBuf-1, 1, fd);
- fclose(fd);
- return nBuf-1;
+ if( fd==0 ){
+ KVVFS_TRACE(("KVVFS-READ %-12s (-1)\n", pStore->zKey));
+ return -1;
+ }else{
+ fread(zBuf, nBuf-1, 1, fd);
+ fclose(fd);
+ KVVFS_TRACE(("KVVFS-READ %-12s (%d) %.30s\n", pStore->zKey,
+ nBuf-1, zBuf));
+ return nBuf-1;
+ }
}
pX = pX->pNext;
}
}
- sqlite3_free(pFile->aData);
+ sqlite3_free(pFile->aJrnl);
sqlite3_free(pFile);
return SQLITE_OK;
}
*/
static int kvvfsEncode(const char *aData, int nData, char *aOut){
int i, j;
- const unsigned *a = (const unsigned char*)aData;
+ const unsigned char *a = (const unsigned char*)aData;
for(i=j=0; i<nData; i++){
unsigned char c = a[i];
if( c!=0 ){
** The return value is the number of bytes actually written into aOut[].
*/
static int kvvfsDecode(const char *aIn, char *aOut, int nOut){
- char *aOut;
- int i, j, k;
+ int i, j;
int c;
i = 0;
j = 0;
kvstorageRead(pFile->pVfs->pStore, "journal", aTxt, szTxt+1);
kvvfsDecodeJournal(pFile, aTxt, szTxt);
sqlite3_free(aTxt);
- if( pFile->aData==0 ) return SQLITE_IOERR;
+ if( pFile->aJrnl==0 ) return SQLITE_IOERR;
}
if( iOfst+iAmt>pFile->nJrnl ){
return SQLITE_IOERR_SHORT_READ;
}
- mcmcpy(zBuf, pFile->aJrnl+iOfst, iAmt);
+ memcpy(zBuf, pFile->aJrnl+iOfst, iAmt);
return SQLITE_OK;
}
sqlite_int64 iOfst
){
unsigned int pgno;
- KVVfsPage *pPage;
- int got;
+ int got, n;
char zKey[30];
char aData[131073];
assert( pFile->szDb>=0 );
pFile->szPage = iAmt;
}
pgno = 1 + iOfst/iAmt;
- sqlite3_snprintf(sizeof(zKey), zKey, "pg-%u", pgno)
+ sqlite3_snprintf(sizeof(zKey), zKey, "pg-%u", pgno);
got = kvstorageRead(pFile->pVfs->pStore, zKey, aData, sizeof(aData)-1);
if( got<0 ){
return SQLITE_IOERR_READ;
assert( iAmt>=512 && iAmt<=65536 );
assert( (iAmt & (iAmt-1))==0 );
pgno = 1 + iOfst/iAmt;
- sqlite3_snprintf(sizeof(zKey), zKey, "pg-%u", pgno)
- nData = kvvfsEncode(zBuf, iAmt, aData);
+ sqlite3_snprintf(sizeof(zKey), zKey, "pg-%u", pgno);
+ kvvfsEncode(zBuf, iAmt, aData);
kvstorageWrite(pFile->pVfs->pStore, zKey, aData);
if( iOfst+iAmt > pFile->szDb ){
pFile->szDb = iOfst + iAmt;
if( pFile->isJournal ){
assert( size==0 );
kvstorageDelete(pFile->pVfs->pStore, "journal");
- sqlite3_free(pFile->aData);
- pFile->aData = 0;
- pFile->nData = 0;
+ sqlite3_free(pFile->aJrnl);
+ pFile->aJrnl = 0;
+ pFile->nJrnl = 0;
return SQLITE_OK;
}
if( pFile->szDb>size
pgno++;
}
pFile->szDb = size;
- kvvfsWriteFileSize(pFile->pVfs->pStore, size);
+ kvvfsWriteFileSize(pFile, size);
return SQLITE_OK;
}
return SQLITE_IOERR;
** Sync an kvvfs-file.
*/
static int kvvfsSync(sqlite3_file *pProtoFile, int flags){
- int i, k, n;
+ int i, n;
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
char *zOut;
if( !pFile->isJournal ){
kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]);
kvstorageWrite(pFile->pVfs->pStore, "journal", zOut);
sqlite3_free(zOut);
- return rc;
+ return SQLITE_OK;
}
/*
** Return the current file-size of an kvvfs-file.
*/
-static int kvvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+static int kvvfsFileSize(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
if( pFile->isJournal ){
*pSize = pFile->nJrnl;
/*
** Lock an kvvfs-file.
*/
-static int kvvfsLock(sqlite3_file *pFile, int eLock){
+static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
assert( !pFile->isJournal );
if( eLock!=SQLITE_LOCK_NONE ){
/*
** Unlock an kvvfs-file.
*/
-static int kvvfsUnlock(sqlite3_file *pFile, int eLock){
+static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
assert( !pFile->isJournal );
if( eLock==SQLITE_LOCK_NONE ){
/*
** Check if another file-handle holds a RESERVED lock on an kvvfs-file.
*/
-static int kvvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
- int rc;
- KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+static int kvvfsCheckReservedLock(sqlite3_file *pProtoFile, int *pResOut){
*pResOut = 0;
- rc = SQLITE_OK;
- return rc;
+ return SQLITE_OK;
}
/*
** File control method. For custom operations on an kvvfs-file.
*/
-static int kvvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
- int rc;
- KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
- rc = SQLITE_NOTFOUND;
- return rc;
+static int kvvfsFileControl(sqlite3_file *pProtoFile, int op, void *pArg){
+ return SQLITE_NOTFOUND;
}
/*
/*
** Return the device characteristic flags supported by an kvvfs-file.
*/
-static int kvvfsDeviceCharacteristics(sqlite3_file *pFile){
+static int kvvfsDeviceCharacteristics(sqlite3_file *pProtoFile){
return 0;
}
pFile->isJournal = sqlite3_strglob("*-journal", zName)==0;
pFile->szPage = -1;
pFile->szDb = -1;
-
+ pFile->base.pMethods = &kvvfs_io_methods;
+ pFile->pVfs = pVfs;
+ if( pVfs->pFiles==0 ){
+ pVfs->pStore = kvstorageOpen();
+ }
+ pFile->pNext = pVfs->pFiles;
+ pVfs->pFiles = pFile;
return SQLITE_OK;
}
size_t nPath = strlen(zPath);
if( nOut<nPath+1 ) nPath = nOut - 1;
memcpy(zOut, zPath, nPath);
- zPath[nPath] = 0;
+ zOut[nPath] = 0;
return SQLITE_OK;
}
return SQLITE_OK;
}
-/*
-** Register debugvfs as the default VFS for this process.
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+/*
+** This routine is called when the extension is loaded.
+**
+** Register the new VFS. Make arrangement to register the virtual table
+** for each new database connection.
*/
-int sqlite3_register_kvvfs(const char *zArg){
+int sqlite3_vfskv_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
return sqlite3_vfs_register(&kvvfs_vfs.base, 1);
}