Bug 615978 - Add SQLITE_DBSTATUS_* memory usage to memory reporter
authorDoug Turner <doug.turner@gmail.com>, Shawn Wilsher <me@shawnwilsher.com>
Thu, 31 Mar 2011 10:19:30 -0700
changeset 64470 9e77e9db71287caeed1692d41ea18afdccf9e8c4
parent 64469 6f02e5c7d02c23f84e37037edeca5b09aa46ebe2
child 64471 f38fa181d9020fea120ef50b238603a3c555f1cc
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs615978
milestone2.2a1pre
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
Bug 615978 - Add SQLITE_DBSTATUS_* memory usage to memory reporter Adds some finer-grained memory reporting about SQLite usage. r=asuth
db/sqlite3/src/sqlite.def
storage/src/mozStorageConnection.cpp
storage/src/mozStorageConnection.h
--- a/db/sqlite3/src/sqlite.def
+++ b/db/sqlite3/src/sqlite.def
@@ -79,16 +79,17 @@ EXPORTS
         sqlite3_create_collation
         sqlite3_create_collation16
         sqlite3_create_function
         sqlite3_create_function16
         sqlite3_create_module
         sqlite3_data_count
         sqlite3_db_handle
         sqlite3_db_mutex
+        sqlite3_db_status
         sqlite3_declare_vtab
         sqlite3_enable_load_extension
         sqlite3_enable_shared_cache
         sqlite3_errcode
         sqlite3_errmsg
         sqlite3_errmsg16
         sqlite3_exec
         sqlite3_expired
--- a/storage/src/mozStorageConnection.cpp
+++ b/storage/src/mozStorageConnection.cpp
@@ -43,16 +43,17 @@
 
 #include <stdio.h>
 
 #include "nsError.h"
 #include "nsIMutableArray.h"
 #include "nsHashSets.h"
 #include "nsAutoPtr.h"
 #include "nsIFile.h"
+#include "nsIMemoryReporter.h"
 #include "nsThreadUtils.h"
 #include "nsAutoLock.h"
 
 #include "mozIStorageAggregateFunction.h"
 #include "mozIStorageCompletionCallback.h"
 #include "mozIStorageFunction.h"
 
 #include "mozStorageAsyncStatementExecution.h"
@@ -322,16 +323,110 @@ private:
   nsRefPtr<Connection> mConnection;
   nsCOMPtr<nsIEventTarget> mCallingThread;
   nsCOMPtr<nsIRunnable> mCallbackEvent;
 };
 
 } // anonymous namespace
 
 ////////////////////////////////////////////////////////////////////////////////
+//// Memory Reporting
+
+class StorageMemoryReporter : public nsIMemoryReporter
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  enum ReporterType {
+    LookAside_Used,
+    Cache_Used,
+    Schema_Used,
+    Stmt_Used
+  };
+
+  StorageMemoryReporter(Connection &aDBConn,
+                        ReporterType aType)
+  : mDBConn(aDBConn)
+  , mType(aType)
+  {
+  }
+
+
+  NS_IMETHOD GetPath(char **memoryPath)
+  {
+    nsCString path;
+
+    path.AppendLiteral("storage/");
+    path.Append(mDBConn.getFilename());
+
+    if (mType == LookAside_Used) {
+      path.AppendLiteral("/LookAside_Used");
+    }
+    else if (mType == Cache_Used) {
+      path.AppendLiteral("/Cache_Used");
+    }
+    else if (mType == Schema_Used) {
+      path.AppendLiteral("/Schema_Used");
+    }
+    else if (mType == Stmt_Used) {
+      path.AppendLiteral("/Stmt_Used");
+    }
+
+    *memoryPath = ::ToNewCString(path);
+    return NS_OK;
+  }
+
+  NS_IMETHOD GetDescription(char **desc)
+  {
+    if (mType == LookAside_Used) {
+      *desc = ::strdup("Number of lookaside memory slots currently checked out");
+    }
+    else if (mType == Cache_Used) {
+      *desc = ::strdup("Approximate number of bytes of heap memory used by all pager caches");
+    }
+    else if (mType == Schema_Used) {
+      *desc = ::strdup("Approximate number of bytes of heap memory used to store the schema for all databases associated with the connection");
+    }
+    else if (mType == Stmt_Used) {
+      *desc = ::strdup("Approximate number of bytes of heap and lookaside memory used by all prepared statements");
+    }
+    return NS_OK;
+  }
+
+  NS_IMETHOD GetMemoryUsed(PRInt64 *memoryUsed)
+  {
+    int type = 0;
+    if (mType == LookAside_Used) {
+      type = SQLITE_DBSTATUS_LOOKASIDE_USED;
+    }
+    else if (mType == Cache_Used) {
+      type = SQLITE_DBSTATUS_CACHE_USED;
+    }
+    else if (mType == Schema_Used) {
+      type = SQLITE_DBSTATUS_SCHEMA_USED;
+    }
+    else if (mType == Stmt_Used) {
+      type = SQLITE_DBSTATUS_STMT_USED;
+    }
+
+    int cur=0, max=0;
+    int rc = ::sqlite3_db_status(mDBConn, type, &cur, &max, 0);
+    *memoryUsed = cur;
+    return convertResultCode(rc);
+  }
+  Connection &mDBConn;
+  nsCString mFileName;
+  ReporterType mType;
+};
+NS_IMPL_THREADSAFE_ISUPPORTS1(
+  StorageMemoryReporter
+, nsIMemoryReporter
+)
+
+////////////////////////////////////////////////////////////////////////////////
 //// Connection
 
 Connection::Connection(Service *aService,
                        int aFlags)
 : sharedAsyncExecutionMutex("Connection::sharedAsyncExecutionMutex")
 , sharedDBMutex("Connection::sharedDBMutex")
 , threadOpenedOn(do_GetCurrentThread())
 , mDBConn(nsnull)
@@ -476,16 +571,36 @@ Connection::initialize(nsIFile *aDatabas
       break;
     case 1:
     default:
       (void)ExecuteSimpleSQL(NS_LITERAL_CSTRING(
           "PRAGMA synchronous = NORMAL;"));
       break;
   }
 
+  nsRefPtr<nsIMemoryReporter> reporter;
+  reporter =
+    new StorageMemoryReporter(*this, StorageMemoryReporter::LookAside_Used);
+  mMemoryReporters.AppendElement(reporter);
+
+  reporter =
+    new StorageMemoryReporter(*this, StorageMemoryReporter::Cache_Used);
+  mMemoryReporters.AppendElement(reporter);
+
+  reporter =
+    new StorageMemoryReporter(*this, StorageMemoryReporter::Schema_Used);
+  mMemoryReporters.AppendElement(reporter);
+
+  reporter = new StorageMemoryReporter(*this, StorageMemoryReporter::Stmt_Used);
+  mMemoryReporters.AppendElement(reporter);
+
+  for (PRUint32 i = 0; i < mMemoryReporters.Length(); i++) {
+    (void)::NS_RegisterMemoryReporter(mMemoryReporters[i]);
+  }
+
   return NS_OK;
 }
 
 nsresult
 Connection::databaseElementExists(enum DatabaseElementType aElementType,
                                   const nsACString &aElementName,
                                   PRBool *_exists)
 {
@@ -612,16 +727,20 @@ Connection::internalClose()
   while ((stmt = ::sqlite3_next_stmt(mDBConn, stmt))) {
     char *msg = ::PR_smprintf("SQL statement '%s' was not finalized",
                               ::sqlite3_sql(stmt));
     NS_WARNING(msg);
     ::PR_smprintf_free(msg);
   }
 #endif
 
+  for (PRUint32 i = 0; i < mMemoryReporters.Length(); i++) {
+    (void)::NS_UnregisterMemoryReporter(mMemoryReporters[i]);
+  }
+
   int srv = ::sqlite3_close(mDBConn);
   NS_ASSERTION(srv == SQLITE_OK,
                "sqlite3_close failed. There are probably outstanding statements that are listed above!");
 
   mDBConn = NULL;
   return convertResultCode(srv);
 }
 
--- a/storage/src/mozStorageConnection.h
+++ b/storage/src/mozStorageConnection.h
@@ -56,16 +56,17 @@
 #include "nsIMutableArray.h"
 
 #include "sqlite3.h"
 
 struct PRLock;
 class nsIFile;
 class nsIEventTarget;
 class nsIThread;
+class nsIMemoryReporter;
 
 namespace mozilla {
 namespace storage {
 
 class Connection : public mozIStorageConnection
                  , public nsIInterfaceRequestor
 {
 public:
@@ -107,16 +108,17 @@ public:
    *        The VFS that SQLite will use when opening this database. NULL means
    *        "default".
    */
   nsresult initialize(nsIFile *aDatabaseFile,
                       const char* aVFSName = NULL);
 
   // fetch the native handle
   sqlite3 *GetNativeConnection() { return mDBConn; }
+  operator sqlite3 *() const { return mDBConn; }
 
   /**
    * Lazily creates and returns a background execution thread.  In the future,
    * the thread may be re-claimed if left idle, so you should call this
    * method just before you dispatch and not save the reference.
    *
    * @returns an event target suitable for asynchronous statement execution.
    */
@@ -196,16 +198,18 @@ private:
   // Generic progress handler
   // Dispatch call to registered progress handler,
   // if there is one. Do nothing in other cases.
   int progressHandler();
 
   sqlite3 *mDBConn;
   nsCOMPtr<nsIFile> mDatabaseFile;
 
+  nsTArray<nsCOMPtr<nsIMemoryReporter> > mMemoryReporters;
+
   /**
    * Lazily created thread for asynchronous statement execution.  Consumers
    * should use getAsyncExecutionTarget rather than directly accessing this
    * field.
    */
   nsCOMPtr<nsIThread> mAsyncExecutionThread;
   /**
    * Set to true by Close() prior to actually shutting down the thread.  This