GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/sqlitevfs.cc Lines: 104 180 57.8 %
Date: 2019-02-03 02:48:13 Branches: 32 86 37.2 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 *
4
 * An optimized virtual file system layer for the client only.  It expects to
5
 * operate on immutable, valid SQlite files.  Hence it can do a few
6
 * optimiziations.  Most notably it doesn't need to know about the path of
7
 * the SQlite file once opened.  It works purely on the file descriptor.
8
 */
9
10
#ifndef __STDC_FORMAT_MACROS
11
#define __STDC_FORMAT_MACROS
12
#endif
13
14
#include "cvmfs_config.h"
15
#include "sqlitevfs.h"
16
17
#include <dlfcn.h>
18
#include <errno.h>
19
#include <fcntl.h>
20
#include <inttypes.h>
21
#include <stdint.h>
22
#include <sys/select.h>
23
#include <sys/time.h>
24
#include <sys/types.h>
25
#include <sys/uio.h>
26
#include <unistd.h>
27
28
#include <cassert>
29
#include <climits>
30
#include <cstring>
31
#include <ctime>
32
33
#include "cache.h"
34
#include "duplex_sqlite3.h"
35
#include "logging.h"
36
#include "platform.h"
37
#include "smalloc.h"
38
#include "statistics.h"
39
#include "util/string.h"
40
41
using namespace std;  // NOLINT
42
43
namespace sqlite {
44
45
namespace {
46
47
const char *kVfsName = "cvmfs-readonly";
48
49
/**
50
 * The private user data attached to the sqlite_vfs object.
51
 */
52
struct VfsRdOnly {
53
107
  VfsRdOnly()
54
    : cache_mgr(NULL)
55
    , n_access(NULL)
56
    , no_open(NULL)
57
    , n_rand(NULL)
58
    , sz_rand(NULL)
59
    , n_read(NULL)
60
    , sz_read(NULL)
61
    , n_sleep(NULL)
62
    , sz_sleep(NULL)
63
107
    , n_time(NULL)
64
107
  { }
65
  CacheManager *cache_mgr;
66
  perf::Counter *n_access;
67
  perf::Counter *no_open;
68
  perf::Counter *n_rand;
69
  perf::Counter *sz_rand;
70
  perf::Counter *n_read;
71
  perf::Counter *sz_read;
72
  perf::Counter *n_sleep;
73
  perf::Counter *sz_sleep;
74
  perf::Counter *n_time;
75
};
76
77
/**
78
 * This is passed to all operations once a file is opened.
79
 */
80
struct VfsRdOnlyFile {
81
  sqlite3_file base;  // Base class. Must be first.
82
  VfsRdOnly *vfs_rdonly;
83
  int fd;
84
  uint64_t size;
85
};
86
87
}  // anonymous namespace
88
89
90
52
static int VfsRdOnlyClose(sqlite3_file *pFile) {
91
52
  VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile);
92
52
  int retval = p->vfs_rdonly->cache_mgr->Close(p->fd);
93
52
  if (retval == 0) {
94
52
    perf::Dec(p->vfs_rdonly->no_open);
95
52
    return SQLITE_OK;
96
  }
97
  return SQLITE_IOERR_CLOSE;
98
}
99
100
101
/**
102
 * On a short read, the remaining bytes must be zero'ed.
103
 * TODO(jblomer): the reads seem to be rather small.  Investigate buffered read.
104
 */
105
483
static int VfsRdOnlyRead(
106
  sqlite3_file *pFile,
107
  void *zBuf,
108
  int iAmt,
109
  sqlite_int64 iOfst
110
) {
111
483
  VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile);
112
483
  ssize_t got = p->vfs_rdonly->cache_mgr->Pread(p->fd, zBuf, iAmt, iOfst);
113
483
  perf::Inc(p->vfs_rdonly->n_read);
114
483
  if (got == iAmt) {
115
483
    perf::Xadd(p->vfs_rdonly->sz_read, iAmt);
116
483
    return SQLITE_OK;
117
  } else if (got < 0) {
118
    return SQLITE_IOERR_READ;
119
  } else {
120
    perf::Xadd(p->vfs_rdonly->sz_read, got);
121
    memset(reinterpret_cast<char *>(zBuf) + got, 0, iAmt - got);
122
    return SQLITE_IOERR_SHORT_READ;
123
  }
124
}
125
126
127
static int VfsRdOnlyWrite(
128
  sqlite3_file *pFile __attribute__((unused)),
129
  const void *zBuf __attribute__((unused)),
130
  int iAmt __attribute__((unused)),
131
  sqlite_int64 iOfst __attribute__((unused)))
132
{
133
  return SQLITE_READONLY;
134
}
135
136
137
static int VfsRdOnlyTruncate(
138
  sqlite3_file *pFile __attribute__((unused)),
139
  sqlite_int64 size __attribute__((unused)))
140
{
141
  return SQLITE_READONLY;
142
}
143
144
145
static int VfsRdOnlySync(
146
  sqlite3_file *pFile __attribute__((unused)),
147
  int flags __attribute__((unused)))
148
{
149
  return SQLITE_OK;
150
}
151
152
153
104
static int VfsRdOnlyFileSize(sqlite3_file *pFile, sqlite_int64 *pSize) {
154
104
  VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile);
155
104
  *pSize = p->size;
156
104
  return SQLITE_OK;
157
}
158
159
160
52
static int VfsRdOnlyLock(
161
  sqlite3_file *p __attribute__((unused)),
162
  int level __attribute__((unused))
163
) {
164
52
  return SQLITE_OK;
165
}
166
167
168
52
static int VfsRdOnlyUnlock(
169
  sqlite3_file *p __attribute__((unused)),
170
  int level __attribute__((unused))
171
) {
172
52
  return SQLITE_OK;
173
}
174
175
176
static int VfsRdOnlyCheckReservedLock(
177
  sqlite3_file *p __attribute__((unused)),
178
  int *pResOut
179
) {
180
  *pResOut = 0;
181
  return SQLITE_OK;
182
}
183
184
185
/**
186
 *  No xFileControl() verbs are implemented by this VFS.
187
 */
188
208
static int VfsRdOnlyFileControl(
189
  sqlite3_file *p __attribute__((unused)),
190
  int op __attribute__((unused)),
191
  void *pArg __attribute__((unused))
192
) {
193
208
  return SQLITE_NOTFOUND;
194
}
195
196
197
/**
198
 * A good unit of bytes to read at once.  But probably only used for writes.
199
 */
200
52
static int VfsRdOnlySectorSize(sqlite3_file *p __attribute__((unused))) {
201
52
  return 4096;
202
}
203
204
205
/**
206
 * Only relevant for writing.
207
 */
208
156
static int VfsRdOnlyDeviceCharacteristics(
209
  sqlite3_file *p __attribute__((unused)))
210
{
211
156
  return 0;
212
}
213
214
215
/**
216
 * Supports only read-only opens.  The "file name" has to be in the form of
217
 * '@<file descriptor>', where file descriptor is usable by the cache manager.
218
 */
219
52
static int VfsRdOnlyOpen(
220
  sqlite3_vfs *vfs,
221
  const char *zName,
222
  sqlite3_file *pFile,
223
  int flags,
224
  int *pOutFlags)
225
{
226
  static const sqlite3_io_methods io_methods = {
227
    1,  // iVersion
228
    VfsRdOnlyClose,
229
    VfsRdOnlyRead,
230
    VfsRdOnlyWrite,
231
    VfsRdOnlyTruncate,
232
    VfsRdOnlySync,
233
    VfsRdOnlyFileSize,
234
    VfsRdOnlyLock,
235
    VfsRdOnlyUnlock,
236
    VfsRdOnlyCheckReservedLock,
237
    VfsRdOnlyFileControl,
238
    VfsRdOnlySectorSize,
239
    VfsRdOnlyDeviceCharacteristics
240
  };
241
242
52
  VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile);
243
  CacheManager *cache_mgr =
244
52
    reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->cache_mgr;
245
  // Prevent xClose from being called in case of errors
246
52
  p->base.pMethods = NULL;
247
248
52
  if (flags & SQLITE_OPEN_READWRITE)
249
    return SQLITE_IOERR;
250
52
  if (flags & SQLITE_OPEN_DELETEONCLOSE)
251
    return SQLITE_IOERR;
252
52
  if (flags & SQLITE_OPEN_EXCLUSIVE)
253
    return SQLITE_IOERR;
254
255

52
  assert(zName && (zName[0] == '@'));
256
52
  p->fd = String2Int64(string(&zName[1]));
257
52
  if (p->fd < 0)
258
    return SQLITE_IOERR;
259
52
  int64_t size = cache_mgr->GetSize(p->fd);
260
52
  if (size < 0) {
261
    cache_mgr->Close(p->fd);
262
    p->fd = -1;
263
    return SQLITE_IOERR_FSTAT;
264
  }
265
52
  if (cache_mgr->Readahead(p->fd) != 0) {
266
    cache_mgr->Close(p->fd);
267
    p->fd = -1;
268
    return SQLITE_IOERR;
269
  }
270
52
  p->size = static_cast<uint64_t>(size);
271
52
  if (pOutFlags)
272
52
    *pOutFlags = flags;
273
52
  p->vfs_rdonly = reinterpret_cast<VfsRdOnly *>(vfs->pAppData);
274
52
  p->base.pMethods = &io_methods;
275
52
  perf::Inc(p->vfs_rdonly->no_open);
276
  LogCvmfs(kLogSql, kLogDebug, "open sqlite3 catalog on fd %d, size %" PRIu64,
277
52
           p->fd, p->size);
278
52
  return SQLITE_OK;
279
}
280
281
282
static int VfsRdOnlyDelete(
283
  sqlite3_vfs* __attribute__((unused)),
284
  const char *zName __attribute__((unused)),
285
  int syncDir __attribute__((unused)))
286
{
287
  return SQLITE_IOERR_DELETE;
288
}
289
290
291
/**
292
 * Cvmfs r/o file catalogs cannot have a write-ahead log or a journal.
293
 */
294
104
static int VfsRdOnlyAccess(
295
  sqlite3_vfs *vfs,
296
  const char *zPath,
297
  int flags,
298
  int *pResOut)
299
{
300
104
  if (flags == SQLITE_ACCESS_READWRITE) {
301
    *pResOut = 0;
302
    return SQLITE_OK;
303
  }
304









104
  if (HasSuffix(zPath, "-wal", false) || HasSuffix(zPath, "-journal", false)) {
305
104
    *pResOut = 0;
306
104
    return SQLITE_OK;
307
  }
308
309
  /*int amode = 0;
310
  switch (flags) {
311
    case SQLITE_ACCESS_EXISTS:
312
      amode = F_OK;
313
      break;
314
    case SQLITE_ACCESS_READ:
315
      amode = R_OK;
316
      break;
317
    default:
318
      assert(false);
319
  }
320
  *pResOut = (access(zPath, amode) == 0);*/
321
  // This VFS deals with file descriptors, we know the files are there
322
  *pResOut = 0;
323
  perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_access);
324
  return SQLITE_OK;
325
}
326
327
328
/**
329
 * Since the path is never stored, there is no need to produce a full path.
330
 */
331
52
int VfsRdOnlyFullPathname(
332
  sqlite3_vfs *vfs __attribute__((unused)),
333
  const char *zPath,
334
  int nOut,
335
  char *zOut)
336
{
337
52
  zOut[nOut-1] = '\0';
338
52
  sqlite3_snprintf(nOut, zOut, "%s", zPath);
339
52
  return SQLITE_OK;
340
}
341
342
343
/**
344
 * Taken from unixRandomness
345
 */
346
static int VfsRdOnlyRandomness(
347
  sqlite3_vfs *vfs,
348
  int nBuf,
349
  char *zBuf)
350
{
351
  assert((size_t)nBuf >= (sizeof(time_t) + sizeof(int)));
352
  perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_rand);
353
  memset(zBuf, 0, nBuf);
354
  pid_t randomnessPid = getpid();
355
  int fd, got;
356
  fd = open("/dev/urandom", O_RDONLY, 0);
357
  if (fd < 0) {
358
    time_t t;
359
    time(&t);
360
    memcpy(zBuf, &t, sizeof(t));
361
    memcpy(&zBuf[sizeof(t)], &randomnessPid, sizeof(randomnessPid));
362
    assert(sizeof(t) + sizeof(randomnessPid) <= (size_t)nBuf);
363
    nBuf = sizeof(t) + sizeof(randomnessPid);
364
  } else {
365
    do {
366
      got = read(fd, zBuf, nBuf);
367
    } while (got < 0 && errno == EINTR);
368
    close(fd);
369
  }
370
  perf::Xadd(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->sz_rand, nBuf);
371
  return nBuf;
372
}
373
374
375
/**
376
 * Like SafeSleepMs, avoid conflict with the ALARM signal.
377
 */
378
static int VfsRdOnlySleep(
379
  sqlite3_vfs *vfs,
380
  int microseconds)
381
{
382
  struct timeval wait_for;
383
  wait_for.tv_sec = microseconds / (1000*1000);
384
  wait_for.tv_usec = microseconds % (1000 * 1000);
385
  select(0, NULL, NULL, NULL, &wait_for);
386
  perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_sleep);
387
  perf::Xadd(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->sz_sleep,
388
             microseconds);
389
  return microseconds;
390
}
391
392
393
/**
394
 * Taken from unixCurrentTimeInt64()
395
 */
396
static int VfsRdOnlyCurrentTimeInt64(
397
  sqlite3_vfs *vfs,
398
  sqlite3_int64 *piNow)
399
{
400
  static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
401
  int rc = SQLITE_OK;
402
  struct timeval sNow;
403
  if (gettimeofday(&sNow, 0) == 0) {
404
    *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
405
    perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_time);
406
  } else {
407
    rc = SQLITE_ERROR;
408
  }
409
  return rc;
410
}
411
412
413
/**
414
 * Taken from unixCurrentTime
415
 */
416
static int VfsRdOnlyCurrentTime(
417
  sqlite3_vfs *vfs,
418
  double *prNow)
419
{
420
  sqlite3_int64 i = 0;
421
  int rc = VfsRdOnlyCurrentTimeInt64(vfs, &i);
422
  *prNow = i/86400000.0;
423
  return rc;
424
}
425
426
427
/**
428
 * So far unused by sqlite.
429
 */
430
static int VfsRdOnlyGetLastError(
431
  sqlite3_vfs *vfs __attribute__((unused)),
432
  int not_used1 __attribute__((unused)),
433
  char *not_used2 __attribute__((unused)))
434
{
435
  return 0;
436
}
437
438
439
/**
440
 * Can only be registered once.
441
 */
442
107
bool RegisterVfsRdOnly(
443
  CacheManager *cache_mgr,
444
  perf::Statistics *statistics,
445
  const VfsOptions options)
446
{
447
  sqlite3_vfs *vfs = reinterpret_cast<sqlite3_vfs *>(
448
107
    smalloc(sizeof(sqlite3_vfs)));
449
107
  memset(vfs, 0, sizeof(sqlite3_vfs));
450
107
  VfsRdOnly *vfs_rdonly = new VfsRdOnly();
451
452
107
  vfs->iVersion = 2;
453
107
  vfs->szOsFile = sizeof(VfsRdOnlyFile);
454
107
  vfs->mxPathname = PATH_MAX;
455
107
  vfs->zName = kVfsName;
456
107
  vfs->pAppData = vfs_rdonly;
457
107
  vfs->xOpen = VfsRdOnlyOpen;
458
107
  vfs->xDelete = VfsRdOnlyDelete;
459
107
  vfs->xAccess = VfsRdOnlyAccess;
460
107
  vfs->xFullPathname = VfsRdOnlyFullPathname;
461
107
  vfs->xDlOpen = NULL;
462
107
  vfs->xDlError = NULL;
463
107
  vfs->xDlSym = NULL;
464
107
  vfs->xDlClose = NULL;
465
107
  vfs->xRandomness = VfsRdOnlyRandomness;
466
107
  vfs->xSleep = VfsRdOnlySleep;
467
107
  vfs->xCurrentTime = VfsRdOnlyCurrentTime;
468
107
  vfs->xGetLastError = VfsRdOnlyGetLastError;
469
107
  vfs->xCurrentTimeInt64 = VfsRdOnlyCurrentTimeInt64;
470
107
  assert(vfs->zName);
471
472
107
  int retval = sqlite3_vfs_register(vfs, options == kVfsOptDefault);
473
107
  if (retval != SQLITE_OK) {
474
    free(const_cast<char *>(vfs->zName));
475
    delete vfs_rdonly;
476
    free(vfs);
477
    return false;
478
  }
479
480
107
  vfs_rdonly->cache_mgr = cache_mgr;
481
  vfs_rdonly->n_access =
482
107
    statistics->Register("sqlite.n_access", "overall number of access() calls");
483
  vfs_rdonly->no_open =
484
107
    statistics->Register("sqlite.no_open", "currently open sqlite files");
485
  vfs_rdonly->n_rand =
486
107
    statistics->Register("sqlite.n_rand", "overall number of random() calls");
487
  vfs_rdonly->sz_rand =
488
107
    statistics->Register("sqlite.sz_rand", "overall number of random bytes");
489
  vfs_rdonly->n_read =
490
107
    statistics->Register("sqlite.n_read", "overall number of read() calls");
491
  vfs_rdonly->sz_read =
492
107
    statistics->Register("sqlite.sz_read", "overall bytes read()");
493
  vfs_rdonly->n_sleep =
494
107
    statistics->Register("sqlite.n_sleep", "overall number of sleep() calls");
495
  vfs_rdonly->sz_sleep =
496
107
    statistics->Register("sqlite.sz_sleep", "overall microseconds slept");
497
  vfs_rdonly->n_time =
498
107
    statistics->Register("sqlite.n_time", "overall number of time() calls");
499
500
107
  return true;
501
}
502
503
504
/**
505
 * If the file system was the default VFS, another default VFS is selected by
506
 * SQlite randomly.
507
 */
508
104
bool UnregisterVfsRdOnly() {
509
104
  sqlite3_vfs *vfs = sqlite3_vfs_find(kVfsName);
510
104
  if (vfs == NULL)
511
    return false;
512
104
  int retval = sqlite3_vfs_unregister(vfs);
513
104
  if (retval != SQLITE_OK)
514
    return false;
515
516
104
  delete reinterpret_cast<VfsRdOnly *>(vfs->pAppData);
517
104
  free(vfs);
518
104
  return true;
519
}
520
521
}  // namespace sqlite