mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 493374 - Avoid marking database as corrupt if initializing additional db objects fails, and avoid creating more than one corrupt file every 24 hours, r=sdwilsh
This commit is contained in:
parent
f319200054
commit
0eaa5c5003
@ -272,6 +272,44 @@ inline void ReverseString(const nsString& aInput, nsAString& aReversed)
|
|||||||
aReversed.Append(aInput[i]);
|
aReversed.Append(aInput[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace places {
|
||||||
|
|
||||||
|
bool hasRecentCorruptDB()
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIFile> profDir;
|
||||||
|
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||||
|
getter_AddRefs(profDir));
|
||||||
|
NS_ENSURE_SUCCESS(rv, false);
|
||||||
|
nsCOMPtr<nsISimpleEnumerator> entries;
|
||||||
|
rv = profDir->GetDirectoryEntries(getter_AddRefs(entries));
|
||||||
|
NS_ENSURE_SUCCESS(rv, false);
|
||||||
|
PRBool hasMore;
|
||||||
|
while (NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) {
|
||||||
|
nsCOMPtr<nsISupports> next;
|
||||||
|
rv = entries->GetNext(getter_AddRefs(next));
|
||||||
|
NS_ENSURE_SUCCESS(rv, false);
|
||||||
|
nsCOMPtr<nsIFile> currFile = do_QueryInterface(next, &rv);
|
||||||
|
NS_ENSURE_SUCCESS(rv, false);
|
||||||
|
|
||||||
|
nsAutoString leafName;
|
||||||
|
rv = currFile->GetLeafName(leafName);
|
||||||
|
NS_ENSURE_SUCCESS(rv, false);
|
||||||
|
if (leafName.Length() >= DB_CORRUPT_FILENAME.Length() &&
|
||||||
|
leafName.Find(".corrupt", DB_FILENAME.Length()) != -1) {
|
||||||
|
PRInt64 lastMod;
|
||||||
|
rv = currFile->GetLastModifiedTime(&lastMod);
|
||||||
|
NS_ENSURE_SUCCESS(rv, false);
|
||||||
|
if (PR_Now() - lastMod > (PRInt64)24 * 60 * 60 * 1000 * 1000)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateBatchScoper
|
// UpdateBatchScoper
|
||||||
//
|
//
|
||||||
// This just sets begin/end of batch updates to correspond to C++ scopes so
|
// This just sets begin/end of batch updates to correspond to C++ scopes so
|
||||||
@ -445,25 +483,36 @@ nsNavHistory::Init()
|
|||||||
// prefs
|
// prefs
|
||||||
LoadPrefs(PR_TRUE);
|
LoadPrefs(PR_TRUE);
|
||||||
|
|
||||||
// init db file
|
// Init the database file. If we won't be able to connect to the database it
|
||||||
|
// is most likely corrupt, so we will backup it and create a new one.
|
||||||
rv = InitDBFile(PR_FALSE);
|
rv = InitDBFile(PR_FALSE);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// init db and statements
|
// Init the database schema. If this will fail there's an high possibility
|
||||||
|
// the schema is corrupt or incorrect, so we will force a new database
|
||||||
|
// initialization.
|
||||||
rv = InitDB();
|
rv = InitDB();
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
// if unable to initialize the db, force-re-initialize it:
|
// Forced InitDBFile will backup the old db and create a new one.
|
||||||
// InitDBFile will backup the old db and create a new one.
|
|
||||||
rv = InitDBFile(PR_TRUE);
|
rv = InitDBFile(PR_TRUE);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
// Try to initialize the schema again on the new database.
|
||||||
rv = InitDB();
|
rv = InitDB();
|
||||||
}
|
}
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// Notify we have finished database initialization
|
// Initialize all the items that are not part of the on-disk database, like
|
||||||
|
// views, temp tables, functions. Do not initialize these in InitDBFile, or
|
||||||
|
// in case of failure we would mark the database as corrupt and try to
|
||||||
|
// replace it, even if it's sane.
|
||||||
|
rv = InitAdditionalDBItems();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// Notify we have finished database initialization.
|
||||||
// Enqueue the notification, so if we init another service that requires
|
// Enqueue the notification, so if we init another service that requires
|
||||||
// nsNavHistoryService we don't recursive try to get it.
|
// nsNavHistoryService we don't recursive try to get it.
|
||||||
nsCOMPtr<PlacesEvent> completeEvent = new PlacesEvent(PLACES_INIT_COMPLETE_EVENT_TOPIC);
|
nsRefPtr<PlacesEvent> completeEvent =
|
||||||
|
new PlacesEvent(PLACES_INIT_COMPLETE_EVENT_TOPIC);
|
||||||
rv = NS_DispatchToMainThread(completeEvent);
|
rv = NS_DispatchToMainThread(completeEvent);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
@ -589,20 +638,39 @@ nsNavHistory::InitDBFile(PRBool aForceInit)
|
|||||||
rv = mDBFile->Append(DB_FILENAME);
|
rv = mDBFile->Append(DB_FILENAME);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// if forcing, backup and remove the old file
|
|
||||||
if (aForceInit) {
|
if (aForceInit) {
|
||||||
|
// If forcing initialization, backup and remove the old file. If we have
|
||||||
|
// already failed in the last 24 hours avoid to create another corrupt file,
|
||||||
|
// since doing so, in some situation, could cause us to create a new corrupt
|
||||||
|
// file at every try to access any Places service. That is bad because it
|
||||||
|
// would quickly fill the user's disk space without any notice.
|
||||||
|
if (!mozilla::places::hasRecentCorruptDB()) {
|
||||||
// backup the database
|
// backup the database
|
||||||
nsCOMPtr<nsIFile> backup;
|
nsCOMPtr<nsIFile> backup;
|
||||||
rv = mDBService->BackupDatabaseFile(mDBFile, DB_CORRUPT_FILENAME, profDir,
|
rv = mDBService->BackupDatabaseFile(mDBFile, DB_CORRUPT_FILENAME, profDir,
|
||||||
getter_AddRefs(backup));
|
getter_AddRefs(backup));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
|
||||||
// close database connection if open
|
// 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();
|
rv = mDBConn->Close();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// and remove the file
|
// Remove the broken database.
|
||||||
rv = mDBFile->Remove(PR_FALSE);
|
rv = mDBFile->Remove(PR_FALSE);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
// If the file is still in use this will fail and we won't be able to
|
||||||
|
// start with a clean database. The process of backing up a corrupt
|
||||||
|
// database will loop on the same database file at any next service
|
||||||
|
// request.
|
||||||
|
// We can't do much at this point, so fire a locked event so that user is
|
||||||
|
// notified that we can't ensure Places to work.
|
||||||
|
nsRefPtr<PlacesEvent> lockedEvent =
|
||||||
|
new PlacesEvent(PLACES_DB_LOCKED_EVENT_TOPIC);
|
||||||
|
(void)NS_DispatchToMainThread(lockedEvent);
|
||||||
|
}
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// If aForceInit is true we were unable to initialize or upgrade the current
|
// If aForceInit is true we were unable to initialize or upgrade the current
|
||||||
@ -649,7 +717,8 @@ nsNavHistory::InitDBFile(PRBool aForceInit)
|
|||||||
// If the database cannot be opened for any reason other than corruption,
|
// If the database cannot be opened for any reason other than corruption,
|
||||||
// send out a notification and do not continue initialization.
|
// send out a notification and do not continue initialization.
|
||||||
// Note: We swallow errors here, since we want service init to fail anyway.
|
// Note: We swallow errors here, since we want service init to fail anyway.
|
||||||
nsCOMPtr<PlacesEvent> lockedEvent = new PlacesEvent(PLACES_DB_LOCKED_EVENT_TOPIC);
|
nsRefPtr<PlacesEvent> lockedEvent =
|
||||||
|
new PlacesEvent(PLACES_DB_LOCKED_EVENT_TOPIC);
|
||||||
(void)NS_DispatchToMainThread(lockedEvent);
|
(void)NS_DispatchToMainThread(lockedEvent);
|
||||||
}
|
}
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
@ -893,11 +962,18 @@ nsNavHistory::InitDB()
|
|||||||
rv = transaction.Commit();
|
rv = transaction.Commit();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// --- PUT SCHEMA-MODIFYING THINGS (like create table) ABOVE THIS LINE ---
|
// 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
|
||||||
|
// THE DISK DATABASE.
|
||||||
|
|
||||||
// DO NOT PUT ANY SCHEMA-MODIFYING THINGS HERE
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
rv = InitTempTables();
|
nsresult
|
||||||
|
nsNavHistory::InitAdditionalDBItems()
|
||||||
|
{
|
||||||
|
nsresult rv = InitTempTables();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
rv = InitViews();
|
rv = InitViews();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
@ -474,6 +474,12 @@ protected:
|
|||||||
* preferences that are used are set.
|
* preferences that are used are set.
|
||||||
*/
|
*/
|
||||||
nsresult InitDB();
|
nsresult InitDB();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes additional database items like: views, temp tables, functions
|
||||||
|
* and statements.
|
||||||
|
*/
|
||||||
|
nsresult InitAdditionalDBItems();
|
||||||
nsresult InitTempTables();
|
nsresult InitTempTables();
|
||||||
nsresult InitViews();
|
nsresult InitViews();
|
||||||
nsresult InitFunctions();
|
nsresult InitFunctions();
|
||||||
|
Loading…
Reference in New Issue
Block a user