Bug 628921 - Changing from WAL to a rollback journal to change page_size may cause a infinite loop @AsyncExecuteStatements::executeStatement.

r=sdwilsh a=blocking
This commit is contained in:
Marco Bonardo 2011-02-16 13:51:26 +01:00
parent d06b864012
commit 296464cbe5
3 changed files with 28 additions and 68 deletions

View File

@ -54,12 +54,8 @@ interface mozIStorageVacuumParticipant : nsISupports {
* The expected page size in bytes for the database. The vacuum manager will
* try to correct the page size during idle based on this value.
*
* @note If the database is using the WAL journal mode and the current page
* size is not the expected one, the journal mode will be changed to
* TRUNCATE because WAL does not allow page size changes.
* The vacuum manager will try to restore WAL mode, but for this to
* work reliably the participant must ensure to always reset statements.
* If restoring the journal mode should fail it will stick to TRUNCATE.
* @note If the database is using the WAL journal mode, the page size won't
* be changed to the requested value. See bug 634374.
* @note Valid page size values are from 512 to 65536.
* The suggested value is mozIStorageConnection::DEFAULT_PAGE_SIZE.
*/

View File

@ -148,7 +148,6 @@ private:
nsCOMPtr<nsIPrefBranch> mPrefBranch;
nsCString mDBFilename;
nsCOMPtr<mozIStorageConnection> mDBConn;
bool mRestoreWAL;
};
////////////////////////////////////////////////////////////////////////////////
@ -180,7 +179,7 @@ NotifyCallback::NotifyCallback(Vacuumer *aVacuumer,
NS_IMETHODIMP
NotifyCallback::HandleCompletion(PRUint16 aReason)
{
// We succeeded if both vacuum are WAL restoration succeeded.
// We succeeded if vacuum succeeded.
nsresult rv = mVacuumer->notifyCompletion(mVacuumSucceeded);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -193,7 +192,6 @@ Vacuumer::Vacuumer(mozIStorageVacuumParticipant *aParticipant,
nsIPrefBranch *aPrefBranch)
: mParticipant(aParticipant)
, mPrefBranch(aPrefBranch)
, mRestoreWAL(false)
{
}
@ -222,7 +220,7 @@ Vacuumer::execute()
expectedPageSize = mozIStorageConnection::DEFAULT_PAGE_SIZE;
}
bool canOptimizePageSize;
bool canOptimizePageSize = false;
{
nsCOMPtr<mozIStorageStatement> stmt;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
@ -237,7 +235,26 @@ Vacuumer::execute()
rv = stmt->GetInt32(0, &currentPageSize);
NS_ENSURE_SUCCESS(rv, false);
NS_ASSERTION(currentPageSize > 0, "Got invalid page size value?");
canOptimizePageSize = currentPageSize != expectedPageSize;
if (currentPageSize != expectedPageSize) {
// Check journal mode. WAL journaling does not allow vacuum to change
// the page size.
// TODO Bug 634374: figure out a strategy to fix page size with WAL.
nsCAutoString journalMode;
{
nsCOMPtr<mozIStorageStatement> stmt;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"PRAGMA journal_mode"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, false);
PRBool hasResult;
rv = stmt->ExecuteStep(&hasResult);
NS_ENSURE_SUCCESS(rv, false);
NS_ENSURE_TRUE(hasResult, false);
rv = stmt->GetUTF8String(0, journalMode);
NS_ENSURE_SUCCESS(rv, false);
}
canOptimizePageSize = !journalMode.EqualsLiteral("wal");
}
}
// Get the database filename. Last vacuum time is stored under this name
@ -282,41 +299,6 @@ Vacuumer::execute()
}
if (canOptimizePageSize) {
// Check journal mode. WAL journaling does not allow vacuum to change page
// size, thus we have to temporarily switch the journal mode to TRUNCATE.
nsCOMPtr<mozIStorageStatement> stmt;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"PRAGMA journal_mode"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, false);
PRBool hasResult;
rv = stmt->ExecuteStep(&hasResult);
NS_ENSURE_SUCCESS(rv, false);
NS_ENSURE_TRUE(hasResult, false);
nsCAutoString journalMode;
rv = stmt->GetUTF8String(0, journalMode);
NS_ENSURE_SUCCESS(rv, false);
rv = stmt->Reset();
NS_ENSURE_SUCCESS(rv, false);
if (journalMode.EqualsLiteral("wal")) {
mRestoreWAL = true;
// Set the journal mode to a backwards compatible one.
nsCOMPtr<mozIStorageAsyncStatement> stmt;
rv = mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
"PRAGMA journal_mode = TRUNCATE"
), getter_AddRefs(stmt));
NS_ENSURE_SUCCESS(rv, false);
nsCOMPtr<BaseCallback> callback = new BaseCallback();
NS_ENSURE_TRUE(callback, false);
nsCOMPtr<mozIStoragePendingStatement> ps;
rv = stmt->ExecuteAsync(callback, getter_AddRefs(ps));
NS_ENSURE_SUCCESS(rv, false);
}
// WARNING: any statement after we check for journal mode must be async
// to ensure the correct execution order.
nsCOMPtr<mozIStorageAsyncStatement> pageSizeStmt;
rv = mDBConn->CreateAsyncStatement(nsPrintfCString(
"PRAGMA page_size = %ld", expectedPageSize
@ -399,27 +381,7 @@ Vacuumer::HandleCompletion(PRUint16 aReason)
(void)mPrefBranch->SetIntPref(mDBFilename.get(), now);
}
// Check if we should restore WAL journal mode.
if (mRestoreWAL) {
// Restoring WAL is expensive, so must be done async.
// End of vacuum will be notified once it finishes.
nsCOMPtr<mozIStorageAsyncStatement> stmt;
(void)mDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
"PRAGMA journal_mode = WAL"
), getter_AddRefs(stmt));
nsCOMPtr<NotifyCallback> callback =
new NotifyCallback(this, aReason == REASON_FINISHED);
// Handle errors now, it's important to notify participant before throwing.
if (!stmt || !callback) {
notifyCompletion(false);
return NS_ERROR_UNEXPECTED;
}
nsCOMPtr<mozIStoragePendingStatement> ps;
stmt->ExecuteAsync(callback, getter_AddRefs(ps));
}
else {
notifyCompletion(aReason == REASON_FINISHED);
}
notifyCompletion(aReason == REASON_FINISHED);
return NS_OK;
}

View File

@ -218,6 +218,7 @@ function test_skipped_optout_vacuum()
synthesize_idle_daily();
},
/* Changing page size on WAL is not supported till Bug 634374 is properly fixed.
function test_page_size_change_with_wal()
{
print("\n*** Test that a VACUUM changes page_size with WAL mode");
@ -282,6 +283,7 @@ function test_page_size_change_with_wal()
synthesize_idle_daily();
},
*/
function test_memory_database_crash()
{
@ -309,7 +311,7 @@ function test_memory_database_crash()
synthesize_idle_daily();
},
/* Test temporarily disabled due to bug 599098.
/* Changing page size on WAL is not supported till Bug 634374 is properly fixed.
function test_wal_restore_fail()
{
print("\n*** Test that a failing WAL restoration notifies failure");