1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Non-working code towards a VFS for text key/value storage.

FossilOrigin-Name: f9c89ee8d5ef46342bea78fa8d4da058d9ea628183ec985642bbda1cdfeacd5f
This commit is contained in:
drh
2022-09-07 17:29:22 +00:00
parent 2e440a0801
commit 59ece7e106
3 changed files with 655 additions and 7 deletions

645
ext/misc/vfskv.c Normal file
View File

@@ -0,0 +1,645 @@
/*
** 2022-09-06
**
** 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 an experimental VFS layer that operates on a
** Key/Value storage engine where both keys and values must be pure
** text.
*/
#include "sqlite3.h"
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stat/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <assert.h>
/*****************************************************************************
** 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 kvstorageSize(KVStorage*, const char *zKey);
static int kvstorageRead(KVStorage*, const char *zKey, char *zBuf, int nBuf);
/*
** Forward declaration of objects used by this utility
*/
typedef struct KVVfsVfs KVVfsVfs;
typedef struct KVVfsFile KVVfsFile;
struct KVVfsVfs {
sqlite3_vfs base; /* VFS methods */
KVStorage *pStore; /* Single command KV storage object */
KVVfsFile *pFiles; /* List of open KVVfsFile objects */
};
struct KVVfsFile {
sqlite3_file base; /* IO methods */
KVVfsVfs *pVfs; /* The VFS to which this file belongs */
KVVfsFile *pNext; /* Next in list of all files */
int isJournal; /* True if this is a journal file */
int nJrnl; /* Space allocated for aJrnl[] */
char *aJrnl; /* Journal content */
};
/*
** Methods for KVVfsFile
*/
static int kvvfsClose(sqlite3_file*);
static int kvvfsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int kvvfsWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
static int kvvfsTruncate(sqlite3_file*, sqlite3_int64 size);
static int kvvfsSync(sqlite3_file*, int flags);
static int kvvfsFileSize(sqlite3_file*, sqlite3_int64 *pSize);
static int kvvfsLock(sqlite3_file*, int);
static int kvvfsUnlock(sqlite3_file*, int);
static int kvvfsCheckReservedLock(sqlite3_file*, int *pResOut);
static int kvvfsFileControl(sqlite3_file*, int op, void *pArg);
static int kvvfsSectorSize(sqlite3_file*);
static int kvvfsDeviceCharacteristics(sqlite3_file*);
/*
** Methods for KVVfsVfs
*/
static int kvvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
static int kvvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);
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 = {
{
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_io_methods kvvfs_io_methods = {
1, /* iVersion */
kvvfsClose, /* xClose */
kvvfsRead, /* xRead */
kvvfsWrite, /* xWrite */
kvvfsTruncate, /* xTruncate */
kvvfsSync, /* xSync */
kvvfsFileSize, /* xFileSize */
kvvfsLock, /* xLock */
kvvfsUnlock, /* xUnlock */
kvvfsCheckReservedLock, /* xCheckReservedLock */
kvvfsFileControl, /* xFileControl */
kvvfsSectorSize, /* xSectorSize */
kvvfsDeviceCharacteristics /* xDeviceCharacteristics */
0, /* xShmMap */
0, /* xShmLock */
0, /* xShmBarrier */
0, /* xShmUnmap */
0, /* xFetch */
0 /* xUnfetch */
};
/****** 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);
}
/* Write content into a key. zKey is of limited size. zData should be
** pure text. In other words, zData has already been encoded.
**
** Return the number of errors.
*/
static int kvstorageWrite(
KVStorage *pStore,
const char *zKey,
const char *zData
){
FILE *fd;
kvstorageMakeKey(pStore, zKey);
fd = fopen(pStore->zKey, "wb");
if( fd==0 ) return 1;
if( fd ){
fputs(zData, fd);
fclose(fd);
}
return 0;
}
/* Delete a key
*/
static int kvstorageDelete(KVStorage *pStore, const char *zKey){
kvstorageMakeKey(pStore, zKey);
unlink(pStore->zKey);
return 0;
}
/* Read the value associated with a key and put the result in the first
** nBuf bytes of zBuf[]. The value might be truncated if zBuf is not large
** enough to hold it all. The value put into zBuf will always be zero
** terminated.
**
** Return the total number of bytes in the data, without truncation, and
** not counting the final zero terminator. Return -1 if the key does
** not exist.
**
** If nBuf==0 then this routine simply returns the size of the data without
** actually reading it.
*/
static int kvstorageRead(
KVStorage *pStore,
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
|| !S_ISREG(buf.st_mode)
){
return -1;
}
if( nBuf<0 ){
return (int)buf.st_size;
}else if( nBuf==1 ){
zBuf[0] = 0;
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;
}
/****** The main VFS code **************************************************/
/*
** Close an kvvfs-file.
*/
static int kvvfsClose(sqlite3_file *pProtoFile){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
KVVfsVfs *pVfs = pFile->pVfs;
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;
}
}
sqlite3_free(pFile->aData);
sqlite3_free(pFile);
return SQLITE_OK;
}
/*
** Encode binary into the text encoded used to persist on disk.
** The output text is stored in aOut[], which must be at least
** nData+1 bytes in length.
**
** Return the actual length of the encoded text, not counting the
** zero terminator at the end.
*/
static int kvvfsEncode(const char *aData, int nData, char *aOut){
int i, j;
const unsigned *a = (const unsigned char*)aData;
for(i=j=0; i<nData; i++){
unsigned char c = a[i];
if( c!=0 ){
aOut[j++] = "0123456789ABCDEF"[c>>4];
aOut[j++] = "0123456789ABCDEF"[c&0xf];
}else{
/* A sequence of 1 or more zeros is stored as a little-endian
** base-26 number using a..z as the digits. So one zero is "b".
** Two zeros is "c". 25 zeros is "z", 26 zeros is "ba" and so forth.
*/
int k;
for(k=1; a[i+k]==0 && i+k<nData; k++){}
i += k;
while( k>0 ){
aOut[j++] = 'a'+(k%26);
k /= 26;
}
}
}
aOut[j] = 0;
return j;
}
/* Convert hex to binary */
static char kvvfsHexToBinary(char c){
if( c>='0' && c<='9' ) return c - '0';
if( c>='a' && c<='f' ) return c - 'a' + 10;
return 0;
}
/*
** Decode the text encoding back to binary. The binary content is
** written into pOut, which must be at least nOut bytes in length.
*/
static int kvvfsDecode(const char *aIn, char *aOut, int nOut){
char *aOut;
int i, j, k;
int c;
i = 0;
j = 0;
while( (c = aIn[i])!=0 ){
if( c>='a' ){
int n = 0;
while( c>='a' && c<='z' ){
n = n*26 + c - 'a';
c = aIn[++i];
}
if( j+n>nOut ) return -1;
while( n-->0 ){
aOut[j++] = 0;
}
}else{
if( j>nOut ) return -1;
aOut[j] = kvvfsHexToBinary(aIn[i])<<4;
i++;
aOut[j] += kvvfsHexToBinary(aIn[i]);
i++;
}
}
return j;
}
/*
** Read from the -journal file.
*/
static int kvvfsReadFromJournal(
KVVfsFile *pFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
assert( pFile->isJournal );
if( pFile->aJrnl==0 ){
int szTxt = kvstorageRead(pFile->pVfs->pStore, "journal", 0, 0);
char *aTxt;
if( szTxt<=4 ){
return SQLITE_IOERR;
}
aTxt = sqlite3_malloc64( szTxt+1 );
if( aTxt==0 ) return SQLITE_NOMEM;
kvstorageRead(pFile->pVfs->pStore, "journal", aTxt, szTxt+1);
kvvfsDecodeJournal(pFile, aTxt, szTxt);
sqlite3_free(aTxt);
if( pFile->aData==0 ) return SQLITE_IOERR;
}
if( iOfst+iAmt>pFile->nJrnl ){
return SQLITE_IOERR_SHORT_READ;
}
mcmcpy(zBuf, pFile->aJrnl+iOfst, iAmt);
return SQLITE_OK;
}
/*
** Read from the database file.
*/
static int kvvfsReadFromDb(
KVVfsFile *pFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
return SQLITE_IOERR;
}
/*
** Read data from an kvvfs-file.
*/
static int kvvfsRead(
sqlite3_file *pProtoFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
int rc;
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
if( pFile->isJournal ){
rc = kvvfsReadFromJournal(pFile,zBuf,iAmt,iOfst);
}else{
rc = kvvfsReadFromDb(pFile,zBuf,iAmt,iOfst);
}
return rc;
}
/*
** Write into the -journal file.
*/
static int kvvfsWriteToJournal(
KVVfsFile *pFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
return SQLITE_IOERR;
}
/*
** Read from the database file.
*/
static int kvvfsWriteToDb(
KVVfsFile *pFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
return SQLITE_IOERR;
}
/*
** Write data into the kvvfs-file.
*/
static int kvvfsWrite(
sqlite3_file *pProtoFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
int rc;
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
if( pFile->isJournal ){
rc = kvvfsWriteToJournal(pFile,zBuf,iAmt,iOfst);
}else{
rc = kvvfsWriteToDb(pFile,zBuf,iAmt,iOfst);
}
return rc;
}
/*
** Truncate an kvvfs-file.
*/
static int kvvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
int rc;
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
rc = SQLITE_IOERR;
return rc;
}
/*
** Sync an kvvfs-file.
*/
static int kvvfsSync(sqlite3_file *pFile, int flags){
int rc;
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
rc = SQLITE_IOERR;
return rc;
}
/*
** Return the current file-size of an kvvfs-file.
*/
static int kvvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
int rc;
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
*pSize = 0;
rc = SQLITE_IOERR;
return rc;
}
/*
** Lock an kvvfs-file.
*/
static int kvvfsLock(sqlite3_file *pFile, int eLock){
int rc;
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
rc = SQLITE_IOERR;
return rc;
}
/*
** Unlock an kvvfs-file.
*/
static int kvvfsUnlock(sqlite3_file *pFile, int eLock){
int rc;
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
rc = SQLITE_IOERR;
return rc;
}
/*
** 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;
*pResOut = 0;
rc = SQLITE_IOERR;
return rc;
}
/*
** 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;
}
/*
** Return the sector-size in bytes for an kvvfs-file.
*/
static int kvvfsSectorSize(sqlite3_file *pFile){
return 4096;
}
/*
** Return the device characteristic flags supported by an kvvfs-file.
*/
static int kvvfsDeviceCharacteristics(sqlite3_file *pFile){
return 0;
}
/*
** Open an kvvfs file handle.
*/
static int kvvfsOpen(
sqlite3_vfs *pProtoVfs,
const char *zName,
sqlite3_file *pProtoFile,
int flags,
int *pOutFlags
){
int rc;
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
KVVfsVfs *pVfs = (KVVfsVfs*)pProtoVfs;
return rc;
}
/*
** Delete the file located at zPath. If the dirSync argument is true,
** ensure the file-system modifications are synced to disk before
** 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, "journal");
}
return SQLITE_OK;
}
/*
** Test for access permissions. Return true if the requested permission
** is available, or false otherwise.
*/
static int kvvfsAccess(
sqlite3_vfs *pVfs,
const char *zPath,
int flags,
int *pResOut
){
*pResOut = 1;
return SQLITE_OK;
}
/*
** Populate buffer zOut with the full canonical pathname corresponding
** to the pathname in zPath. zOut is guaranteed to point to a buffer
** of at least (INST_MAX_PATHNAME+1) bytes.
*/
static int kvvfsFullPathname(
sqlite3_vfs *pVfs,
const char *zPath,
int nOut,
char *zOut
){
size_t nPath = strlen(zPath);
if( nOut<nPath+1 ) nPath = nOut - 1;
memcpy(zOut, zPath, nPath);
zPath[nPath] = 0;
return SQLITE_OK;
}
/*
** Open the dynamic library located at zPath and return a handle.
*/
static void *kvvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
return 0;
}
/*
** Populate the buffer pointed to by zBufOut with nByte bytes of
** random data.
*/
static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
memset(zBufOut, 0, nByte);
return nByte;
}
/*
** Sleep for nMicro microseconds. Return the number of microseconds
** actually slept.
*/
static int kvvfsSleep(sqlite3_vfs *pVfs, int nMicro){
return SQLITE_OK;
}
/*
** Return the current time as a Julian Day number in *pTimeOut.
*/
static int kvvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
*pTimeOut = 2459829.13362986;
return SQLITE_OK;
}
static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
*pTimeOut = (sqlite3_int64)(2459829.13362986*86400000.0);
return SQLITE_OK;
}
/*
** Register debugvfs as the default VFS for this process.
*/
int sqlite3_register_kvvfs(const char *zArg){
return sqlite3_vfs_register(&kvvfs_vfs.base, 1);
}

View File

@@ -1,5 +1,5 @@
C Add\sthe\stool/omittest-msvc.tcl\sscript\sthat\swill\stry\sto\sbuild\susing\sMSVC\nusing\svarious\scompile-time\soptions,\sto\sensure\sthat\sthe\scompile-time\soptions\nall\sbuild\swithout\serrors.
D 2022-09-05T22:54:36.015
C Non-working\scode\stowards\sa\sVFS\sfor\stext\skey/value\sstorage.
D 2022-09-07T17:29:22.881
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -335,6 +335,7 @@ F ext/misc/uint.c 053fed3bce2e89583afcd4bf804d75d659879bbcedac74d0fa9ed548839a03
F ext/misc/unionvtab.c 36237f0607ca954ac13a4a0e2d2ac40c33bc6e032a5f55f431713061ef1625f9
F ext/misc/urifuncs.c f71360d14fa9e7626b563f1f781c6148109462741c5235ac63ae0f8917b9c751
F ext/misc/uuid.c 5bb2264c1b64d163efa46509544fd7500cb8769cb7c16dd52052da8d961505cf
F ext/misc/vfskv.c aebaf8b59b70a066c2c0ba9344db0494ff50452ff6b4e79c9133e7a2ea112a99
F ext/misc/vfslog.c 3932ab932eeb2601dbc4447cb14d445aaa9fbe43b863ef5f014401c3420afd20
F ext/misc/vfsstat.c 474d08efc697b8eba300082cb1eb74a5f0f3df31ed257db1cb07e72ab0e53dfb
F ext/misc/vtablog.c 5538acd0c8ddaae372331bee11608d76973436b77d6a91e8635cfc9432fba5ae
@@ -2000,9 +2001,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P f74a5ea8c986dc33d3afcda169c38abbe55728c56716cf9991a5e2ef7fc4917a 82b89f8a074858a81d841dfc26436e8d39ce4907b8f989eba4d848db16758303
R 6ca49c20c002174082011fae5352b9a2
T +closed 82b89f8a074858a81d841dfc26436e8d39ce4907b8f989eba4d848db16758303
P 6b00ecb59fd303f7985902c35a46db9e729201d4beaedea46596b728d9e4b1c8
R 26f26a2d9ce78c288f974e48234fd3a7
T *branch * kv-vfs
T *sym-kv-vfs *
T -sym-trunk *
U drh
Z 072f191f34018bff25742e9863a6762e
Z 68d678ebfc334c4be8e66c0fb69610ed
# Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
6b00ecb59fd303f7985902c35a46db9e729201d4beaedea46596b728d9e4b1c8
f9c89ee8d5ef46342bea78fa8d4da058d9ea628183ec985642bbda1cdfeacd5f