4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 ******************************************************************************
13 ** This file contains an experimental VFS layer that operates on a
14 ** Key/Value storage engine where both keys and values must be pure
17 #include <sqliteInt.h>
18 #if SQLITE_OS_KV || (SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL))
20 /*****************************************************************************
24 /* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */
26 #define SQLITE_KV_TRACE(X) printf X
28 #define SQLITE_KV_TRACE(X)
31 /* SQLITE_KV_LOG() is used for tracing calls to the VFS interface */
33 #define SQLITE_KV_LOG(X) printf X
35 #define SQLITE_KV_LOG(X)
40 ** Forward declaration of objects used by this VFS implementation
42 typedef struct KVVfsFile KVVfsFile
;
44 /* A single open file. There are only two files represented by this
45 ** VFS - the database and the rollback journal.
48 sqlite3_file base
; /* IO methods */
49 const char *zClass
; /* Storage class */
50 int isJournal
; /* True if this is a journal file */
51 unsigned int nJrnl
; /* Space allocated for aJrnl[] */
52 char *aJrnl
; /* Journal content */
53 int szPage
; /* Last known page size */
54 sqlite3_int64 szDb
; /* Database file size. -1 means unknown */
55 char *aData
; /* Buffer to hold page data */
57 #define SQLITE_KVOS_SZ 133073
60 ** Methods for KVVfsFile
62 static int kvvfsClose(sqlite3_file
*);
63 static int kvvfsReadDb(sqlite3_file
*, void*, int iAmt
, sqlite3_int64 iOfst
);
64 static int kvvfsReadJrnl(sqlite3_file
*, void*, int iAmt
, sqlite3_int64 iOfst
);
65 static int kvvfsWriteDb(sqlite3_file
*,const void*,int iAmt
, sqlite3_int64
);
66 static int kvvfsWriteJrnl(sqlite3_file
*,const void*,int iAmt
, sqlite3_int64
);
67 static int kvvfsTruncateDb(sqlite3_file
*, sqlite3_int64 size
);
68 static int kvvfsTruncateJrnl(sqlite3_file
*, sqlite3_int64 size
);
69 static int kvvfsSyncDb(sqlite3_file
*, int flags
);
70 static int kvvfsSyncJrnl(sqlite3_file
*, int flags
);
71 static int kvvfsFileSizeDb(sqlite3_file
*, sqlite3_int64
*pSize
);
72 static int kvvfsFileSizeJrnl(sqlite3_file
*, sqlite3_int64
*pSize
);
73 static int kvvfsLock(sqlite3_file
*, int);
74 static int kvvfsUnlock(sqlite3_file
*, int);
75 static int kvvfsCheckReservedLock(sqlite3_file
*, int *pResOut
);
76 static int kvvfsFileControlDb(sqlite3_file
*, int op
, void *pArg
);
77 static int kvvfsFileControlJrnl(sqlite3_file
*, int op
, void *pArg
);
78 static int kvvfsSectorSize(sqlite3_file
*);
79 static int kvvfsDeviceCharacteristics(sqlite3_file
*);
82 ** Methods for sqlite3_vfs
84 static int kvvfsOpen(sqlite3_vfs
*, const char *, sqlite3_file
*, int , int *);
85 static int kvvfsDelete(sqlite3_vfs
*, const char *zName
, int syncDir
);
86 static int kvvfsAccess(sqlite3_vfs
*, const char *zName
, int flags
, int *);
87 static int kvvfsFullPathname(sqlite3_vfs
*, const char *zName
, int, char *zOut
);
88 static void *kvvfsDlOpen(sqlite3_vfs
*, const char *zFilename
);
89 static int kvvfsRandomness(sqlite3_vfs
*, int nByte
, char *zOut
);
90 static int kvvfsSleep(sqlite3_vfs
*, int microseconds
);
91 static int kvvfsCurrentTime(sqlite3_vfs
*, double*);
92 static int kvvfsCurrentTimeInt64(sqlite3_vfs
*, sqlite3_int64
*);
94 static sqlite3_vfs sqlite3OsKvvfsObject
= {
96 sizeof(KVVfsFile
), /* szOsFile */
97 1024, /* mxPathname */
101 kvvfsOpen
, /* xOpen */
102 kvvfsDelete
, /* xDelete */
103 kvvfsAccess
, /* xAccess */
104 kvvfsFullPathname
, /* xFullPathname */
105 kvvfsDlOpen
, /* xDlOpen */
109 kvvfsRandomness
, /* xRandomness */
110 kvvfsSleep
, /* xSleep */
111 kvvfsCurrentTime
, /* xCurrentTime */
112 0, /* xGetLastError */
113 kvvfsCurrentTimeInt64
/* xCurrentTimeInt64 */
116 /* Methods for sqlite3_file objects referencing a database file
118 static sqlite3_io_methods kvvfs_db_io_methods
= {
120 kvvfsClose
, /* xClose */
121 kvvfsReadDb
, /* xRead */
122 kvvfsWriteDb
, /* xWrite */
123 kvvfsTruncateDb
, /* xTruncate */
124 kvvfsSyncDb
, /* xSync */
125 kvvfsFileSizeDb
, /* xFileSize */
126 kvvfsLock
, /* xLock */
127 kvvfsUnlock
, /* xUnlock */
128 kvvfsCheckReservedLock
, /* xCheckReservedLock */
129 kvvfsFileControlDb
, /* xFileControl */
130 kvvfsSectorSize
, /* xSectorSize */
131 kvvfsDeviceCharacteristics
, /* xDeviceCharacteristics */
140 /* Methods for sqlite3_file objects referencing a rollback journal
142 static sqlite3_io_methods kvvfs_jrnl_io_methods
= {
144 kvvfsClose
, /* xClose */
145 kvvfsReadJrnl
, /* xRead */
146 kvvfsWriteJrnl
, /* xWrite */
147 kvvfsTruncateJrnl
, /* xTruncate */
148 kvvfsSyncJrnl
, /* xSync */
149 kvvfsFileSizeJrnl
, /* xFileSize */
150 kvvfsLock
, /* xLock */
151 kvvfsUnlock
, /* xUnlock */
152 kvvfsCheckReservedLock
, /* xCheckReservedLock */
153 kvvfsFileControlJrnl
, /* xFileControl */
154 kvvfsSectorSize
, /* xSectorSize */
155 kvvfsDeviceCharacteristics
, /* xDeviceCharacteristics */
164 /****** Storage subsystem **************************************************/
165 #include <sys/types.h>
166 #include <sys/stat.h>
169 /* Forward declarations for the low-level storage engine
171 static int kvstorageWrite(const char*, const char *zKey
, const char *zData
);
172 static int kvstorageDelete(const char*, const char *zKey
);
173 static int kvstorageRead(const char*, const char *zKey
, char *zBuf
, int nBuf
);
174 #define KVSTORAGE_KEY_SZ 32
176 /* Expand the key name with an appropriate prefix and put the result
177 ** zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least
178 ** KVSTORAGE_KEY_SZ bytes.
180 static void kvstorageMakeKey(
185 sqlite3_snprintf(KVSTORAGE_KEY_SZ
, zKeyOut
, "kvvfs-%s-%s", zClass
, zKeyIn
);
188 /* Write content into a key. zClass is the particular namespace of the
189 ** underlying key/value store to use - either "local" or "session".
191 ** Both zKey and zData are zero-terminated pure text strings.
193 ** Return the number of errors.
195 static int kvstorageWrite(
201 char zXKey
[KVSTORAGE_KEY_SZ
];
202 kvstorageMakeKey(zClass
, zKey
, zXKey
);
203 fd
= fopen(zXKey
, "wb");
205 SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey
,
206 (int)strlen(zData
), zData
,
207 strlen(zData
)>50 ? "..." : ""));
216 /* Delete a key (with its corresponding data) from the key/value
217 ** namespace given by zClass. If the key does not previously exist,
218 ** this routine is a no-op.
220 static int kvstorageDelete(const char *zClass
, const char *zKey
){
221 char zXKey
[KVSTORAGE_KEY_SZ
];
222 kvstorageMakeKey(zClass
, zKey
, zXKey
);
224 SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey
));
228 /* Read the value associated with a zKey from the key/value namespace given
229 ** by zClass and put the text data associated with that key in the first
230 ** nBuf bytes of zBuf[]. The value might be truncated if zBuf is not large
231 ** enough to hold it all. The value put into zBuf must always be zero
232 ** terminated, even if it gets truncated because nBuf is not large enough.
234 ** Return the total number of bytes in the data, without truncation, and
235 ** not counting the final zero terminator. Return -1 if the key does
238 ** If nBuf<=0 then this routine simply returns the size of the data without
239 ** actually reading it.
241 static int kvstorageRead(
249 char zXKey
[KVSTORAGE_KEY_SZ
];
250 kvstorageMakeKey(zClass
, zKey
, zXKey
);
251 if( access(zXKey
, R_OK
)!=0
252 || stat(zXKey
, &buf
)!=0
253 || !S_ISREG(buf
.st_mode
)
255 SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey
));
259 return (int)buf
.st_size
;
262 SQLITE_KV_TRACE(("KVVFS-READ %-15s (%d)\n", zXKey
,
264 return (int)buf
.st_size
;
266 if( nBuf
> buf
.st_size
+ 1 ){
267 nBuf
= buf
.st_size
+ 1;
269 fd
= fopen(zXKey
, "rb");
271 SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey
));
274 sqlite3_int64 n
= fread(zBuf
, 1, nBuf
-1, fd
);
277 SQLITE_KV_TRACE(("KVVFS-READ %-15s (%lld) %.50s%s\n", zXKey
,
278 n
, zBuf
, n
>50 ? "..." : ""));
284 ** An internal level of indirection which enables us to replace the
285 ** kvvfs i/o methods with JavaScript implementations in WASM builds.
286 ** Maintenance reminder: if this struct changes in any way, the JSON
287 ** rendering of its structure must be updated in
288 ** sqlite3_wasm_enum_json(). There are no binary compatibility
289 ** concerns, so it does not need an iVersion member. This file is
290 ** necessarily always compiled together with sqlite3_wasm_enum_json(),
291 ** and JS code dynamically creates the mapping of members based on
292 ** that JSON description.
294 typedef struct sqlite3_kvvfs_methods sqlite3_kvvfs_methods
;
295 struct sqlite3_kvvfs_methods
{
296 int (*xRead
)(const char *zClass
, const char *zKey
, char *zBuf
, int nBuf
);
297 int (*xWrite
)(const char *zClass
, const char *zKey
, const char *zData
);
298 int (*xDelete
)(const char *zClass
, const char *zKey
);
303 ** This object holds the kvvfs I/O methods which may be swapped out
304 ** for JavaScript-side implementations in WASM builds. In such builds
305 ** it cannot be const, but in native builds it should be so that
306 ** the compiler can hopefully optimize this level of indirection out.
307 ** That said, kvvfs is intended primarily for use in WASM builds.
309 ** Note that this is not explicitly flagged as static because the
310 ** amalgamation build will tag it with SQLITE_PRIVATE.
315 sqlite3_kvvfs_methods sqlite3KvvfsMethods
= {
322 /****** Utility subroutines ************************************************/
325 ** Encode binary into the text encoded used to persist on disk.
326 ** The output text is stored in aOut[], which must be at least
327 ** nData+1 bytes in length.
329 ** Return the actual length of the encoded text, not counting the
330 ** zero terminator at the end.
335 ** * Non-zero bytes are encoded as upper-case hexadecimal
337 ** * A sequence of one or more zero-bytes that are not at the
338 ** beginning of the buffer are encoded as a little-endian
339 ** base-26 number using a..z. "a" means 0. "b" means 1,
340 ** "z" means 25. "ab" means 26. "ac" means 52. And so forth.
342 ** * Because there is no overlap between the encoding characters
343 ** of hexadecimal and base-26 numbers, it is always clear where
344 ** one stops and the next begins.
346 static int kvvfsEncode(const char *aData
, int nData
, char *aOut
){
348 const unsigned char *a
= (const unsigned char*)aData
;
349 for(i
=j
=0; i
<nData
; i
++){
350 unsigned char c
= a
[i
];
352 aOut
[j
++] = "0123456789ABCDEF"[c
>>4];
353 aOut
[j
++] = "0123456789ABCDEF"[c
&0xf];
355 /* A sequence of 1 or more zeros is stored as a little-endian
356 ** base-26 number using a..z as the digits. So one zero is "b".
357 ** Two zeros is "c". 25 zeros is "z", 26 zeros is "ab", 27 is "bb",
361 for(k
=1; i
+k
<nData
&& a
[i
+k
]==0; k
++){}
364 aOut
[j
++] = 'a'+(k
%26);
373 static const signed char kvvfsHexValue
[256] = {
374 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
375 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
376 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
377 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
378 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
379 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
380 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
381 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
383 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
384 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
385 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
386 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
387 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
388 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
389 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
390 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
394 ** Decode the text encoding back to binary. The binary content is
395 ** written into pOut, which must be at least nOut bytes in length.
397 ** The return value is the number of bytes actually written into aOut[].
399 static int kvvfsDecode(const char *a
, char *aOut
, int nOut
){
402 const unsigned char *aIn
= (const unsigned char*)a
;
406 c
= kvvfsHexValue
[aIn
[i
]];
412 while( c
>='a' && c
<='z' ){
417 if( j
+n
>nOut
) return -1;
418 memset(&aOut
[j
], 0, n
);
420 if( c
==0 || mult
==1 ) break; /* progress stalled if mult==1 */
423 c
= kvvfsHexValue
[aIn
[++i
]];
433 ** Decode a complete journal file. Allocate space in pFile->aJrnl
434 ** and store the decoding there. Or leave pFile->aJrnl set to NULL
435 ** if an error is encountered.
437 ** The first few characters of the text encoding will be a little-endian
438 ** base-26 number (digits a..z) that is the total number of bytes
439 ** in the decoded journal file image. This base-26 number is followed
440 ** by a single space, then the encoding of the journal. The space
441 ** separator is required to act as a terminator for the base-26 number.
443 static void kvvfsDecodeJournal(
444 KVVfsFile
*pFile
, /* Store decoding in pFile->aJrnl */
445 const char *zTxt
, /* Text encoding. Zero-terminated */
446 int nTxt
/* Bytes in zTxt, excluding zero terminator */
452 while( (c
= zTxt
[i
++])>='a' && c
<='z' ){
453 n
+= (zTxt
[i
] - 'a')*mult
;
456 sqlite3_free(pFile
->aJrnl
);
457 pFile
->aJrnl
= sqlite3_malloc64( n
);
458 if( pFile
->aJrnl
==0 ){
463 n
= kvvfsDecode(zTxt
+i
, pFile
->aJrnl
, pFile
->nJrnl
);
464 if( n
<pFile
->nJrnl
){
465 sqlite3_free(pFile
->aJrnl
);
472 ** Read or write the "sz" element, containing the database file size.
474 static sqlite3_int64
kvvfsReadFileSize(KVVfsFile
*pFile
){
477 sqlite3KvvfsMethods
.xRead(pFile
->zClass
, "sz", zData
, sizeof(zData
)-1);
478 return strtoll(zData
, 0, 0);
480 static int kvvfsWriteFileSize(KVVfsFile
*pFile
, sqlite3_int64 sz
){
482 sqlite3_snprintf(sizeof(zData
), zData
, "%lld", sz
);
483 return sqlite3KvvfsMethods
.xWrite(pFile
->zClass
, "sz", zData
);
486 /****** sqlite3_io_methods methods ******************************************/
489 ** Close an kvvfs-file.
491 static int kvvfsClose(sqlite3_file
*pProtoFile
){
492 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
494 SQLITE_KV_LOG(("xClose %s %s\n", pFile
->zClass
,
495 pFile
->isJournal
? "journal" : "db"));
496 sqlite3_free(pFile
->aJrnl
);
497 sqlite3_free(pFile
->aData
);
502 ** Read from the -journal file.
504 static int kvvfsReadJrnl(
505 sqlite3_file
*pProtoFile
,
510 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
511 assert( pFile
->isJournal
);
512 SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile
->zClass
, iAmt
, iOfst
));
513 if( pFile
->aJrnl
==0 ){
514 int szTxt
= kvstorageRead(pFile
->zClass
, "jrnl", 0, 0);
519 aTxt
= sqlite3_malloc64( szTxt
+1 );
520 if( aTxt
==0 ) return SQLITE_NOMEM
;
521 kvstorageRead(pFile
->zClass
, "jrnl", aTxt
, szTxt
+1);
522 kvvfsDecodeJournal(pFile
, aTxt
, szTxt
);
524 if( pFile
->aJrnl
==0 ) return SQLITE_IOERR
;
526 if( iOfst
+iAmt
>pFile
->nJrnl
){
527 return SQLITE_IOERR_SHORT_READ
;
529 memcpy(zBuf
, pFile
->aJrnl
+iOfst
, iAmt
);
534 ** Read from the database file.
536 static int kvvfsReadDb(
537 sqlite3_file
*pProtoFile
,
542 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
546 char *aData
= pFile
->aData
;
549 SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile
->zClass
, iAmt
, iOfst
));
550 if( iOfst
+iAmt
>=512 ){
551 if( (iOfst
% iAmt
)!=0 ){
552 return SQLITE_IOERR_READ
;
554 if( (iAmt
& (iAmt
-1))!=0 || iAmt
<512 || iAmt
>65536 ){
555 return SQLITE_IOERR_READ
;
557 pFile
->szPage
= iAmt
;
558 pgno
= 1 + iOfst
/iAmt
;
562 sqlite3_snprintf(sizeof(zKey
), zKey
, "%u", pgno
);
563 got
= sqlite3KvvfsMethods
.xRead(pFile
->zClass
, zKey
,
564 aData
, SQLITE_KVOS_SZ
-1);
569 if( iOfst
+iAmt
<512 ){
572 n
= kvvfsDecode(aData
, &aData
[2000], SQLITE_KVOS_SZ
-2000);
574 memcpy(zBuf
, &aData
[2000+iOfst
], iAmt
);
580 n
= kvvfsDecode(aData
, zBuf
, iAmt
);
584 memset(zBuf
+n
, 0, iAmt
-n
);
585 return SQLITE_IOERR_SHORT_READ
;
592 ** Write into the -journal file.
594 static int kvvfsWriteJrnl(
595 sqlite3_file
*pProtoFile
,
600 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
601 sqlite3_int64 iEnd
= iOfst
+iAmt
;
602 SQLITE_KV_LOG(("xWrite('%s-journal',%d,%lld)\n", pFile
->zClass
, iAmt
, iOfst
));
603 if( iEnd
>=0x10000000 ) return SQLITE_FULL
;
604 if( pFile
->aJrnl
==0 || pFile
->nJrnl
<iEnd
){
605 char *aNew
= sqlite3_realloc(pFile
->aJrnl
, iEnd
);
607 return SQLITE_IOERR_NOMEM
;
610 if( pFile
->nJrnl
<iOfst
){
611 memset(pFile
->aJrnl
+pFile
->nJrnl
, 0, iOfst
-pFile
->nJrnl
);
615 memcpy(pFile
->aJrnl
+iOfst
, zBuf
, iAmt
);
620 ** Write into the database file.
622 static int kvvfsWriteDb(
623 sqlite3_file
*pProtoFile
,
628 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
631 char *aData
= pFile
->aData
;
632 SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile
->zClass
, iAmt
, iOfst
));
633 assert( iAmt
>=512 && iAmt
<=65536 );
634 assert( (iAmt
& (iAmt
-1))==0 );
635 assert( pFile
->szPage
<0 || pFile
->szPage
==iAmt
);
636 pFile
->szPage
= iAmt
;
637 pgno
= 1 + iOfst
/iAmt
;
638 sqlite3_snprintf(sizeof(zKey
), zKey
, "%u", pgno
);
639 kvvfsEncode(zBuf
, iAmt
, aData
);
640 if( sqlite3KvvfsMethods
.xWrite(pFile
->zClass
, zKey
, aData
) ){
643 if( iOfst
+iAmt
> pFile
->szDb
){
644 pFile
->szDb
= iOfst
+ iAmt
;
650 ** Truncate an kvvfs-file.
652 static int kvvfsTruncateJrnl(sqlite3_file
*pProtoFile
, sqlite_int64 size
){
653 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
654 SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile
->zClass
, size
));
656 sqlite3KvvfsMethods
.xDelete(pFile
->zClass
, "jrnl");
657 sqlite3_free(pFile
->aJrnl
);
662 static int kvvfsTruncateDb(sqlite3_file
*pProtoFile
, sqlite_int64 size
){
663 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
666 && (size
% pFile
->szPage
)==0
669 unsigned int pgno
, pgnoMax
;
670 SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile
->zClass
, size
));
671 pgno
= 1 + size
/pFile
->szPage
;
672 pgnoMax
= 2 + pFile
->szDb
/pFile
->szPage
;
673 while( pgno
<=pgnoMax
){
674 sqlite3_snprintf(sizeof(zKey
), zKey
, "%u", pgno
);
675 sqlite3KvvfsMethods
.xDelete(pFile
->zClass
, zKey
);
679 return kvvfsWriteFileSize(pFile
, size
) ? SQLITE_IOERR
: SQLITE_OK
;
685 ** Sync an kvvfs-file.
687 static int kvvfsSyncJrnl(sqlite3_file
*pProtoFile
, int flags
){
689 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
691 SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile
->zClass
));
692 if( pFile
->nJrnl
<=0 ){
693 return kvvfsTruncateJrnl(pProtoFile
, 0);
695 zOut
= sqlite3_malloc64( pFile
->nJrnl
*2 + 50 );
697 return SQLITE_IOERR_NOMEM
;
702 zOut
[i
++] = 'a' + (n
%26);
706 kvvfsEncode(pFile
->aJrnl
, pFile
->nJrnl
, &zOut
[i
]);
707 i
= sqlite3KvvfsMethods
.xWrite(pFile
->zClass
, "jrnl", zOut
);
709 return i
? SQLITE_IOERR
: SQLITE_OK
;
711 static int kvvfsSyncDb(sqlite3_file
*pProtoFile
, int flags
){
716 ** Return the current file-size of an kvvfs-file.
718 static int kvvfsFileSizeJrnl(sqlite3_file
*pProtoFile
, sqlite_int64
*pSize
){
719 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
720 SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile
->zClass
));
721 *pSize
= pFile
->nJrnl
;
724 static int kvvfsFileSizeDb(sqlite3_file
*pProtoFile
, sqlite_int64
*pSize
){
725 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
726 SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile
->zClass
));
727 if( pFile
->szDb
>=0 ){
728 *pSize
= pFile
->szDb
;
730 *pSize
= kvvfsReadFileSize(pFile
);
736 ** Lock an kvvfs-file.
738 static int kvvfsLock(sqlite3_file
*pProtoFile
, int eLock
){
739 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
740 assert( !pFile
->isJournal
);
741 SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile
->zClass
, eLock
));
743 if( eLock
!=SQLITE_LOCK_NONE
){
744 pFile
->szDb
= kvvfsReadFileSize(pFile
);
750 ** Unlock an kvvfs-file.
752 static int kvvfsUnlock(sqlite3_file
*pProtoFile
, int eLock
){
753 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
754 assert( !pFile
->isJournal
);
755 SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile
->zClass
, eLock
));
756 if( eLock
==SQLITE_LOCK_NONE
){
763 ** Check if another file-handle holds a RESERVED lock on an kvvfs-file.
765 static int kvvfsCheckReservedLock(sqlite3_file
*pProtoFile
, int *pResOut
){
766 SQLITE_KV_LOG(("xCheckReservedLock\n"));
772 ** File control method. For custom operations on an kvvfs-file.
774 static int kvvfsFileControlJrnl(sqlite3_file
*pProtoFile
, int op
, void *pArg
){
775 SQLITE_KV_LOG(("xFileControl(%d) on journal\n", op
));
776 return SQLITE_NOTFOUND
;
778 static int kvvfsFileControlDb(sqlite3_file
*pProtoFile
, int op
, void *pArg
){
779 SQLITE_KV_LOG(("xFileControl(%d) on database\n", op
));
780 if( op
==SQLITE_FCNTL_SYNC
){
781 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
783 SQLITE_KV_LOG(("xSync('%s-db')\n", pFile
->zClass
));
784 if( pFile
->szDb
>0 && 0!=kvvfsWriteFileSize(pFile
, pFile
->szDb
) ){
789 return SQLITE_NOTFOUND
;
793 ** Return the sector-size in bytes for an kvvfs-file.
795 static int kvvfsSectorSize(sqlite3_file
*pFile
){
800 ** Return the device characteristic flags supported by an kvvfs-file.
802 static int kvvfsDeviceCharacteristics(sqlite3_file
*pProtoFile
){
806 /****** sqlite3_vfs methods *************************************************/
809 ** Open an kvvfs file handle.
811 static int kvvfsOpen(
812 sqlite3_vfs
*pProtoVfs
,
814 sqlite3_file
*pProtoFile
,
818 KVVfsFile
*pFile
= (KVVfsFile
*)pProtoFile
;
819 if( zName
==0 ) zName
= "";
820 SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName
));
821 if( strcmp(zName
, "local")==0
822 || strcmp(zName
, "session")==0
824 pFile
->isJournal
= 0;
825 pFile
->base
.pMethods
= &kvvfs_db_io_methods
;
827 if( strcmp(zName
, "local-journal")==0
828 || strcmp(zName
, "session-journal")==0
830 pFile
->isJournal
= 1;
831 pFile
->base
.pMethods
= &kvvfs_jrnl_io_methods
;
833 return SQLITE_CANTOPEN
;
836 pFile
->zClass
= "session";
838 pFile
->zClass
= "local";
840 pFile
->aData
= sqlite3_malloc64(SQLITE_KVOS_SZ
);
841 if( pFile
->aData
==0 ){
852 ** Delete the file located at zPath. If the dirSync argument is true,
853 ** ensure the file-system modifications are synced to disk before
856 static int kvvfsDelete(sqlite3_vfs
*pVfs
, const char *zPath
, int dirSync
){
857 if( strcmp(zPath
, "local-journal")==0 ){
858 sqlite3KvvfsMethods
.xDelete("local", "jrnl");
860 if( strcmp(zPath
, "session-journal")==0 ){
861 sqlite3KvvfsMethods
.xDelete("session", "jrnl");
867 ** Test for access permissions. Return true if the requested permission
868 ** is available, or false otherwise.
870 static int kvvfsAccess(
871 sqlite3_vfs
*pProtoVfs
,
876 SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath
));
877 if( strcmp(zPath
, "local-journal")==0 ){
878 *pResOut
= sqlite3KvvfsMethods
.xRead("local", "jrnl", 0, 0)>0;
880 if( strcmp(zPath
, "session-journal")==0 ){
881 *pResOut
= sqlite3KvvfsMethods
.xRead("session", "jrnl", 0, 0)>0;
883 if( strcmp(zPath
, "local")==0 ){
884 *pResOut
= sqlite3KvvfsMethods
.xRead("local", "sz", 0, 0)>0;
886 if( strcmp(zPath
, "session")==0 ){
887 *pResOut
= sqlite3KvvfsMethods
.xRead("session", "sz", 0, 0)>0;
892 SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut
));
897 ** Populate buffer zOut with the full canonical pathname corresponding
898 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
899 ** of at least (INST_MAX_PATHNAME+1) bytes.
901 static int kvvfsFullPathname(
908 #ifdef SQLITE_OS_KV_ALWAYS_LOCAL
911 nPath
= strlen(zPath
);
912 SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath
));
913 if( nOut
<nPath
+1 ) nPath
= nOut
- 1;
914 memcpy(zOut
, zPath
, nPath
);
920 ** Open the dynamic library located at zPath and return a handle.
922 static void *kvvfsDlOpen(sqlite3_vfs
*pVfs
, const char *zPath
){
927 ** Populate the buffer pointed to by zBufOut with nByte bytes of
930 static int kvvfsRandomness(sqlite3_vfs
*pVfs
, int nByte
, char *zBufOut
){
931 memset(zBufOut
, 0, nByte
);
936 ** Sleep for nMicro microseconds. Return the number of microseconds
939 static int kvvfsSleep(sqlite3_vfs
*pVfs
, int nMicro
){
944 ** Return the current time as a Julian Day number in *pTimeOut.
946 static int kvvfsCurrentTime(sqlite3_vfs
*pVfs
, double *pTimeOut
){
949 rc
= kvvfsCurrentTimeInt64(0, &i
);
950 *pTimeOut
= i
/86400000.0;
953 #include <sys/time.h>
954 static int kvvfsCurrentTimeInt64(sqlite3_vfs
*pVfs
, sqlite3_int64
*pTimeOut
){
955 static const sqlite3_int64 unixEpoch
= 24405875*(sqlite3_int64
)8640000;
957 (void)gettimeofday(&sNow
, 0); /* Cannot fail given valid arguments */
958 *pTimeOut
= unixEpoch
+ 1000*(sqlite3_int64
)sNow
.tv_sec
+ sNow
.tv_usec
/1000;
961 #endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */
965 ** This routine is called initialize the KV-vfs as the default VFS.
967 int sqlite3_os_init(void){
968 return sqlite3_vfs_register(&sqlite3OsKvvfsObject
, 1);
970 int sqlite3_os_end(void){
973 #endif /* SQLITE_OS_KV */
975 #if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
976 int sqlite3KvvfsInit(void){
977 return sqlite3_vfs_register(&sqlite3OsKvvfsObject
, 0);