Bug 691509 - Run ANALYZE at each schema change (and force a schema change).
authorMarco Bonardo <mbonardo@mozilla.com>
Fri, 07 Oct 2011 21:10:44 +0200
changeset 78372 87a98d668e0c0af76a745bece734a140c65af981
parent 78371 b16c81fc5e94fa7ac444a4e105d54f51fe292f30
child 78373 198dbe19cfaa8f5ba2ebed179cd554cdd68b0d85
push id21291
push userkhuey@mozilla.com
push dateSun, 09 Oct 2011 14:20:19 +0000
treeherdermozilla-central@36cadf889624 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs691509
milestone10.0a1
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 691509 - Run ANALYZE at each schema change (and force a schema change). Partly copied from a patch by Richard Newman. r=dietrich
toolkit/components/places/nsNavHistory.cpp
toolkit/components/places/nsPlacesExpiration.js
toolkit/components/places/tests/head_common.js
toolkit/components/places/tests/migration/test_current_from_v10.js
toolkit/components/places/tests/migration/test_current_from_v10_migrated_from_v11.js
toolkit/components/places/tests/migration/test_v11_from_v10.js
toolkit/components/places/tests/migration/test_v11_from_v10_migrated_from_v11.js
toolkit/components/places/tests/migration/xpcshell.ini
toolkit/components/places/tests/unit/test_analyze.js
toolkit/components/places/tests/unit/xpcshell.ini
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -158,17 +158,17 @@ using namespace mozilla::places;
 // crashes we could lose all the transactions in the file.  But a too small
 // file could hurt performance.
 #define DATABASE_MAX_WAL_SIZE_IN_KIBIBYTES 512
 
 #define BYTES_PER_MEBIBYTE 1048576
 
 // This is the schema version, update it at any schema change and add a
 // corresponding migrateVxx method below.
-#define DATABASE_SCHEMA_VERSION 11
+#define DATABASE_SCHEMA_VERSION 12
 
 // Filename of the database.
 #define DATABASE_FILENAME NS_LITERAL_STRING("places.sqlite")
 
 // Filename used to backup corrupt databases.
 #define DATABASE_CORRUPT_FILENAME NS_LITERAL_STRING("places.sqlite.corrupt")
 
 // In order to avoid calling PR_now() too often we use a cached "now" value
@@ -308,16 +308,59 @@ namespace mozilla {
                "AND t_t.parent = ") +
                nsPrintfCString("%lld", aTagsFolder) + NS_LITERAL_CSTRING(" "
              ")"));
       }
 
       _sqlFragment.AppendLiteral(" AS tags ");
     }
 
+    /**
+     * Updates sqlite_stat1 table through ANALYZE.
+     * Since also nsPlacesExpiration.js executes ANALYZE, the analyzed tables
+     * must be the same in both components.  So ensure they are in sync.
+     */
+    nsresult updateSQLiteStatistics(mozIStorageConnection* aDBConn)
+    {
+      nsCOMPtr<mozIStorageAsyncStatement> analyzePlacesStmt;
+      nsresult rv = aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
+        "ANALYZE moz_places"
+      ), getter_AddRefs(analyzePlacesStmt));
+      NS_ENSURE_SUCCESS(rv, rv);
+      nsCOMPtr<mozIStorageAsyncStatement> analyzeBookmarksStmt;
+      rv = aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
+        "ANALYZE moz_bookmarks"
+      ), getter_AddRefs(analyzeBookmarksStmt));
+      NS_ENSURE_SUCCESS(rv, rv);
+      nsCOMPtr<mozIStorageAsyncStatement> analyzeVisitsStmt;
+      rv = aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
+        "ANALYZE moz_historyvisits"
+      ), getter_AddRefs(analyzeVisitsStmt));
+      NS_ENSURE_SUCCESS(rv, rv);
+      nsCOMPtr<mozIStorageAsyncStatement> analyzeInputStmt;
+      rv = aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
+        "ANALYZE moz_inputhistory"
+      ), getter_AddRefs(analyzeInputStmt));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      mozIStorageBaseStatement *stmts[] = {
+        analyzePlacesStmt,
+        analyzeBookmarksStmt,
+        analyzeVisitsStmt,
+        analyzeInputStmt
+      };
+
+      nsCOMPtr<mozIStoragePendingStatement> ps;
+      rv = aDBConn->ExecuteAsync(stmts, NS_ARRAY_LENGTH(stmts), nsnull,
+                                 getter_AddRefs(ps));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      return NS_OK;
+    }
+
   } // namespace places
 } // namespace mozilla
 
 
 namespace {
 
 /**
  * This class sets begin/end of batch updates to correspond to C++ scopes so
@@ -923,16 +966,19 @@ nsNavHistory::InitDB()
     rv = nsAnnotationService::InitTables(mDBConn);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Set the schema version to the current one.
   rv = UpdateSchemaVersion();
   NS_ENSURE_SUCCESS(rv, rv);
 
+  rv = updateSQLiteStatistics(mDBConn);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   ForceWALCheckpoint(mDBConn);
 
   // ANY FAILURE IN THIS METHOD WILL CAUSE US TO MARK THE DATABASE AS CORRUPT
   // AND TRY TO REPLACE IT.
   // DO NOT PUT HERE ANYTHING THAT IS NOT RELATED TO INITIALIZATION OR MODIFYING
--- a/toolkit/components/places/nsPlacesExpiration.js
+++ b/toolkit/components/places/nsPlacesExpiration.js
@@ -399,16 +399,18 @@ const EXPIRATION_QUERIES = {
     sql: "DELETE FROM expiration_notify",
     actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN |
              ACTION.IDLE | ACTION.DEBUG
   },
 
   // The following queries are used to adjust the sqlite_stat1 table to help the
   // query planner create better queries.  These should always be run LAST, and
   // are therefore at the end of the object.
+  // Since also nsNavHistory.cpp executes ANALYZE, the analyzed tables
+  // must be the same in both components.  So ensure they are in sync.
 
   QUERY_ANALYZE_MOZ_PLACES: {
     sql: "ANALYZE moz_places",
     actions: ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY | ACTION.IDLE |
              ACTION.DEBUG
   },
   QUERY_ANALYZE_MOZ_BOOKMARKS: {
     sql: "ANALYZE moz_bookmarks",
--- a/toolkit/components/places/tests/head_common.js
+++ b/toolkit/components/places/tests/head_common.js
@@ -30,16 +30,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+const CURRENT_SCHEMA_VERSION = 12;
+
 const NS_APP_USER_PROFILE_50_DIR = "ProfD";
 const NS_APP_PROFILE_DIR_STARTUP = "ProfDS";
 const NS_APP_BOOKMARKS_50_FILE = "BMarks";
 
 // Shortcuts to transitions type.
 const TRANSITION_LINK = Ci.nsINavHistoryService.TRANSITION_LINK;
 const TRANSITION_TYPED = Ci.nsINavHistoryService.TRANSITION_TYPED;
 const TRANSITION_BOOKMARK = Ci.nsINavHistoryService.TRANSITION_BOOKMARK;
@@ -140,17 +142,17 @@ function DBConn() {
  */ 
 function readInputStreamData(aStream) {
   let bistream = Cc["@mozilla.org/binaryinputstream;1"].
                  createInstance(Ci.nsIBinaryInputStream);
   try {
     bistream.setInputStream(aStream);
     let expectedData = [];
     let avail;
-    while (avail = bistream.available()) {
+    while ((avail = bistream.available())) {
       expectedData = expectedData.concat(bistream.readByteArray(avail));
     }
     return expectedData;
   } finally {
     bistream.close();
   }
 }
 
rename from toolkit/components/places/tests/migration/test_v11_from_v10.js
rename to toolkit/components/places/tests/migration/test_current_from_v10.js
--- a/toolkit/components/places/tests/migration/test_v11_from_v10.js
+++ b/toolkit/components/places/tests/migration/test_current_from_v10.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
- * This file tests migration invariants from schema version 10 to schema version
- * 11.
+ * This file tests migration invariants from schema version 10 to the current
+ * schema version.
  */
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Constants
 
 const kGuidAnnotationName = "sync/guid";
 const kExpectedAnnotations = 5;
 const kExpectedValidGuids = 2;
@@ -291,17 +291,17 @@ function test_final_state()
     // WAL journal mode should be set on this database.
     do_check_eq(stmt.getString(0).toLowerCase(), "wal");
     stmt.finalize();
   }
 
   do_check_true(db.indexExists("moz_bookmarks_guid_uniqueindex"));
   do_check_true(db.indexExists("moz_places_guid_uniqueindex"));
 
-  do_check_eq(db.schemaVersion, 11);
+  do_check_eq(db.schemaVersion, CURRENT_SCHEMA_VERSION);
 
   db.close();
   run_next_test();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Test Runner
 
rename from toolkit/components/places/tests/migration/test_v11_from_v10_migrated_from_v11.js
rename to toolkit/components/places/tests/migration/test_current_from_v10_migrated_from_v11.js
--- a/toolkit/components/places/tests/migration/test_v11_from_v10_migrated_from_v11.js
+++ b/toolkit/components/places/tests/migration/test_current_from_v10_migrated_from_v11.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * This file tests migration invariants from a database with schema version 11
  * that was then downgraded to a database with a schema version 10.  Places
- * should then migrate this database to one with a schema version of 11.
+ * should then migrate this database to one with the current schema version.
  */
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Test Functions
 
 function test_initial_state()
 {
   // Mostly sanity checks our starting DB to make sure it's setup as we expect
@@ -104,17 +104,17 @@ function test_place_guids_non_null()
 function test_final_state()
 {
   // We open a new database mostly so that we can check that the settings were
   // actually saved.
   let dbFile = gProfD.clone();
   dbFile.append(kDBName);
   let db = Services.storage.openUnsharedDatabase(dbFile);
 
-  do_check_eq(db.schemaVersion, 11);
+  do_check_eq(db.schemaVersion, CURRENT_SCHEMA_VERSION);
 
   db.close();
   run_next_test();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Test Runner
 
--- a/toolkit/components/places/tests/migration/xpcshell.ini
+++ b/toolkit/components/places/tests/migration/xpcshell.ini
@@ -1,6 +1,6 @@
 [DEFAULT]
 head = head_migration.js
 tail = 
 
-[test_v11_from_v10.js]
-[test_v11_from_v10_migrated_from_v11.js]
+[test_current_from_v10.js]
+[test_current_from_v10_migrated_from_v11.js]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unit/test_analyze.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests sqlite_sta1 table exists, it should be created by analyze, but since
+// the tables are empty it won't contain any data.
+
+function run_test() {
+  do_test_pending();
+
+  let stmt = DBConn().createAsyncStatement(
+    "SELECT ROWID FROM sqlite_stat1"
+  );
+  stmt.executeAsync({
+    _gotResult: false,
+    handleResult: function(aResultSet) {
+      this._gotResult = true;
+    },
+    handleError: function(aError) {
+      do_throw("Unexpected error (" + aError.result + "): " + aError.message);
+    },
+    handleCompletion: function(aReason) {
+      do_check_false(this._gotResult);
+       do_test_finished();
+    }
+  });
+  stmt.finalize();
+}
--- a/toolkit/components/places/tests/unit/xpcshell.ini
+++ b/toolkit/components/places/tests/unit/xpcshell.ini
@@ -43,16 +43,17 @@ skip-if = os == "android"
 [test_463863.js]
 [test_485442_crash_bug_nsNavHistoryQuery_GetUri.js]
 [test_486978_sort_by_date_queries.js]
 [test_536081.js]
 [test_adaptive.js]
 # Bug 676989: test hangs consistently on Android
 skip-if = os == "android"
 [test_adaptive_bug527311.js]
+[test_analyze.js]
 [test_annotations.js]
 [test_asyncExecuteLegacyQueries.js]
 # Bug 676989: test hangs consistently on Android
 skip-if = os == "android"
 [test_async_history_api.js]
 [test_autocomplete_stopSearch_no_throw.js]
 [test_bookmark_catobs.js]
 [test_bookmarks_setNullTitle.js]