This commit is contained in:
Marco Bonardo 2010-08-14 09:57:09 +02:00
Родитель 5b47738196 6382d8f9d4
Коммит b958ffa13d
4 изменённых файлов: 57 добавлений и 137 удалений

Просмотреть файл

@ -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 \

Просмотреть файл

@ -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<mozIStorageStatement> 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(&currentSchemaVersion);
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<mozIStorageStatement> 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<mozIStorageStatement> 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<mozIStorageStatement> journalToMemory;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"PRAGMA journal_mode = MEMORY"),
getter_AddRefs(journalToMemory));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStorageAsyncStatement> vacuum;
rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING("VACUUM"),
getter_AddRefs(vacuum));
nsCOMPtr<mozIStorageStatement> vacuum;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("VACUUM"),
getter_AddRefs(vacuum));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStorageStatement> 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<mozIStoragePendingStatement> 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,

Просмотреть файл

@ -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<mozIStorageService> mDBService;
nsCOMPtr<mozIStorageConnection> mDBConn;
nsCOMPtr<nsIFile> mDBFile;
PRInt32 mDBPageSize;
nsCOMPtr<mozIStorageStatement> mDBGetURLPageInfo; // kGetInfoIndex_* results
nsCOMPtr<mozIStorageStatement> 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

Просмотреть файл

@ -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);