diff --git a/toolkit/components/places/src/Makefile.in b/toolkit/components/places/src/Makefile.in index ded0ff87015..7cc1047eb92 100644 --- a/toolkit/components/places/src/Makefile.in +++ b/toolkit/components/places/src/Makefile.in @@ -82,9 +82,6 @@ EXTRA_DSO_LDOPTS += \ LOCAL_INCLUDES += -I$(srcdir)/../../build -# This is the default value. Must be in sync with the one defined in SQLite. -DEFINES += -DSQLITE_DEFAULT_PAGE_SIZE=32768 - EXTRA_COMPONENTS = \ toolkitplaces.manifest \ nsLivemarkService.js \ diff --git a/toolkit/components/places/src/nsNavHistory.cpp b/toolkit/components/places/src/nsNavHistory.cpp index ffde69475f9..d457d05171c 100644 --- a/toolkit/components/places/src/nsNavHistory.cpp +++ b/toolkit/components/places/src/nsNavHistory.cpp @@ -65,7 +65,6 @@ #include "nsThreadUtils.h" #include "nsAppDirectoryServiceDefs.h" #include "nsMathUtils.h" -#include "mozIStorageAsyncStatement.h" #include "nsNavBookmarks.h" #include "nsAnnotationService.h" @@ -142,6 +141,10 @@ using namespace mozilla::places; // Filename used to backup corrupt databases. #define DATABASE_CORRUPT_FILENAME NS_LITERAL_STRING("places.sqlite.corrupt") +// We use the TRUNCATE journal mode to reduce the number of fsyncs. Without +// this setting we had a Ts hit on Linux. See bug 460315 for details. +#define DATABASE_JOURNAL_MODE "TRUNCATE" + // Fraction of free pages in the database to force a vacuum between // DATABASE_MAX_TIME_BEFORE_VACUUM and DATABASE_MIN_TIME_BEFORE_VACUUM. #define DATABASE_VACUUM_FREEPAGES_THRESHOLD 0.1 @@ -374,8 +377,6 @@ PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsNavHistory, gHistoryService) nsNavHistory::nsNavHistory() : mBatchLevel(0) , mBatchDBTransaction(nsnull) -, mDBPageSize(0) -, mCurrentJournalMode(JOURNAL_DELETE) , mCachedNow(0) , mExpireNowTimer(nsnull) , mLastSessionID(0) @@ -619,83 +620,26 @@ nsNavHistory::InitDBFile(PRBool aForceInit) } -nsresult -nsNavHistory::SetJournalMode(enum JournalMode aJournalMode) { - nsCAutoString journalMode; - switch (aJournalMode) { - case JOURNAL_DELETE: - journalMode.AssignLiteral("delete"); - break; - case JOURNAL_TRUNCATE: - journalMode.AssignLiteral("truncate"); - break; - case JOURNAL_MEMORY: - journalMode.AssignLiteral("memory"); - break; - case JOURNAL_WAL: - journalMode.AssignLiteral("wal"); - break; - default: - NS_ABORT_IF_FALSE(false, "Trying to set an unknown journal mode."); - } - - nsCOMPtr statement; - nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( - "PRAGMA journal_mode = ") + journalMode, - getter_AddRefs(statement)); - NS_ENSURE_SUCCESS(rv, rv); - - mozStorageStatementScoper scoper(statement); - PRBool hasResult; - rv = statement->ExecuteStep(&hasResult); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(hasResult, NS_ERROR_FAILURE); - - nsCAutoString currentJournalMode; - rv = statement->GetUTF8String(0, currentJournalMode); - NS_ENSURE_SUCCESS(rv, rv); - bool succeeded = currentJournalMode.Equals(journalMode); - NS_WARN_IF_FALSE(succeeded, - nsPrintfCString(128, "Setting journal mode failed: %s", - PromiseFlatCString(journalMode).get()).get()); - if (succeeded) { - mCurrentJournalMode = aJournalMode; - } - else { - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - - nsresult nsNavHistory::InitDB() { - // WARNING: - // Any unfinalized statement will cause failure on setting WAL journal mode. - // Be sure to avoid them till journal mode has been set. - // Get the database schema version. PRInt32 currentSchemaVersion = 0; nsresult rv = mDBConn->GetSchemaVersion(¤tSchemaVersion); NS_ENSURE_SUCCESS(rv, rv); - { - // Get the page size. This may be different than the default if the - // database file already existed with a different page size. - nsCOMPtr statement; - rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("PRAGMA page_size"), - getter_AddRefs(statement)); - NS_ENSURE_SUCCESS(rv, rv); - PRBool hasResult; - mozStorageStatementScoper scoper(statement); - rv = statement->ExecuteStep(&hasResult); - NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && hasResult, NS_ERROR_FAILURE); - rv = statement->GetInt32(0, &mDBPageSize); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(mDBPageSize > 0, NS_ERROR_UNEXPECTED); - } + // Get the page size. This may be different than the default if the + // database file already existed with a different page size. + nsCOMPtr statement; + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("PRAGMA page_size"), + getter_AddRefs(statement)); + NS_ENSURE_SUCCESS(rv, rv); + + PRBool hasResult; + mozStorageStatementScoper scoper(statement); + rv = statement->ExecuteStep(&hasResult); + NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && hasResult, NS_ERROR_FAILURE); + PRInt32 pageSize = statement->AsInt32(0); // Ensure that temp tables are held in memory, not on disk. We use temp // tables mainly for fsync and I/O reduction. @@ -727,10 +671,10 @@ nsNavHistory::InitDB() PRInt64 cacheSize = physMem * cachePercentage / 100; // Compute number of cached pages, this will be our cache size. - PRInt64 cachePages = cacheSize / mDBPageSize; - nsCAutoString cacheSizePragma("PRAGMA cache_size = "); - cacheSizePragma.AppendInt(cachePages); - rv = mDBConn->ExecuteSimpleSQL(cacheSizePragma); + PRInt64 cachePages = cacheSize / pageSize; + nsCAutoString pageSizePragma("PRAGMA cache_size = "); + pageSizePragma.AppendInt(cachePages); + rv = mDBConn->ExecuteSimpleSQL(pageSizePragma); NS_ENSURE_SUCCESS(rv, rv); // Lock the database file. This is done partly to avoid third party @@ -739,14 +683,9 @@ nsNavHistory::InitDB() "PRAGMA locking_mode = EXCLUSIVE")); NS_ENSURE_SUCCESS(rv, rv); - // Be sure to set journal mode after page_size, WAL would prevent the change - // otherwise. - if (NS_FAILED(SetJournalMode(JOURNAL_WAL))) { - // Ignore errors, if we fail here the database could be considered corrupt - // and we won't be able to go on, even if it's just matter of a bogus - // filesystem. The default mode (DELETE) will be fine in such a case. - (void)SetJournalMode(JOURNAL_TRUNCATE); - } + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "PRAGMA journal_mode = " DATABASE_JOURNAL_MODE)); + NS_ENSURE_SUCCESS(rv, rv); // We are going to initialize tables, so everything from now on should be in // a transaction for performances. @@ -1841,7 +1780,9 @@ nsNavHistory::MigrateV9Up(mozIStorageConnection *aDBConn) // reducing write times by a half, but will temporary consume more memory // and increase risks of corruption if we should crash in the middle of this // update. - (void)SetJournalMode(JOURNAL_MEMORY); + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "PRAGMA journal_mode = MEMORY")); + NS_ENSURE_SUCCESS(rv, rv); rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "UPDATE moz_places SET last_visit_date = " @@ -1851,9 +1792,9 @@ nsNavHistory::MigrateV9Up(mozIStorageConnection *aDBConn) NS_ENSURE_SUCCESS(rv, rv); // Restore the default journal mode. - if (NS_FAILED(SetJournalMode(JOURNAL_WAL))) { - (void)SetJournalMode(JOURNAL_TRUNCATE); - } + rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "PRAGMA journal_mode = " DATABASE_JOURNAL_MODE)); + NS_ENSURE_SUCCESS(rv, rv); } return transaction.Commit(); @@ -5931,25 +5872,38 @@ nsNavHistory::VacuumDatabase() nsnull); } - // If journal mode is WAL, a VACUUM cannot upgrade page_size value. - // If current page_size is not the expected one, journal mode must be - // changed to a rollback one. Once done we won't be able to go back to WAL - // mode though, since unfinalized statements exist. Just keep using - // compatible mode till next restart. - // See http://www.sqlite.org/wal.html - if (mCurrentJournalMode == JOURNAL_WAL && - mDBPageSize != SQLITE_DEFAULT_PAGE_SIZE) { - (void)SetJournalMode(JOURNAL_TRUNCATE); - } + // Actually vacuuming a database is a slow operation, since it could take + // seconds. Part of the time is spent in updating the journal file on disk + // and this is particularly bad on devices with slow I/O. Temporary + // moving the journal to memory could increase a bit the possibility of + // corruption if we crash during this time, but makes the process really + // faster. + nsCOMPtr journalToMemory; + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "PRAGMA journal_mode = MEMORY"), + getter_AddRefs(journalToMemory)); + NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr vacuum; - rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING("VACUUM"), - getter_AddRefs(vacuum)); + nsCOMPtr vacuum; + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("VACUUM"), + getter_AddRefs(vacuum)); NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr journalToDefault; + rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING( + "PRAGMA journal_mode = " DATABASE_JOURNAL_MODE), + getter_AddRefs(journalToDefault)); + NS_ENSURE_SUCCESS(rv, rv); + + mozIStorageBaseStatement *stmts[] = { + journalToMemory, + vacuum, + journalToDefault + }; nsCOMPtr ps; - rv = vacuum->ExecuteAsync(nsnull, getter_AddRefs(ps)); + rv = mDBConn->ExecuteAsync(stmts, NS_ARRAY_LENGTH(stmts), nsnull, + getter_AddRefs(ps)); NS_ENSURE_SUCCESS(rv, rv); - vacuum->Finalize(); if (mPrefBranch) { (void)mPrefBranch->SetIntPref(PREF_LAST_VACUUM, diff --git a/toolkit/components/places/src/nsNavHistory.h b/toolkit/components/places/src/nsNavHistory.h index 045dea4d423..3614c87e069 100644 --- a/toolkit/components/places/src/nsNavHistory.h +++ b/toolkit/components/places/src/nsNavHistory.h @@ -122,18 +122,6 @@ namespace places { , DB_SET_PLACE_TITLE = 9 }; - enum JournalMode { - // Default SQLite jousrnal mode. - JOURNAL_DELETE = 0 - // Can reduce fsyncs on Linux when journal is deleted (See bug 460315). - // We fallback to this mode when WAL is unavailable. - , JOURNAL_TRUNCATE - // Unsafe in case of crashes on database swap or low memory. - , JOURNAL_MEMORY - // Can reduce number of fsyncs. We try to use this mode by default. - , JOURNAL_WAL - }; - } // namespace places } // namespace mozilla @@ -481,7 +469,6 @@ protected: nsCOMPtr mDBService; nsCOMPtr mDBConn; nsCOMPtr mDBFile; - PRInt32 mDBPageSize; nsCOMPtr mDBGetURLPageInfo; // kGetInfoIndex_* results nsCOMPtr mDBGetIdPageInfo; // kGetInfoIndex_* results @@ -549,12 +536,6 @@ protected: */ nsresult InitDBFile(PRBool aForceInit); - /** - * Set journal mode on the database. - */ - nsresult SetJournalMode(enum mozilla::places::JournalMode aJournalMode); - enum mozilla::places::JournalMode mCurrentJournalMode; - /** * Initializes the database. This performs any necessary migrations for the * database. All migration is done inside a transaction that is rolled back diff --git a/toolkit/components/places/src/nsPlacesDBFlush.js b/toolkit/components/places/src/nsPlacesDBFlush.js index 09ce78d48dd..e797b9b2721 100644 --- a/toolkit/components/places/src/nsPlacesDBFlush.js +++ b/toolkit/components/places/src/nsPlacesDBFlush.js @@ -138,18 +138,6 @@ nsPlacesDBFlush.prototype = { // Close the database connection, this was the last sync and we can't // ensure database coherence from now on. this._self._finalizeInternalStatements(); - - // Before closing the connection we have to set back journal mode to - // a backwards compatible value. Newer journal modes like WAL make - // the database incompatible with old versions of the browser, setting - // an old mode restores database version. - // See http://www.sqlite.org/draft/wal.html - let journalStmt = this._self._db.createAsyncStatement( - "PRAGMA journal_mode = truncate" - ); - journalStmt.executeAsync(); - journalStmt.finalize(); - this._self._db.asyncClose(); } }, Ci.nsIThread.DISPATCH_NORMAL);