| Directory: | cvmfs/ |
|---|---|
| File: | cvmfs/sqlitevfs.cc |
| Date: | 2026-04-19 02:41:37 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 123 | 215 | 57.2% |
| Branches: | 71 | 180 | 39.4% |
| 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 | * optimizations. 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 | |||
| 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/smalloc.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 | 1262 | VfsRdOnly() | |
| 54 | 1262 | : cache_mgr(NULL) | |
| 55 | 1262 | , n_access(NULL) | |
| 56 | 1262 | , no_open(NULL) | |
| 57 | 1262 | , n_rand(NULL) | |
| 58 | 1262 | , sz_rand(NULL) | |
| 59 | 1262 | , n_read(NULL) | |
| 60 | 1262 | , sz_read(NULL) | |
| 61 | 1262 | , n_sleep(NULL) | |
| 62 | 1262 | , sz_sleep(NULL) | |
| 63 | 1262 | , n_time(NULL) { } | |
| 64 | CacheManager *cache_mgr; | ||
| 65 | perf::Counter *n_access; | ||
| 66 | perf::Counter *no_open; | ||
| 67 | perf::Counter *n_rand; | ||
| 68 | perf::Counter *sz_rand; | ||
| 69 | perf::Counter *n_read; | ||
| 70 | perf::Counter *sz_read; | ||
| 71 | perf::Counter *n_sleep; | ||
| 72 | perf::Counter *sz_sleep; | ||
| 73 | perf::Counter *n_time; | ||
| 74 | }; | ||
| 75 | |||
| 76 | /** | ||
| 77 | * This is passed to all operations once a file is opened. | ||
| 78 | */ | ||
| 79 | struct VfsRdOnlyFile { | ||
| 80 | sqlite3_file base; // Base class. Must be first. | ||
| 81 | VfsRdOnly *vfs_rdonly; | ||
| 82 | int fd; | ||
| 83 | uint64_t size; | ||
| 84 | }; | ||
| 85 | |||
| 86 | /** | ||
| 87 | * File descriptor mappings | ||
| 88 | */ | ||
| 89 | std::vector<int> *fd_from_ = NULL; | ||
| 90 | std::vector<int> *fd_to_ = NULL; | ||
| 91 | |||
| 92 | } // anonymous namespace | ||
| 93 | |||
| 94 | 6909 | static void ApplyFdMap(VfsRdOnlyFile *pFile) { | |
| 95 | 6909 | const unsigned N = fd_from_->size(); | |
| 96 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6909 times.
|
6909 | for (unsigned i = 0; i < N; ++i) { |
| 97 | ✗ | if (pFile->fd == (*fd_from_)[i]) { | |
| 98 | ✗ | LogCvmfs(kLogSql, kLogDebug, "map fd %d --> %d", (*fd_from_)[i], | |
| 99 | ✗ | (*fd_to_)[i]); | |
| 100 | ✗ | pFile->fd = (*fd_to_)[i]; | |
| 101 | ✗ | fd_from_->erase(fd_from_->begin() + i); | |
| 102 | ✗ | fd_to_->erase(fd_to_->begin() + i); | |
| 103 | ✗ | return; | |
| 104 | } | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | |||
| 109 | 589 | static int VfsRdOnlyClose(sqlite3_file *pFile) { | |
| 110 | 589 | VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile); | |
| 111 | 589 | ApplyFdMap(p); | |
| 112 | 589 | const int retval = p->vfs_rdonly->cache_mgr->Close(p->fd); | |
| 113 |
1/2✓ Branch 0 taken 589 times.
✗ Branch 1 not taken.
|
589 | if (retval == 0) { |
| 114 | 589 | perf::Dec(p->vfs_rdonly->no_open); | |
| 115 | 589 | return SQLITE_OK; | |
| 116 | } | ||
| 117 | ✗ | return SQLITE_IOERR_CLOSE; | |
| 118 | } | ||
| 119 | |||
| 120 | |||
| 121 | /** | ||
| 122 | * On a short read, the remaining bytes must be zero'ed. | ||
| 123 | * TODO(jblomer): the reads seem to be rather small. Investigate buffered read. | ||
| 124 | */ | ||
| 125 | 6320 | static int VfsRdOnlyRead(sqlite3_file *pFile, | |
| 126 | void *zBuf, | ||
| 127 | int iAmt, | ||
| 128 | sqlite_int64 iOfst) { | ||
| 129 | 6320 | VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile); | |
| 130 | 6320 | ApplyFdMap(p); | |
| 131 | 6320 | const ssize_t got = p->vfs_rdonly->cache_mgr->Pread(p->fd, zBuf, iAmt, iOfst); | |
| 132 | 6320 | perf::Inc(p->vfs_rdonly->n_read); | |
| 133 |
1/2✓ Branch 0 taken 6320 times.
✗ Branch 1 not taken.
|
6320 | if (got == iAmt) { |
| 134 | 6320 | perf::Xadd(p->vfs_rdonly->sz_read, iAmt); | |
| 135 | 6320 | return SQLITE_OK; | |
| 136 | ✗ | } else if (got < 0) { | |
| 137 | ✗ | return SQLITE_IOERR_READ; | |
| 138 | } else { | ||
| 139 | ✗ | perf::Xadd(p->vfs_rdonly->sz_read, got); | |
| 140 | ✗ | memset(reinterpret_cast<char *>(zBuf) + got, 0, iAmt - got); | |
| 141 | ✗ | return SQLITE_IOERR_SHORT_READ; | |
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | |||
| 146 | ✗ | static int VfsRdOnlyWrite(sqlite3_file *pFile __attribute__((unused)), | |
| 147 | const void *zBuf __attribute__((unused)), | ||
| 148 | int iAmt __attribute__((unused)), | ||
| 149 | sqlite_int64 iOfst __attribute__((unused))) { | ||
| 150 | ✗ | return SQLITE_READONLY; | |
| 151 | } | ||
| 152 | |||
| 153 | |||
| 154 | ✗ | static int VfsRdOnlyTruncate(sqlite3_file *pFile __attribute__((unused)), | |
| 155 | sqlite_int64 size __attribute__((unused))) { | ||
| 156 | ✗ | return SQLITE_READONLY; | |
| 157 | } | ||
| 158 | |||
| 159 | |||
| 160 | ✗ | static int VfsRdOnlySync(sqlite3_file *pFile __attribute__((unused)), | |
| 161 | int flags __attribute__((unused))) { | ||
| 162 | ✗ | return SQLITE_OK; | |
| 163 | } | ||
| 164 | |||
| 165 | |||
| 166 | 589 | static int VfsRdOnlyFileSize(sqlite3_file *pFile, sqlite_int64 *pSize) { | |
| 167 | 589 | VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile); | |
| 168 | 589 | *pSize = p->size; | |
| 169 | 589 | return SQLITE_OK; | |
| 170 | } | ||
| 171 | |||
| 172 | |||
| 173 | 589 | static int VfsRdOnlyLock(sqlite3_file *p __attribute__((unused)), | |
| 174 | int level __attribute__((unused))) { | ||
| 175 | 589 | return SQLITE_OK; | |
| 176 | } | ||
| 177 | |||
| 178 | |||
| 179 | 589 | static int VfsRdOnlyUnlock(sqlite3_file *p __attribute__((unused)), | |
| 180 | int level __attribute__((unused))) { | ||
| 181 | 589 | return SQLITE_OK; | |
| 182 | } | ||
| 183 | |||
| 184 | |||
| 185 | ✗ | static int VfsRdOnlyCheckReservedLock(sqlite3_file *p __attribute__((unused)), | |
| 186 | int *pResOut) { | ||
| 187 | ✗ | *pResOut = 0; | |
| 188 | ✗ | return SQLITE_OK; | |
| 189 | } | ||
| 190 | |||
| 191 | |||
| 192 | /** | ||
| 193 | * No xFileControl() verbs are implemented by this VFS. | ||
| 194 | */ | ||
| 195 | 2945 | static int VfsRdOnlyFileControl(sqlite3_file *p __attribute__((unused)), | |
| 196 | int op __attribute__((unused)), | ||
| 197 | void *pArg __attribute__((unused))) { | ||
| 198 | 2945 | return SQLITE_NOTFOUND; | |
| 199 | } | ||
| 200 | |||
| 201 | |||
| 202 | /** | ||
| 203 | * A good unit of bytes to read at once. But probably only used for writes. | ||
| 204 | */ | ||
| 205 | 589 | static int VfsRdOnlySectorSize(sqlite3_file *p __attribute__((unused))) { | |
| 206 | 589 | return 4096; | |
| 207 | } | ||
| 208 | |||
| 209 | |||
| 210 | /** | ||
| 211 | * Only relevant for writing. | ||
| 212 | */ | ||
| 213 | 1767 | static int VfsRdOnlyDeviceCharacteristics(sqlite3_file *p | |
| 214 | __attribute__((unused))) { | ||
| 215 | 1767 | return 0; | |
| 216 | } | ||
| 217 | |||
| 218 | |||
| 219 | /** | ||
| 220 | * Supports only read-only opens. The "file name" has to be in the form of | ||
| 221 | * '@<file descriptor>', where file descriptor is usable by the cache manager. | ||
| 222 | */ | ||
| 223 | 589 | static int VfsRdOnlyOpen(sqlite3_vfs *vfs, | |
| 224 | const char *zName, | ||
| 225 | sqlite3_file *pFile, | ||
| 226 | int flags, | ||
| 227 | int *pOutFlags) { | ||
| 228 | static const sqlite3_io_methods io_methods = {1, // iVersion | ||
| 229 | VfsRdOnlyClose, | ||
| 230 | VfsRdOnlyRead, | ||
| 231 | VfsRdOnlyWrite, | ||
| 232 | VfsRdOnlyTruncate, | ||
| 233 | VfsRdOnlySync, | ||
| 234 | VfsRdOnlyFileSize, | ||
| 235 | VfsRdOnlyLock, | ||
| 236 | VfsRdOnlyUnlock, | ||
| 237 | VfsRdOnlyCheckReservedLock, | ||
| 238 | VfsRdOnlyFileControl, | ||
| 239 | VfsRdOnlySectorSize, | ||
| 240 | VfsRdOnlyDeviceCharacteristics}; | ||
| 241 | |||
| 242 | 589 | VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile); | |
| 243 | 589 | CacheManager *cache_mgr = reinterpret_cast<VfsRdOnly *>(vfs->pAppData) | |
| 244 | ->cache_mgr; | ||
| 245 | // Prevent xClose from being called in case of errors | ||
| 246 | 589 | p->base.pMethods = NULL; | |
| 247 | |||
| 248 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 589 times.
|
589 | if (flags & SQLITE_OPEN_READWRITE) |
| 249 | ✗ | return SQLITE_IOERR; | |
| 250 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 589 times.
|
589 | if (flags & SQLITE_OPEN_DELETEONCLOSE) |
| 251 | ✗ | return SQLITE_IOERR; | |
| 252 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 589 times.
|
589 | if (flags & SQLITE_OPEN_EXCLUSIVE) |
| 253 | ✗ | return SQLITE_IOERR; | |
| 254 | |||
| 255 |
2/4✓ Branch 0 taken 589 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 589 times.
✗ Branch 3 not taken.
|
589 | assert(zName && (zName[0] == '@')); |
| 256 |
2/4✓ Branch 2 taken 589 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 589 times.
✗ Branch 6 not taken.
|
589 | p->fd = String2Int64(string(&zName[1])); |
| 257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 589 times.
|
589 | if (p->fd < 0) |
| 258 | ✗ | return SQLITE_IOERR; | |
| 259 | 589 | const int64_t size = cache_mgr->GetSize(p->fd); | |
| 260 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 589 times.
|
589 | if (size < 0) { |
| 261 | ✗ | cache_mgr->Close(p->fd); | |
| 262 | ✗ | p->fd = -1; | |
| 263 | ✗ | return SQLITE_IOERR_FSTAT; | |
| 264 | } | ||
| 265 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 589 times.
|
589 | if (cache_mgr->Readahead(p->fd) != 0) { |
| 266 | ✗ | cache_mgr->Close(p->fd); | |
| 267 | ✗ | p->fd = -1; | |
| 268 | ✗ | return SQLITE_IOERR; | |
| 269 | } | ||
| 270 | 589 | p->size = static_cast<uint64_t>(size); | |
| 271 |
1/2✓ Branch 0 taken 589 times.
✗ Branch 1 not taken.
|
589 | if (pOutFlags) |
| 272 | 589 | *pOutFlags = flags; | |
| 273 | 589 | p->vfs_rdonly = reinterpret_cast<VfsRdOnly *>(vfs->pAppData); | |
| 274 | 589 | p->base.pMethods = &io_methods; | |
| 275 | 589 | perf::Inc(p->vfs_rdonly->no_open); | |
| 276 | 589 | LogCvmfs(kLogSql, kLogDebug, "open sqlite3 catalog on fd %d, size %" PRIu64, | |
| 277 | p->fd, p->size); | ||
| 278 | 589 | return SQLITE_OK; | |
| 279 | } | ||
| 280 | |||
| 281 | |||
| 282 | ✗ | static int VfsRdOnlyDelete(sqlite3_vfs * __attribute__((unused)), | |
| 283 | const char *zName __attribute__((unused)), | ||
| 284 | int syncDir __attribute__((unused))) { | ||
| 285 | ✗ | return SQLITE_IOERR_DELETE; | |
| 286 | } | ||
| 287 | |||
| 288 | |||
| 289 | /** | ||
| 290 | * Cvmfs r/o file catalogs cannot have a write-ahead log or a journal. | ||
| 291 | */ | ||
| 292 | 1178 | static int VfsRdOnlyAccess(sqlite3_vfs *vfs, | |
| 293 | const char *zPath, | ||
| 294 | int flags, | ||
| 295 | int *pResOut) { | ||
| 296 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1178 times.
|
1178 | if (flags == SQLITE_ACCESS_READWRITE) { |
| 297 | ✗ | *pResOut = 0; | |
| 298 | ✗ | return SQLITE_OK; | |
| 299 | } | ||
| 300 |
22/50✓ Branch 2 taken 1178 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1178 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1178 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 589 times.
✓ Branch 12 taken 589 times.
✓ Branch 15 taken 589 times.
✗ Branch 16 not taken.
✓ Branch 19 taken 589 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 589 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 589 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 589 times.
✓ Branch 27 taken 589 times.
✓ Branch 29 taken 589 times.
✓ Branch 30 taken 589 times.
✓ Branch 32 taken 589 times.
✓ Branch 33 taken 589 times.
✓ Branch 35 taken 589 times.
✓ Branch 36 taken 589 times.
✓ Branch 38 taken 1178 times.
✗ Branch 39 not taken.
✓ Branch 41 taken 1178 times.
✗ Branch 42 not taken.
✓ Branch 44 taken 1178 times.
✗ Branch 45 not taken.
✓ Branch 47 taken 1178 times.
✗ Branch 48 not taken.
✓ Branch 50 taken 1178 times.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
|
1178 | if (HasSuffix(zPath, "-wal", false) || HasSuffix(zPath, "-journal", false)) { |
| 301 | 1178 | *pResOut = 0; | |
| 302 | 1178 | return SQLITE_OK; | |
| 303 | } | ||
| 304 | |||
| 305 | // This VFS deals with file descriptors, we know the files are there | ||
| 306 | ✗ | *pResOut = 0; | |
| 307 | ✗ | perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_access); | |
| 308 | ✗ | return SQLITE_OK; | |
| 309 | } | ||
| 310 | |||
| 311 | |||
| 312 | /** | ||
| 313 | * Since the path is never stored, there is no need to produce a full path. | ||
| 314 | */ | ||
| 315 | 589 | int VfsRdOnlyFullPathname(sqlite3_vfs *vfs __attribute__((unused)), | |
| 316 | const char *zPath, | ||
| 317 | int nOut, | ||
| 318 | char *zOut) { | ||
| 319 | 589 | zOut[nOut - 1] = '\0'; | |
| 320 | 589 | sqlite3_snprintf(nOut, zOut, "%s", zPath); | |
| 321 | 589 | return SQLITE_OK; | |
| 322 | } | ||
| 323 | |||
| 324 | |||
| 325 | /** | ||
| 326 | * Taken from unixRandomness | ||
| 327 | */ | ||
| 328 | ✗ | static int VfsRdOnlyRandomness(sqlite3_vfs *vfs, int nBuf, char *zBuf) { | |
| 329 | ✗ | assert(static_cast<size_t>(nBuf) >= (sizeof(time_t) + sizeof(int))); | |
| 330 | ✗ | perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_rand); | |
| 331 | ✗ | memset(zBuf, 0, nBuf); | |
| 332 | ✗ | pid_t randomnessPid = getpid(); | |
| 333 | int fd, got; | ||
| 334 | ✗ | fd = open("/dev/urandom", O_RDONLY, 0); | |
| 335 | ✗ | if (fd < 0) { | |
| 336 | time_t t; | ||
| 337 | ✗ | time(&t); | |
| 338 | ✗ | memcpy(zBuf, &t, sizeof(t)); | |
| 339 | ✗ | memcpy(&zBuf[sizeof(t)], &randomnessPid, sizeof(randomnessPid)); | |
| 340 | ✗ | assert(sizeof(t) + sizeof(randomnessPid) <= static_cast<size_t>(nBuf)); | |
| 341 | ✗ | nBuf = sizeof(t) + sizeof(randomnessPid); | |
| 342 | } else { | ||
| 343 | do { | ||
| 344 | ✗ | got = read(fd, zBuf, nBuf); | |
| 345 | ✗ | } while (got < 0 && errno == EINTR); | |
| 346 | ✗ | close(fd); | |
| 347 | } | ||
| 348 | ✗ | perf::Xadd(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->sz_rand, nBuf); | |
| 349 | ✗ | return nBuf; | |
| 350 | } | ||
| 351 | |||
| 352 | |||
| 353 | /** | ||
| 354 | * Like SafeSleepMs, avoid conflict with the ALARM signal. | ||
| 355 | */ | ||
| 356 | ✗ | static int VfsRdOnlySleep(sqlite3_vfs *vfs, int microseconds) { | |
| 357 | struct timeval wait_for; | ||
| 358 | ✗ | wait_for.tv_sec = microseconds / (1000 * 1000); | |
| 359 | ✗ | wait_for.tv_usec = microseconds % (1000 * 1000); | |
| 360 | ✗ | select(0, NULL, NULL, NULL, &wait_for); | |
| 361 | ✗ | perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_sleep); | |
| 362 | ✗ | perf::Xadd(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->sz_sleep, | |
| 363 | microseconds); | ||
| 364 | ✗ | return microseconds; | |
| 365 | } | ||
| 366 | |||
| 367 | |||
| 368 | /** | ||
| 369 | * Taken from unixCurrentTimeInt64() | ||
| 370 | */ | ||
| 371 | ✗ | static int VfsRdOnlyCurrentTimeInt64(sqlite3_vfs *vfs, sqlite3_int64 *piNow) { | |
| 372 | static const sqlite3_int64 unixEpoch = 24405875 * (sqlite3_int64)8640000; | ||
| 373 | ✗ | int rc = SQLITE_OK; | |
| 374 | struct timeval sNow; | ||
| 375 | ✗ | if (gettimeofday(&sNow, 0) == 0) { | |
| 376 | ✗ | *piNow = unixEpoch + 1000 * (sqlite3_int64)sNow.tv_sec | |
| 377 | ✗ | + sNow.tv_usec / 1000; | |
| 378 | ✗ | perf::Inc(reinterpret_cast<VfsRdOnly *>(vfs->pAppData)->n_time); | |
| 379 | } else { | ||
| 380 | ✗ | rc = SQLITE_ERROR; | |
| 381 | } | ||
| 382 | ✗ | return rc; | |
| 383 | } | ||
| 384 | |||
| 385 | |||
| 386 | /** | ||
| 387 | * Taken from unixCurrentTime | ||
| 388 | */ | ||
| 389 | ✗ | static int VfsRdOnlyCurrentTime(sqlite3_vfs *vfs, double *prNow) { | |
| 390 | ✗ | sqlite3_int64 i = 0; | |
| 391 | ✗ | const int rc = VfsRdOnlyCurrentTimeInt64(vfs, &i); | |
| 392 | ✗ | *prNow = i / 86400000.0; | |
| 393 | ✗ | return rc; | |
| 394 | } | ||
| 395 | |||
| 396 | |||
| 397 | /** | ||
| 398 | * So far unused by sqlite. | ||
| 399 | */ | ||
| 400 | ✗ | static int VfsRdOnlyGetLastError(sqlite3_vfs *vfs __attribute__((unused)), | |
| 401 | int not_used1 __attribute__((unused)), | ||
| 402 | char *not_used2 __attribute__((unused))) { | ||
| 403 | ✗ | return 0; | |
| 404 | } | ||
| 405 | |||
| 406 | |||
| 407 | /** | ||
| 408 | * Can only be registered once. | ||
| 409 | */ | ||
| 410 | 1262 | bool RegisterVfsRdOnly(CacheManager *cache_mgr, | |
| 411 | perf::Statistics *statistics, | ||
| 412 | const VfsOptions options) { | ||
| 413 | 1262 | fd_from_ = new std::vector<int>(); | |
| 414 | 1262 | fd_to_ = new std::vector<int>(); | |
| 415 | |||
| 416 | sqlite3_vfs *vfs = reinterpret_cast<sqlite3_vfs *>( | ||
| 417 | 1262 | smalloc(sizeof(sqlite3_vfs))); | |
| 418 | 1262 | memset(vfs, 0, sizeof(sqlite3_vfs)); | |
| 419 | 1262 | VfsRdOnly *vfs_rdonly = new VfsRdOnly(); | |
| 420 | |||
| 421 | 1262 | vfs->iVersion = 2; | |
| 422 | 1262 | vfs->szOsFile = sizeof(VfsRdOnlyFile); | |
| 423 | 1262 | vfs->mxPathname = PATH_MAX; | |
| 424 | 1262 | vfs->zName = kVfsName; | |
| 425 | 1262 | vfs->pAppData = vfs_rdonly; | |
| 426 | 1262 | vfs->xOpen = VfsRdOnlyOpen; | |
| 427 | 1262 | vfs->xDelete = VfsRdOnlyDelete; | |
| 428 | 1262 | vfs->xAccess = VfsRdOnlyAccess; | |
| 429 | 1262 | vfs->xFullPathname = VfsRdOnlyFullPathname; | |
| 430 | 1262 | vfs->xDlOpen = NULL; | |
| 431 | 1262 | vfs->xDlError = NULL; | |
| 432 | 1262 | vfs->xDlSym = NULL; | |
| 433 | 1262 | vfs->xDlClose = NULL; | |
| 434 | 1262 | vfs->xRandomness = VfsRdOnlyRandomness; | |
| 435 | 1262 | vfs->xSleep = VfsRdOnlySleep; | |
| 436 | 1262 | vfs->xCurrentTime = VfsRdOnlyCurrentTime; | |
| 437 | 1262 | vfs->xGetLastError = VfsRdOnlyGetLastError; | |
| 438 | 1262 | vfs->xCurrentTimeInt64 = VfsRdOnlyCurrentTimeInt64; | |
| 439 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1262 times.
|
1262 | assert(vfs->zName); |
| 440 | |||
| 441 | 1262 | const int retval = sqlite3_vfs_register(vfs, options == kVfsOptDefault); | |
| 442 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1262 times.
|
1262 | if (retval != SQLITE_OK) { |
| 443 | ✗ | free(const_cast<char *>(vfs->zName)); | |
| 444 | ✗ | delete vfs_rdonly; | |
| 445 | ✗ | free(vfs); | |
| 446 | ✗ | return false; | |
| 447 | } | ||
| 448 | |||
| 449 | 1262 | vfs_rdonly->cache_mgr = cache_mgr; | |
| 450 |
3/6✓ Branch 2 taken 1262 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1262 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1262 times.
✗ Branch 10 not taken.
|
1262 | vfs_rdonly->n_access = statistics->Register( |
| 451 | "sqlite.n_access", "overall number of access() calls"); | ||
| 452 |
3/6✓ Branch 2 taken 1262 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1262 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1262 times.
✗ Branch 10 not taken.
|
1262 | vfs_rdonly->no_open = statistics->Register("sqlite.no_open", |
| 453 | "currently open sqlite files"); | ||
| 454 |
3/6✓ Branch 2 taken 1262 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1262 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1262 times.
✗ Branch 10 not taken.
|
1262 | vfs_rdonly->n_rand = statistics->Register("sqlite.n_rand", |
| 455 | "overall number of random() calls"); | ||
| 456 |
3/6✓ Branch 2 taken 1262 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1262 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1262 times.
✗ Branch 10 not taken.
|
1262 | vfs_rdonly->sz_rand = statistics->Register("sqlite.sz_rand", |
| 457 | "overall number of random bytes"); | ||
| 458 |
3/6✓ Branch 2 taken 1262 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1262 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1262 times.
✗ Branch 10 not taken.
|
1262 | vfs_rdonly->n_read = statistics->Register("sqlite.n_read", |
| 459 | "overall number of read() calls"); | ||
| 460 |
3/6✓ Branch 2 taken 1262 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1262 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1262 times.
✗ Branch 10 not taken.
|
1262 | vfs_rdonly->sz_read = statistics->Register("sqlite.sz_read", |
| 461 | "overall bytes read()"); | ||
| 462 |
3/6✓ Branch 2 taken 1262 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1262 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1262 times.
✗ Branch 10 not taken.
|
1262 | vfs_rdonly->n_sleep = statistics->Register("sqlite.n_sleep", |
| 463 | "overall number of sleep() calls"); | ||
| 464 |
3/6✓ Branch 2 taken 1262 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1262 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1262 times.
✗ Branch 10 not taken.
|
1262 | vfs_rdonly->sz_sleep = statistics->Register("sqlite.sz_sleep", |
| 465 | "overall microseconds slept"); | ||
| 466 |
3/6✓ Branch 2 taken 1262 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1262 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1262 times.
✗ Branch 10 not taken.
|
1262 | vfs_rdonly->n_time = statistics->Register("sqlite.n_time", |
| 467 | "overall number of time() calls"); | ||
| 468 | |||
| 469 | 1262 | return true; | |
| 470 | } | ||
| 471 | |||
| 472 | |||
| 473 | /** | ||
| 474 | * If the file system was the default VFS, another default VFS is selected by | ||
| 475 | * SQlite randomly. | ||
| 476 | */ | ||
| 477 | 1259 | bool UnregisterVfsRdOnly() { | |
| 478 | 1259 | sqlite3_vfs *vfs = sqlite3_vfs_find(kVfsName); | |
| 479 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1259 times.
|
1259 | if (vfs == NULL) |
| 480 | ✗ | return false; | |
| 481 | 1259 | const int retval = sqlite3_vfs_unregister(vfs); | |
| 482 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1259 times.
|
1259 | if (retval != SQLITE_OK) |
| 483 | ✗ | return false; | |
| 484 | |||
| 485 |
1/2✓ Branch 0 taken 1259 times.
✗ Branch 1 not taken.
|
1259 | delete reinterpret_cast<VfsRdOnly *>(vfs->pAppData); |
| 486 | 1259 | free(vfs); | |
| 487 | |||
| 488 |
1/2✓ Branch 0 taken 1259 times.
✗ Branch 1 not taken.
|
1259 | delete fd_from_; |
| 489 |
1/2✓ Branch 0 taken 1259 times.
✗ Branch 1 not taken.
|
1259 | delete fd_to_; |
| 490 | 1259 | fd_from_ = NULL; | |
| 491 | 1259 | fd_to_ = NULL; | |
| 492 | |||
| 493 | 1259 | return true; | |
| 494 | } | ||
| 495 | |||
| 496 | ✗ | void RegisterFdMapping(int from, int to) { | |
| 497 | ✗ | fd_from_->push_back(from); | |
| 498 | ✗ | fd_to_->push_back(to); | |
| 499 | } | ||
| 500 | |||
| 501 | ✗ | void ReplaceCacheManager(CacheManager *new_cache_mgr) { | |
| 502 | ✗ | sqlite3_vfs *vfs = sqlite3_vfs_find(kVfsName); | |
| 503 | ✗ | if (vfs == NULL) | |
| 504 | ✗ | return; | |
| 505 | ✗ | static_cast<VfsRdOnly *>(vfs->pAppData)->cache_mgr = new_cache_mgr; | |
| 506 | } | ||
| 507 | |||
| 508 | } // namespace sqlite | ||
| 509 |