Backed out changesets 50f4ba15a3c7 and cafa8ba33704 (bug 796388) for mochitest-2 orange.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 29 Jan 2013 16:38:37 -0500
changeset 130154 46c47be9d44e79b556d1d44aa233dbfbf1dfc5aa
parent 130153 962cf4a5231c1f64a572b0c09c533fa29c7dd47b
child 130155 0aea65518be3c19767cdc5df1aee23815775ef25
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs796388
milestone21.0a1
backs out50f4ba15a3c7d651030016f28cf8acfa2a160448
cafa8ba33704a3b41cf49f2428e1c9d7ad20a22f
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changesets 50f4ba15a3c7 and cafa8ba33704 (bug 796388) for mochitest-2 orange.
storage/src/Makefile.in
storage/src/TelemetryVFS.cpp
storage/src/mozStorageConnection.cpp
storage/src/mozStorageService.cpp
storage/src/mozStorageService.h
storage/test/unit/test_telemetry_vfs.js
storage/test/unit/xpcshell.ini
toolkit/components/telemetry/Histograms.json
--- a/storage/src/Makefile.in
+++ b/storage/src/Makefile.in
@@ -58,16 +58,17 @@ CPPSRCS = \
   mozStorageBindingParamsArray.cpp \
   mozStorageBindingParams.cpp \
   mozStorageAsyncStatement.cpp \
   mozStorageAsyncStatementJSHelper.cpp \
   mozStorageAsyncStatementParams.cpp \
   StorageBaseStatementInternal.cpp \
   SQLCollations.cpp \
   VacuumManager.cpp \
+  TelemetryVFS.cpp \
   FileSystemModule.cpp \
   $(NULL)
 
 # For nsDependentJSString
 LOCAL_INCLUDES = \
   $(SQLITE_CFLAGS) \
   -I$(topsrcdir)/db/sqlite3/src \
   -I$(topsrcdir)/dom/base \
new file mode 100644
--- /dev/null
+++ b/storage/src/TelemetryVFS.cpp
@@ -0,0 +1,531 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <string.h>
+#include "mozilla/Telemetry.h"
+#include "mozilla/Preferences.h"
+#include "sqlite3.h"
+#include "nsThreadUtils.h"
+#include "mozilla/Util.h"
+#include "mozilla/dom/quota/QuotaManager.h"
+
+/**
+ * This preference is a workaround to allow users/sysadmins to identify
+ * that the profile exists on an NFS share whose implementation
+ * is incompatible with SQLite's default locking implementation.
+ * Bug 433129 attempted to automatically identify such file-systems, 
+ * but a reliable way was not found and it was determined that the fallback 
+ * locking is slower than POSIX locking, so we do not want to do it by default.
+*/
+#define PREF_NFS_FILESYSTEM   "storage.nfs_filesystem"
+
+namespace {
+
+using namespace mozilla;
+using namespace mozilla::dom::quota;
+
+struct Histograms {
+  const char *name;
+  const Telemetry::ID readB;
+  const Telemetry::ID writeB;
+  const Telemetry::ID readMS;
+  const Telemetry::ID writeMS;
+  const Telemetry::ID syncMS;
+};
+
+#define SQLITE_TELEMETRY(FILENAME, HGRAM) \
+  { FILENAME, \
+    Telemetry::MOZ_SQLITE_ ## HGRAM ## _READ_B, \
+    Telemetry::MOZ_SQLITE_ ## HGRAM ## _WRITE_B, \
+    Telemetry::MOZ_SQLITE_ ## HGRAM ## _READ_MS, \
+    Telemetry::MOZ_SQLITE_ ## HGRAM ## _WRITE_MS, \
+    Telemetry::MOZ_SQLITE_ ## HGRAM ## _SYNC_MS \
+  }
+
+Histograms gHistograms[] = {
+  SQLITE_TELEMETRY("places.sqlite", PLACES),
+  SQLITE_TELEMETRY("cookies.sqlite", COOKIES),
+  SQLITE_TELEMETRY("webappsstore.sqlite", WEBAPPS),
+  SQLITE_TELEMETRY(NULL, OTHER)
+};
+#undef SQLITE_TELEMETRY
+
+/** RAII class for measuring how long io takes on/off main thread
+ */
+class IOThreadAutoTimer {
+public:
+  /** 
+   * IOThreadAutoTimer measures time spent in IO. Additionally it
+   * automatically determines whether IO is happening on the main
+   * thread and picks an appropriate histogram.
+   *
+   * @param id takes a telemetry histogram id. The id+1 must be an
+   * equivalent histogram for the main thread. Eg, MOZ_SQLITE_OPEN_MS 
+   * is followed by MOZ_SQLITE_OPEN_MAIN_THREAD_MS.
+   */
+  IOThreadAutoTimer(Telemetry::ID id)
+    : start(TimeStamp::Now()),
+      id(id)
+  {
+  }
+
+  ~IOThreadAutoTimer() {
+    uint32_t mainThread = NS_IsMainThread() ? 1 : 0;
+    Telemetry::AccumulateTimeDelta(static_cast<Telemetry::ID>(id + mainThread),
+                                   start);
+  }
+
+private:
+  const TimeStamp start;
+  const Telemetry::ID id;
+};
+
+struct telemetry_file {
+  // Base class.  Must be first
+  sqlite3_file base;
+
+  // histograms pertaining to this file
+  Histograms *histograms;
+
+  // quota object for this file
+  nsRefPtr<QuotaObject> quotaObject;
+
+  // This contains the vfs that actually does work
+  sqlite3_file pReal[1];
+};
+
+/*
+** Close a telemetry_file.
+*/
+int
+xClose(sqlite3_file *pFile)
+{
+  telemetry_file *p = (telemetry_file *)pFile;
+  int rc;
+  rc = p->pReal->pMethods->xClose(p->pReal);
+  if( rc==SQLITE_OK ){
+    delete p->base.pMethods;
+    p->base.pMethods = NULL;
+    p->quotaObject = nullptr;
+  }
+  return rc;
+}
+
+/*
+** Read data from a telemetry_file.
+*/
+int
+xRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst)
+{
+  telemetry_file *p = (telemetry_file *)pFile;
+  IOThreadAutoTimer ioTimer(p->histograms->readMS);
+  int rc;
+  rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
+  // sqlite likes to read from empty files, this is normal, ignore it.
+  if (rc != SQLITE_IOERR_SHORT_READ)
+    Telemetry::Accumulate(p->histograms->readB, rc == SQLITE_OK ? iAmt : 0);
+  return rc;
+}
+
+/*
+** Write data to a telemetry_file.
+*/
+int
+xWrite(sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst)
+{
+  telemetry_file *p = (telemetry_file *)pFile;
+  if (p->quotaObject && !p->quotaObject->MaybeAllocateMoreSpace(iOfst, iAmt)) {
+    return SQLITE_FULL;
+  }
+  IOThreadAutoTimer ioTimer(p->histograms->writeMS);
+  int rc;
+  rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
+  Telemetry::Accumulate(p->histograms->writeB, rc == SQLITE_OK ? iAmt : 0);
+  return rc;
+}
+
+/*
+** Truncate a telemetry_file.
+*/
+int
+xTruncate(sqlite3_file *pFile, sqlite_int64 size)
+{
+  IOThreadAutoTimer ioTimer(Telemetry::MOZ_SQLITE_TRUNCATE_MS);
+  telemetry_file *p = (telemetry_file *)pFile;
+  int rc;
+  Telemetry::AutoTimer<Telemetry::MOZ_SQLITE_TRUNCATE_MS> timer;
+  rc = p->pReal->pMethods->xTruncate(p->pReal, size);
+  if (rc == SQLITE_OK && p->quotaObject) {
+    p->quotaObject->UpdateSize(size);
+  }
+  return rc;
+}
+
+/*
+** Sync a telemetry_file.
+*/
+int
+xSync(sqlite3_file *pFile, int flags)
+{
+  telemetry_file *p = (telemetry_file *)pFile;
+  IOThreadAutoTimer ioTimer(p->histograms->syncMS);
+  return p->pReal->pMethods->xSync(p->pReal, flags);
+}
+
+/*
+** Return the current file-size of a telemetry_file.
+*/
+int
+xFileSize(sqlite3_file *pFile, sqlite_int64 *pSize)
+{
+  telemetry_file *p = (telemetry_file *)pFile;
+  int rc;
+  rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
+  return rc;
+}
+
+/*
+** Lock a telemetry_file.
+*/
+int
+xLock(sqlite3_file *pFile, int eLock)
+{
+  telemetry_file *p = (telemetry_file *)pFile;
+  int rc;
+  rc = p->pReal->pMethods->xLock(p->pReal, eLock);
+  return rc;
+}
+
+/*
+** Unlock a telemetry_file.
+*/
+int
+xUnlock(sqlite3_file *pFile, int eLock)
+{
+  telemetry_file *p = (telemetry_file *)pFile;
+  int rc;
+  rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
+  return rc;
+}
+
+/*
+** Check if another file-handle holds a RESERVED lock on a telemetry_file.
+*/
+int
+xCheckReservedLock(sqlite3_file *pFile, int *pResOut)
+{
+  telemetry_file *p = (telemetry_file *)pFile;
+  int rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
+  return rc;
+}
+
+/*
+** File control method. For custom operations on a telemetry_file.
+*/
+int
+xFileControl(sqlite3_file *pFile, int op, void *pArg)
+{
+  telemetry_file *p = (telemetry_file *)pFile;
+  int rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
+  return rc;
+}
+
+/*
+** Return the sector-size in bytes for a telemetry_file.
+*/
+int
+xSectorSize(sqlite3_file *pFile)
+{
+  telemetry_file *p = (telemetry_file *)pFile;
+  int rc;
+  rc = p->pReal->pMethods->xSectorSize(p->pReal);
+  return rc;
+}
+
+/*
+** Return the device characteristic flags supported by a telemetry_file.
+*/
+int
+xDeviceCharacteristics(sqlite3_file *pFile)
+{
+  telemetry_file *p = (telemetry_file *)pFile;
+  int rc;
+  rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
+  return rc;
+}
+
+/*
+** Shared-memory operations.
+*/
+int
+xShmLock(sqlite3_file *pFile, int ofst, int n, int flags)
+{
+  telemetry_file *p = (telemetry_file *)pFile;
+  return p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
+}
+
+int
+xShmMap(sqlite3_file *pFile, int iRegion, int szRegion, int isWrite, void volatile **pp)
+{
+  telemetry_file *p = (telemetry_file *)pFile;
+  int rc;
+  rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
+  return rc;
+}
+
+void
+xShmBarrier(sqlite3_file *pFile){
+  telemetry_file *p = (telemetry_file *)pFile;
+  p->pReal->pMethods->xShmBarrier(p->pReal);
+}
+
+int
+xShmUnmap(sqlite3_file *pFile, int delFlag){
+  telemetry_file *p = (telemetry_file *)pFile;
+  int rc;
+  rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
+  return rc;
+}
+ 
+int
+xOpen(sqlite3_vfs* vfs, const char *zName, sqlite3_file* pFile,
+          int flags, int *pOutFlags)
+{
+  IOThreadAutoTimer ioTimer(Telemetry::MOZ_SQLITE_OPEN_MS);
+  Telemetry::AutoTimer<Telemetry::MOZ_SQLITE_OPEN_MS> timer;
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  int rc;
+  telemetry_file *p = (telemetry_file *)pFile;
+  Histograms *h = NULL;
+  // check if the filename is one we are probing for
+  for(size_t i = 0;i < sizeof(gHistograms)/sizeof(gHistograms[0]);i++) {
+    h = &gHistograms[i];
+    // last probe is the fallback probe
+    if (!h->name)
+      break;
+    if (!zName)
+      continue;
+    const char *match = strstr(zName, h->name);
+    if (!match)
+      continue;
+    char c = match[strlen(h->name)];
+    // include -wal/-journal too
+    if (!c || c == '-')
+      break;
+  }
+  p->histograms = h;
+
+  const char* origin;
+  if ((flags & SQLITE_OPEN_URI) &&
+      (origin = sqlite3_uri_parameter(zName, "origin"))) {
+    QuotaManager* quotaManager = QuotaManager::Get();
+    MOZ_ASSERT(quotaManager);
+
+    p->quotaObject = quotaManager->GetQuotaObject(nsDependentCString(origin),
+                                                  NS_ConvertUTF8toUTF16(zName));
+
+  }
+
+  rc = orig_vfs->xOpen(orig_vfs, zName, p->pReal, flags, pOutFlags);
+  if( rc != SQLITE_OK )
+    return rc;
+  if( p->pReal->pMethods ){
+    sqlite3_io_methods *pNew = new sqlite3_io_methods;
+    const sqlite3_io_methods *pSub = p->pReal->pMethods;
+    memset(pNew, 0, sizeof(*pNew));
+    pNew->iVersion = pSub->iVersion;
+    pNew->xClose = xClose;
+    pNew->xRead = xRead;
+    pNew->xWrite = xWrite;
+    pNew->xTruncate = xTruncate;
+    pNew->xSync = xSync;
+    pNew->xFileSize = xFileSize;
+    pNew->xLock = xLock;
+    pNew->xUnlock = xUnlock;
+    pNew->xCheckReservedLock = xCheckReservedLock;
+    pNew->xFileControl = xFileControl;
+    pNew->xSectorSize = xSectorSize;
+    pNew->xDeviceCharacteristics = xDeviceCharacteristics;
+    if( pNew->iVersion>=2 ){
+      pNew->xShmMap = pSub->xShmMap ? xShmMap : 0;
+      pNew->xShmLock = pSub->xShmLock ? xShmLock : 0;
+      pNew->xShmBarrier = pSub->xShmBarrier ? xShmBarrier : 0;
+      pNew->xShmUnmap = pSub->xShmUnmap ? xShmUnmap : 0;
+    }
+    pFile->pMethods = pNew;
+  }
+  return rc;
+}
+
+int
+xDelete(sqlite3_vfs* vfs, const char *zName, int syncDir)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  return orig_vfs->xDelete(orig_vfs, zName, syncDir);
+}
+
+int
+xAccess(sqlite3_vfs *vfs, const char *zName, int flags, int *pResOut)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  return orig_vfs->xAccess(orig_vfs, zName, flags, pResOut);
+}
+
+int
+xFullPathname(sqlite3_vfs *vfs, const char *zName, int nOut, char *zOut)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  return orig_vfs->xFullPathname(orig_vfs, zName, nOut, zOut);
+}
+
+void*
+xDlOpen(sqlite3_vfs *vfs, const char *zFilename)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  return orig_vfs->xDlOpen(orig_vfs, zFilename);
+}
+
+void
+xDlError(sqlite3_vfs *vfs, int nByte, char *zErrMsg)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  orig_vfs->xDlError(orig_vfs, nByte, zErrMsg);
+}
+
+void 
+(*xDlSym(sqlite3_vfs *vfs, void *pHdle, const char *zSym))(void){
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  return orig_vfs->xDlSym(orig_vfs, pHdle, zSym);
+}
+
+void
+xDlClose(sqlite3_vfs *vfs, void *pHandle)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  orig_vfs->xDlClose(orig_vfs, pHandle);
+}
+
+int
+xRandomness(sqlite3_vfs *vfs, int nByte, char *zOut)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  return orig_vfs->xRandomness(orig_vfs, nByte, zOut);
+}
+
+int
+xSleep(sqlite3_vfs *vfs, int microseconds)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  return orig_vfs->xSleep(orig_vfs, microseconds);
+}
+
+int
+xCurrentTime(sqlite3_vfs *vfs, double *prNow)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  return orig_vfs->xCurrentTime(orig_vfs, prNow);
+}
+
+int
+xGetLastError(sqlite3_vfs *vfs, int nBuf, char *zBuf)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  return orig_vfs->xGetLastError(orig_vfs, nBuf, zBuf);
+}
+
+int
+xCurrentTimeInt64(sqlite3_vfs *vfs, sqlite3_int64 *piNow)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  return orig_vfs->xCurrentTimeInt64(orig_vfs, piNow);
+}
+
+static
+int
+xSetSystemCall(sqlite3_vfs *vfs, const char *zName, sqlite3_syscall_ptr pFunc)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  return orig_vfs->xSetSystemCall(orig_vfs, zName, pFunc);
+}
+
+static
+sqlite3_syscall_ptr
+xGetSystemCall(sqlite3_vfs *vfs, const char *zName)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  return orig_vfs->xGetSystemCall(orig_vfs, zName);
+}
+
+static
+const char *
+xNextSystemCall(sqlite3_vfs *vfs, const char *zName)
+{
+  sqlite3_vfs *orig_vfs = static_cast<sqlite3_vfs*>(vfs->pAppData);
+  return orig_vfs->xNextSystemCall(orig_vfs, zName);
+}
+
+}
+
+namespace mozilla {
+namespace storage {
+
+sqlite3_vfs* ConstructTelemetryVFS()
+{
+#if defined(XP_WIN)
+#define EXPECTED_VFS     "win32"
+#define EXPECTED_VFS_NFS "win32"
+#else
+#define EXPECTED_VFS     "unix"
+#define EXPECTED_VFS_NFS "unix-excl"
+#endif
+  
+  bool expected_vfs;
+  sqlite3_vfs *vfs;
+  if (Preferences::GetBool(PREF_NFS_FILESYSTEM)) {
+    vfs = sqlite3_vfs_find(EXPECTED_VFS_NFS);
+    expected_vfs = (vfs != nullptr);
+  }
+  else {
+    vfs = sqlite3_vfs_find(NULL);
+    expected_vfs = vfs->zName && !strcmp(vfs->zName, EXPECTED_VFS);
+  }
+  if (!expected_vfs) {
+    return NULL;
+  }
+
+  sqlite3_vfs *tvfs = new ::sqlite3_vfs;
+  memset(tvfs, 0, sizeof(::sqlite3_vfs));
+  tvfs->iVersion = 3;
+  // If the SQLite VFS version is updated, this shim must be updated as well.
+  MOZ_ASSERT(vfs->iVersion == tvfs->iVersion);
+  tvfs->szOsFile = sizeof(telemetry_file) - sizeof(sqlite3_file) + vfs->szOsFile;
+  tvfs->mxPathname = vfs->mxPathname;
+  tvfs->zName = "telemetry-vfs";
+  tvfs->pAppData = vfs;
+  tvfs->xOpen = xOpen;
+  tvfs->xDelete = xDelete;
+  tvfs->xAccess = xAccess;
+  tvfs->xFullPathname = xFullPathname;
+  tvfs->xDlOpen = xDlOpen;
+  tvfs->xDlError = xDlError;
+  tvfs->xDlSym = xDlSym;
+  tvfs->xDlClose = xDlClose;
+  tvfs->xRandomness = xRandomness;
+  tvfs->xSleep = xSleep;
+  tvfs->xCurrentTime = xCurrentTime;
+  tvfs->xGetLastError = xGetLastError;
+  // Added in version 2.
+  tvfs->xCurrentTimeInt64 = xCurrentTimeInt64;
+  // Added in version 3.
+  tvfs->xSetSystemCall = xSetSystemCall;
+  tvfs->xGetSystemCall = xGetSystemCall;
+  tvfs->xNextSystemCall = xNextSystemCall;
+
+  return tvfs;
+}
+
+}
+}
--- a/storage/src/mozStorageConnection.cpp
+++ b/storage/src/mozStorageConnection.cpp
@@ -497,17 +497,17 @@ Connection::initialize(nsIFile *aDatabas
 
   mDatabaseFile = aDatabaseFile;
 
   nsAutoString path;
   nsresult rv = aDatabaseFile->GetPath(path);
   NS_ENSURE_SUCCESS(rv, rv);
 
   int srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn,
-                              mFlags, mStorageService->getVFSName());
+                              mFlags, NULL);
   if (srv != SQLITE_OK) {
     mDBConn = nullptr;
     return convertResultCode(srv);
   }
 
   rv = initializeInternal(aDatabaseFile);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -526,18 +526,17 @@ Connection::initialize(nsIFileURL *aFile
   nsCOMPtr<nsIFile> databaseFile;
   nsresult rv = aFileURL->GetFile(getter_AddRefs(databaseFile));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoCString spec;
   rv = aFileURL->GetSpec(spec);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  int srv = ::sqlite3_open_v2(spec.get(), &mDBConn, mFlags,
-                              mStorageService->getVFSName());
+  int srv = ::sqlite3_open_v2(spec.get(), &mDBConn, mFlags, NULL);
   if (srv != SQLITE_OK) {
     mDBConn = nullptr;
     return convertResultCode(srv);
   }
 
   rv = initializeInternal(databaseFile);
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/storage/src/mozStorageService.cpp
+++ b/storage/src/mozStorageService.cpp
@@ -34,35 +34,16 @@
 #include "nsIMemoryReporter.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Defines
 
 #define PREF_TS_SYNCHRONOUS "toolkit.storage.synchronous"
 #define PREF_TS_SYNCHRONOUS_DEFAULT 1
 
-/**
- * This preference is a workaround to allow users/sysadmins to identify
- * that the profile exists on an NFS share whose implementation is
- * incompatible with SQLite's default locking implementation.  Bug
- * 433129 attempted to automatically identify such file-systems, but a
- * reliable way was not found and it was determined that the fallback
- * locking is slower than POSIX locking, so we do not want to do it by
- * default.
- */
-#define PREF_NFS_FILESYSTEM   "storage.nfs_filesystem"
-
-#if defined(XP_WIN)
-#define STANDARD_VFS "win32"
-#define NFS_VFS "win32"
-#else
-#define STANDARD_VFS "unix"
-#define NFS_VFS "unix-excl"
-#endif
-
 namespace mozilla {
 namespace storage {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Memory Reporting
 
 static int64_t
 GetStorageSQLiteMemoryUsed()
@@ -243,23 +224,21 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(
 //// Helpers
 
 class ServiceMainThreadInitializer : public nsRunnable
 {
 public:
   ServiceMainThreadInitializer(Service *aService,
                                nsIObserver *aObserver,
                                nsIXPConnect **aXPConnectPtr,
-                               int32_t *aSynchronousPrefValPtr,
-                               const char **aVFSNamePtr)
+                               int32_t *aSynchronousPrefValPtr)
   : mService(aService)
   , mObserver(aObserver)
   , mXPConnectPtr(aXPConnectPtr)
   , mSynchronousPrefValPtr(aSynchronousPrefValPtr)
-  , mVFSNamePtr(aVFSNamePtr)
   {
   }
 
   NS_IMETHOD Run()
   {
     NS_PRECONDITION(NS_IsMainThread(), "Must be running on the main thread!");
 
     // NOTE:  All code that can only run on the main thread and needs to be run
@@ -284,39 +263,31 @@ public:
 
     // We need to obtain the toolkit.storage.synchronous preferences on the main
     // thread because the preference service can only be accessed there.  This
     // is cached in the service for all future Open[Unshared]Database calls.
     int32_t synchronous =
       Preferences::GetInt(PREF_TS_SYNCHRONOUS, PREF_TS_SYNCHRONOUS_DEFAULT);
     ::PR_ATOMIC_SET(mSynchronousPrefValPtr, synchronous);
 
-    // Likewise for whether we're on an NFS filesystem.
-    if (Preferences::GetBool(PREF_NFS_FILESYSTEM)) {
-      *mVFSNamePtr = NFS_VFS;
-    } else {
-      *mVFSNamePtr = STANDARD_VFS;
-    }
-
     // Create and register our SQLite memory reporters.  Registration can only
     // happen on the main thread (otherwise you'll get cryptic crashes).
     mService->mStorageSQLiteReporter = new NS_MEMORY_REPORTER_NAME(StorageSQLite);
     mService->mStorageSQLiteMultiReporter = new StorageSQLiteMultiReporter(mService);
     (void)::NS_RegisterMemoryReporter(mService->mStorageSQLiteReporter);
     (void)::NS_RegisterMemoryMultiReporter(mService->mStorageSQLiteMultiReporter);
 
     return NS_OK;
   }
 
 private:
   Service *mService;
   nsIObserver *mObserver;
   nsIXPConnect **mXPConnectPtr;
   int32_t *mSynchronousPrefValPtr;
-  const char **mVFSNamePtr;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Service
 
 NS_IMPL_THREADSAFE_ISUPPORTS2(
   Service,
   mozIStorageService,
@@ -383,49 +354,47 @@ int32_t Service::sSynchronousPref;
 
 // static
 int32_t
 Service::getSynchronousPref()
 {
   return sSynchronousPref;
 }
 
-const char *Service::sVFSName;
-
-// static
-const char *
-Service::getVFSName()
-{
-  return sVFSName;
-}
-
 Service::Service()
 : mMutex("Service::mMutex")
+, mSqliteVFS(nullptr)
 , mRegistrationMutex("Service::mRegistrationMutex")
 , mConnections()
 , mStorageSQLiteReporter(nullptr)
 , mStorageSQLiteMultiReporter(nullptr)
 {
 }
 
 Service::~Service()
 {
   (void)::NS_UnregisterMemoryReporter(mStorageSQLiteReporter);
   (void)::NS_UnregisterMemoryMultiReporter(mStorageSQLiteMultiReporter);
 
+  int rc = sqlite3_vfs_unregister(mSqliteVFS);
+  if (rc != SQLITE_OK)
+    NS_WARNING("Failed to unregister sqlite vfs wrapper.");
+
   // Shutdown the sqlite3 API.  Warn if shutdown did not turn out okay, but
   // there is nothing actionable we can do in that case.
-  int rc = ::sqlite3_shutdown();
+  rc = ::sqlite3_shutdown();
   if (rc != SQLITE_OK)
     NS_WARNING("sqlite3 did not shutdown cleanly.");
 
   DebugOnly<bool> shutdownObserved = !sXPConnect;
   NS_ASSERTION(shutdownObserved, "Shutdown was not observed!");
 
   gService = nullptr;
+  delete mSqliteVFS;
+  mSqliteVFS = nullptr;
 }
 
 void
 Service::registerConnection(Connection *aConnection)
 {
   mRegistrationMutex.AssertNotCurrentThreadOwns();
   MutexAutoLock mutex(mRegistrationMutex);
   (void)mConnections.AppendElement(aConnection);
@@ -457,16 +426,18 @@ Service::getConnections(/* inout */ nsTA
 }
 
 void
 Service::shutdown()
 {
   NS_IF_RELEASE(sXPConnect);
 }
 
+sqlite3_vfs *ConstructTelemetryVFS();
+
 #ifdef MOZ_STORAGE_MEMORY
 #  include "mozmemory.h"
 
 namespace {
 
 // By default, SQLite tracks the size of all its heap blocks by adding an extra
 // 8 bytes at the start of the block to hold the size.  Unfortunately, this
 // causes a lot of 2^N-sized allocations to be rounded up by jemalloc
@@ -590,24 +561,32 @@ Service::initialize()
 
   // Explicitly initialize sqlite3.  Although this is implicitly called by
   // various sqlite3 functions (and the sqlite3_open calls in our case),
   // the documentation suggests calling this directly.  So we do.
   rc = ::sqlite3_initialize();
   if (rc != SQLITE_OK)
     return convertResultCode(rc);
 
+  mSqliteVFS = ConstructTelemetryVFS();
+  if (mSqliteVFS) {
+    rc = sqlite3_vfs_register(mSqliteVFS, 1);
+    if (rc != SQLITE_OK)
+      return convertResultCode(rc);
+  } else {
+    NS_WARNING("Failed to register telemetry VFS");
+  }
+
   // Set the default value for the toolkit.storage.synchronous pref.  It will be
   // updated with the user preference on the main thread.
   sSynchronousPref = PREF_TS_SYNCHRONOUS_DEFAULT;
 
   // Run the things that need to run on the main thread there.
   nsCOMPtr<nsIRunnable> event =
-    new ServiceMainThreadInitializer(this, this, &sXPConnect, &sSynchronousPref,
-                                     &sVFSName);
+    new ServiceMainThreadInitializer(this, this, &sXPConnect, &sSynchronousPref);
   if (event && ::NS_IsMainThread()) {
     (void)event->Run();
   }
   else {
     (void)::NS_DispatchToMainThread(event);
   }
 
   return NS_OK;
--- a/storage/src/mozStorageService.h
+++ b/storage/src/mozStorageService.h
@@ -14,16 +14,17 @@
 #include "nsTArray.h"
 #include "mozilla/Mutex.h"
 
 #include "mozIStorageService.h"
 
 class nsIMemoryReporter;
 class nsIMemoryMultiReporter;
 class nsIXPConnect;
+struct sqlite3_vfs;
 
 namespace mozilla {
 namespace storage {
 
 class Connection;
 class Service : public mozIStorageService
               , public nsIObserver
 {
@@ -63,21 +64,16 @@ public:
   static already_AddRefed<nsIXPConnect> getXPConnect();
 
   /**
    * Obtains the cached data for the toolkit.storage.synchronous preference.
    */
   static int32_t getSynchronousPref();
 
   /**
-   * Returns the name of the sqlite3 VFS to use for file-backed databases.
-   */
-  static const char *getVFSName();
-
-  /**
    * Registers the connection with the storage service.  Connections are
    * registered so they can be iterated over.
    *
    * @pre mRegistrationMutex is not held
    *
    * @param  aConnection
    *         The connection to register.
    */
@@ -113,16 +109,18 @@ private:
 
   /**
    * Used for 1) locking around calls when initializing connections so that we
    * can ensure that the state of sqlite3_enable_shared_cache is sane and 2)
    * synchronizing access to mLocaleCollation.
    */
   Mutex mMutex;
   
+  sqlite3_vfs *mSqliteVFS;
+
   /**
    * Protects mConnections.
    */
   Mutex mRegistrationMutex;
 
   /**
    * The list of connections we have created.  Modifications to it are
    * protected by |mRegistrationMutex|.
@@ -158,17 +156,15 @@ private:
   nsCOMPtr<nsIMemoryMultiReporter> mStorageSQLiteMultiReporter;
 
   static Service *gService;
 
   static nsIXPConnect *sXPConnect;
 
   static int32_t sSynchronousPref;
 
-  static const char *sVFSName;
-
   friend class ServiceMainThreadInitializer;
 };
 
 } // namespace storage
 } // namespace mozilla
 
 #endif /* MOZSTORAGESERVICE_H */
new file mode 100644
--- /dev/null
+++ b/storage/test/unit/test_telemetry_vfs.js
@@ -0,0 +1,30 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Make sure that there are telemetry entries created by sqlite io
+
+function run_sql(d, sql) {
+  var stmt = d.createStatement(sql)
+  stmt.execute()
+  stmt.finalize();
+}
+
+function new_file(name)
+{
+  var file = dirSvc.get("ProfD", Ci.nsIFile);
+  file.append(name);
+  return file;
+}
+function run_test()
+{
+  const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
+  let read_hgram = Telemetry.getHistogramById("MOZ_SQLITE_OTHER_READ_B");
+  let old_sum = read_hgram.snapshot().sum;
+  const file = new_file("telemetry.sqlite");
+  var d = getDatabase(file);
+  run_sql(d, "CREATE TABLE bloat(data varchar)");
+  run_sql(d, "DROP TABLE bloat")
+  do_check_true(read_hgram.snapshot().sum > old_sum)
+}
+
--- a/storage/test/unit/xpcshell.ini
+++ b/storage/test/unit/xpcshell.ini
@@ -26,10 +26,11 @@ fail-if = os == "android"
 [test_storage_function.js]
 [test_storage_progresshandler.js]
 [test_storage_service.js]
 [test_storage_service_unshared.js]
 [test_storage_statement.js]
 [test_storage_value_array.js]
 [test_unicode.js]
 [test_vacuum.js]
+[test_telemetry_vfs.js]
 # Bug 676981: test fails consistently on Android
 # fail-if = os == "android"
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -1473,16 +1473,232 @@
     "description": "Whether the user has requested not to see the Plugin Hang UI again"
   },
   "PLUGIN_SHUTDOWN_MS": {
     "kind": "exponential",
     "high": "5000",
     "n_buckets": 20,
     "description": "Time spent shutting down plugins (ms)"
   },
+  "MOZ_SQLITE_OPEN_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite open() (ms)"
+  },
+  "MOZ_SQLITE_OPEN_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite open() (ms)"
+  },
+  "MOZ_SQLITE_TRUNCATE_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite truncate() (ms)"
+  },
+  "MOZ_SQLITE_TRUNCATE_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite truncate() (ms)"
+  },
+  "MOZ_SQLITE_OTHER_READ_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite read() (ms)"
+  },
+  "MOZ_SQLITE_OTHER_READ_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite read() (ms)"
+  },
+  "MOZ_SQLITE_PLACES_READ_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite read() (ms)"
+  },
+  "MOZ_SQLITE_PLACES_READ_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite read() (ms)"
+  },
+  "MOZ_SQLITE_COOKIES_READ_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite read() (ms)"
+  },
+  "MOZ_SQLITE_COOKIES_READ_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite read() (ms)"
+  },
+  "MOZ_SQLITE_WEBAPPS_READ_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite read() (ms)"
+  },
+  "MOZ_SQLITE_WEBAPPS_READ_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite read() (ms)"
+  },
+  "MOZ_SQLITE_OTHER_WRITE_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite write() (ms)"
+  },
+  "MOZ_SQLITE_OTHER_WRITE_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite write() (ms)"
+  },
+  "MOZ_SQLITE_PLACES_WRITE_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite write() (ms)"
+  },
+  "MOZ_SQLITE_PLACES_WRITE_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite write() (ms)"
+  },
+  "MOZ_SQLITE_COOKIES_WRITE_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite write() (ms)"
+  },
+  "MOZ_SQLITE_COOKIES_WRITE_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite write() (ms)"
+  },
+  "MOZ_SQLITE_WEBAPPS_WRITE_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite write() (ms)"
+  },
+  "MOZ_SQLITE_WEBAPPS_WRITE_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite write() (ms)"
+  },
+  "MOZ_SQLITE_OTHER_SYNC_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite fsync() (ms)"
+  },
+  "MOZ_SQLITE_OTHER_SYNC_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite fsync() (ms)"
+  },
+  "MOZ_SQLITE_PLACES_SYNC_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite fsync() (ms)"
+  },
+  "MOZ_SQLITE_PLACES_SYNC_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite fsync() (ms)"
+  },
+  "MOZ_SQLITE_COOKIES_SYNC_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite fsync() (ms)"
+  },
+  "MOZ_SQLITE_COOKIES_SYNC_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite fsync() (ms)"
+  },
+  "MOZ_SQLITE_WEBAPPS_SYNC_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite fsync() (ms)"
+  },
+  "MOZ_SQLITE_WEBAPPS_SYNC_MAIN_THREAD_MS": {
+    "kind": "exponential",
+    "high": "3000",
+    "n_buckets": 10,
+    "description": "Time spent on SQLite fsync() (ms)"
+  },
+  "MOZ_SQLITE_OTHER_READ_B": {
+    "kind": "linear",
+    "high": "32768",
+    "n_buckets": 3,
+    "description": "SQLite read() (bytes)"
+  },
+  "MOZ_SQLITE_PLACES_READ_B": {
+    "kind": "linear",
+    "high": "32768",
+    "n_buckets": 3,
+    "description": "SQLite read() (bytes)"
+  },
+  "MOZ_SQLITE_COOKIES_READ_B": {
+    "kind": "linear",
+    "high": "32768",
+    "n_buckets": 3,
+    "description": "SQLite read() (bytes)"
+  },
+  "MOZ_SQLITE_WEBAPPS_READ_B": {
+    "kind": "linear",
+    "high": "32768",
+    "n_buckets": 3,
+    "description": "SQLite read() (bytes)"
+  },
+  "MOZ_SQLITE_PLACES_WRITE_B": {
+    "kind": "linear",
+    "high": "32768",
+    "n_buckets": 3,
+    "description": "SQLite write (bytes)"
+  },
+  "MOZ_SQLITE_COOKIES_WRITE_B": {
+    "kind": "linear",
+    "high": "32768",
+    "n_buckets": 3,
+    "description": "SQLite write (bytes)"
+  },
+  "MOZ_SQLITE_WEBAPPS_WRITE_B": {
+    "kind": "linear",
+    "high": "32768",
+    "n_buckets": 3,
+    "description": "SQLite write (bytes)"
+  },
+  "MOZ_SQLITE_OTHER_WRITE_B": {
+    "kind": "linear",
+    "high": "32768",
+    "n_buckets": 3,
+    "description": "SQLite write (bytes)"
+  },
   "MOZ_STORAGE_ASYNC_REQUESTS_MS": {
     "kind": "exponential",
     "high": "32768",
     "n_buckets": 20,
     "description": "mozStorage async requests completion (ms)"
   },
   "MOZ_STORAGE_ASYNC_REQUESTS_SUCCESS": {
     "kind": "boolean",