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"
9 #include "mozilla/Preferences.h"
11 #include "nsThreadUtils.h"
12 #include "mozilla/dom/quota/PersistenceType.h"
13 #include "mozilla/dom/quota/QuotaManager.h"
14 #include "mozilla/dom/quota/QuotaObject.h"
15 #include "mozilla/IOInterposer.h"
17 // The last VFS version for which this file has been updated.
18 #define LAST_KNOWN_VFS_VERSION 3
20 // The last io_methods version for which this file has been updated.
21 #define LAST_KNOWN_IOMETHODS_VERSION 3
24 * This preference is a workaround to allow users/sysadmins to identify
25 * that the profile exists on an NFS share whose implementation
26 * is incompatible with SQLite's default locking implementation.
27 * Bug 433129 attempted to automatically identify such file-systems,
28 * but a reliable way was not found and it was determined that the fallback
29 * locking is slower than POSIX locking, so we do not want to do it by default.
31 #define PREF_NFS_FILESYSTEM "storage.nfs_filesystem"
35 using namespace mozilla
;
36 using namespace mozilla::dom::quota
;
40 const Telemetry::ID readB
;
41 const Telemetry::ID writeB
;
42 const Telemetry::ID readMS
;
43 const Telemetry::ID writeMS
;
44 const Telemetry::ID syncMS
;
47 #define SQLITE_TELEMETRY(FILENAME, HGRAM) \
49 Telemetry::MOZ_SQLITE_ ## HGRAM ## _READ_B, \
50 Telemetry::MOZ_SQLITE_ ## HGRAM ## _WRITE_B, \
51 Telemetry::MOZ_SQLITE_ ## HGRAM ## _READ_MS, \
52 Telemetry::MOZ_SQLITE_ ## HGRAM ## _WRITE_MS, \
53 Telemetry::MOZ_SQLITE_ ## HGRAM ## _SYNC_MS \
56 Histograms gHistograms
[] = {
57 SQLITE_TELEMETRY("places.sqlite", PLACES
),
58 SQLITE_TELEMETRY("cookies.sqlite", COOKIES
),
59 SQLITE_TELEMETRY("webappsstore.sqlite", WEBAPPS
),
60 SQLITE_TELEMETRY(nullptr, OTHER
)
62 #undef SQLITE_TELEMETRY
64 /** RAII class for measuring how long io takes on/off main thread
66 class IOThreadAutoTimer
{
69 * IOThreadAutoTimer measures time spent in IO. Additionally it
70 * automatically determines whether IO is happening on the main
71 * thread and picks an appropriate histogram.
73 * @param id takes a telemetry histogram id. The id+1 must be an
74 * equivalent histogram for the main thread. Eg, MOZ_SQLITE_OPEN_MS
75 * is followed by MOZ_SQLITE_OPEN_MAIN_THREAD_MS.
77 * @param aOp optionally takes an IO operation to report through the
78 * IOInterposer. Filename will be reported as NULL, and reference will be
79 * either "sqlite-mainthread" or "sqlite-otherthread".
81 explicit IOThreadAutoTimer(Telemetry::ID id
,
82 IOInterposeObserver::Operation aOp
= IOInterposeObserver::OpNone
)
83 : start(TimeStamp::Now()),
90 * This constructor is for when we want to report an operation to
91 * IOInterposer but do not require a telemetry probe.
93 * @param aOp IO Operation to report through the IOInterposer.
95 explicit IOThreadAutoTimer(IOInterposeObserver::Operation aOp
)
96 : start(TimeStamp::Now()),
97 id(Telemetry::HistogramCount
),
104 TimeStamp
end(TimeStamp::Now());
105 uint32_t mainThread
= NS_IsMainThread() ? 1 : 0;
106 if (id
!= Telemetry::HistogramCount
) {
107 Telemetry::AccumulateTimeDelta(static_cast<Telemetry::ID
>(id
+ mainThread
),
110 // We don't report SQLite I/O on Windows because we have a comprehensive
111 // mechanism for intercepting I/O on that platform that captures a superset
112 // of the data captured here.
113 #if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(XP_WIN)
114 if (IOInterposer::IsObservedOperation(op
)) {
115 const char* main_ref
= "sqlite-mainthread";
116 const char* other_ref
= "sqlite-otherthread";
118 // Create observation
119 IOInterposeObserver::Observation
ob(op
, start
, end
,
120 (mainThread
? main_ref
: other_ref
));
121 // Report observation
122 IOInterposer::Report(ob
);
124 #endif /* defined(MOZ_ENABLE_PROFILER_SPS) && !defined(XP_WIN) */
128 const TimeStamp start
;
129 const Telemetry::ID id
;
130 IOInterposeObserver::Operation op
;
133 struct telemetry_file
{
134 // Base class. Must be first
137 // histograms pertaining to this file
138 Histograms
*histograms
;
140 // quota object for this file
141 RefPtr
<QuotaObject
> quotaObject
;
143 // The chunk size for this file. See the documentation for
144 // sqlite3_file_control() and FCNTL_CHUNK_SIZE.
147 // This contains the vfs that actually does work
148 sqlite3_file pReal
[1];
152 DatabasePathFromWALPath(const char *zWALName
)
155 * Do some sketchy pointer arithmetic to find the parameter key. The WAL
156 * filename is in the middle of a big allocated block that contains:
159 * - Main Database Path
161 * - Multiple URI components consisting of:
169 * - WAL Path (zWALName)
172 * Because the main database path is preceded by a random value we have to be
173 * careful when trying to figure out when we should terminate this loop.
175 MOZ_ASSERT(zWALName
);
177 nsDependentCSubstring
dbPath(zWALName
, strlen(zWALName
));
179 // Chop off the "-wal" suffix.
180 NS_NAMED_LITERAL_CSTRING(kWALSuffix
, "-wal");
181 MOZ_ASSERT(StringEndsWith(dbPath
, kWALSuffix
));
183 dbPath
.Rebind(zWALName
, dbPath
.Length() - kWALSuffix
.Length());
184 MOZ_ASSERT(!dbPath
.IsEmpty());
186 // We want to scan to the end of the key/value URI pairs. Skip the preceding
187 // null and go to the last char of the journal path.
188 const char* cursor
= zWALName
- 2;
190 // Make sure we just skipped a null.
191 MOZ_ASSERT(!*(cursor
+ 1));
193 // Walk backwards over the journal path.
198 // There should be another null here.
200 MOZ_ASSERT(!*cursor
);
202 // Back up one more char to the last char of the previous string. It may be
203 // the database path or it may be a key/value URI pair.
208 // Verify that we just walked over the journal path. Account for the two
209 // nulls we just skipped.
210 const char *journalStart
= cursor
+ 3;
212 nsDependentCSubstring
journalPath(journalStart
,
213 strlen(journalStart
));
215 // Chop off the "-journal" suffix.
216 NS_NAMED_LITERAL_CSTRING(kJournalSuffix
, "-journal");
217 MOZ_ASSERT(StringEndsWith(journalPath
, kJournalSuffix
));
219 journalPath
.Rebind(journalStart
,
220 journalPath
.Length() - kJournalSuffix
.Length());
221 MOZ_ASSERT(!journalPath
.IsEmpty());
223 // Make sure that the database name is a substring of the journal name.
224 MOZ_ASSERT(journalPath
== dbPath
);
228 // Now we're either at the end of the key/value URI pairs or we're at the
229 // end of the database path. Carefully walk backwards one character at a
230 // time to do this safely without running past the beginning of the database
232 const char *const dbPathStart
= dbPath
.BeginReading();
233 const char *dbPathCursor
= dbPath
.EndReading() - 1;
234 bool isDBPath
= true;
237 MOZ_ASSERT(*dbPathCursor
, "dbPathCursor should never see a null char!");
240 isDBPath
= dbPathStart
<= dbPathCursor
&&
241 *dbPathCursor
== *cursor
&&
246 // This isn't the database path so it must be a value. Scan past it and
248 for (size_t stringCount
= 0; stringCount
< 2; stringCount
++) {
249 // Scan past the string to the preceding null character.
254 // Back up one more char to the last char of preceding string.
258 // Reset and start again.
259 dbPathCursor
= dbPath
.EndReading() - 1;
265 MOZ_ASSERT(isDBPath
);
268 if (dbPathStart
== dbPathCursor
) {
269 // Found the full database path, we're all done.
270 MOZ_ASSERT(nsDependentCString(cursor
) == dbPath
);
274 // Change the cursors and go through the loop again.
279 MOZ_CRASH("Should never get here!");
282 already_AddRefed
<QuotaObject
>
283 GetQuotaObjectFromNameAndParameters(const char *zName
,
284 const char *zURIParameterKey
)
287 MOZ_ASSERT(zURIParameterKey
);
289 const char *persistenceType
=
290 sqlite3_uri_parameter(zURIParameterKey
, "persistenceType");
291 if (!persistenceType
) {
295 const char *group
= sqlite3_uri_parameter(zURIParameterKey
, "group");
297 NS_WARNING("SQLite URI had 'persistenceType' but not 'group'?!");
301 const char *origin
= sqlite3_uri_parameter(zURIParameterKey
, "origin");
303 NS_WARNING("SQLite URI had 'persistenceType' and 'group' but not "
308 QuotaManager
*quotaManager
= QuotaManager::Get();
309 MOZ_ASSERT(quotaManager
);
311 return quotaManager
->GetQuotaObject(
312 PersistenceTypeFromText(nsDependentCString(persistenceType
)),
313 nsDependentCString(group
),
314 nsDependentCString(origin
),
315 NS_ConvertUTF8toUTF16(zName
));
319 MaybeEstablishQuotaControl(const char *zName
,
320 telemetry_file
*pFile
,
324 MOZ_ASSERT(!pFile
->quotaObject
);
326 if (!(flags
& (SQLITE_OPEN_URI
| SQLITE_OPEN_WAL
))) {
332 const char *zURIParameterKey
= (flags
& SQLITE_OPEN_WAL
) ?
333 DatabasePathFromWALPath(zName
) :
336 MOZ_ASSERT(zURIParameterKey
);
339 GetQuotaObjectFromNameAndParameters(zName
, zURIParameterKey
);
343 ** Close a telemetry_file.
346 xClose(sqlite3_file
*pFile
)
348 telemetry_file
*p
= (telemetry_file
*)pFile
;
350 { // Scope for IOThreadAutoTimer
351 IOThreadAutoTimer
ioTimer(IOInterposeObserver::OpClose
);
352 rc
= p
->pReal
->pMethods
->xClose(p
->pReal
);
355 delete p
->base
.pMethods
;
356 p
->base
.pMethods
= nullptr;
357 p
->quotaObject
= nullptr;
359 p
->fileChunkSize
= 0;
366 ** Read data from a telemetry_file.
369 xRead(sqlite3_file
*pFile
, void *zBuf
, int iAmt
, sqlite_int64 iOfst
)
371 telemetry_file
*p
= (telemetry_file
*)pFile
;
372 IOThreadAutoTimer
ioTimer(p
->histograms
->readMS
, IOInterposeObserver::OpRead
);
374 rc
= p
->pReal
->pMethods
->xRead(p
->pReal
, zBuf
, iAmt
, iOfst
);
375 // sqlite likes to read from empty files, this is normal, ignore it.
376 if (rc
!= SQLITE_IOERR_SHORT_READ
)
377 Telemetry::Accumulate(p
->histograms
->readB
, rc
== SQLITE_OK
? iAmt
: 0);
382 ** Return the current file-size of a telemetry_file.
385 xFileSize(sqlite3_file
*pFile
, sqlite_int64
*pSize
)
387 IOThreadAutoTimer
ioTimer(IOInterposeObserver::OpStat
);
388 telemetry_file
*p
= (telemetry_file
*)pFile
;
390 rc
= p
->pReal
->pMethods
->xFileSize(p
->pReal
, pSize
);
395 ** Write data to a telemetry_file.
398 xWrite(sqlite3_file
*pFile
, const void *zBuf
, int iAmt
, sqlite_int64 iOfst
)
400 telemetry_file
*p
= (telemetry_file
*)pFile
;
401 IOThreadAutoTimer
ioTimer(p
->histograms
->writeMS
, IOInterposeObserver::OpWrite
);
403 if (p
->quotaObject
) {
404 MOZ_ASSERT(INT64_MAX
- iOfst
>= iAmt
);
405 if (!p
->quotaObject
->MaybeUpdateSize(iOfst
+ iAmt
, /* aTruncate */ false)) {
409 rc
= p
->pReal
->pMethods
->xWrite(p
->pReal
, zBuf
, iAmt
, iOfst
);
410 Telemetry::Accumulate(p
->histograms
->writeB
, rc
== SQLITE_OK
? iAmt
: 0);
411 if (p
->quotaObject
&& rc
!= SQLITE_OK
) {
412 NS_WARNING("xWrite failed on a quota-controlled file, attempting to "
413 "update its current size...");
414 sqlite_int64 currentSize
;
415 if (xFileSize(pFile
, ¤tSize
) == SQLITE_OK
) {
416 p
->quotaObject
->MaybeUpdateSize(currentSize
, /* aTruncate */ true);
423 ** Truncate a telemetry_file.
426 xTruncate(sqlite3_file
*pFile
, sqlite_int64 size
)
428 IOThreadAutoTimer
ioTimer(Telemetry::MOZ_SQLITE_TRUNCATE_MS
);
429 telemetry_file
*p
= (telemetry_file
*)pFile
;
431 Telemetry::AutoTimer
<Telemetry::MOZ_SQLITE_TRUNCATE_MS
> timer
;
432 if (p
->quotaObject
) {
433 if (p
->fileChunkSize
> 0) {
434 // Round up to the smallest multiple of the chunk size that will hold all
437 ((size
+ p
->fileChunkSize
- 1) / p
->fileChunkSize
) * p
->fileChunkSize
;
439 if (!p
->quotaObject
->MaybeUpdateSize(size
, /* aTruncate */ true)) {
443 rc
= p
->pReal
->pMethods
->xTruncate(p
->pReal
, size
);
444 if (p
->quotaObject
) {
445 if (rc
== SQLITE_OK
) {
447 // Make sure xTruncate set the size exactly as we calculated above.
448 sqlite_int64 newSize
;
449 MOZ_ASSERT(xFileSize(pFile
, &newSize
) == SQLITE_OK
);
450 MOZ_ASSERT(newSize
== size
);
453 NS_WARNING("xTruncate failed on a quota-controlled file, attempting to "
454 "update its current size...");
455 if (xFileSize(pFile
, &size
) == SQLITE_OK
) {
456 p
->quotaObject
->MaybeUpdateSize(size
, /* aTruncate */ true);
464 ** Sync a telemetry_file.
467 xSync(sqlite3_file
*pFile
, int flags
)
469 telemetry_file
*p
= (telemetry_file
*)pFile
;
470 IOThreadAutoTimer
ioTimer(p
->histograms
->syncMS
, IOInterposeObserver::OpFSync
);
471 return p
->pReal
->pMethods
->xSync(p
->pReal
, flags
);
475 ** Lock a telemetry_file.
478 xLock(sqlite3_file
*pFile
, int eLock
)
480 telemetry_file
*p
= (telemetry_file
*)pFile
;
482 rc
= p
->pReal
->pMethods
->xLock(p
->pReal
, eLock
);
487 ** Unlock a telemetry_file.
490 xUnlock(sqlite3_file
*pFile
, int eLock
)
492 telemetry_file
*p
= (telemetry_file
*)pFile
;
494 rc
= p
->pReal
->pMethods
->xUnlock(p
->pReal
, eLock
);
499 ** Check if another file-handle holds a RESERVED lock on a telemetry_file.
502 xCheckReservedLock(sqlite3_file
*pFile
, int *pResOut
)
504 telemetry_file
*p
= (telemetry_file
*)pFile
;
505 int rc
= p
->pReal
->pMethods
->xCheckReservedLock(p
->pReal
, pResOut
);
510 ** File control method. For custom operations on a telemetry_file.
513 xFileControl(sqlite3_file
*pFile
, int op
, void *pArg
)
515 telemetry_file
*p
= (telemetry_file
*)pFile
;
517 // Hook SQLITE_FCNTL_SIZE_HINT for quota-controlled files and do the necessary
518 // work before passing to the SQLite VFS.
519 if (op
== SQLITE_FCNTL_SIZE_HINT
&& p
->quotaObject
) {
520 sqlite3_int64 hintSize
= *static_cast<sqlite3_int64
*>(pArg
);
521 sqlite3_int64 currentSize
;
522 rc
= xFileSize(pFile
, ¤tSize
);
523 if (rc
!= SQLITE_OK
) {
526 if (hintSize
> currentSize
) {
527 rc
= xTruncate(pFile
, hintSize
);
528 if (rc
!= SQLITE_OK
) {
533 rc
= p
->pReal
->pMethods
->xFileControl(p
->pReal
, op
, pArg
);
534 // Grab the file chunk size after the SQLite VFS has approved.
535 if (op
== SQLITE_FCNTL_CHUNK_SIZE
&& rc
== SQLITE_OK
) {
536 p
->fileChunkSize
= *static_cast<int*>(pArg
);
539 if (op
== SQLITE_FCNTL_SIZE_HINT
&& p
->quotaObject
&& rc
== SQLITE_OK
) {
540 sqlite3_int64 hintSize
= *static_cast<sqlite3_int64
*>(pArg
);
541 if (p
->fileChunkSize
> 0) {
543 ((hintSize
+ p
->fileChunkSize
- 1) / p
->fileChunkSize
) *
546 sqlite3_int64 currentSize
;
547 MOZ_ASSERT(xFileSize(pFile
, ¤tSize
) == SQLITE_OK
);
548 MOZ_ASSERT(currentSize
>= hintSize
);
555 ** Return the sector-size in bytes for a telemetry_file.
558 xSectorSize(sqlite3_file
*pFile
)
560 telemetry_file
*p
= (telemetry_file
*)pFile
;
562 rc
= p
->pReal
->pMethods
->xSectorSize(p
->pReal
);
567 ** Return the device characteristic flags supported by a telemetry_file.
570 xDeviceCharacteristics(sqlite3_file
*pFile
)
572 telemetry_file
*p
= (telemetry_file
*)pFile
;
574 rc
= p
->pReal
->pMethods
->xDeviceCharacteristics(p
->pReal
);
579 ** Shared-memory operations.
582 xShmLock(sqlite3_file
*pFile
, int ofst
, int n
, int flags
)
584 telemetry_file
*p
= (telemetry_file
*)pFile
;
585 return p
->pReal
->pMethods
->xShmLock(p
->pReal
, ofst
, n
, flags
);
589 xShmMap(sqlite3_file
*pFile
, int iRegion
, int szRegion
, int isWrite
, void volatile **pp
)
591 telemetry_file
*p
= (telemetry_file
*)pFile
;
593 rc
= p
->pReal
->pMethods
->xShmMap(p
->pReal
, iRegion
, szRegion
, isWrite
, pp
);
598 xShmBarrier(sqlite3_file
*pFile
){
599 telemetry_file
*p
= (telemetry_file
*)pFile
;
600 p
->pReal
->pMethods
->xShmBarrier(p
->pReal
);
604 xShmUnmap(sqlite3_file
*pFile
, int delFlag
){
605 telemetry_file
*p
= (telemetry_file
*)pFile
;
607 rc
= p
->pReal
->pMethods
->xShmUnmap(p
->pReal
, delFlag
);
612 xFetch(sqlite3_file
*pFile
, sqlite3_int64 iOff
, int iAmt
, void **pp
)
614 telemetry_file
*p
= (telemetry_file
*)pFile
;
615 MOZ_ASSERT(p
->pReal
->pMethods
->iVersion
>= 3);
616 return p
->pReal
->pMethods
->xFetch(p
->pReal
, iOff
, iAmt
, pp
);
620 xUnfetch(sqlite3_file
*pFile
, sqlite3_int64 iOff
, void *pResOut
)
622 telemetry_file
*p
= (telemetry_file
*)pFile
;
623 MOZ_ASSERT(p
->pReal
->pMethods
->iVersion
>= 3);
624 return p
->pReal
->pMethods
->xUnfetch(p
->pReal
, iOff
, pResOut
);
628 xOpen(sqlite3_vfs
* vfs
, const char *zName
, sqlite3_file
* pFile
,
629 int flags
, int *pOutFlags
)
631 IOThreadAutoTimer
ioTimer(Telemetry::MOZ_SQLITE_OPEN_MS
,
632 IOInterposeObserver::OpCreateOrOpen
);
633 Telemetry::AutoTimer
<Telemetry::MOZ_SQLITE_OPEN_MS
> timer
;
634 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
636 telemetry_file
*p
= (telemetry_file
*)pFile
;
637 Histograms
*h
= nullptr;
638 // check if the filename is one we are probing for
639 for(size_t i
= 0;i
< sizeof(gHistograms
)/sizeof(gHistograms
[0]);i
++) {
641 // last probe is the fallback probe
646 const char *match
= strstr(zName
, h
->name
);
649 char c
= match
[strlen(h
->name
)];
650 // include -wal/-journal too
656 MaybeEstablishQuotaControl(zName
, p
, flags
);
658 rc
= orig_vfs
->xOpen(orig_vfs
, zName
, p
->pReal
, flags
, pOutFlags
);
659 if( rc
!= SQLITE_OK
)
661 if( p
->pReal
->pMethods
){
662 sqlite3_io_methods
*pNew
= new sqlite3_io_methods
;
663 const sqlite3_io_methods
*pSub
= p
->pReal
->pMethods
;
664 memset(pNew
, 0, sizeof(*pNew
));
665 // If the io_methods version is higher than the last known one, you should
666 // update this VFS adding appropriate IO methods for any methods added in
667 // the version change.
668 pNew
->iVersion
= pSub
->iVersion
;
669 MOZ_ASSERT(pNew
->iVersion
<= LAST_KNOWN_IOMETHODS_VERSION
);
670 pNew
->xClose
= xClose
;
672 pNew
->xWrite
= xWrite
;
673 pNew
->xTruncate
= xTruncate
;
675 pNew
->xFileSize
= xFileSize
;
677 pNew
->xUnlock
= xUnlock
;
678 pNew
->xCheckReservedLock
= xCheckReservedLock
;
679 pNew
->xFileControl
= xFileControl
;
680 pNew
->xSectorSize
= xSectorSize
;
681 pNew
->xDeviceCharacteristics
= xDeviceCharacteristics
;
682 if (pNew
->iVersion
>= 2) {
683 // Methods added in version 2.
684 pNew
->xShmMap
= pSub
->xShmMap
? xShmMap
: 0;
685 pNew
->xShmLock
= pSub
->xShmLock
? xShmLock
: 0;
686 pNew
->xShmBarrier
= pSub
->xShmBarrier
? xShmBarrier
: 0;
687 pNew
->xShmUnmap
= pSub
->xShmUnmap
? xShmUnmap
: 0;
689 if (pNew
->iVersion
>= 3) {
690 // Methods added in version 3.
691 // SQLite 3.7.17 calls these methods without checking for nullptr first,
692 // so we always define them. Verify that we're not going to call
694 MOZ_ASSERT(pSub
->xFetch
);
695 pNew
->xFetch
= xFetch
;
696 MOZ_ASSERT(pSub
->xUnfetch
);
697 pNew
->xUnfetch
= xUnfetch
;
699 pFile
->pMethods
= pNew
;
705 xDelete(sqlite3_vfs
* vfs
, const char *zName
, int syncDir
)
707 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
709 RefPtr
<QuotaObject
> quotaObject
;
711 if (StringEndsWith(nsDependentCString(zName
), NS_LITERAL_CSTRING("-wal"))) {
712 const char *zURIParameterKey
= DatabasePathFromWALPath(zName
);
713 MOZ_ASSERT(zURIParameterKey
);
715 quotaObject
= GetQuotaObjectFromNameAndParameters(zName
, zURIParameterKey
);
718 rc
= orig_vfs
->xDelete(orig_vfs
, zName
, syncDir
);
719 if (rc
== SQLITE_OK
&& quotaObject
) {
720 MOZ_ALWAYS_TRUE(quotaObject
->MaybeUpdateSize(0, /* aTruncate */ true));
727 xAccess(sqlite3_vfs
*vfs
, const char *zName
, int flags
, int *pResOut
)
729 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
730 return orig_vfs
->xAccess(orig_vfs
, zName
, flags
, pResOut
);
734 xFullPathname(sqlite3_vfs
*vfs
, const char *zName
, int nOut
, char *zOut
)
736 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
737 return orig_vfs
->xFullPathname(orig_vfs
, zName
, nOut
, zOut
);
741 xDlOpen(sqlite3_vfs
*vfs
, const char *zFilename
)
743 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
744 return orig_vfs
->xDlOpen(orig_vfs
, zFilename
);
748 xDlError(sqlite3_vfs
*vfs
, int nByte
, char *zErrMsg
)
750 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
751 orig_vfs
->xDlError(orig_vfs
, nByte
, zErrMsg
);
755 (*xDlSym(sqlite3_vfs
*vfs
, void *pHdle
, const char *zSym
))(void){
756 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
757 return orig_vfs
->xDlSym(orig_vfs
, pHdle
, zSym
);
761 xDlClose(sqlite3_vfs
*vfs
, void *pHandle
)
763 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
764 orig_vfs
->xDlClose(orig_vfs
, pHandle
);
768 xRandomness(sqlite3_vfs
*vfs
, int nByte
, char *zOut
)
770 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
771 return orig_vfs
->xRandomness(orig_vfs
, nByte
, zOut
);
775 xSleep(sqlite3_vfs
*vfs
, int microseconds
)
777 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
778 return orig_vfs
->xSleep(orig_vfs
, microseconds
);
782 xCurrentTime(sqlite3_vfs
*vfs
, double *prNow
)
784 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
785 return orig_vfs
->xCurrentTime(orig_vfs
, prNow
);
789 xGetLastError(sqlite3_vfs
*vfs
, int nBuf
, char *zBuf
)
791 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
792 return orig_vfs
->xGetLastError(orig_vfs
, nBuf
, zBuf
);
796 xCurrentTimeInt64(sqlite3_vfs
*vfs
, sqlite3_int64
*piNow
)
798 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
799 return orig_vfs
->xCurrentTimeInt64(orig_vfs
, piNow
);
804 xSetSystemCall(sqlite3_vfs
*vfs
, const char *zName
, sqlite3_syscall_ptr pFunc
)
806 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
807 return orig_vfs
->xSetSystemCall(orig_vfs
, zName
, pFunc
);
812 xGetSystemCall(sqlite3_vfs
*vfs
, const char *zName
)
814 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
815 return orig_vfs
->xGetSystemCall(orig_vfs
, zName
);
820 xNextSystemCall(sqlite3_vfs
*vfs
, const char *zName
)
822 sqlite3_vfs
*orig_vfs
= static_cast<sqlite3_vfs
*>(vfs
->pAppData
);
823 return orig_vfs
->xNextSystemCall(orig_vfs
, zName
);
831 sqlite3_vfs
* ConstructTelemetryVFS()
834 #define EXPECTED_VFS "win32"
835 #define EXPECTED_VFS_NFS "win32"
837 #define EXPECTED_VFS "unix"
838 #define EXPECTED_VFS_NFS "unix-excl"
843 if (Preferences::GetBool(PREF_NFS_FILESYSTEM
)) {
844 vfs
= sqlite3_vfs_find(EXPECTED_VFS_NFS
);
845 expected_vfs
= (vfs
!= nullptr);
848 vfs
= sqlite3_vfs_find(nullptr);
849 expected_vfs
= vfs
->zName
&& !strcmp(vfs
->zName
, EXPECTED_VFS
);
855 sqlite3_vfs
*tvfs
= new ::sqlite3_vfs
;
856 memset(tvfs
, 0, sizeof(::sqlite3_vfs
));
857 // If the VFS version is higher than the last known one, you should update
858 // this VFS adding appropriate methods for any methods added in the version
860 tvfs
->iVersion
= vfs
->iVersion
;
861 MOZ_ASSERT(vfs
->iVersion
<= LAST_KNOWN_VFS_VERSION
);
862 tvfs
->szOsFile
= sizeof(telemetry_file
) - sizeof(sqlite3_file
) + vfs
->szOsFile
;
863 tvfs
->mxPathname
= vfs
->mxPathname
;
864 tvfs
->zName
= "telemetry-vfs";
865 tvfs
->pAppData
= vfs
;
867 tvfs
->xDelete
= xDelete
;
868 tvfs
->xAccess
= xAccess
;
869 tvfs
->xFullPathname
= xFullPathname
;
870 tvfs
->xDlOpen
= xDlOpen
;
871 tvfs
->xDlError
= xDlError
;
872 tvfs
->xDlSym
= xDlSym
;
873 tvfs
->xDlClose
= xDlClose
;
874 tvfs
->xRandomness
= xRandomness
;
875 tvfs
->xSleep
= xSleep
;
876 tvfs
->xCurrentTime
= xCurrentTime
;
877 tvfs
->xGetLastError
= xGetLastError
;
878 if (tvfs
->iVersion
>= 2) {
879 // Methods added in version 2.
880 tvfs
->xCurrentTimeInt64
= xCurrentTimeInt64
;
882 if (tvfs
->iVersion
>= 3) {
883 // Methods added in version 3.
884 tvfs
->xSetSystemCall
= xSetSystemCall
;
885 tvfs
->xGetSystemCall
= xGetSystemCall
;
886 tvfs
->xNextSystemCall
= xNextSystemCall
;
891 } // namespace storage
892 } // namespace mozilla