1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "mozilla/Telemetry.h"
10 #include "nsThreadUtils.h"
11 #include "mozilla/dom/quota/PersistenceType.h"
12 #include "mozilla/dom/quota/QuotaManager.h"
13 #include "mozilla/dom/quota/QuotaObject.h"
14 #include "mozilla/net/IOActivityMonitor.h"
15 #include "mozilla/IOInterposer.h"
17 #include "mozilla/StaticPrefs_storage.h"
20 # include "mozilla/StaticPrefs_dom.h"
23 // The last VFS version for which this file has been updated.
24 #define LAST_KNOWN_VFS_VERSION 3
26 // The last io_methods version for which this file has been updated.
27 #define LAST_KNOWN_IOMETHODS_VERSION 3
31 using namespace mozilla
;
32 using namespace mozilla::dom::quota
;
33 using namespace mozilla::net
;
37 const Telemetry::HistogramID readB
;
38 const Telemetry::HistogramID writeB
;
39 const Telemetry::HistogramID readMS
;
40 const Telemetry::HistogramID writeMS
;
41 const Telemetry::HistogramID syncMS
;
44 #define SQLITE_TELEMETRY(FILENAME, HGRAM) \
46 FILENAME, Telemetry::MOZ_SQLITE_##HGRAM##_READ_B, \
47 Telemetry::MOZ_SQLITE_##HGRAM##_WRITE_B, \
48 Telemetry::MOZ_SQLITE_##HGRAM##_READ_MS, \
49 Telemetry::MOZ_SQLITE_##HGRAM##_WRITE_MS, \
50 Telemetry::MOZ_SQLITE_##HGRAM##_SYNC_MS \
53 Histograms gHistograms
[] = {SQLITE_TELEMETRY("places.sqlite", PLACES
),
54 SQLITE_TELEMETRY("cookies.sqlite", COOKIES
),
55 SQLITE_TELEMETRY("webappsstore.sqlite", WEBAPPS
),
56 SQLITE_TELEMETRY(nullptr, OTHER
)};
57 #undef SQLITE_TELEMETRY
59 /** RAII class for measuring how long io takes on/off main thread
61 class IOThreadAutoTimer
{
64 * IOThreadAutoTimer measures time spent in IO. Additionally it
65 * automatically determines whether IO is happening on the main
66 * thread and picks an appropriate histogram.
68 * @param id takes a telemetry histogram id. The id+1 must be an
69 * equivalent histogram for the main thread. Eg, MOZ_SQLITE_OPEN_MS
70 * is followed by MOZ_SQLITE_OPEN_MAIN_THREAD_MS.
72 * @param aOp optionally takes an IO operation to report through the
73 * IOInterposer. Filename will be reported as NULL, and reference will be
74 * either "sqlite-mainthread" or "sqlite-otherthread".
76 explicit IOThreadAutoTimer(
77 Telemetry::HistogramID aId
,
78 IOInterposeObserver::Operation aOp
= IOInterposeObserver::OpNone
)
79 : start(TimeStamp::Now()),
89 * This constructor is for when we want to report an operation to
90 * IOInterposer but do not require a telemetry probe.
92 * @param aOp IO Operation to report through the IOInterposer.
94 explicit IOThreadAutoTimer(IOInterposeObserver::Operation aOp
)
95 : start(TimeStamp::Now()),
96 id(Telemetry::HistogramCount
)
104 ~IOThreadAutoTimer() {
105 TimeStamp
end(TimeStamp::Now());
106 uint32_t mainThread
= NS_IsMainThread() ? 1 : 0;
107 if (id
!= Telemetry::HistogramCount
) {
108 Telemetry::AccumulateTimeDelta(
109 static_cast<Telemetry::HistogramID
>(id
+ mainThread
), start
, end
);
111 // We don't report SQLite I/O on Windows because we have a comprehensive
112 // mechanism for intercepting I/O on that platform that captures a superset
113 // of the data captured here.
115 if (IOInterposer::IsObservedOperation(op
)) {
116 const char* main_ref
= "sqlite-mainthread";
117 const char* other_ref
= "sqlite-otherthread";
119 // Create observation
120 IOInterposeObserver::Observation
ob(op
, start
, end
,
121 (mainThread
? main_ref
: other_ref
));
122 // Report observation
123 IOInterposer::Report(ob
);
125 #endif /* !defined(XP_WIN) */
129 const TimeStamp start
;
130 const Telemetry::HistogramID id
;
132 IOInterposeObserver::Operation op
;
136 struct telemetry_file
{
137 // Base class. Must be first
140 // histograms pertaining to this file
141 Histograms
* histograms
;
143 // quota object for this file
144 RefPtr
<QuotaObject
> quotaObject
;
146 // The chunk size for this file. See the documentation for
147 // sqlite3_file_control() and FCNTL_CHUNK_SIZE.
153 // This contains the vfs that actually does work
154 sqlite3_file pReal
[1];
157 already_AddRefed
<QuotaObject
> GetQuotaObjectFromName(const char* zName
) {
160 const char* directoryLockIdParam
=
161 sqlite3_uri_parameter(zName
, "directoryLockId");
162 if (!directoryLockIdParam
) {
167 const int64_t directoryLockId
=
168 nsDependentCString(directoryLockIdParam
).ToInteger64(&rv
);
169 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv
));
171 QuotaManager
* quotaManager
= QuotaManager::Get();
172 MOZ_ASSERT(quotaManager
);
174 return quotaManager
->GetQuotaObject(directoryLockId
,
175 NS_ConvertUTF8toUTF16(zName
));
178 void MaybeEstablishQuotaControl(const char* zName
, telemetry_file
* pFile
,
181 MOZ_ASSERT(!pFile
->quotaObject
);
183 if (!(flags
& (SQLITE_OPEN_URI
| SQLITE_OPEN_WAL
))) {
186 pFile
->quotaObject
= GetQuotaObjectFromName(zName
);
190 ** Close a telemetry_file.
192 int xClose(sqlite3_file
* pFile
) {
193 telemetry_file
* p
= (telemetry_file
*)pFile
;
195 { // Scope for IOThreadAutoTimer
196 IOThreadAutoTimer
ioTimer(IOInterposeObserver::OpClose
);
197 rc
= p
->pReal
->pMethods
->xClose(p
->pReal
);
199 if (rc
== SQLITE_OK
) {
200 delete p
->base
.pMethods
;
201 p
->base
.pMethods
= nullptr;
202 p
->quotaObject
= nullptr;
203 delete[] p
->location
;
205 p
->fileChunkSize
= 0;
212 ** Read data from a telemetry_file.
214 int xRead(sqlite3_file
* pFile
, void* zBuf
, int iAmt
, sqlite_int64 iOfst
) {
215 telemetry_file
* p
= (telemetry_file
*)pFile
;
216 IOThreadAutoTimer
ioTimer(p
->histograms
->readMS
, IOInterposeObserver::OpRead
);
218 rc
= p
->pReal
->pMethods
->xRead(p
->pReal
, zBuf
, iAmt
, iOfst
);
219 if (rc
== SQLITE_OK
&& IOActivityMonitor::IsActive()) {
220 IOActivityMonitor::Read(nsDependentCString(p
->location
), iAmt
);
222 // sqlite likes to read from empty files, this is normal, ignore it.
223 if (rc
!= SQLITE_IOERR_SHORT_READ
)
224 Telemetry::Accumulate(p
->histograms
->readB
, rc
== SQLITE_OK
? iAmt
: 0);
229 ** Return the current file-size of a telemetry_file.
231 int xFileSize(sqlite3_file
* pFile
, sqlite_int64
* pSize
) {
232 IOThreadAutoTimer
ioTimer(IOInterposeObserver::OpStat
);
233 telemetry_file
* p
= (telemetry_file
*)pFile
;
235 rc
= p
->pReal
->pMethods
->xFileSize(p
->pReal
, pSize
);
240 ** Write data to a telemetry_file.
242 int xWrite(sqlite3_file
* pFile
, const void* zBuf
, int iAmt
,
243 sqlite_int64 iOfst
) {
244 telemetry_file
* p
= (telemetry_file
*)pFile
;
245 IOThreadAutoTimer
ioTimer(p
->histograms
->writeMS
,
246 IOInterposeObserver::OpWrite
);
248 if (p
->quotaObject
) {
249 MOZ_ASSERT(INT64_MAX
- iOfst
>= iAmt
);
250 if (!p
->quotaObject
->MaybeUpdateSize(iOfst
+ iAmt
, /* aTruncate */ false)) {
254 rc
= p
->pReal
->pMethods
->xWrite(p
->pReal
, zBuf
, iAmt
, iOfst
);
255 if (rc
== SQLITE_OK
&& IOActivityMonitor::IsActive()) {
256 IOActivityMonitor::Write(nsDependentCString(p
->location
), iAmt
);
259 Telemetry::Accumulate(p
->histograms
->writeB
, rc
== SQLITE_OK
? iAmt
: 0);
260 if (p
->quotaObject
&& rc
!= SQLITE_OK
) {
262 "xWrite failed on a quota-controlled file, attempting to "
263 "update its current size...");
264 sqlite_int64 currentSize
;
265 if (xFileSize(pFile
, ¤tSize
) == SQLITE_OK
) {
266 DebugOnly
<bool> res
=
267 p
->quotaObject
->MaybeUpdateSize(currentSize
, /* aTruncate */ true);
275 ** Truncate a telemetry_file.
277 int xTruncate(sqlite3_file
* pFile
, sqlite_int64 size
) {
278 IOThreadAutoTimer
ioTimer(Telemetry::MOZ_SQLITE_TRUNCATE_MS
);
279 telemetry_file
* p
= (telemetry_file
*)pFile
;
281 Telemetry::AutoTimer
<Telemetry::MOZ_SQLITE_TRUNCATE_MS
> timer
;
282 if (p
->quotaObject
) {
283 if (p
->fileChunkSize
> 0) {
284 // Round up to the smallest multiple of the chunk size that will hold all
287 ((size
+ p
->fileChunkSize
- 1) / p
->fileChunkSize
) * p
->fileChunkSize
;
289 if (!p
->quotaObject
->MaybeUpdateSize(size
, /* aTruncate */ true)) {
293 rc
= p
->pReal
->pMethods
->xTruncate(p
->pReal
, size
);
294 if (p
->quotaObject
) {
295 if (rc
== SQLITE_OK
) {
297 // Make sure xTruncate set the size exactly as we calculated above.
298 sqlite_int64 newSize
;
299 MOZ_ASSERT(xFileSize(pFile
, &newSize
) == SQLITE_OK
);
300 MOZ_ASSERT(newSize
== size
);
304 "xTruncate failed on a quota-controlled file, attempting to "
305 "update its current size...");
306 if (xFileSize(pFile
, &size
) == SQLITE_OK
) {
307 DebugOnly
<bool> res
=
308 p
->quotaObject
->MaybeUpdateSize(size
, /* aTruncate */ true);
317 ** Sync a telemetry_file.
319 int xSync(sqlite3_file
* pFile
, int flags
) {
320 telemetry_file
* p
= (telemetry_file
*)pFile
;
321 IOThreadAutoTimer
ioTimer(p
->histograms
->syncMS
,
322 IOInterposeObserver::OpFSync
);
323 return p
->pReal
->pMethods
->xSync(p
->pReal
, flags
);
327 ** Lock a telemetry_file.
329 int xLock(sqlite3_file
* pFile
, int eLock
) {
330 telemetry_file
* p
= (telemetry_file
*)pFile
;
332 rc
= p
->pReal
->pMethods
->xLock(p
->pReal
, eLock
);
337 ** Unlock a telemetry_file.
339 int xUnlock(sqlite3_file
* pFile
, int eLock
) {
340 telemetry_file
* p
= (telemetry_file
*)pFile
;
342 rc
= p
->pReal
->pMethods
->xUnlock(p
->pReal
, eLock
);
347 ** Check if another file-handle holds a RESERVED lock on a telemetry_file.
349 int xCheckReservedLock(sqlite3_file
* pFile
, int* pResOut
) {
350 telemetry_file
* p
= (telemetry_file
*)pFile
;
351 int rc
= p
->pReal
->pMethods
->xCheckReservedLock(p
->pReal
, pResOut
);
356 ** File control method. For custom operations on a telemetry_file.
358 int xFileControl(sqlite3_file
* pFile
, int op
, void* pArg
) {
359 telemetry_file
* p
= (telemetry_file
*)pFile
;
361 // Hook SQLITE_FCNTL_SIZE_HINT for quota-controlled files and do the necessary
362 // work before passing to the SQLite VFS.
363 if (op
== SQLITE_FCNTL_SIZE_HINT
&& p
->quotaObject
) {
364 sqlite3_int64 hintSize
= *static_cast<sqlite3_int64
*>(pArg
);
365 sqlite3_int64 currentSize
;
366 rc
= xFileSize(pFile
, ¤tSize
);
367 if (rc
!= SQLITE_OK
) {
370 if (hintSize
> currentSize
) {
371 rc
= xTruncate(pFile
, hintSize
);
372 if (rc
!= SQLITE_OK
) {
377 rc
= p
->pReal
->pMethods
->xFileControl(p
->pReal
, op
, pArg
);
378 // Grab the file chunk size after the SQLite VFS has approved.
379 if (op
== SQLITE_FCNTL_CHUNK_SIZE
&& rc
== SQLITE_OK
) {
380 p
->fileChunkSize
= *static_cast<int*>(pArg
);
383 if (op
== SQLITE_FCNTL_SIZE_HINT
&& p
->quotaObject
&& rc
== SQLITE_OK
) {
384 sqlite3_int64 hintSize
= *static_cast<sqlite3_int64
*>(pArg
);
385 if (p
->fileChunkSize
> 0) {
386 hintSize
= ((hintSize
+ p
->fileChunkSize
- 1) / p
->fileChunkSize
) *
389 sqlite3_int64 currentSize
;
390 MOZ_ASSERT(xFileSize(pFile
, ¤tSize
) == SQLITE_OK
);
391 MOZ_ASSERT(currentSize
>= hintSize
);
398 ** Return the sector-size in bytes for a telemetry_file.
400 int xSectorSize(sqlite3_file
* pFile
) {
401 telemetry_file
* p
= (telemetry_file
*)pFile
;
403 rc
= p
->pReal
->pMethods
->xSectorSize(p
->pReal
);
408 ** Return the device characteristic flags supported by a telemetry_file.
410 int xDeviceCharacteristics(sqlite3_file
* pFile
) {
411 telemetry_file
* p
= (telemetry_file
*)pFile
;
413 rc
= p
->pReal
->pMethods
->xDeviceCharacteristics(p
->pReal
);
418 ** Shared-memory operations.
420 int xShmLock(sqlite3_file
* pFile
, int ofst
, int n
, int flags
) {
421 telemetry_file
* p
= (telemetry_file
*)pFile
;
422 return p
->pReal
->pMethods
->xShmLock(p
->pReal
, ofst
, n
, flags
);
425 int xShmMap(sqlite3_file
* pFile
, int iRegion
, int szRegion
, int isWrite
,
426 void volatile** pp
) {
427 telemetry_file
* p
= (telemetry_file
*)pFile
;
429 rc
= p
->pReal
->pMethods
->xShmMap(p
->pReal
, iRegion
, szRegion
, isWrite
, pp
);
433 void xShmBarrier(sqlite3_file
* pFile
) {
434 telemetry_file
* p
= (telemetry_file
*)pFile
;
435 p
->pReal
->pMethods
->xShmBarrier(p
->pReal
);
438 int xShmUnmap(sqlite3_file
* pFile
, int delFlag
) {
439 telemetry_file
* p
= (telemetry_file
*)pFile
;
441 rc
= p
->pReal
->pMethods
->xShmUnmap(p
->pReal
, delFlag
);
445 int xFetch(sqlite3_file
* pFile
, sqlite3_int64 iOff
, int iAmt
, void** pp
) {
446 telemetry_file
* p
= (telemetry_file
*)pFile
;
447 MOZ_ASSERT(p
->pReal
->pMethods
->iVersion
>= 3);
448 return p
->pReal
->pMethods
->xFetch(p
->pReal
, iOff
, iAmt
, pp
);
451 int xUnfetch(sqlite3_file
* pFile
, sqlite3_int64 iOff
, void* pResOut
) {
452 telemetry_file
* p
= (telemetry_file
*)pFile
;
453 MOZ_ASSERT(p
->pReal
->pMethods
->iVersion
>= 3);
454 return p
->pReal
->pMethods
->xUnfetch(p
->pReal
, iOff
, pResOut
);
457 int xOpen(sqlite3_vfs
* vfs
, const char* zName
, sqlite3_file
* pFile
, int flags
,
459 IOThreadAutoTimer
ioTimer(Telemetry::MOZ_SQLITE_OPEN_MS
,
460 IOInterposeObserver::OpCreateOrOpen
);
461 Telemetry::AutoTimer
<Telemetry::MOZ_SQLITE_OPEN_MS
> timer
;
462 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
464 telemetry_file
* p
= (telemetry_file
*)pFile
;
465 Histograms
* h
= nullptr;
466 // check if the filename is one we are probing for
467 for (size_t i
= 0; i
< sizeof(gHistograms
) / sizeof(gHistograms
[0]); i
++) {
469 // last probe is the fallback probe
471 if (!zName
) continue;
472 const char* match
= strstr(zName
, h
->name
);
473 if (!match
) continue;
474 char c
= match
[strlen(h
->name
)];
475 // include -wal/-journal too
476 if (!c
|| c
== '-') break;
480 MaybeEstablishQuotaControl(zName
, p
, flags
);
482 rc
= orig_vfs
->xOpen(orig_vfs
, zName
, p
->pReal
, flags
, pOutFlags
);
483 if (rc
!= SQLITE_OK
) return rc
;
486 p
->location
= new char[7 + strlen(zName
) + 1];
487 strcpy(p
->location
, "file://");
488 strcpy(p
->location
+ 7, zName
);
490 p
->location
= new char[8];
491 strcpy(p
->location
, "file://");
494 if (p
->pReal
->pMethods
) {
495 sqlite3_io_methods
* pNew
= new sqlite3_io_methods
;
496 const sqlite3_io_methods
* pSub
= p
->pReal
->pMethods
;
497 memset(pNew
, 0, sizeof(*pNew
));
498 // If the io_methods version is higher than the last known one, you should
499 // update this VFS adding appropriate IO methods for any methods added in
500 // the version change.
501 pNew
->iVersion
= pSub
->iVersion
;
502 MOZ_ASSERT(pNew
->iVersion
<= LAST_KNOWN_IOMETHODS_VERSION
);
503 pNew
->xClose
= xClose
;
505 pNew
->xWrite
= xWrite
;
506 pNew
->xTruncate
= xTruncate
;
508 pNew
->xFileSize
= xFileSize
;
510 pNew
->xUnlock
= xUnlock
;
511 pNew
->xCheckReservedLock
= xCheckReservedLock
;
512 pNew
->xFileControl
= xFileControl
;
513 pNew
->xSectorSize
= xSectorSize
;
514 pNew
->xDeviceCharacteristics
= xDeviceCharacteristics
;
515 if (pNew
->iVersion
>= 2) {
516 // Methods added in version 2.
517 pNew
->xShmMap
= pSub
->xShmMap
? xShmMap
: 0;
518 pNew
->xShmLock
= pSub
->xShmLock
? xShmLock
: 0;
519 pNew
->xShmBarrier
= pSub
->xShmBarrier
? xShmBarrier
: 0;
520 pNew
->xShmUnmap
= pSub
->xShmUnmap
? xShmUnmap
: 0;
522 if (pNew
->iVersion
>= 3) {
523 // Methods added in version 3.
524 // SQLite 3.7.17 calls these methods without checking for nullptr first,
525 // so we always define them. Verify that we're not going to call
527 MOZ_ASSERT(pSub
->xFetch
);
528 pNew
->xFetch
= xFetch
;
529 MOZ_ASSERT(pSub
->xUnfetch
);
530 pNew
->xUnfetch
= xUnfetch
;
532 pFile
->pMethods
= pNew
;
537 int xDelete(sqlite3_vfs
* vfs
, const char* zName
, int syncDir
) {
538 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
540 RefPtr
<QuotaObject
> quotaObject
;
542 if (StringEndsWith(nsDependentCString(zName
), "-wal"_ns
)) {
543 quotaObject
= GetQuotaObjectFromName(zName
);
546 rc
= orig_vfs
->xDelete(orig_vfs
, zName
, syncDir
);
547 if (rc
== SQLITE_OK
&& quotaObject
) {
548 MOZ_ALWAYS_TRUE(quotaObject
->MaybeUpdateSize(0, /* aTruncate */ true));
554 int xAccess(sqlite3_vfs
* vfs
, const char* zName
, int flags
, int* pResOut
) {
555 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
556 return orig_vfs
->xAccess(orig_vfs
, zName
, flags
, pResOut
);
559 int xFullPathname(sqlite3_vfs
* vfs
, const char* zName
, int nOut
, char* zOut
) {
561 // SQLite uses GetFullPathnameW which also normailizes file path. If a file
562 // component ends with a dot, it would be removed. However, it's not desired.
564 // And that would result SQLite uses wrong database and quotaObject.
565 // Note that we are safe to avoid the GetFullPathnameW call for \\?\ prefixed
567 // And note that this hack will be removed once the issue is fixed directly in
570 // zName that starts with "//?/" is the case when a file URI was passed and
571 // zName that starts with "\\?\" is the case when a normal path was passed
573 if (StaticPrefs::dom_quotaManager_overrideXFullPathname() &&
574 ((zName
[0] == '/' && zName
[1] == '/' && zName
[2] == '?' &&
576 (zName
[0] == '\\' && zName
[1] == '\\' && zName
[2] == '?' &&
577 zName
[3] == '\\'))) {
578 MOZ_ASSERT(nOut
>= vfs
->mxPathname
);
579 MOZ_ASSERT(nOut
> strlen(zName
));
582 while (zName
[index
] != '\0') {
583 if (zName
[index
] == '/') {
586 zOut
[index
] = zName
[index
];
597 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
598 return orig_vfs
->xFullPathname(orig_vfs
, zName
, nOut
, zOut
);
601 void* xDlOpen(sqlite3_vfs
* vfs
, const char* zFilename
) {
602 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
603 return orig_vfs
->xDlOpen(orig_vfs
, zFilename
);
606 void xDlError(sqlite3_vfs
* vfs
, int nByte
, char* zErrMsg
) {
607 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
608 orig_vfs
->xDlError(orig_vfs
, nByte
, zErrMsg
);
611 void (*xDlSym(sqlite3_vfs
* vfs
, void* pHdle
, const char* zSym
))(void) {
612 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
613 return orig_vfs
->xDlSym(orig_vfs
, pHdle
, zSym
);
616 void xDlClose(sqlite3_vfs
* vfs
, void* pHandle
) {
617 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
618 orig_vfs
->xDlClose(orig_vfs
, pHandle
);
621 int xRandomness(sqlite3_vfs
* vfs
, int nByte
, char* zOut
) {
622 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
623 return orig_vfs
->xRandomness(orig_vfs
, nByte
, zOut
);
626 int xSleep(sqlite3_vfs
* vfs
, int microseconds
) {
627 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
628 return orig_vfs
->xSleep(orig_vfs
, microseconds
);
631 int xCurrentTime(sqlite3_vfs
* vfs
, double* prNow
) {
632 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
633 return orig_vfs
->xCurrentTime(orig_vfs
, prNow
);
636 int xGetLastError(sqlite3_vfs
* vfs
, int nBuf
, char* zBuf
) {
637 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
638 return orig_vfs
->xGetLastError(orig_vfs
, nBuf
, zBuf
);
641 int xCurrentTimeInt64(sqlite3_vfs
* vfs
, sqlite3_int64
* piNow
) {
642 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
643 return orig_vfs
->xCurrentTimeInt64(orig_vfs
, piNow
);
646 static int xSetSystemCall(sqlite3_vfs
* vfs
, const char* zName
,
647 sqlite3_syscall_ptr pFunc
) {
648 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
649 return orig_vfs
->xSetSystemCall(orig_vfs
, zName
, pFunc
);
652 static sqlite3_syscall_ptr
xGetSystemCall(sqlite3_vfs
* vfs
, const char* zName
) {
653 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
654 return orig_vfs
->xGetSystemCall(orig_vfs
, zName
);
657 static const char* xNextSystemCall(sqlite3_vfs
* vfs
, const char* zName
) {
658 sqlite3_vfs
* orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
659 return orig_vfs
->xNextSystemCall(orig_vfs
, zName
);
667 const char* GetTelemetryVFSName(bool exclusive
) {
668 return exclusive
? "telemetry-vfs-excl" : "telemetry-vfs";
671 UniquePtr
<sqlite3_vfs
> ConstructTelemetryVFS(bool exclusive
) {
673 # define EXPECTED_VFS "win32"
674 # define EXPECTED_VFS_EXCL "win32"
676 # define EXPECTED_VFS "unix"
677 # define EXPECTED_VFS_EXCL "unix-excl"
683 // Use the non-exclusive VFS.
684 vfs
= sqlite3_vfs_find(nullptr);
685 expected_vfs
= vfs
->zName
&& !strcmp(vfs
->zName
, EXPECTED_VFS
);
687 vfs
= sqlite3_vfs_find(EXPECTED_VFS_EXCL
);
688 expected_vfs
= (vfs
!= nullptr);
694 auto tvfs
= MakeUnique
<::sqlite3_vfs
>();
695 memset(tvfs
.get(), 0, sizeof(::sqlite3_vfs
));
696 // If the VFS version is higher than the last known one, you should update
697 // this VFS adding appropriate methods for any methods added in the version
699 tvfs
->iVersion
= vfs
->iVersion
;
700 MOZ_ASSERT(vfs
->iVersion
<= LAST_KNOWN_VFS_VERSION
);
702 sizeof(telemetry_file
) - sizeof(sqlite3_file
) + vfs
->szOsFile
;
703 tvfs
->mxPathname
= vfs
->mxPathname
;
704 tvfs
->zName
= GetTelemetryVFSName(exclusive
);
705 tvfs
->pAppData
= vfs
;
707 tvfs
->xDelete
= xDelete
;
708 tvfs
->xAccess
= xAccess
;
709 tvfs
->xFullPathname
= xFullPathname
;
710 tvfs
->xDlOpen
= xDlOpen
;
711 tvfs
->xDlError
= xDlError
;
712 tvfs
->xDlSym
= xDlSym
;
713 tvfs
->xDlClose
= xDlClose
;
714 tvfs
->xRandomness
= xRandomness
;
715 tvfs
->xSleep
= xSleep
;
716 tvfs
->xCurrentTime
= xCurrentTime
;
717 tvfs
->xGetLastError
= xGetLastError
;
718 if (tvfs
->iVersion
>= 2) {
719 // Methods added in version 2.
720 tvfs
->xCurrentTimeInt64
= xCurrentTimeInt64
;
722 if (tvfs
->iVersion
>= 3) {
723 // Methods added in version 3.
724 tvfs
->xSetSystemCall
= xSetSystemCall
;
725 tvfs
->xGetSystemCall
= xGetSystemCall
;
726 tvfs
->xNextSystemCall
= xNextSystemCall
;
731 already_AddRefed
<QuotaObject
> GetQuotaObjectForFile(sqlite3_file
* pFile
) {
734 telemetry_file
* p
= (telemetry_file
*)pFile
;
735 RefPtr
<QuotaObject
> result
= p
->quotaObject
;
736 return result
.forget();
739 } // namespace storage
740 } // namespace mozilla