xref: /sqlite-3.40.0/src/os_kv.c (revision d92c652a)
1 /*
2 ** 2022-09-06
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
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.
10 **
11 ******************************************************************************
12 **
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
15 ** text.
16 */
17 #include <sqliteInt.h>
18 #if SQLITE_OS_KV || (SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL))
19 
20 /*****************************************************************************
21 ** Debugging logic
22 */
23 
24 /* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */
25 #if 0
26 #define SQLITE_KV_TRACE(X)  printf X
27 #else
28 #define SQLITE_KV_TRACE(X)
29 #endif
30 
31 /* SQLITE_KV_LOG() is used for tracing calls to the VFS interface */
32 #if 0
33 #define SQLITE_KV_LOG(X)  printf X
34 #else
35 #define SQLITE_KV_LOG(X)
36 #endif
37 
38 
39 /*
40 ** Forward declaration of objects used by this VFS implementation
41 */
42 typedef struct KVVfsFile KVVfsFile;
43 
44 /* A single open file.  There are only two files represented by this
45 ** VFS - the database and the rollback journal.
46 */
47 struct KVVfsFile {
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 };
56 
57 /*
58 ** Methods for KVVfsFile
59 */
60 static int kvvfsClose(sqlite3_file*);
61 static int kvvfsReadDb(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
62 static int kvvfsReadJrnl(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
63 static int kvvfsWriteDb(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
64 static int kvvfsWriteJrnl(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
65 static int kvvfsTruncateDb(sqlite3_file*, sqlite3_int64 size);
66 static int kvvfsTruncateJrnl(sqlite3_file*, sqlite3_int64 size);
67 static int kvvfsSyncDb(sqlite3_file*, int flags);
68 static int kvvfsSyncJrnl(sqlite3_file*, int flags);
69 static int kvvfsFileSizeDb(sqlite3_file*, sqlite3_int64 *pSize);
70 static int kvvfsFileSizeJrnl(sqlite3_file*, sqlite3_int64 *pSize);
71 static int kvvfsLock(sqlite3_file*, int);
72 static int kvvfsUnlock(sqlite3_file*, int);
73 static int kvvfsCheckReservedLock(sqlite3_file*, int *pResOut);
74 static int kvvfsFileControlDb(sqlite3_file*, int op, void *pArg);
75 static int kvvfsFileControlJrnl(sqlite3_file*, int op, void *pArg);
76 static int kvvfsSectorSize(sqlite3_file*);
77 static int kvvfsDeviceCharacteristics(sqlite3_file*);
78 
79 /*
80 ** Methods for sqlite3_vfs
81 */
82 static int kvvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
83 static int kvvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);
84 static int kvvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
85 static int kvvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
86 static void *kvvfsDlOpen(sqlite3_vfs*, const char *zFilename);
87 static int kvvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);
88 static int kvvfsSleep(sqlite3_vfs*, int microseconds);
89 static int kvvfsCurrentTime(sqlite3_vfs*, double*);
90 static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
91 
92 static sqlite3_vfs sqlite3OsKvvfsObject = {
93   1,                              /* iVersion */
94   sizeof(KVVfsFile),              /* szOsFile */
95   1024,                           /* mxPathname */
96   0,                              /* pNext */
97   "kvvfs",                        /* zName */
98   0,                              /* pAppData */
99   kvvfsOpen,                      /* xOpen */
100   kvvfsDelete,                    /* xDelete */
101   kvvfsAccess,                    /* xAccess */
102   kvvfsFullPathname,              /* xFullPathname */
103   kvvfsDlOpen,                    /* xDlOpen */
104   0,                              /* xDlError */
105   0,                              /* xDlSym */
106   0,                              /* xDlClose */
107   kvvfsRandomness,                /* xRandomness */
108   kvvfsSleep,                     /* xSleep */
109   kvvfsCurrentTime,               /* xCurrentTime */
110   0,                              /* xGetLastError */
111   kvvfsCurrentTimeInt64           /* xCurrentTimeInt64 */
112 };
113 
114 /* Methods for sqlite3_file objects referencing a database file
115 */
116 static sqlite3_io_methods kvvfs_db_io_methods = {
117   1,                              /* iVersion */
118   kvvfsClose,                     /* xClose */
119   kvvfsReadDb,                    /* xRead */
120   kvvfsWriteDb,                   /* xWrite */
121   kvvfsTruncateDb,                /* xTruncate */
122   kvvfsSyncDb,                    /* xSync */
123   kvvfsFileSizeDb,                /* xFileSize */
124   kvvfsLock,                      /* xLock */
125   kvvfsUnlock,                    /* xUnlock */
126   kvvfsCheckReservedLock,         /* xCheckReservedLock */
127   kvvfsFileControlDb,             /* xFileControl */
128   kvvfsSectorSize,                /* xSectorSize */
129   kvvfsDeviceCharacteristics,     /* xDeviceCharacteristics */
130   0,                              /* xShmMap */
131   0,                              /* xShmLock */
132   0,                              /* xShmBarrier */
133   0,                              /* xShmUnmap */
134   0,                              /* xFetch */
135   0                               /* xUnfetch */
136 };
137 
138 /* Methods for sqlite3_file objects referencing a rollback journal
139 */
140 static sqlite3_io_methods kvvfs_jrnl_io_methods = {
141   1,                              /* iVersion */
142   kvvfsClose,                     /* xClose */
143   kvvfsReadJrnl,                  /* xRead */
144   kvvfsWriteJrnl,                 /* xWrite */
145   kvvfsTruncateJrnl,              /* xTruncate */
146   kvvfsSyncJrnl,                  /* xSync */
147   kvvfsFileSizeJrnl,              /* xFileSize */
148   kvvfsLock,                      /* xLock */
149   kvvfsUnlock,                    /* xUnlock */
150   kvvfsCheckReservedLock,         /* xCheckReservedLock */
151   kvvfsFileControlJrnl,           /* xFileControl */
152   kvvfsSectorSize,                /* xSectorSize */
153   kvvfsDeviceCharacteristics,     /* xDeviceCharacteristics */
154   0,                              /* xShmMap */
155   0,                              /* xShmLock */
156   0,                              /* xShmBarrier */
157   0,                              /* xShmUnmap */
158   0,                              /* xFetch */
159   0                               /* xUnfetch */
160 };
161 
162 /****** Storage subsystem **************************************************/
163 #include <sys/types.h>
164 #include <sys/stat.h>
165 #include <unistd.h>
166 
167 /* Forward declarations for the low-level storage engine
168 */
169 static int kvstorageWrite(const char*, const char *zKey, const char *zData);
170 static int kvstorageDelete(const char*, const char *zKey);
171 static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf);
172 #define KVSTORAGE_KEY_SZ  32
173 
174 /* Expand the key name with an appropriate prefix and put the result
175 ** zKeyOut[].  The zKeyOut[] buffer is assumed to hold at least
176 ** KVSTORAGE_KEY_SZ bytes.
177 */
178 static void kvstorageMakeKey(
179   const char *zClass,
180   const char *zKeyIn,
181   char *zKeyOut
182 ){
183   sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn);
184 }
185 
186 /* Write content into a key.  zClass is the particular namespace of the
187 ** underlying key/value store to use - either "local" or "session".
188 **
189 ** Both zKey and zData are zero-terminated pure text strings.
190 **
191 ** Return the number of errors.
192 */
193 static int kvstorageWrite(
194   const char *zClass,
195   const char *zKey,
196   const char *zData
197 ){
198   FILE *fd;
199   char zXKey[KVSTORAGE_KEY_SZ];
200   kvstorageMakeKey(zClass, zKey, zXKey);
201   fd = fopen(zXKey, "wb");
202   if( fd ){
203     SQLITE_KV_TRACE(("KVVFS-WRITE  %-15s (%d) %.50s%s\n", zXKey,
204                  (int)strlen(zData), zData,
205                  strlen(zData)>50 ? "..." : ""));
206     fputs(zData, fd);
207     fclose(fd);
208     return 0;
209   }else{
210     return 1;
211   }
212 }
213 
214 /* Delete a key (with its corresponding data) from the key/value
215 ** namespace given by zClass.  If the key does not previously exist,
216 ** this routine is a no-op.
217 */
218 static int kvstorageDelete(const char *zClass, const char *zKey){
219   char zXKey[KVSTORAGE_KEY_SZ];
220   kvstorageMakeKey(zClass, zKey, zXKey);
221   unlink(zXKey);
222   SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey));
223   return 0;
224 }
225 
226 /* Read the value associated with a zKey from the key/value namespace given
227 ** by zClass and put the text data associated with that key in the first
228 ** nBuf bytes of zBuf[].  The value might be truncated if zBuf is not large
229 ** enough to hold it all.  The value put into zBuf must always be zero
230 ** terminated, even if it gets truncated because nBuf is not large enough.
231 **
232 ** Return the total number of bytes in the data, without truncation, and
233 ** not counting the final zero terminator.   Return -1 if the key does
234 ** not exist.
235 **
236 ** If nBuf<=0 then this routine simply returns the size of the data without
237 ** actually reading it.
238 */
239 static int kvstorageRead(
240   const char *zClass,
241   const char *zKey,
242   char *zBuf,
243   int nBuf
244 ){
245   FILE *fd;
246   struct stat buf;
247   char zXKey[KVSTORAGE_KEY_SZ];
248   kvstorageMakeKey(zClass, zKey, zXKey);
249   if( access(zXKey, R_OK)!=0
250    || stat(zXKey, &buf)!=0
251    || !S_ISREG(buf.st_mode)
252   ){
253     SQLITE_KV_TRACE(("KVVFS-READ   %-15s (-1)\n", zXKey));
254     return -1;
255   }
256   if( nBuf<=0 ){
257     return (int)buf.st_size;
258   }else if( nBuf==1 ){
259     zBuf[0] = 0;
260     SQLITE_KV_TRACE(("KVVFS-READ   %-15s (%d)\n", zXKey,
261                  (int)buf.st_size));
262     return (int)buf.st_size;
263   }
264   if( nBuf > buf.st_size + 1 ){
265     nBuf = buf.st_size + 1;
266   }
267   fd = fopen(zXKey, "rb");
268   if( fd==0 ){
269     SQLITE_KV_TRACE(("KVVFS-READ   %-15s (-1)\n", zXKey));
270     return -1;
271   }else{
272     sqlite3_int64 n = fread(zBuf, 1, nBuf-1, fd);
273     fclose(fd);
274     zBuf[n] = 0;
275     SQLITE_KV_TRACE(("KVVFS-READ   %-15s (%lld) %.50s%s\n", zXKey,
276                  n, zBuf, n>50 ? "..." : ""));
277     return (int)n;
278   }
279 }
280 
281 /*
282 ** An internal level of indirection which enables us to replace the
283 ** kvvfs i/o methods with JavaScript implementations in WASM builds.
284 ** Maintenance reminder: if this struct changes in any way, the JSON
285 ** rendering of its structure must be updated in
286 ** sqlite3_wasm_enum_json(). There are no binary compatibility
287 ** concerns, so it does not need an iVersion member. This file is
288 ** necessarily always compiled together with sqlite3_wasm_enum_json(),
289 ** and JS code dynamically creates the mapping of members based on
290 ** that JSON description.
291 */
292 typedef struct sqlite3_kvvfs_methods sqlite3_kvvfs_methods;
293 struct sqlite3_kvvfs_methods {
294   int (*xRead)(const char *zClass, const char *zKey, char *zBuf, int nBuf);
295   int (*xWrite)(const char *zClass, const char *zKey, const char *zData);
296   int (*xDelete)(const char *zClass, const char *zKey);
297   const int nKeySize;
298 };
299 
300 /*
301 ** This object holds the kvvfs I/O methods which may be swapped out
302 ** for JavaScript-side implementations in WASM builds. In such builds
303 ** it cannot be const, but in native builds it should be so that
304 ** the compiler can hopefully optimize this level of indirection out.
305 ** That said, kvvfs is intended primarily for use in WASM builds.
306 **
307 ** Note that this is not explicitly flagged as static because the
308 ** amalgamation build will tag it with SQLITE_PRIVATE.
309 */
310 #ifndef SQLITE_WASM
311 const
312 #endif
313 sqlite3_kvvfs_methods sqlite3KvvfsMethods = {
314 kvstorageRead,
315 kvstorageWrite,
316 kvstorageDelete,
317 KVSTORAGE_KEY_SZ
318 };
319 
320 /****** Utility subroutines ************************************************/
321 
322 /*
323 ** Encode binary into the text encoded used to persist on disk.
324 ** The output text is stored in aOut[], which must be at least
325 ** nData+1 bytes in length.
326 **
327 ** Return the actual length of the encoded text, not counting the
328 ** zero terminator at the end.
329 **
330 ** Encoding format
331 ** ---------------
332 **
333 **   *  Non-zero bytes are encoded as upper-case hexadecimal
334 **
335 **   *  A sequence of one or more zero-bytes that are not at the
336 **      beginning of the buffer are encoded as a little-endian
337 **      base-26 number using a..z.  "a" means 0.  "b" means 1,
338 **      "z" means 25.  "ab" means 26.  "ac" means 52.  And so forth.
339 **
340 **   *  Because there is no overlap between the encoding characters
341 **      of hexadecimal and base-26 numbers, it is always clear where
342 **      one stops and the next begins.
343 */
344 static int kvvfsEncode(const char *aData, int nData, char *aOut){
345   int i, j;
346   const unsigned char *a = (const unsigned char*)aData;
347   for(i=j=0; i<nData; i++){
348     unsigned char c = a[i];
349     if( c!=0 ){
350       aOut[j++] = "0123456789ABCDEF"[c>>4];
351       aOut[j++] = "0123456789ABCDEF"[c&0xf];
352     }else{
353       /* A sequence of 1 or more zeros is stored as a little-endian
354       ** base-26 number using a..z as the digits. So one zero is "b".
355       ** Two zeros is "c". 25 zeros is "z", 26 zeros is "ab", 27 is "bb",
356       ** and so forth.
357       */
358       int k;
359       for(k=1; i+k<nData && a[i+k]==0; k++){}
360       i += k-1;
361       while( k>0 ){
362         aOut[j++] = 'a'+(k%26);
363         k /= 26;
364       }
365     }
366   }
367   aOut[j] = 0;
368   return j;
369 }
370 
371 static const signed char kvvfsHexValue[256] = {
372   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
373   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
374   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
375    0,  1,  2,  3,  4,  5,  6,  7,    8,  9, -1, -1, -1, -1, -1, -1,
376   -1, 10, 11, 12, 13, 14, 15, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
377   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
378   -1, -1, -1, -1, -1, -1, -1, -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 
381   -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
382   -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 };
390 
391 /*
392 ** Decode the text encoding back to binary.  The binary content is
393 ** written into pOut, which must be at least nOut bytes in length.
394 **
395 ** The return value is the number of bytes actually written into aOut[].
396 */
397 static int kvvfsDecode(const char *a, char *aOut, int nOut){
398   int i, j;
399   int c;
400   const unsigned char *aIn = (const unsigned char*)a;
401   i = 0;
402   j = 0;
403   while( 1 ){
404     c = kvvfsHexValue[aIn[i]];
405     if( c<0 ){
406       int n = 0;
407       int mult = 1;
408       c = aIn[i];
409       if( c==0 ) break;
410       while( c>='a' && c<='z' ){
411         n += (c - 'a')*mult;
412         mult *= 26;
413         c = aIn[++i];
414       }
415       if( j+n>nOut ) return -1;
416       memset(&aOut[j], 0, n);
417       j += n;
418       c = aIn[i];
419       if( c==0 ) break;
420     }else{
421       aOut[j] = c<<4;
422       c = kvvfsHexValue[aIn[++i]];
423       if( c<0 ) break;
424       aOut[j++] += c;
425       i++;
426     }
427   }
428   return j;
429 }
430 
431 /*
432 ** Decode a complete journal file.  Allocate space in pFile->aJrnl
433 ** and store the decoding there.  Or leave pFile->aJrnl set to NULL
434 ** if an error is encountered.
435 **
436 ** The first few characters of the text encoding will be a little-endian
437 ** base-26 number (digits a..z) that is the total number of bytes
438 ** in the decoded journal file image.  This base-26 number is followed
439 ** by a single space, then the encoding of the journal.  The space
440 ** separator is required to act as a terminator for the base-26 number.
441 */
442 static void kvvfsDecodeJournal(
443   KVVfsFile *pFile,      /* Store decoding in pFile->aJrnl */
444   const char *zTxt,      /* Text encoding.  Zero-terminated */
445   int nTxt               /* Bytes in zTxt, excluding zero terminator */
446 ){
447   unsigned int n = 0;
448   int c, i, mult;
449   i = 0;
450   mult = 1;
451   while( (c = zTxt[i++])>='a' && c<='z' ){
452     n += (zTxt[i] - 'a')*mult;
453     mult *= 26;
454   }
455   sqlite3_free(pFile->aJrnl);
456   pFile->aJrnl = sqlite3_malloc64( n );
457   if( pFile->aJrnl==0 ){
458     pFile->nJrnl = 0;
459     return;
460   }
461   pFile->nJrnl = n;
462   n = kvvfsDecode(zTxt+i, pFile->aJrnl, pFile->nJrnl);
463   if( n<pFile->nJrnl ){
464     sqlite3_free(pFile->aJrnl);
465     pFile->aJrnl = 0;
466     pFile->nJrnl = 0;
467   }
468 }
469 
470 /*
471 ** Read or write the "sz" element, containing the database file size.
472 */
473 static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){
474   char zData[50];
475   zData[0] = 0;
476   sqlite3KvvfsMethods.xRead(pFile->zClass, "sz", zData, sizeof(zData)-1);
477   return strtoll(zData, 0, 0);
478 }
479 static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){
480   char zData[50];
481   sqlite3_snprintf(sizeof(zData), zData, "%lld", sz);
482   return sqlite3KvvfsMethods.xWrite(pFile->zClass, "sz", zData);
483 }
484 
485 /****** sqlite3_io_methods methods ******************************************/
486 
487 /*
488 ** Close an kvvfs-file.
489 */
490 static int kvvfsClose(sqlite3_file *pProtoFile){
491   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
492 
493   SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass,
494              pFile->isJournal ? "journal" : "db"));
495   sqlite3_free(pFile->aJrnl);
496   return SQLITE_OK;
497 }
498 
499 /*
500 ** Read from the -journal file.
501 */
502 static int kvvfsReadJrnl(
503   sqlite3_file *pProtoFile,
504   void *zBuf,
505   int iAmt,
506   sqlite_int64 iOfst
507 ){
508   KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
509   assert( pFile->isJournal );
510   SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
511   if( pFile->aJrnl==0 ){
512     int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0);
513     char *aTxt;
514     if( szTxt<=4 ){
515       return SQLITE_IOERR;
516     }
517     aTxt = sqlite3_malloc64( szTxt+1 );
518     if( aTxt==0 ) return SQLITE_NOMEM;
519     kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1);
520     kvvfsDecodeJournal(pFile, aTxt, szTxt);
521     sqlite3_free(aTxt);
522     if( pFile->aJrnl==0 ) return SQLITE_IOERR;
523   }
524   if( iOfst+iAmt>pFile->nJrnl ){
525     return SQLITE_IOERR_SHORT_READ;
526   }
527   memcpy(zBuf, pFile->aJrnl+iOfst, iAmt);
528   return SQLITE_OK;
529 }
530 
531 /*
532 ** Read from the database file.
533 */
534 static int kvvfsReadDb(
535   sqlite3_file *pProtoFile,
536   void *zBuf,
537   int iAmt,
538   sqlite_int64 iOfst
539 ){
540   KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
541   unsigned int pgno;
542   int got, n;
543   char zKey[30];
544   char aData[133073];
545   assert( iOfst>=0 );
546   assert( iAmt>=0 );
547   SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
548   if( iOfst+iAmt>=512 ){
549     if( (iOfst % iAmt)!=0 ){
550       return SQLITE_IOERR_READ;
551     }
552     if( (iAmt & (iAmt-1))!=0 || iAmt<512 || iAmt>65536 ){
553       return SQLITE_IOERR_READ;
554     }
555     pFile->szPage = iAmt;
556     pgno = 1 + iOfst/iAmt;
557   }else{
558     pgno = 1;
559   }
560   sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
561   got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey, aData, sizeof(aData)-1);
562   if( got<0 ){
563     n = 0;
564   }else{
565     aData[got] = 0;
566     if( iOfst+iAmt<512 ){
567       int k = iOfst+iAmt;
568       aData[k*2] = 0;
569       n = kvvfsDecode(aData, &aData[2000], sizeof(aData)-2000);
570       if( n>=iOfst+iAmt ){
571         memcpy(zBuf, &aData[2000+iOfst], iAmt);
572         n = iAmt;
573       }else{
574         n = 0;
575       }
576     }else{
577       n = kvvfsDecode(aData, zBuf, iAmt);
578     }
579   }
580   if( n<iAmt ){
581     memset(zBuf+n, 0, iAmt-n);
582     return SQLITE_IOERR_SHORT_READ;
583   }
584   return SQLITE_OK;
585 }
586 
587 
588 /*
589 ** Write into the -journal file.
590 */
591 static int kvvfsWriteJrnl(
592   sqlite3_file *pProtoFile,
593   const void *zBuf,
594   int iAmt,
595   sqlite_int64 iOfst
596 ){
597   KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
598   sqlite3_int64 iEnd = iOfst+iAmt;
599   SQLITE_KV_LOG(("xWrite('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
600   if( iEnd>=0x10000000 ) return SQLITE_FULL;
601   if( pFile->aJrnl==0 || pFile->nJrnl<iEnd ){
602     char *aNew = sqlite3_realloc(pFile->aJrnl, iEnd);
603     if( aNew==0 ){
604       return SQLITE_IOERR_NOMEM;
605     }
606     pFile->aJrnl = aNew;
607     if( pFile->nJrnl<iOfst ){
608       memset(pFile->aJrnl+pFile->nJrnl, 0, iOfst-pFile->nJrnl);
609     }
610     pFile->nJrnl = iEnd;
611   }
612   memcpy(pFile->aJrnl+iOfst, zBuf, iAmt);
613   return SQLITE_OK;
614 }
615 
616 /*
617 ** Write into the database file.
618 */
619 static int kvvfsWriteDb(
620   sqlite3_file *pProtoFile,
621   const void *zBuf,
622   int iAmt,
623   sqlite_int64 iOfst
624 ){
625   KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
626   unsigned int pgno;
627   char zKey[30];
628   char aData[131073];
629   SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
630   assert( iAmt>=512 && iAmt<=65536 );
631   assert( (iAmt & (iAmt-1))==0 );
632   pgno = 1 + iOfst/iAmt;
633   sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
634   kvvfsEncode(zBuf, iAmt, aData);
635   if( sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){
636     return SQLITE_IOERR;
637   }
638   if( iOfst+iAmt > pFile->szDb ){
639     pFile->szDb = iOfst + iAmt;
640   }
641   return SQLITE_OK;
642 }
643 
644 /*
645 ** Truncate an kvvfs-file.
646 */
647 static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){
648   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
649   SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size));
650   assert( size==0 );
651   sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl");
652   sqlite3_free(pFile->aJrnl);
653   pFile->aJrnl = 0;
654   pFile->nJrnl = 0;
655   return SQLITE_OK;
656 }
657 static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){
658   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
659   if( pFile->szDb>size
660    && pFile->szPage>0
661    && (size % pFile->szPage)==0
662   ){
663     char zKey[50];
664     unsigned int pgno, pgnoMax;
665     SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size));
666     pgno = 1 + size/pFile->szPage;
667     pgnoMax = 2 + pFile->szDb/pFile->szPage;
668     while( pgno<=pgnoMax ){
669       sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
670       sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey);
671       pgno++;
672     }
673     pFile->szDb = size;
674     return kvvfsWriteFileSize(pFile, size) ? SQLITE_IOERR : SQLITE_OK;
675   }
676   return SQLITE_IOERR;
677 }
678 
679 /*
680 ** Sync an kvvfs-file.
681 */
682 static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){
683   int i, n;
684   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
685   char *zOut;
686   SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile->zClass));
687   if( pFile->nJrnl<=0 ){
688     return kvvfsTruncateJrnl(pProtoFile, 0);
689   }
690   zOut = sqlite3_malloc64( pFile->nJrnl*2 + 50 );
691   if( zOut==0 ){
692     return SQLITE_IOERR_NOMEM;
693   }
694   n = pFile->nJrnl;
695   i = 0;
696   do{
697     zOut[i++] = 'a' + (n%26);
698     n /= 26;
699   }while( n>0 );
700   zOut[i++] = ' ';
701   kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]);
702   i = sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut);
703   sqlite3_free(zOut);
704   return i ? SQLITE_IOERR : SQLITE_OK;
705 }
706 static int kvvfsSyncDb(sqlite3_file *pProtoFile, int flags){
707   return SQLITE_OK;
708 }
709 
710 /*
711 ** Return the current file-size of an kvvfs-file.
712 */
713 static int kvvfsFileSizeJrnl(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
714   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
715   SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile->zClass));
716   *pSize = pFile->nJrnl;
717   return SQLITE_OK;
718 }
719 static int kvvfsFileSizeDb(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
720   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
721   SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile->zClass));
722   if( pFile->szDb>=0 ){
723     *pSize = pFile->szDb;
724   }else{
725     *pSize = kvvfsReadFileSize(pFile);
726   }
727   return SQLITE_OK;
728 }
729 
730 /*
731 ** Lock an kvvfs-file.
732 */
733 static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){
734   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
735   assert( !pFile->isJournal );
736   SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock));
737 
738   if( eLock!=SQLITE_LOCK_NONE ){
739     pFile->szDb = kvvfsReadFileSize(pFile);
740   }
741   return SQLITE_OK;
742 }
743 
744 /*
745 ** Unlock an kvvfs-file.
746 */
747 static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){
748   KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
749   assert( !pFile->isJournal );
750   SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock));
751   if( eLock==SQLITE_LOCK_NONE ){
752     pFile->szDb = -1;
753   }
754   return SQLITE_OK;
755 }
756 
757 /*
758 ** Check if another file-handle holds a RESERVED lock on an kvvfs-file.
759 */
760 static int kvvfsCheckReservedLock(sqlite3_file *pProtoFile, int *pResOut){
761   SQLITE_KV_LOG(("xCheckReservedLock\n"));
762   *pResOut = 0;
763   return SQLITE_OK;
764 }
765 
766 /*
767 ** File control method. For custom operations on an kvvfs-file.
768 */
769 static int kvvfsFileControlJrnl(sqlite3_file *pProtoFile, int op, void *pArg){
770   SQLITE_KV_LOG(("xFileControl(%d) on journal\n", op));
771   return SQLITE_NOTFOUND;
772 }
773 static int kvvfsFileControlDb(sqlite3_file *pProtoFile, int op, void *pArg){
774   SQLITE_KV_LOG(("xFileControl(%d) on database\n", op));
775   if( op==SQLITE_FCNTL_SYNC ){
776     KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
777     int rc = SQLITE_OK;
778     SQLITE_KV_LOG(("xSync('%s-db')\n", pFile->zClass));
779     if( pFile->szDb>0 && 0!=kvvfsWriteFileSize(pFile, pFile->szDb) ){
780       rc = SQLITE_IOERR;
781     }
782     return rc;
783   }
784   return SQLITE_NOTFOUND;
785 }
786 
787 /*
788 ** Return the sector-size in bytes for an kvvfs-file.
789 */
790 static int kvvfsSectorSize(sqlite3_file *pFile){
791   return 512;
792 }
793 
794 /*
795 ** Return the device characteristic flags supported by an kvvfs-file.
796 */
797 static int kvvfsDeviceCharacteristics(sqlite3_file *pProtoFile){
798   return 0;
799 }
800 
801 /****** sqlite3_vfs methods *************************************************/
802 
803 /*
804 ** Open an kvvfs file handle.
805 */
806 static int kvvfsOpen(
807   sqlite3_vfs *pProtoVfs,
808   const char *zName,
809   sqlite3_file *pProtoFile,
810   int flags,
811   int *pOutFlags
812 ){
813   KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
814   SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName));
815   if( strcmp(zName, "local")==0
816    || strcmp(zName, "session")==0
817   ){
818     pFile->isJournal = 0;
819     pFile->base.pMethods = &kvvfs_db_io_methods;
820   }else
821   if( strcmp(zName, "local-journal")==0
822    || strcmp(zName, "session-journal")==0
823   ){
824     pFile->isJournal = 1;
825     pFile->base.pMethods = &kvvfs_jrnl_io_methods;
826   }else{
827     return SQLITE_CANTOPEN;
828   }
829   if( zName[0]=='s' ){
830     pFile->zClass = "session";
831   }else{
832     pFile->zClass = "local";
833   }
834   pFile->aJrnl = 0;
835   pFile->nJrnl = 0;
836   pFile->szPage = -1;
837   pFile->szDb = -1;
838   return SQLITE_OK;
839 }
840 
841 /*
842 ** Delete the file located at zPath. If the dirSync argument is true,
843 ** ensure the file-system modifications are synced to disk before
844 ** returning.
845 */
846 static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
847   if( strcmp(zPath, "local-journal")==0 ){
848     sqlite3KvvfsMethods.xDelete("local", "jrnl");
849   }else
850   if( strcmp(zPath, "session-journal")==0 ){
851     sqlite3KvvfsMethods.xDelete("session", "jrnl");
852   }
853   return SQLITE_OK;
854 }
855 
856 /*
857 ** Test for access permissions. Return true if the requested permission
858 ** is available, or false otherwise.
859 */
860 static int kvvfsAccess(
861   sqlite3_vfs *pProtoVfs,
862   const char *zPath,
863   int flags,
864   int *pResOut
865 ){
866   SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath));
867   if( strcmp(zPath, "local-journal")==0 ){
868     *pResOut = sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0;
869   }else
870   if( strcmp(zPath, "session-journal")==0 ){
871     *pResOut = sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0;
872   }else
873   if( strcmp(zPath, "local")==0 ){
874     *pResOut = sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0;
875   }else
876   if( strcmp(zPath, "session")==0 ){
877     *pResOut = sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0;
878   }else
879   {
880     *pResOut = 0;
881   }
882   SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut));
883   return SQLITE_OK;
884 }
885 
886 /*
887 ** Populate buffer zOut with the full canonical pathname corresponding
888 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
889 ** of at least (INST_MAX_PATHNAME+1) bytes.
890 */
891 static int kvvfsFullPathname(
892   sqlite3_vfs *pVfs,
893   const char *zPath,
894   int nOut,
895   char *zOut
896 ){
897   size_t nPath;
898 #ifdef SQLITE_OS_KV_ALWAYS_LOCAL
899   zPath = "local";
900 #endif
901   nPath = strlen(zPath);
902   SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath));
903   if( nOut<nPath+1 ) nPath = nOut - 1;
904   memcpy(zOut, zPath, nPath);
905   zOut[nPath] = 0;
906   return SQLITE_OK;
907 }
908 
909 /*
910 ** Open the dynamic library located at zPath and return a handle.
911 */
912 static void *kvvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
913   return 0;
914 }
915 
916 /*
917 ** Populate the buffer pointed to by zBufOut with nByte bytes of
918 ** random data.
919 */
920 static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
921   memset(zBufOut, 0, nByte);
922   return nByte;
923 }
924 
925 /*
926 ** Sleep for nMicro microseconds. Return the number of microseconds
927 ** actually slept.
928 */
929 static int kvvfsSleep(sqlite3_vfs *pVfs, int nMicro){
930   return SQLITE_OK;
931 }
932 
933 /*
934 ** Return the current time as a Julian Day number in *pTimeOut.
935 */
936 static int kvvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
937   sqlite3_int64 i = 0;
938   int rc;
939   rc = kvvfsCurrentTimeInt64(0, &i);
940   *pTimeOut = i/86400000.0;
941   return rc;
942 }
943 #include <sys/time.h>
944 static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
945   static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
946   struct timeval sNow;
947   (void)gettimeofday(&sNow, 0);  /* Cannot fail given valid arguments */
948   *pTimeOut = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
949   return SQLITE_OK;
950 }
951 #endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */
952 
953 #if SQLITE_OS_KV
954 /*
955 ** This routine is called initialize the KV-vfs as the default VFS.
956 */
957 int sqlite3_os_init(void){
958   return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 1);
959 }
960 int sqlite3_os_end(void){
961   return SQLITE_OK;
962 }
963 #endif /* SQLITE_OS_KV */
964 
965 #if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
966 int sqlite3KvvfsInit(void){
967   return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 0);
968 }
969 #endif
970