1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/storage/src/TelemetryVFS.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,623 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include <string.h> 1.11 +#include "mozilla/Telemetry.h" 1.12 +#include "mozilla/Preferences.h" 1.13 +#include "sqlite3.h" 1.14 +#include "nsThreadUtils.h" 1.15 +#include "mozilla/dom/quota/PersistenceType.h" 1.16 +#include "mozilla/dom/quota/QuotaManager.h" 1.17 +#include "mozilla/dom/quota/QuotaObject.h" 1.18 +#include "mozilla/IOInterposer.h" 1.19 + 1.20 +// The last VFS version for which this file has been updated. 1.21 +#define LAST_KNOWN_VFS_VERSION 3 1.22 + 1.23 +// The last io_methods version for which this file has been updated. 1.24 +#define LAST_KNOWN_IOMETHODS_VERSION 3 1.25 + 1.26 +/** 1.27 + * This preference is a workaround to allow users/sysadmins to identify 1.28 + * that the profile exists on an NFS share whose implementation 1.29 + * is incompatible with SQLite's default locking implementation. 1.30 + * Bug 433129 attempted to automatically identify such file-systems, 1.31 + * but a reliable way was not found and it was determined that the fallback 1.32 + * locking is slower than POSIX locking, so we do not want to do it by default. 1.33 +*/ 1.34 +#define PREF_NFS_FILESYSTEM "storage.nfs_filesystem" 1.35 + 1.36 +namespace { 1.37 + 1.38 +using namespace mozilla; 1.39 +using namespace mozilla::dom::quota; 1.40 + 1.41 +struct Histograms { 1.42 + const char *name; 1.43 + const Telemetry::ID readB; 1.44 + const Telemetry::ID writeB; 1.45 + const Telemetry::ID readMS; 1.46 + const Telemetry::ID writeMS; 1.47 + const Telemetry::ID syncMS; 1.48 +}; 1.49 + 1.50 +#define SQLITE_TELEMETRY(FILENAME, HGRAM) \ 1.51 + { FILENAME, \ 1.52 + Telemetry::MOZ_SQLITE_ ## HGRAM ## _READ_B, \ 1.53 + Telemetry::MOZ_SQLITE_ ## HGRAM ## _WRITE_B, \ 1.54 + Telemetry::MOZ_SQLITE_ ## HGRAM ## _READ_MS, \ 1.55 + Telemetry::MOZ_SQLITE_ ## HGRAM ## _WRITE_MS, \ 1.56 + Telemetry::MOZ_SQLITE_ ## HGRAM ## _SYNC_MS \ 1.57 + } 1.58 + 1.59 +Histograms gHistograms[] = { 1.60 + SQLITE_TELEMETRY("places.sqlite", PLACES), 1.61 + SQLITE_TELEMETRY("cookies.sqlite", COOKIES), 1.62 + SQLITE_TELEMETRY("webappsstore.sqlite", WEBAPPS), 1.63 + SQLITE_TELEMETRY(nullptr, OTHER) 1.64 +}; 1.65 +#undef SQLITE_TELEMETRY 1.66 + 1.67 +/** RAII class for measuring how long io takes on/off main thread 1.68 + */ 1.69 +class IOThreadAutoTimer { 1.70 +public: 1.71 + /** 1.72 + * IOThreadAutoTimer measures time spent in IO. Additionally it 1.73 + * automatically determines whether IO is happening on the main 1.74 + * thread and picks an appropriate histogram. 1.75 + * 1.76 + * @param id takes a telemetry histogram id. The id+1 must be an 1.77 + * equivalent histogram for the main thread. Eg, MOZ_SQLITE_OPEN_MS 1.78 + * is followed by MOZ_SQLITE_OPEN_MAIN_THREAD_MS. 1.79 + * 1.80 + * @param aOp optionally takes an IO operation to report through the 1.81 + * IOInterposer. Filename will be reported as NULL, and reference will be 1.82 + * either "sqlite-mainthread" or "sqlite-otherthread". 1.83 + */ 1.84 + IOThreadAutoTimer(Telemetry::ID id, 1.85 + IOInterposeObserver::Operation aOp = IOInterposeObserver::OpNone) 1.86 + : start(TimeStamp::Now()), 1.87 + id(id), 1.88 + op(aOp) 1.89 + { 1.90 + } 1.91 + 1.92 + /** 1.93 + * This constructor is for when we want to report an operation to 1.94 + * IOInterposer but do not require a telemetry probe. 1.95 + * 1.96 + * @param aOp IO Operation to report through the IOInterposer. 1.97 + */ 1.98 + IOThreadAutoTimer(IOInterposeObserver::Operation aOp) 1.99 + : start(TimeStamp::Now()), 1.100 + id(Telemetry::HistogramCount), 1.101 + op(aOp) 1.102 + { 1.103 + } 1.104 + 1.105 + ~IOThreadAutoTimer() 1.106 + { 1.107 + TimeStamp end(TimeStamp::Now()); 1.108 + uint32_t mainThread = NS_IsMainThread() ? 1 : 0; 1.109 + if (id != Telemetry::HistogramCount) { 1.110 + Telemetry::AccumulateTimeDelta(static_cast<Telemetry::ID>(id + mainThread), 1.111 + start, end); 1.112 + } 1.113 + // We don't report SQLite I/O on Windows because we have a comprehensive 1.114 + // mechanism for intercepting I/O on that platform that captures a superset 1.115 + // of the data captured here. 1.116 +#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(XP_WIN) 1.117 + if (IOInterposer::IsObservedOperation(op)) { 1.118 + const char* main_ref = "sqlite-mainthread"; 1.119 + const char* other_ref = "sqlite-otherthread"; 1.120 + 1.121 + // Create observation 1.122 + IOInterposeObserver::Observation ob(op, start, end, 1.123 + (mainThread ? main_ref : other_ref)); 1.124 + // Report observation 1.125 + IOInterposer::Report(ob); 1.126 + } 1.127 +#endif /* defined(MOZ_ENABLE_PROFILER_SPS) && !defined(XP_WIN) */ 1.128 + } 1.129 + 1.130 +private: 1.131 + const TimeStamp start; 1.132 + const Telemetry::ID id; 1.133 + IOInterposeObserver::Operation op; 1.134 +}; 1.135 + 1.136 +struct telemetry_file { 1.137 + // Base class. Must be first 1.138 + sqlite3_file base; 1.139 + 1.140 + // histograms pertaining to this file 1.141 + Histograms *histograms; 1.142 + 1.143 + // quota object for this file 1.144 + nsRefPtr<QuotaObject> quotaObject; 1.145 + 1.146 + // This contains the vfs that actually does work 1.147 + sqlite3_file pReal[1]; 1.148 +}; 1.149 + 1.150 +/* 1.151 +** Close a telemetry_file. 1.152 +*/ 1.153 +int 1.154 +xClose(sqlite3_file *pFile) 1.155 +{ 1.156 + telemetry_file *p = (telemetry_file *)pFile; 1.157 + int rc; 1.158 + { // Scope for IOThreadAutoTimer 1.159 + IOThreadAutoTimer ioTimer(IOInterposeObserver::OpClose); 1.160 + rc = p->pReal->pMethods->xClose(p->pReal); 1.161 + } 1.162 + if( rc==SQLITE_OK ){ 1.163 + delete p->base.pMethods; 1.164 + p->base.pMethods = nullptr; 1.165 + p->quotaObject = nullptr; 1.166 + } 1.167 + return rc; 1.168 +} 1.169 + 1.170 +/* 1.171 +** Read data from a telemetry_file. 1.172 +*/ 1.173 +int 1.174 +xRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst) 1.175 +{ 1.176 + telemetry_file *p = (telemetry_file *)pFile; 1.177 + IOThreadAutoTimer ioTimer(p->histograms->readMS, IOInterposeObserver::OpRead); 1.178 + int rc; 1.179 + rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst); 1.180 + // sqlite likes to read from empty files, this is normal, ignore it. 1.181 + if (rc != SQLITE_IOERR_SHORT_READ) 1.182 + Telemetry::Accumulate(p->histograms->readB, rc == SQLITE_OK ? iAmt : 0); 1.183 + return rc; 1.184 +} 1.185 + 1.186 +/* 1.187 +** Write data to a telemetry_file. 1.188 +*/ 1.189 +int 1.190 +xWrite(sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst) 1.191 +{ 1.192 + telemetry_file *p = (telemetry_file *)pFile; 1.193 + if (p->quotaObject && !p->quotaObject->MaybeAllocateMoreSpace(iOfst, iAmt)) { 1.194 + return SQLITE_FULL; 1.195 + } 1.196 + IOThreadAutoTimer ioTimer(p->histograms->writeMS, IOInterposeObserver::OpWrite); 1.197 + int rc; 1.198 + rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst); 1.199 + Telemetry::Accumulate(p->histograms->writeB, rc == SQLITE_OK ? iAmt : 0); 1.200 + return rc; 1.201 +} 1.202 + 1.203 +/* 1.204 +** Truncate a telemetry_file. 1.205 +*/ 1.206 +int 1.207 +xTruncate(sqlite3_file *pFile, sqlite_int64 size) 1.208 +{ 1.209 + IOThreadAutoTimer ioTimer(Telemetry::MOZ_SQLITE_TRUNCATE_MS); 1.210 + telemetry_file *p = (telemetry_file *)pFile; 1.211 + int rc; 1.212 + Telemetry::AutoTimer<Telemetry::MOZ_SQLITE_TRUNCATE_MS> timer; 1.213 + rc = p->pReal->pMethods->xTruncate(p->pReal, size); 1.214 + if (rc == SQLITE_OK && p->quotaObject) { 1.215 + p->quotaObject->UpdateSize(size); 1.216 + } 1.217 + return rc; 1.218 +} 1.219 + 1.220 +/* 1.221 +** Sync a telemetry_file. 1.222 +*/ 1.223 +int 1.224 +xSync(sqlite3_file *pFile, int flags) 1.225 +{ 1.226 + telemetry_file *p = (telemetry_file *)pFile; 1.227 + IOThreadAutoTimer ioTimer(p->histograms->syncMS, IOInterposeObserver::OpFSync); 1.228 + return p->pReal->pMethods->xSync(p->pReal, flags); 1.229 +} 1.230 + 1.231 +/* 1.232 +** Return the current file-size of a telemetry_file. 1.233 +*/ 1.234 +int 1.235 +xFileSize(sqlite3_file *pFile, sqlite_int64 *pSize) 1.236 +{ 1.237 + IOThreadAutoTimer ioTimer(IOInterposeObserver::OpStat); 1.238 + telemetry_file *p = (telemetry_file *)pFile; 1.239 + int rc; 1.240 + rc = p->pReal->pMethods->xFileSize(p->pReal, pSize); 1.241 + return rc; 1.242 +} 1.243 + 1.244 +/* 1.245 +** Lock a telemetry_file. 1.246 +*/ 1.247 +int 1.248 +xLock(sqlite3_file *pFile, int eLock) 1.249 +{ 1.250 + telemetry_file *p = (telemetry_file *)pFile; 1.251 + int rc; 1.252 + rc = p->pReal->pMethods->xLock(p->pReal, eLock); 1.253 + return rc; 1.254 +} 1.255 + 1.256 +/* 1.257 +** Unlock a telemetry_file. 1.258 +*/ 1.259 +int 1.260 +xUnlock(sqlite3_file *pFile, int eLock) 1.261 +{ 1.262 + telemetry_file *p = (telemetry_file *)pFile; 1.263 + int rc; 1.264 + rc = p->pReal->pMethods->xUnlock(p->pReal, eLock); 1.265 + return rc; 1.266 +} 1.267 + 1.268 +/* 1.269 +** Check if another file-handle holds a RESERVED lock on a telemetry_file. 1.270 +*/ 1.271 +int 1.272 +xCheckReservedLock(sqlite3_file *pFile, int *pResOut) 1.273 +{ 1.274 + telemetry_file *p = (telemetry_file *)pFile; 1.275 + int rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut); 1.276 + return rc; 1.277 +} 1.278 + 1.279 +/* 1.280 +** File control method. For custom operations on a telemetry_file. 1.281 +*/ 1.282 +int 1.283 +xFileControl(sqlite3_file *pFile, int op, void *pArg) 1.284 +{ 1.285 + telemetry_file *p = (telemetry_file *)pFile; 1.286 + int rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg); 1.287 + return rc; 1.288 +} 1.289 + 1.290 +/* 1.291 +** Return the sector-size in bytes for a telemetry_file. 1.292 +*/ 1.293 +int 1.294 +xSectorSize(sqlite3_file *pFile) 1.295 +{ 1.296 + telemetry_file *p = (telemetry_file *)pFile; 1.297 + int rc; 1.298 + rc = p->pReal->pMethods->xSectorSize(p->pReal); 1.299 + return rc; 1.300 +} 1.301 + 1.302 +/* 1.303 +** Return the device characteristic flags supported by a telemetry_file. 1.304 +*/ 1.305 +int 1.306 +xDeviceCharacteristics(sqlite3_file *pFile) 1.307 +{ 1.308 + telemetry_file *p = (telemetry_file *)pFile; 1.309 + int rc; 1.310 + rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal); 1.311 + return rc; 1.312 +} 1.313 + 1.314 +/* 1.315 +** Shared-memory operations. 1.316 +*/ 1.317 +int 1.318 +xShmLock(sqlite3_file *pFile, int ofst, int n, int flags) 1.319 +{ 1.320 + telemetry_file *p = (telemetry_file *)pFile; 1.321 + return p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags); 1.322 +} 1.323 + 1.324 +int 1.325 +xShmMap(sqlite3_file *pFile, int iRegion, int szRegion, int isWrite, void volatile **pp) 1.326 +{ 1.327 + telemetry_file *p = (telemetry_file *)pFile; 1.328 + int rc; 1.329 + rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp); 1.330 + return rc; 1.331 +} 1.332 + 1.333 +void 1.334 +xShmBarrier(sqlite3_file *pFile){ 1.335 + telemetry_file *p = (telemetry_file *)pFile; 1.336 + p->pReal->pMethods->xShmBarrier(p->pReal); 1.337 +} 1.338 + 1.339 +int 1.340 +xShmUnmap(sqlite3_file *pFile, int delFlag){ 1.341 + telemetry_file *p = (telemetry_file *)pFile; 1.342 + int rc; 1.343 + rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag); 1.344 + return rc; 1.345 +} 1.346 + 1.347 +int 1.348 +xFetch(sqlite3_file *pFile, sqlite3_int64 iOff, int iAmt, void **pp) 1.349 +{ 1.350 + telemetry_file *p = (telemetry_file *)pFile; 1.351 + MOZ_ASSERT(p->pReal->pMethods->iVersion >= 3); 1.352 + return p->pReal->pMethods->xFetch(p->pReal, iOff, iAmt, pp); 1.353 +} 1.354 + 1.355 +int 1.356 +xUnfetch(sqlite3_file *pFile, sqlite3_int64 iOff, void *pResOut) 1.357 +{ 1.358 + telemetry_file *p = (telemetry_file *)pFile; 1.359 + MOZ_ASSERT(p->pReal->pMethods->iVersion >= 3); 1.360 + return p->pReal->pMethods->xUnfetch(p->pReal, iOff, pResOut); 1.361 +} 1.362 + 1.363 +int 1.364 +xOpen(sqlite3_vfs* vfs, const char *zName, sqlite3_file* pFile, 1.365 + int flags, int *pOutFlags) 1.366 +{ 1.367 + IOThreadAutoTimer ioTimer(Telemetry::MOZ_SQLITE_OPEN_MS, 1.368 + IOInterposeObserver::OpCreateOrOpen); 1.369 + Telemetry::AutoTimer<Telemetry::MOZ_SQLITE_OPEN_MS> timer; 1.370 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.371 + int rc; 1.372 + telemetry_file *p = (telemetry_file *)pFile; 1.373 + Histograms *h = nullptr; 1.374 + // check if the filename is one we are probing for 1.375 + for(size_t i = 0;i < sizeof(gHistograms)/sizeof(gHistograms[0]);i++) { 1.376 + h = &gHistograms[i]; 1.377 + // last probe is the fallback probe 1.378 + if (!h->name) 1.379 + break; 1.380 + if (!zName) 1.381 + continue; 1.382 + const char *match = strstr(zName, h->name); 1.383 + if (!match) 1.384 + continue; 1.385 + char c = match[strlen(h->name)]; 1.386 + // include -wal/-journal too 1.387 + if (!c || c == '-') 1.388 + break; 1.389 + } 1.390 + p->histograms = h; 1.391 + 1.392 + const char* persistenceType; 1.393 + const char* group; 1.394 + const char* origin; 1.395 + if ((flags & SQLITE_OPEN_URI) && 1.396 + (persistenceType = sqlite3_uri_parameter(zName, "persistenceType")) && 1.397 + (group = sqlite3_uri_parameter(zName, "group")) && 1.398 + (origin = sqlite3_uri_parameter(zName, "origin"))) { 1.399 + QuotaManager* quotaManager = QuotaManager::Get(); 1.400 + MOZ_ASSERT(quotaManager); 1.401 + 1.402 + p->quotaObject = quotaManager->GetQuotaObject(PersistenceTypeFromText( 1.403 + nsDependentCString(persistenceType)), nsDependentCString(group), 1.404 + nsDependentCString(origin), NS_ConvertUTF8toUTF16(zName)); 1.405 + } 1.406 + 1.407 + rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags); 1.408 + if( rc != SQLITE_OK ) 1.409 + return rc; 1.410 + if( p->pReal->pMethods ){ 1.411 + sqlite3_io_methods *pNew = new sqlite3_io_methods; 1.412 + const sqlite3_io_methods *pSub = p->pReal->pMethods; 1.413 + memset(pNew, 0, sizeof(*pNew)); 1.414 + // If the io_methods version is higher than the last known one, you should 1.415 + // update this VFS adding appropriate IO methods for any methods added in 1.416 + // the version change. 1.417 + pNew->iVersion = pSub->iVersion; 1.418 + MOZ_ASSERT(pNew->iVersion <= LAST_KNOWN_IOMETHODS_VERSION); 1.419 + pNew->xClose = xClose; 1.420 + pNew->xRead = xRead; 1.421 + pNew->xWrite = xWrite; 1.422 + pNew->xTruncate = xTruncate; 1.423 + pNew->xSync = xSync; 1.424 + pNew->xFileSize = xFileSize; 1.425 + pNew->xLock = xLock; 1.426 + pNew->xUnlock = xUnlock; 1.427 + pNew->xCheckReservedLock = xCheckReservedLock; 1.428 + pNew->xFileControl = xFileControl; 1.429 + pNew->xSectorSize = xSectorSize; 1.430 + pNew->xDeviceCharacteristics = xDeviceCharacteristics; 1.431 + if (pNew->iVersion >= 2) { 1.432 + // Methods added in version 2. 1.433 + pNew->xShmMap = pSub->xShmMap ? xShmMap : 0; 1.434 + pNew->xShmLock = pSub->xShmLock ? xShmLock : 0; 1.435 + pNew->xShmBarrier = pSub->xShmBarrier ? xShmBarrier : 0; 1.436 + pNew->xShmUnmap = pSub->xShmUnmap ? xShmUnmap : 0; 1.437 + } 1.438 + if (pNew->iVersion >= 3) { 1.439 + // Methods added in version 3. 1.440 + // SQLite 3.7.17 calls these methods without checking for nullptr first, 1.441 + // so we always define them. Verify that we're not going to call 1.442 + // nullptrs, though. 1.443 + MOZ_ASSERT(pSub->xFetch); 1.444 + pNew->xFetch = xFetch; 1.445 + MOZ_ASSERT(pSub->xUnfetch); 1.446 + pNew->xUnfetch = xUnfetch; 1.447 + } 1.448 + pFile->pMethods = pNew; 1.449 + } 1.450 + return rc; 1.451 +} 1.452 + 1.453 +int 1.454 +xDelete(sqlite3_vfs* vfs, const char *zName, int syncDir) 1.455 +{ 1.456 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.457 + return orig_vfs->xDelete(orig_vfs, zName, syncDir); 1.458 +} 1.459 + 1.460 +int 1.461 +xAccess(sqlite3_vfs *vfs, const char *zName, int flags, int *pResOut) 1.462 +{ 1.463 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.464 + return orig_vfs->xAccess(orig_vfs, zName, flags, pResOut); 1.465 +} 1.466 + 1.467 +int 1.468 +xFullPathname(sqlite3_vfs *vfs, const char *zName, int nOut, char *zOut) 1.469 +{ 1.470 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.471 + return orig_vfs->xFullPathname(orig_vfs, zName, nOut, zOut); 1.472 +} 1.473 + 1.474 +void* 1.475 +xDlOpen(sqlite3_vfs *vfs, const char *zFilename) 1.476 +{ 1.477 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.478 + return orig_vfs->xDlOpen(orig_vfs, zFilename); 1.479 +} 1.480 + 1.481 +void 1.482 +xDlError(sqlite3_vfs *vfs, int nByte, char *zErrMsg) 1.483 +{ 1.484 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.485 + orig_vfs->xDlError(orig_vfs, nByte, zErrMsg); 1.486 +} 1.487 + 1.488 +void 1.489 +(*xDlSym(sqlite3_vfs *vfs, void *pHdle, const char *zSym))(void){ 1.490 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.491 + return orig_vfs->xDlSym(orig_vfs, pHdle, zSym); 1.492 +} 1.493 + 1.494 +void 1.495 +xDlClose(sqlite3_vfs *vfs, void *pHandle) 1.496 +{ 1.497 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.498 + orig_vfs->xDlClose(orig_vfs, pHandle); 1.499 +} 1.500 + 1.501 +int 1.502 +xRandomness(sqlite3_vfs *vfs, int nByte, char *zOut) 1.503 +{ 1.504 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.505 + return orig_vfs->xRandomness(orig_vfs, nByte, zOut); 1.506 +} 1.507 + 1.508 +int 1.509 +xSleep(sqlite3_vfs *vfs, int microseconds) 1.510 +{ 1.511 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.512 + return orig_vfs->xSleep(orig_vfs, microseconds); 1.513 +} 1.514 + 1.515 +int 1.516 +xCurrentTime(sqlite3_vfs *vfs, double *prNow) 1.517 +{ 1.518 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.519 + return orig_vfs->xCurrentTime(orig_vfs, prNow); 1.520 +} 1.521 + 1.522 +int 1.523 +xGetLastError(sqlite3_vfs *vfs, int nBuf, char *zBuf) 1.524 +{ 1.525 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.526 + return orig_vfs->xGetLastError(orig_vfs, nBuf, zBuf); 1.527 +} 1.528 + 1.529 +int 1.530 +xCurrentTimeInt64(sqlite3_vfs *vfs, sqlite3_int64 *piNow) 1.531 +{ 1.532 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.533 + return orig_vfs->xCurrentTimeInt64(orig_vfs, piNow); 1.534 +} 1.535 + 1.536 +static 1.537 +int 1.538 +xSetSystemCall(sqlite3_vfs *vfs, const char *zName, sqlite3_syscall_ptr pFunc) 1.539 +{ 1.540 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.541 + return orig_vfs->xSetSystemCall(orig_vfs, zName, pFunc); 1.542 +} 1.543 + 1.544 +static 1.545 +sqlite3_syscall_ptr 1.546 +xGetSystemCall(sqlite3_vfs *vfs, const char *zName) 1.547 +{ 1.548 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.549 + return orig_vfs->xGetSystemCall(orig_vfs, zName); 1.550 +} 1.551 + 1.552 +static 1.553 +const char * 1.554 +xNextSystemCall(sqlite3_vfs *vfs, const char *zName) 1.555 +{ 1.556 + sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData); 1.557 + return orig_vfs->xNextSystemCall(orig_vfs, zName); 1.558 +} 1.559 + 1.560 +} 1.561 + 1.562 +namespace mozilla { 1.563 +namespace storage { 1.564 + 1.565 +sqlite3_vfs* ConstructTelemetryVFS() 1.566 +{ 1.567 +#if defined(XP_WIN) 1.568 +#define EXPECTED_VFS "win32" 1.569 +#define EXPECTED_VFS_NFS "win32" 1.570 +#else 1.571 +#define EXPECTED_VFS "unix" 1.572 +#define EXPECTED_VFS_NFS "unix-excl" 1.573 +#endif 1.574 + 1.575 + bool expected_vfs; 1.576 + sqlite3_vfs *vfs; 1.577 + if (Preferences::GetBool(PREF_NFS_FILESYSTEM)) { 1.578 + vfs = sqlite3_vfs_find(EXPECTED_VFS_NFS); 1.579 + expected_vfs = (vfs != nullptr); 1.580 + } 1.581 + else { 1.582 + vfs = sqlite3_vfs_find(nullptr); 1.583 + expected_vfs = vfs->zName && !strcmp(vfs->zName, EXPECTED_VFS); 1.584 + } 1.585 + if (!expected_vfs) { 1.586 + return nullptr; 1.587 + } 1.588 + 1.589 + sqlite3_vfs *tvfs = new ::sqlite3_vfs; 1.590 + memset(tvfs, 0, sizeof(::sqlite3_vfs)); 1.591 + // If the VFS version is higher than the last known one, you should update 1.592 + // this VFS adding appropriate methods for any methods added in the version 1.593 + // change. 1.594 + tvfs->iVersion = vfs->iVersion; 1.595 + MOZ_ASSERT(vfs->iVersion <= LAST_KNOWN_VFS_VERSION); 1.596 + tvfs->szOsFile = sizeof(telemetry_file) - sizeof(sqlite3_file) + vfs->szOsFile; 1.597 + tvfs->mxPathname = vfs->mxPathname; 1.598 + tvfs->zName = "telemetry-vfs"; 1.599 + tvfs->pAppData = vfs; 1.600 + tvfs->xOpen = xOpen; 1.601 + tvfs->xDelete = xDelete; 1.602 + tvfs->xAccess = xAccess; 1.603 + tvfs->xFullPathname = xFullPathname; 1.604 + tvfs->xDlOpen = xDlOpen; 1.605 + tvfs->xDlError = xDlError; 1.606 + tvfs->xDlSym = xDlSym; 1.607 + tvfs->xDlClose = xDlClose; 1.608 + tvfs->xRandomness = xRandomness; 1.609 + tvfs->xSleep = xSleep; 1.610 + tvfs->xCurrentTime = xCurrentTime; 1.611 + tvfs->xGetLastError = xGetLastError; 1.612 + if (tvfs->iVersion >= 2) { 1.613 + // Methods added in version 2. 1.614 + tvfs->xCurrentTimeInt64 = xCurrentTimeInt64; 1.615 + } 1.616 + if (tvfs->iVersion >= 3) { 1.617 + // Methods added in version 3. 1.618 + tvfs->xSetSystemCall = xSetSystemCall; 1.619 + tvfs->xGetSystemCall = xGetSystemCall; 1.620 + tvfs->xNextSystemCall = xNextSystemCall; 1.621 + } 1.622 + return tvfs; 1.623 +} 1.624 + 1.625 +} 1.626 +}