CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
sqlitevfs.cc
Go to the documentation of this file.
1 
10 #ifndef __STDC_FORMAT_MACROS
11 #define __STDC_FORMAT_MACROS
12 #endif
13 
14 
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 #include <vector>
33 
34 #include "cache.h"
35 #include "duplex_sqlite3.h"
36 #include "statistics.h"
37 #include "util/logging.h"
38 #include "util/platform.h"
39 #include "util/smalloc.h"
40 #include "util/string.h"
41 
42 using namespace std; // NOLINT
43 
44 namespace sqlite {
45 
46 namespace {
47 
48 const char *kVfsName = "cvmfs-readonly";
49 
53 struct VfsRdOnly {
55  : cache_mgr(NULL)
56  , n_access(NULL)
57  , no_open(NULL)
58  , n_rand(NULL)
59  , sz_rand(NULL)
60  , n_read(NULL)
61  , sz_read(NULL)
62  , n_sleep(NULL)
63  , sz_sleep(NULL)
64  , n_time(NULL) { }
75 };
76 
80 struct VfsRdOnlyFile {
81  sqlite3_file base; // Base class. Must be first.
83  int fd;
84  uint64_t size;
85 };
86 
90 std::vector<int> *fd_from_ = NULL;
91 std::vector<int> *fd_to_ = NULL;
92 
93 } // anonymous namespace
94 
95 static void ApplyFdMap(VfsRdOnlyFile *pFile) {
96  const unsigned N = fd_from_->size();
97  for (unsigned i = 0; i < N; ++i) {
98  if (pFile->fd == (*fd_from_)[i]) {
99  LogCvmfs(kLogSql, kLogDebug, "map fd %d --> %d", (*fd_from_)[i],
100  (*fd_to_)[i]);
101  pFile->fd = (*fd_to_)[i];
102  fd_from_->erase(fd_from_->begin() + i);
103  fd_to_->erase(fd_to_->begin() + i);
104  return;
105  }
106  }
107 }
108 
109 
110 static int VfsRdOnlyClose(sqlite3_file *pFile) {
111  VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile);
112  ApplyFdMap(p);
113  const int retval = p->vfs_rdonly->cache_mgr->Close(p->fd);
114  if (retval == 0) {
115  perf::Dec(p->vfs_rdonly->no_open);
116  return SQLITE_OK;
117  }
118  return SQLITE_IOERR_CLOSE;
119 }
120 
121 
126 static int VfsRdOnlyRead(sqlite3_file *pFile,
127  void *zBuf,
128  int iAmt,
129  sqlite_int64 iOfst) {
130  VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile);
131  ApplyFdMap(p);
132  const ssize_t got = p->vfs_rdonly->cache_mgr->Pread(p->fd, zBuf, iAmt, iOfst);
133  perf::Inc(p->vfs_rdonly->n_read);
134  if (got == iAmt) {
135  perf::Xadd(p->vfs_rdonly->sz_read, iAmt);
136  return SQLITE_OK;
137  } else if (got < 0) {
138  return SQLITE_IOERR_READ;
139  } else {
140  perf::Xadd(p->vfs_rdonly->sz_read, got);
141  memset(reinterpret_cast<char *>(zBuf) + got, 0, iAmt - got);
142  return SQLITE_IOERR_SHORT_READ;
143  }
144 }
145 
146 
147 static int VfsRdOnlyWrite(sqlite3_file *pFile __attribute__((unused)),
148  const void *zBuf __attribute__((unused)),
149  int iAmt __attribute__((unused)),
150  sqlite_int64 iOfst __attribute__((unused))) {
151  return SQLITE_READONLY;
152 }
153 
154 
155 static int VfsRdOnlyTruncate(sqlite3_file *pFile __attribute__((unused)),
156  sqlite_int64 size __attribute__((unused))) {
157  return SQLITE_READONLY;
158 }
159 
160 
161 static int VfsRdOnlySync(sqlite3_file *pFile __attribute__((unused)),
162  int flags __attribute__((unused))) {
163  return SQLITE_OK;
164 }
165 
166 
167 static int VfsRdOnlyFileSize(sqlite3_file *pFile, sqlite_int64 *pSize) {
168  VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile);
169  *pSize = p->size;
170  return SQLITE_OK;
171 }
172 
173 
174 static int VfsRdOnlyLock(sqlite3_file *p __attribute__((unused)),
175  int level __attribute__((unused))) {
176  return SQLITE_OK;
177 }
178 
179 
180 static int VfsRdOnlyUnlock(sqlite3_file *p __attribute__((unused)),
181  int level __attribute__((unused))) {
182  return SQLITE_OK;
183 }
184 
185 
186 static int VfsRdOnlyCheckReservedLock(sqlite3_file *p __attribute__((unused)),
187  int *pResOut) {
188  *pResOut = 0;
189  return SQLITE_OK;
190 }
191 
192 
196 static int VfsRdOnlyFileControl(sqlite3_file *p __attribute__((unused)),
197  int op __attribute__((unused)),
198  void *pArg __attribute__((unused))) {
199  return SQLITE_NOTFOUND;
200 }
201 
202 
206 static int VfsRdOnlySectorSize(sqlite3_file *p __attribute__((unused))) {
207  return 4096;
208 }
209 
210 
214 static int VfsRdOnlyDeviceCharacteristics(sqlite3_file *p
215  __attribute__((unused))) {
216  return 0;
217 }
218 
219 
224 static int VfsRdOnlyOpen(sqlite3_vfs *vfs,
225  const char *zName,
226  sqlite3_file *pFile,
227  int flags,
228  int *pOutFlags) {
229  static const sqlite3_io_methods io_methods = {1, // iVersion
242 
243  VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile);
244  CacheManager *cache_mgr = reinterpret_cast<VfsRdOnly *>(vfs->pAppData)
245  ->cache_mgr;
246  // Prevent xClose from being called in case of errors
247  p->base.pMethods = NULL;
248 
249  if (flags & SQLITE_OPEN_READWRITE)
250  return SQLITE_IOERR;
251  if (flags & SQLITE_OPEN_DELETEONCLOSE)
252  return SQLITE_IOERR;
253  if (flags & SQLITE_OPEN_EXCLUSIVE)
254  return SQLITE_IOERR;
255 
256  assert(zName && (zName[0] == '@'));
257  p->fd = String2Int64(string(&zName[1]));
258  if (p->fd < 0)
259  return SQLITE_IOERR;
260  const int64_t size = cache_mgr->GetSize(p->fd);
261  if (size < 0) {
262  cache_mgr->Close(p->fd);
263  p->fd = -1;
264  return SQLITE_IOERR_FSTAT;
265  }
266  if (cache_mgr->Readahead(p->fd) != 0) {
267  cache_mgr->Close(p->fd);
268  p->fd = -1;
269  return SQLITE_IOERR;
270  }
271  p->size = static_cast<uint64_t>(size);
272  if (pOutFlags)
273  *pOutFlags = flags;
274  p->vfs_rdonly = reinterpret_cast<VfsRdOnly *>(vfs->pAppData);
275  p->base.pMethods = &io_methods;
276  perf::Inc(p->vfs_rdonly->no_open);
277  LogCvmfs(kLogSql, kLogDebug, "open sqlite3 catalog on fd %d, size %" PRIu64,
278  p->fd, p->size);
279  return SQLITE_OK;
280 }
281 
282 
283 static int VfsRdOnlyDelete(sqlite3_vfs * __attribute__((unused)),
284  const char *zName __attribute__((unused)),
285  int syncDir __attribute__((unused))) {
286  return SQLITE_IOERR_DELETE;
287 }
288 
289 
293 static int VfsRdOnlyAccess(sqlite3_vfs *vfs,
294  const char *zPath,
295  int flags,
296  int *pResOut) {
297  if (flags == SQLITE_ACCESS_READWRITE) {
298  *pResOut = 0;
299  return SQLITE_OK;
300  }
301  if (HasSuffix(zPath, "-wal", false) || HasSuffix(zPath, "-journal", false)) {
302  *pResOut = 0;
303  return SQLITE_OK;
304  }
305 
306  // This VFS deals with file descriptors, we know the files are there
307  *pResOut = 0;
308  perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_access);
309  return SQLITE_OK;
310 }
311 
312 
316 int VfsRdOnlyFullPathname(sqlite3_vfs *vfs __attribute__((unused)),
317  const char *zPath,
318  int nOut,
319  char *zOut) {
320  zOut[nOut - 1] = '\0';
321  sqlite3_snprintf(nOut, zOut, "%s", zPath);
322  return SQLITE_OK;
323 }
324 
325 
329 static int VfsRdOnlyRandomness(sqlite3_vfs *vfs, int nBuf, char *zBuf) {
330  assert(static_cast<size_t>(nBuf) >= (sizeof(time_t) + sizeof(int)));
331  perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_rand);
332  memset(zBuf, 0, nBuf);
333  pid_t randomnessPid = getpid();
334  int fd, got;
335  fd = open("/dev/urandom", O_RDONLY, 0);
336  if (fd < 0) {
337  time_t t;
338  time(&t);
339  memcpy(zBuf, &t, sizeof(t));
340  memcpy(&zBuf[sizeof(t)], &randomnessPid, sizeof(randomnessPid));
341  assert(sizeof(t) + sizeof(randomnessPid) <= static_cast<size_t>(nBuf));
342  nBuf = sizeof(t) + sizeof(randomnessPid);
343  } else {
344  do {
345  got = read(fd, zBuf, nBuf);
346  } while (got < 0 && errno == EINTR);
347  close(fd);
348  }
349  perf::Xadd(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->sz_rand, nBuf);
350  return nBuf;
351 }
352 
353 
357 static int VfsRdOnlySleep(sqlite3_vfs *vfs, int microseconds) {
358  struct timeval wait_for;
359  wait_for.tv_sec = microseconds / (1000 * 1000);
360  wait_for.tv_usec = microseconds % (1000 * 1000);
361  select(0, NULL, NULL, NULL, &wait_for);
362  perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_sleep);
363  perf::Xadd(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->sz_sleep,
364  microseconds);
365  return microseconds;
366 }
367 
368 
372 static int VfsRdOnlyCurrentTimeInt64(sqlite3_vfs *vfs, sqlite3_int64 *piNow) {
373  static const sqlite3_int64 unixEpoch = 24405875 * (sqlite3_int64)8640000;
374  int rc = SQLITE_OK;
375  struct timeval sNow;
376  if (gettimeofday(&sNow, 0) == 0) {
377  *piNow = unixEpoch + 1000 * (sqlite3_int64)sNow.tv_sec
378  + sNow.tv_usec / 1000;
379  perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_time);
380  } else {
381  rc = SQLITE_ERROR;
382  }
383  return rc;
384 }
385 
386 
390 static int VfsRdOnlyCurrentTime(sqlite3_vfs *vfs, double *prNow) {
391  sqlite3_int64 i = 0;
392  const int rc = VfsRdOnlyCurrentTimeInt64(vfs, &i);
393  *prNow = i / 86400000.0;
394  return rc;
395 }
396 
397 
401 static int VfsRdOnlyGetLastError(sqlite3_vfs *vfs __attribute__((unused)),
402  int not_used1 __attribute__((unused)),
403  char *not_used2 __attribute__((unused))) {
404  return 0;
405 }
406 
407 
412  perf::Statistics *statistics,
413  const VfsOptions options) {
414  fd_from_ = new std::vector<int>();
415  fd_to_ = new std::vector<int>();
416 
417  sqlite3_vfs *vfs = reinterpret_cast<sqlite3_vfs *>(
418  smalloc(sizeof(sqlite3_vfs)));
419  memset(vfs, 0, sizeof(sqlite3_vfs));
420  VfsRdOnly *vfs_rdonly = new VfsRdOnly();
421 
422  vfs->iVersion = 2;
423  vfs->szOsFile = sizeof(VfsRdOnlyFile);
424  vfs->mxPathname = PATH_MAX;
425  vfs->zName = kVfsName;
426  vfs->pAppData = vfs_rdonly;
427  vfs->xOpen = VfsRdOnlyOpen;
428  vfs->xDelete = VfsRdOnlyDelete;
429  vfs->xAccess = VfsRdOnlyAccess;
430  vfs->xFullPathname = VfsRdOnlyFullPathname;
431  vfs->xDlOpen = NULL;
432  vfs->xDlError = NULL;
433  vfs->xDlSym = NULL;
434  vfs->xDlClose = NULL;
435  vfs->xRandomness = VfsRdOnlyRandomness;
436  vfs->xSleep = VfsRdOnlySleep;
437  vfs->xCurrentTime = VfsRdOnlyCurrentTime;
438  vfs->xGetLastError = VfsRdOnlyGetLastError;
439  vfs->xCurrentTimeInt64 = VfsRdOnlyCurrentTimeInt64;
440  assert(vfs->zName);
441 
442  const int retval = sqlite3_vfs_register(vfs, options == kVfsOptDefault);
443  if (retval != SQLITE_OK) {
444  free(const_cast<char *>(vfs->zName));
445  delete vfs_rdonly;
446  free(vfs);
447  return false;
448  }
449 
450  vfs_rdonly->cache_mgr = cache_mgr;
451  vfs_rdonly->n_access = statistics->Register(
452  "sqlite.n_access", "overall number of access() calls");
453  vfs_rdonly->no_open = statistics->Register("sqlite.no_open",
454  "currently open sqlite files");
455  vfs_rdonly->n_rand = statistics->Register("sqlite.n_rand",
456  "overall number of random() calls");
457  vfs_rdonly->sz_rand = statistics->Register("sqlite.sz_rand",
458  "overall number of random bytes");
459  vfs_rdonly->n_read = statistics->Register("sqlite.n_read",
460  "overall number of read() calls");
461  vfs_rdonly->sz_read = statistics->Register("sqlite.sz_read",
462  "overall bytes read()");
463  vfs_rdonly->n_sleep = statistics->Register("sqlite.n_sleep",
464  "overall number of sleep() calls");
465  vfs_rdonly->sz_sleep = statistics->Register("sqlite.sz_sleep",
466  "overall microseconds slept");
467  vfs_rdonly->n_time = statistics->Register("sqlite.n_time",
468  "overall number of time() calls");
469 
470  return true;
471 }
472 
473 
479  sqlite3_vfs *vfs = sqlite3_vfs_find(kVfsName);
480  if (vfs == NULL)
481  return false;
482  const int retval = sqlite3_vfs_unregister(vfs);
483  if (retval != SQLITE_OK)
484  return false;
485 
486  delete reinterpret_cast<VfsRdOnly *>(vfs->pAppData);
487  free(vfs);
488 
489  delete fd_from_;
490  delete fd_to_;
491  fd_from_ = NULL;
492  fd_to_ = NULL;
493 
494  return true;
495 }
496 
497 void RegisterFdMapping(int from, int to) {
498  fd_from_->push_back(from);
499  fd_to_->push_back(to);
500 }
501 
502 void ReplaceCacheManager(CacheManager *new_cache_mgr) {
503  sqlite3_vfs *vfs = sqlite3_vfs_find(kVfsName);
504  if (vfs == NULL)
505  return;
506  static_cast<VfsRdOnly *>(vfs->pAppData)->cache_mgr = new_cache_mgr;
507 }
508 
509 } // namespace sqlite
static int VfsRdOnlySync(sqlite3_file *pFile __attribute__((unused)), int flags __attribute__((unused)))
Definition: sqlitevfs.cc:161
void Dec(class Counter *counter)
Definition: statistics.h:49
Counter * Register(const std::string &name, const std::string &desc)
Definition: statistics.cc:163
void RegisterFdMapping(int from, int to)
Definition: sqlitevfs.cc:497
virtual int64_t GetSize(int fd)=0
int64_t Xadd(class Counter *counter, const int64_t delta)
Definition: statistics.h:51
VfsOptions
Definition: sqlitevfs.h:17
static int VfsRdOnlyOpen(sqlite3_vfs *vfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags)
Definition: sqlitevfs.cc:224
static int VfsRdOnlySleep(sqlite3_vfs *vfs, int microseconds)
Definition: sqlitevfs.cc:357
static void ApplyFdMap(VfsRdOnlyFile *pFile)
Definition: sqlitevfs.cc:95
static int VfsRdOnlyTruncate(sqlite3_file *pFile __attribute__((unused)), sqlite_int64 size __attribute__((unused)))
Definition: sqlitevfs.cc:155
static int VfsRdOnlyDeviceCharacteristics(sqlite3_file *p __attribute__((unused)))
Definition: sqlitevfs.cc:214
assert((mem||(size==0))&&"Out Of Memory")
void ReplaceCacheManager(CacheManager *new_cache_mgr)
Definition: sqlitevfs.cc:502
bool UnregisterVfsRdOnly()
Definition: sqlitevfs.cc:478
struct cvmcache_object_info __attribute__
Definition: atomic.h:24
static int VfsRdOnlyWrite(sqlite3_file *pFile __attribute__((unused)), const void *zBuf __attribute__((unused)), int iAmt __attribute__((unused)), sqlite_int64 iOfst __attribute__((unused)))
Definition: sqlitevfs.cc:147
int64_t String2Int64(const string &value)
Definition: string.cc:234
static int VfsRdOnlyFileControl(sqlite3_file *p __attribute__((unused)), int op __attribute__((unused)), void *pArg __attribute__((unused)))
Definition: sqlitevfs.cc:196
static int VfsRdOnlyRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst)
Definition: sqlitevfs.cc:126
bool RegisterVfsRdOnly(CacheManager *cache_mgr, perf::Statistics *statistics, const VfsOptions options)
Definition: sqlitevfs.cc:411
static int VfsRdOnlyDelete(sqlite3_vfs *__attribute__((unused)), const char *zName __attribute__((unused)), int syncDir __attribute__((unused)))
Definition: sqlitevfs.cc:283
bool HasSuffix(const std::string &str, const std::string &suffix, const bool ignore_case)
Definition: string.cc:296
static int VfsRdOnlyUnlock(sqlite3_file *p __attribute__((unused)), int level __attribute__((unused)))
Definition: sqlitevfs.cc:180
int VfsRdOnlyFullPathname(sqlite3_vfs *vfs __attribute__((unused)), const char *zPath, int nOut, char *zOut)
Definition: sqlitevfs.cc:316
static int VfsRdOnlyCheckReservedLock(sqlite3_file *p __attribute__((unused)), int *pResOut)
Definition: sqlitevfs.cc:186
static int VfsRdOnlyLock(sqlite3_file *p __attribute__((unused)), int level __attribute__((unused)))
Definition: sqlitevfs.cc:174
static int VfsRdOnlyClose(sqlite3_file *pFile)
Definition: sqlitevfs.cc:110
static int VfsRdOnlyRandomness(sqlite3_vfs *vfs, int nBuf, char *zBuf)
Definition: sqlitevfs.cc:329
static int VfsRdOnlySectorSize(sqlite3_file *p __attribute__((unused)))
Definition: sqlitevfs.cc:206
void Inc(class Counter *counter)
Definition: statistics.h:50
virtual int Close(int fd)=0
static int VfsRdOnlyGetLastError(sqlite3_vfs *vfs __attribute__((unused)), int not_used1 __attribute__((unused)), char *not_used2 __attribute__((unused)))
Definition: sqlitevfs.cc:401
static int VfsRdOnlyFileSize(sqlite3_file *pFile, sqlite_int64 *pSize)
Definition: sqlitevfs.cc:167
static int VfsRdOnlyCurrentTimeInt64(sqlite3_vfs *vfs, sqlite3_int64 *piNow)
Definition: sqlitevfs.cc:372
static int VfsRdOnlyCurrentTime(sqlite3_vfs *vfs, double *prNow)
Definition: sqlitevfs.cc:390
virtual int Readahead(int fd)=0
static int VfsRdOnlyAccess(sqlite3_vfs *vfs, const char *zPath, int flags, int *pResOut)
Definition: sqlitevfs.cc:293
static void size_t size
Definition: smalloc.h:54
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:545