mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-05 08:35:26 +00:00
Bug 609286 (Part 2) - Detect a corrupt Places.sqlite and replace the database on next startup.
r=dietrich a=blocking
This commit is contained in:
parent
eff14e19f8
commit
aad8664464
@ -126,6 +126,8 @@ using namespace mozilla::places;
|
||||
|
||||
#define PREF_CACHE_TO_MEMORY_PERCENTAGE "database.cache_to_memory_percentage"
|
||||
|
||||
#define PREF_FORCE_DATABASE_REPLACEMENT "database.replaceOnStartup"
|
||||
|
||||
// Default integer value for PREF_CACHE_TO_MEMORY_PERCENTAGE.
|
||||
// This is 6% of machine memory, giving 15MB for a user with 256MB of memory.
|
||||
// Out of this cache, SQLite will use at most the size of the database file.
|
||||
@ -574,11 +576,9 @@ nsNavHistory::Init()
|
||||
nsresult
|
||||
nsNavHistory::InitDBFile(PRBool aForceInit)
|
||||
{
|
||||
if (aForceInit) {
|
||||
NS_ASSERTION(mDBConn,
|
||||
"When forcing initialization, a database connection must exist!");
|
||||
NS_ASSERTION(mDBService,
|
||||
"When forcing initialization, the database service must exist!");
|
||||
if (!mDBService) {
|
||||
mDBService = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_STATE(mDBService);
|
||||
}
|
||||
|
||||
// Get database file handle.
|
||||
@ -606,10 +606,12 @@ nsNavHistory::InitDBFile(PRBool aForceInit)
|
||||
}
|
||||
|
||||
// Close database connection if open.
|
||||
// If there's any not finalized statement or this fails for any reason
|
||||
// we won't be able to remove the database.
|
||||
rv = mDBConn->Close();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (mDBConn) {
|
||||
// If there's any not finalized statement or this fails for any reason
|
||||
// we won't be able to remove the database.
|
||||
rv = mDBConn->Close();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Remove the broken database.
|
||||
rv = mDBFile->Remove(PR_FALSE);
|
||||
@ -636,14 +638,28 @@ nsNavHistory::InitDBFile(PRBool aForceInit)
|
||||
rv = mDBFile->Exists(&dbExists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// If the database didn't previously exist, we create it.
|
||||
if (!dbExists)
|
||||
if (!dbExists) {
|
||||
mDatabaseStatus = DATABASE_STATUS_CREATE;
|
||||
}
|
||||
else {
|
||||
// Check if maintenance required a database replacement.
|
||||
PRBool forceDatabaseReplacement;
|
||||
if (NS_SUCCEEDED(mPrefBranch->GetBoolPref(PREF_FORCE_DATABASE_REPLACEMENT,
|
||||
&forceDatabaseReplacement)) &&
|
||||
forceDatabaseReplacement) {
|
||||
// Be sure to clear the pref to avoid handling it more than once.
|
||||
rv = mPrefBranch->ClearUserPref(PREF_FORCE_DATABASE_REPLACEMENT);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Re-enter this same method, forcing the replacement.
|
||||
rv = InitDBFile(PR_TRUE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Open the database file. If it does not exist a new one will be created.
|
||||
mDBService = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Open un unshared connection, both for safety and speed.
|
||||
// Use a unshared connection, both for safety and performance.
|
||||
rv = mDBService->OpenUnsharedDatabase(mDBFile, getter_AddRefs(mDBConn));
|
||||
if (rv == NS_ERROR_FILE_CORRUPTED) {
|
||||
// The database is corrupt, try to create a new one.
|
||||
|
BIN
toolkit/components/places/tests/unit/default.sqlite
Normal file
BIN
toolkit/components/places/tests/unit/default.sqlite
Normal file
Binary file not shown.
@ -0,0 +1,46 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that history initialization correctly handles a request to forcibly
|
||||
// replace the current database.
|
||||
|
||||
function run_test() {
|
||||
// Ensure that our database doesn't already exist.
|
||||
let (dbFile = gProfD.clone()) {
|
||||
dbFile.append("places.sqlite");
|
||||
do_check_false(dbFile.exists());
|
||||
}
|
||||
let (dbFile = gProfD.clone()) {
|
||||
dbFile.append("places.sqlite.corrupt");
|
||||
do_check_false(dbFile.exists());
|
||||
}
|
||||
|
||||
let file = do_get_file("default.sqlite");
|
||||
file.copyTo(gProfD, "places.sqlite");
|
||||
|
||||
// Create some unique stuff to check later.
|
||||
let db = Services.storage.openUnsharedDatabase(file);
|
||||
db.executeSimpleSQL("CREATE TABLE test (id INTEGER PRIMARY KEY)");
|
||||
db.close();
|
||||
|
||||
Services.prefs.setBoolPref("places.database.replaceOnStartup", true);
|
||||
do_check_eq(PlacesUtils.history.databaseStatus,
|
||||
PlacesUtils.history.DATABASE_STATUS_CORRUPT);
|
||||
|
||||
let (dbFile = gProfD.clone()) {
|
||||
dbFile.append("places.sqlite");
|
||||
do_check_true(dbFile.exists());
|
||||
|
||||
// Check the new database is really a new one.
|
||||
let db = Services.storage.openUnsharedDatabase(file);
|
||||
try {
|
||||
db.executeSimpleSQL("DELETE * FROM test");
|
||||
do_throw("The new database should not have our unique content");
|
||||
} catch(ex) {}
|
||||
db.close();
|
||||
}
|
||||
let (dbFile = gProfD.clone()) {
|
||||
dbFile.append("places.sqlite.corrupt");
|
||||
do_check_true(dbFile.exists());
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user