mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 332935 r=bryner Speed up form history using datbase caching and preloading.
This commit is contained in:
parent
bf4e81d46f
commit
4039642bee
@ -21,6 +21,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Hewitt <hewitt@netscape.com> (Original Author)
|
||||
* Brett Wilson <brettw@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -62,6 +63,16 @@
|
||||
#include "nsIAutoCompleteSimpleResult.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
// The size of the database cache. This is the number of database PAGES that
|
||||
// can be cached in memory. Normally, pages are 1K unless the size has been
|
||||
// explicitly changed.
|
||||
//
|
||||
// 4MB should be much larger than normal form histories. Normal form histories
|
||||
// will be several hundered KB at most. If the form history is smaller, the
|
||||
// extra memory will never be allocated, so there is no penalty for larger
|
||||
// numbers. See StartCache
|
||||
#define DATABASE_CACHE_PAGES 4000
|
||||
|
||||
// nsFormHistoryResult is a specialized autocomplete result class that knows
|
||||
// how to remove entries from the form history table.
|
||||
class nsFormHistoryResult : public nsIAutoCompleteSimpleResult
|
||||
@ -374,14 +385,18 @@ nsFormHistory::OpenDatabase()
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIFile> formHistoryFile;
|
||||
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(formHistoryFile));
|
||||
rv = GetDatabaseFile(getter_AddRefs(formHistoryFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
formHistoryFile->Append(NS_LITERAL_STRING("formhistory.sqlite"));
|
||||
rv = mStorageService->OpenDatabase(formHistoryFile, getter_AddRefs(mDBConn));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// We execute many statements before the database cache is started to create
|
||||
// the tables (which can not be done which the cache is locked in memory by
|
||||
// the dummy statement--see StartCache). This transaction will keep the cache
|
||||
// between these statements, which should improve startup performance because
|
||||
// we won't have to keep requesting pages from the OS.
|
||||
mozStorageTransaction transaction(mDBConn, PR_FALSE);
|
||||
|
||||
PRBool exists;
|
||||
mDBConn->TableExists(NS_LITERAL_CSTRING("moz_formhistory"), &exists);
|
||||
if (!exists) {
|
||||
@ -411,6 +426,12 @@ nsFormHistory::OpenDatabase()
|
||||
getter_AddRefs(mDBInsertNameValue));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// should commit before starting cache
|
||||
transaction.Commit();
|
||||
|
||||
// ignore errors since the cache is not critical for operation
|
||||
StartCache();
|
||||
|
||||
#ifdef MOZ_MORKREADER
|
||||
if (!exists) {
|
||||
// Locate the old formhistory.dat file and import it.
|
||||
@ -430,6 +451,113 @@ nsFormHistory::OpenDatabase()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsFormHistory::GetDatabaseFile(nsIFile** aFile)
|
||||
{
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, aFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return (*aFile)->Append(NS_LITERAL_STRING("formhistory.sqlite"));
|
||||
}
|
||||
|
||||
|
||||
// nsFormHistory::StartCache
|
||||
//
|
||||
// This function starts the dummy statement that locks the cache in memory.
|
||||
// As long as there is an open connection sharing the same cache, the cache
|
||||
// won't be expired. Therefore, we create a dummy table with some data in
|
||||
// it, and open a statement over the data. As long as this statement is
|
||||
// open, we can go fast.
|
||||
//
|
||||
// This dummy statement prevents the schema from being modified. If you
|
||||
// want to add or change a table or index schema, you must stop the dummy
|
||||
// statement first. See nsNavHistory::StartDummyStatement for a slightly
|
||||
// more detailed discussion.
|
||||
//
|
||||
// Note that we should not use a transaction in this function since that
|
||||
// will commit the dummy statement and everything will break.
|
||||
//
|
||||
// This function also initializes the cache.
|
||||
|
||||
nsresult
|
||||
nsFormHistory::StartCache()
|
||||
{
|
||||
// do nothing if the dummy statement is already running
|
||||
if (mDummyStatement)
|
||||
return NS_OK;
|
||||
|
||||
// dummy database connection
|
||||
nsCOMPtr<nsIFile> formHistoryFile;
|
||||
nsresult rv = GetDatabaseFile(getter_AddRefs(formHistoryFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mStorageService->OpenDatabase(formHistoryFile,
|
||||
getter_AddRefs(mDummyConnection));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Make sure the dummy table exists
|
||||
PRBool tableExists;
|
||||
rv = mDummyConnection->TableExists(NS_LITERAL_CSTRING("moz_dummy_table"), &tableExists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (! tableExists) {
|
||||
rv = mDummyConnection->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("CREATE TABLE moz_dummy_table (id INTEGER PRIMARY KEY)"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// This table is guaranteed to have something in it and will keep the dummy
|
||||
// statement open. If the table is empty, it won't hold the statement open.
|
||||
// the PRIMARY KEY value on ID means that it is unique. The OR IGNORE means
|
||||
// that if there is already a value of 1 there, this insert will be ignored,
|
||||
// which is what we want so as to avoid growing the table infinitely.
|
||||
rv = mDummyConnection->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("INSERT OR IGNORE INTO moz_dummy_table VALUES (1)"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mDummyConnection->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT id FROM moz_dummy_table LIMIT 1"),
|
||||
getter_AddRefs(mDummyStatement));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// we have to step the dummy statement so that it will hold a lock on the DB
|
||||
PRBool dummyHasResults;
|
||||
rv = mDummyStatement->ExecuteStep(&dummyHasResults);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Set the cache size
|
||||
nsCAutoString cacheSizePragma("PRAGMA cache_size=");
|
||||
cacheSizePragma.AppendInt(DATABASE_CACHE_PAGES);
|
||||
rv = mDummyConnection->ExecuteSimpleSQL(cacheSizePragma);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// preload the cache
|
||||
rv = mDummyConnection->Preload();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsFormHistory::StopCache
|
||||
//
|
||||
// Call this before doing any schema modifying operations. You should
|
||||
// start the dummy statement again to give good performance.
|
||||
// See StartCache.
|
||||
|
||||
nsresult
|
||||
nsFormHistory::StopCache()
|
||||
{
|
||||
// do nothing if the dummy statement isn't running
|
||||
if (! mDummyStatement)
|
||||
return NS_OK;
|
||||
|
||||
nsresult rv = mDummyStatement->Reset();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mDummyStatement = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsFormHistory::AutoCompleteSearch(const nsAString &aInputName,
|
||||
const nsAString &aInputValue,
|
||||
|
@ -121,7 +121,8 @@ public:
|
||||
// Database I/O
|
||||
nsresult OpenDatabase();
|
||||
nsresult CloseDatabase();
|
||||
|
||||
nsresult GetDatabaseFile(nsIFile** aFile);
|
||||
|
||||
static PRBool FormHistoryEnabled();
|
||||
static nsFormHistory *gFormHistory;
|
||||
static PRBool gFormHistoryEnabled;
|
||||
@ -134,6 +135,12 @@ public:
|
||||
nsCOMPtr<mozIStorageStatement> mDBFindEntryByName;
|
||||
nsCOMPtr<mozIStorageStatement> mDBSelectEntries;
|
||||
nsCOMPtr<mozIStorageStatement> mDBInsertNameValue;
|
||||
|
||||
// dummy statement (see StartCache)
|
||||
nsresult StartCache();
|
||||
nsresult StopCache();
|
||||
nsCOMPtr<mozIStorageConnection> mDummyConnection;
|
||||
nsCOMPtr<mozIStorageStatement> mDummyStatement;
|
||||
};
|
||||
|
||||
#ifdef MOZ_MORKREADER
|
||||
|
Loading…
Reference in New Issue
Block a user