| Directory: | cvmfs/ |
|---|---|
| File: | cvmfs/sqlitevfs.cc |
| Date: | 2025-10-19 02:35:28 |
| 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/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 | |||
| 50 | /** | ||
| 51 | * The private user data attached to the sqlite_vfs object. | ||
| 52 | */ | ||
| 53 | struct VfsRdOnly { | ||
| 54 | 2342 | VfsRdOnly() | |
| 55 | 2342 | : cache_mgr(NULL) | |
| 56 | 2342 | , n_access(NULL) | |
| 57 | 2342 | , no_open(NULL) | |
| 58 | 2342 | , n_rand(NULL) | |
| 59 | 2342 | , sz_rand(NULL) | |
| 60 | 2342 | , n_read(NULL) | |
| 61 | 2342 | , sz_read(NULL) | |
| 62 | 2342 | , n_sleep(NULL) | |
| 63 | 2342 | , sz_sleep(NULL) | |
| 64 | 2342 | , n_time(NULL) { } | |
| 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 | /** | ||
| 88 | * File descriptor mappings | ||
| 89 | */ | ||
| 90 | std::vector<int> *fd_from_ = NULL; | ||
| 91 | std::vector<int> *fd_to_ = NULL; | ||
| 92 | |||
| 93 | } // anonymous namespace | ||
| 94 | |||
| 95 | 13057 | static void ApplyFdMap(VfsRdOnlyFile *pFile) { | |
| 96 | 13057 | const unsigned N = fd_from_->size(); | |
| 97 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13057 times.
|
13057 | 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 | 1219 | static int VfsRdOnlyClose(sqlite3_file *pFile) { | |
| 111 | 1219 | VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile); | |
| 112 | 1219 | ApplyFdMap(p); | |
| 113 | 1219 | const int retval = p->vfs_rdonly->cache_mgr->Close(p->fd); | |
| 114 |
1/2✓ Branch 0 taken 1219 times.
✗ Branch 1 not taken.
|
1219 | if (retval == 0) { |
| 115 | 1219 | perf::Dec(p->vfs_rdonly->no_open); | |
| 116 | 1219 | return SQLITE_OK; | |
| 117 | } | ||
| 118 | ✗ | return SQLITE_IOERR_CLOSE; | |
| 119 | } | ||
| 120 | |||
| 121 | |||
| 122 | /** | ||
| 123 | * On a short read, the remaining bytes must be zero'ed. | ||
| 124 | * TODO(jblomer): the reads seem to be rather small. Investigate buffered read. | ||
| 125 | */ | ||
| 126 | 11838 | static int VfsRdOnlyRead(sqlite3_file *pFile, | |
| 127 | void *zBuf, | ||
| 128 | int iAmt, | ||
| 129 | sqlite_int64 iOfst) { | ||
| 130 | 11838 | VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile); | |
| 131 | 11838 | ApplyFdMap(p); | |
| 132 | 11838 | const ssize_t got = p->vfs_rdonly->cache_mgr->Pread(p->fd, zBuf, iAmt, iOfst); | |
| 133 | 11838 | perf::Inc(p->vfs_rdonly->n_read); | |
| 134 |
1/2✓ Branch 0 taken 11838 times.
✗ Branch 1 not taken.
|
11838 | if (got == iAmt) { |
| 135 | 11838 | perf::Xadd(p->vfs_rdonly->sz_read, iAmt); | |
| 136 | 11838 | 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 | 1219 | static int VfsRdOnlyFileSize(sqlite3_file *pFile, sqlite_int64 *pSize) { | |
| 168 | 1219 | VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile); | |
| 169 | 1219 | *pSize = p->size; | |
| 170 | 1219 | return SQLITE_OK; | |
| 171 | } | ||
| 172 | |||
| 173 | |||
| 174 | 1219 | static int VfsRdOnlyLock(sqlite3_file *p __attribute__((unused)), | |
| 175 | int level __attribute__((unused))) { | ||
| 176 | 1219 | return SQLITE_OK; | |
| 177 | } | ||
| 178 | |||
| 179 | |||
| 180 | 1219 | static int VfsRdOnlyUnlock(sqlite3_file *p __attribute__((unused)), | |
| 181 | int level __attribute__((unused))) { | ||
| 182 | 1219 | 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 | |||
| 193 | /** | ||
| 194 | * No xFileControl() verbs are implemented by this VFS. | ||
| 195 | */ | ||
| 196 | 6095 | static int VfsRdOnlyFileControl(sqlite3_file *p __attribute__((unused)), | |
| 197 | int op __attribute__((unused)), | ||
| 198 | void *pArg __attribute__((unused))) { | ||
| 199 | 6095 | return SQLITE_NOTFOUND; | |
| 200 | } | ||
| 201 | |||
| 202 | |||
| 203 | /** | ||
| 204 | * A good unit of bytes to read at once. But probably only used for writes. | ||
| 205 | */ | ||
| 206 | 1219 | static int VfsRdOnlySectorSize(sqlite3_file *p __attribute__((unused))) { | |
| 207 | 1219 | return 4096; | |
| 208 | } | ||
| 209 | |||
| 210 | |||
| 211 | /** | ||
| 212 | * Only relevant for writing. | ||
| 213 | */ | ||
| 214 | 3657 | static int VfsRdOnlyDeviceCharacteristics(sqlite3_file *p | |
| 215 | __attribute__((unused))) { | ||
| 216 | 3657 | return 0; | |
| 217 | } | ||
| 218 | |||
| 219 | |||
| 220 | /** | ||
| 221 | * Supports only read-only opens. The "file name" has to be in the form of | ||
| 222 | * '@<file descriptor>', where file descriptor is usable by the cache manager. | ||
| 223 | */ | ||
| 224 | 1219 | 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 | ||
| 230 | VfsRdOnlyClose, | ||
| 231 | VfsRdOnlyRead, | ||
| 232 | VfsRdOnlyWrite, | ||
| 233 | VfsRdOnlyTruncate, | ||
| 234 | VfsRdOnlySync, | ||
| 235 | VfsRdOnlyFileSize, | ||
| 236 | VfsRdOnlyLock, | ||
| 237 | VfsRdOnlyUnlock, | ||
| 238 | VfsRdOnlyCheckReservedLock, | ||
| 239 | VfsRdOnlyFileControl, | ||
| 240 | VfsRdOnlySectorSize, | ||
| 241 | VfsRdOnlyDeviceCharacteristics}; | ||
| 242 | |||
| 243 | 1219 | VfsRdOnlyFile *p = reinterpret_cast<VfsRdOnlyFile *>(pFile); | |
| 244 | 1219 | CacheManager *cache_mgr = reinterpret_cast<VfsRdOnly *>(vfs->pAppData) | |
| 245 | ->cache_mgr; | ||
| 246 | // Prevent xClose from being called in case of errors | ||
| 247 | 1219 | p->base.pMethods = NULL; | |
| 248 | |||
| 249 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1219 times.
|
1219 | if (flags & SQLITE_OPEN_READWRITE) |
| 250 | ✗ | return SQLITE_IOERR; | |
| 251 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1219 times.
|
1219 | if (flags & SQLITE_OPEN_DELETEONCLOSE) |
| 252 | ✗ | return SQLITE_IOERR; | |
| 253 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1219 times.
|
1219 | if (flags & SQLITE_OPEN_EXCLUSIVE) |
| 254 | ✗ | return SQLITE_IOERR; | |
| 255 | |||
| 256 |
2/4✓ Branch 0 taken 1219 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1219 times.
✗ Branch 3 not taken.
|
1219 | assert(zName && (zName[0] == '@')); |
| 257 |
2/4✓ Branch 2 taken 1219 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1219 times.
✗ Branch 6 not taken.
|
1219 | p->fd = String2Int64(string(&zName[1])); |
| 258 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1219 times.
|
1219 | if (p->fd < 0) |
| 259 | ✗ | return SQLITE_IOERR; | |
| 260 | 1219 | const int64_t size = cache_mgr->GetSize(p->fd); | |
| 261 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1219 times.
|
1219 | if (size < 0) { |
| 262 | ✗ | cache_mgr->Close(p->fd); | |
| 263 | ✗ | p->fd = -1; | |
| 264 | ✗ | return SQLITE_IOERR_FSTAT; | |
| 265 | } | ||
| 266 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1219 times.
|
1219 | if (cache_mgr->Readahead(p->fd) != 0) { |
| 267 | ✗ | cache_mgr->Close(p->fd); | |
| 268 | ✗ | p->fd = -1; | |
| 269 | ✗ | return SQLITE_IOERR; | |
| 270 | } | ||
| 271 | 1219 | p->size = static_cast<uint64_t>(size); | |
| 272 |
1/2✓ Branch 0 taken 1219 times.
✗ Branch 1 not taken.
|
1219 | if (pOutFlags) |
| 273 | 1219 | *pOutFlags = flags; | |
| 274 | 1219 | p->vfs_rdonly = reinterpret_cast<VfsRdOnly *>(vfs->pAppData); | |
| 275 | 1219 | p->base.pMethods = &io_methods; | |
| 276 | 1219 | perf::Inc(p->vfs_rdonly->no_open); | |
| 277 | 1219 | LogCvmfs(kLogSql, kLogDebug, "open sqlite3 catalog on fd %d, size %" PRIu64, | |
| 278 | p->fd, p->size); | ||
| 279 | 1219 | 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 | |||
| 290 | /** | ||
| 291 | * Cvmfs r/o file catalogs cannot have a write-ahead log or a journal. | ||
| 292 | */ | ||
| 293 | 2438 | static int VfsRdOnlyAccess(sqlite3_vfs *vfs, | |
| 294 | const char *zPath, | ||
| 295 | int flags, | ||
| 296 | int *pResOut) { | ||
| 297 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2438 times.
|
2438 | if (flags == SQLITE_ACCESS_READWRITE) { |
| 298 | ✗ | *pResOut = 0; | |
| 299 | ✗ | return SQLITE_OK; | |
| 300 | } | ||
| 301 |
22/50✓ Branch 2 taken 2438 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2438 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2438 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1219 times.
✓ Branch 12 taken 1219 times.
✓ Branch 15 taken 1219 times.
✗ Branch 16 not taken.
✓ Branch 19 taken 1219 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1219 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 1219 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 1219 times.
✓ Branch 27 taken 1219 times.
✓ Branch 29 taken 1219 times.
✓ Branch 30 taken 1219 times.
✓ Branch 32 taken 1219 times.
✓ Branch 33 taken 1219 times.
✓ Branch 35 taken 1219 times.
✓ Branch 36 taken 1219 times.
✓ Branch 38 taken 2438 times.
✗ Branch 39 not taken.
✓ Branch 41 taken 2438 times.
✗ Branch 42 not taken.
✓ Branch 44 taken 2438 times.
✗ Branch 45 not taken.
✓ Branch 47 taken 2438 times.
✗ Branch 48 not taken.
✓ Branch 50 taken 2438 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.
|
2438 | if (HasSuffix(zPath, "-wal", false) || HasSuffix(zPath, "-journal", false)) { |
| 302 | 2438 | *pResOut = 0; | |
| 303 | 2438 | 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 | |||
| 313 | /** | ||
| 314 | * Since the path is never stored, there is no need to produce a full path. | ||
| 315 | */ | ||
| 316 | 1219 | int VfsRdOnlyFullPathname(sqlite3_vfs *vfs __attribute__((unused)), | |
| 317 | const char *zPath, | ||
| 318 | int nOut, | ||
| 319 | char *zOut) { | ||
| 320 | 1219 | zOut[nOut - 1] = '\0'; | |
| 321 | 1219 | sqlite3_snprintf(nOut, zOut, "%s", zPath); | |
| 322 | 1219 | return SQLITE_OK; | |
| 323 | } | ||
| 324 | |||
| 325 | |||
| 326 | /** | ||
| 327 | * Taken from unixRandomness | ||
| 328 | */ | ||
| 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 | |||
| 354 | /** | ||
| 355 | * Like SafeSleepMs, avoid conflict with the ALARM signal. | ||
| 356 | */ | ||
| 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 | |||
| 369 | /** | ||
| 370 | * Taken from unixCurrentTimeInt64() | ||
| 371 | */ | ||
| 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 | |||
| 387 | /** | ||
| 388 | * Taken from unixCurrentTime | ||
| 389 | */ | ||
| 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 | |||
| 398 | /** | ||
| 399 | * So far unused by sqlite. | ||
| 400 | */ | ||
| 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 | |||
| 408 | /** | ||
| 409 | * Can only be registered once. | ||
| 410 | */ | ||
| 411 | 2342 | bool RegisterVfsRdOnly(CacheManager *cache_mgr, | |
| 412 | perf::Statistics *statistics, | ||
| 413 | const VfsOptions options) { | ||
| 414 | 2342 | fd_from_ = new std::vector<int>(); | |
| 415 | 2342 | fd_to_ = new std::vector<int>(); | |
| 416 | |||
| 417 | sqlite3_vfs *vfs = reinterpret_cast<sqlite3_vfs *>( | ||
| 418 | 2342 | smalloc(sizeof(sqlite3_vfs))); | |
| 419 | 2342 | memset(vfs, 0, sizeof(sqlite3_vfs)); | |
| 420 | 2342 | VfsRdOnly *vfs_rdonly = new VfsRdOnly(); | |
| 421 | |||
| 422 | 2342 | vfs->iVersion = 2; | |
| 423 | 2342 | vfs->szOsFile = sizeof(VfsRdOnlyFile); | |
| 424 | 2342 | vfs->mxPathname = PATH_MAX; | |
| 425 | 2342 | vfs->zName = kVfsName; | |
| 426 | 2342 | vfs->pAppData = vfs_rdonly; | |
| 427 | 2342 | vfs->xOpen = VfsRdOnlyOpen; | |
| 428 | 2342 | vfs->xDelete = VfsRdOnlyDelete; | |
| 429 | 2342 | vfs->xAccess = VfsRdOnlyAccess; | |
| 430 | 2342 | vfs->xFullPathname = VfsRdOnlyFullPathname; | |
| 431 | 2342 | vfs->xDlOpen = NULL; | |
| 432 | 2342 | vfs->xDlError = NULL; | |
| 433 | 2342 | vfs->xDlSym = NULL; | |
| 434 | 2342 | vfs->xDlClose = NULL; | |
| 435 | 2342 | vfs->xRandomness = VfsRdOnlyRandomness; | |
| 436 | 2342 | vfs->xSleep = VfsRdOnlySleep; | |
| 437 | 2342 | vfs->xCurrentTime = VfsRdOnlyCurrentTime; | |
| 438 | 2342 | vfs->xGetLastError = VfsRdOnlyGetLastError; | |
| 439 | 2342 | vfs->xCurrentTimeInt64 = VfsRdOnlyCurrentTimeInt64; | |
| 440 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2342 times.
|
2342 | assert(vfs->zName); |
| 441 | |||
| 442 | 2342 | const int retval = sqlite3_vfs_register(vfs, options == kVfsOptDefault); | |
| 443 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2342 times.
|
2342 | if (retval != SQLITE_OK) { |
| 444 | ✗ | free(const_cast<char *>(vfs->zName)); | |
| 445 | ✗ | delete vfs_rdonly; | |
| 446 | ✗ | free(vfs); | |
| 447 | ✗ | return false; | |
| 448 | } | ||
| 449 | |||
| 450 | 2342 | vfs_rdonly->cache_mgr = cache_mgr; | |
| 451 |
3/6✓ Branch 2 taken 2342 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2342 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2342 times.
✗ Branch 10 not taken.
|
2342 | vfs_rdonly->n_access = statistics->Register( |
| 452 | "sqlite.n_access", "overall number of access() calls"); | ||
| 453 |
3/6✓ Branch 2 taken 2342 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2342 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2342 times.
✗ Branch 10 not taken.
|
2342 | vfs_rdonly->no_open = statistics->Register("sqlite.no_open", |
| 454 | "currently open sqlite files"); | ||
| 455 |
3/6✓ Branch 2 taken 2342 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2342 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2342 times.
✗ Branch 10 not taken.
|
2342 | vfs_rdonly->n_rand = statistics->Register("sqlite.n_rand", |
| 456 | "overall number of random() calls"); | ||
| 457 |
3/6✓ Branch 2 taken 2342 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2342 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2342 times.
✗ Branch 10 not taken.
|
2342 | vfs_rdonly->sz_rand = statistics->Register("sqlite.sz_rand", |
| 458 | "overall number of random bytes"); | ||
| 459 |
3/6✓ Branch 2 taken 2342 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2342 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2342 times.
✗ Branch 10 not taken.
|
2342 | vfs_rdonly->n_read = statistics->Register("sqlite.n_read", |
| 460 | "overall number of read() calls"); | ||
| 461 |
3/6✓ Branch 2 taken 2342 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2342 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2342 times.
✗ Branch 10 not taken.
|
2342 | vfs_rdonly->sz_read = statistics->Register("sqlite.sz_read", |
| 462 | "overall bytes read()"); | ||
| 463 |
3/6✓ Branch 2 taken 2342 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2342 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2342 times.
✗ Branch 10 not taken.
|
2342 | vfs_rdonly->n_sleep = statistics->Register("sqlite.n_sleep", |
| 464 | "overall number of sleep() calls"); | ||
| 465 |
3/6✓ Branch 2 taken 2342 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2342 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2342 times.
✗ Branch 10 not taken.
|
2342 | vfs_rdonly->sz_sleep = statistics->Register("sqlite.sz_sleep", |
| 466 | "overall microseconds slept"); | ||
| 467 |
3/6✓ Branch 2 taken 2342 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2342 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2342 times.
✗ Branch 10 not taken.
|
2342 | vfs_rdonly->n_time = statistics->Register("sqlite.n_time", |
| 468 | "overall number of time() calls"); | ||
| 469 | |||
| 470 | 2342 | return true; | |
| 471 | } | ||
| 472 | |||
| 473 | |||
| 474 | /** | ||
| 475 | * If the file system was the default VFS, another default VFS is selected by | ||
| 476 | * SQlite randomly. | ||
| 477 | */ | ||
| 478 | 2339 | bool UnregisterVfsRdOnly() { | |
| 479 | 2339 | sqlite3_vfs *vfs = sqlite3_vfs_find(kVfsName); | |
| 480 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2339 times.
|
2339 | if (vfs == NULL) |
| 481 | ✗ | return false; | |
| 482 | 2339 | const int retval = sqlite3_vfs_unregister(vfs); | |
| 483 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2339 times.
|
2339 | if (retval != SQLITE_OK) |
| 484 | ✗ | return false; | |
| 485 | |||
| 486 |
1/2✓ Branch 0 taken 2339 times.
✗ Branch 1 not taken.
|
2339 | delete reinterpret_cast<VfsRdOnly *>(vfs->pAppData); |
| 487 | 2339 | free(vfs); | |
| 488 | |||
| 489 |
1/2✓ Branch 0 taken 2339 times.
✗ Branch 1 not taken.
|
2339 | delete fd_from_; |
| 490 |
1/2✓ Branch 0 taken 2339 times.
✗ Branch 1 not taken.
|
2339 | delete fd_to_; |
| 491 | 2339 | fd_from_ = NULL; | |
| 492 | 2339 | fd_to_ = NULL; | |
| 493 | |||
| 494 | 2339 | 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 | ||
| 510 |