Chromium Code Reviews| Index: chrome/browser/extensions/api/storage/storage_api.cc |
| diff --git a/chrome/browser/extensions/api/storage/storage_api.cc b/chrome/browser/extensions/api/storage/storage_api.cc |
| index 1d6b361110b9b72aa7694a844be3f8073014ee09..1637d1e1a9364cfb81b3674d49a0c26a74f70433 100644 |
| --- a/chrome/browser/extensions/api/storage/storage_api.cc |
| +++ b/chrome/browser/extensions/api/storage/storage_api.cc |
| @@ -24,7 +24,8 @@ using content::BrowserThread; |
| // SettingsFunction |
| SettingsFunction::SettingsFunction() |
| - : settings_namespace_(settings_namespace::INVALID) {} |
| + : settings_namespace_(settings_namespace::INVALID), |
| + tried_restoring_storage_(false) {} |
|
Devlin
2014/02/25 19:39:36
So, after more debugging than I'd like to admit, I
not at google - send to devlin
2014/02/25 20:39:20
Heh been there :)
|
| SettingsFunction::~SettingsFunction() {} |
| @@ -73,23 +74,21 @@ void SettingsFunction::AsyncRunWithStorage(ValueStore* storage) { |
| base::Bind(&SettingsFunction::SendResponse, this, success)); |
| } |
| -bool SettingsFunction::UseReadResult(ValueStore::ReadResult read_result) { |
| - if (read_result->HasError()) { |
| - error_ = read_result->error().message; |
| - return false; |
| - } |
| +bool SettingsFunction::UseReadResult(ValueStore::ReadResult result, |
| + ValueStore* storage) { |
| + if (result->HasError()) |
| + return HandleError(result->error(), storage); |
| - base::DictionaryValue* result = new base::DictionaryValue(); |
| - result->Swap(&read_result->settings()); |
| - SetResult(result); |
| + base::DictionaryValue* dict = new base::DictionaryValue(); |
| + dict->Swap(&result->settings()); |
| + SetResult(dict); |
| return true; |
| } |
| -bool SettingsFunction::UseWriteResult(ValueStore::WriteResult result) { |
| - if (result->HasError()) { |
| - error_ = result->error().message; |
| - return false; |
| - } |
| +bool SettingsFunction::UseWriteResult(ValueStore::WriteResult result, |
| + ValueStore* storage) { |
| + if (result->HasError()) |
| + return HandleError(result->error(), storage); |
| if (!result->changes().empty()) { |
| observers_->Notify( |
| @@ -102,6 +101,29 @@ bool SettingsFunction::UseWriteResult(ValueStore::WriteResult result) { |
| return true; |
| } |
| +bool SettingsFunction::HandleError(const ValueStore::Error& error, |
| + ValueStore* storage) { |
| + // If the method failed due to corruption, and we haven't tried to fix it, we |
| + // can try to restore the storage and re-run it. Otherwise, the method has |
| + // failed. |
| + if (error.code == ValueStore::CORRUPTION && !tried_restoring_storage_) { |
| + tried_restoring_storage_ = true; |
| + |
| + // If the corruption is on a particular key, try to restore that key and |
| + // re-run. |
| + if (error.key.get() && storage->RestoreKey(*error.key)) |
| + return RunWithStorage(storage); |
| + |
| + // If the full database is corrupted, try to restore the whole thing and |
| + // re-run. |
| + if (storage->Restore()) |
| + return RunWithStorage(storage); |
| + } |
| + |
| + error_ = error.message; |
| + return false; |
| +} |
| + |
| // Concrete settings functions |
| namespace { |
| @@ -161,32 +183,34 @@ bool StorageStorageAreaGetFunction::RunWithStorage(ValueStore* storage) { |
| switch (input->GetType()) { |
| case base::Value::TYPE_NULL: |
| - return UseReadResult(storage->Get()); |
| + return UseReadResult(storage->Get(), storage); |
| case base::Value::TYPE_STRING: { |
| std::string as_string; |
| input->GetAsString(&as_string); |
| - return UseReadResult(storage->Get(as_string)); |
| + return UseReadResult(storage->Get(as_string), storage); |
| } |
| case base::Value::TYPE_LIST: { |
| std::vector<std::string> as_string_list; |
| AddAllStringValues(*static_cast<base::ListValue*>(input), |
| &as_string_list); |
| - return UseReadResult(storage->Get(as_string_list)); |
| + return UseReadResult(storage->Get(as_string_list), storage); |
| } |
| case base::Value::TYPE_DICTIONARY: { |
| - base::DictionaryValue* as_dict = static_cast<base::DictionaryValue*>(input); |
| + base::DictionaryValue* as_dict = |
| + static_cast<base::DictionaryValue*>(input); |
| ValueStore::ReadResult result = storage->Get(GetKeys(*as_dict)); |
| if (result->HasError()) { |
| - return UseReadResult(result.Pass()); |
| + return UseReadResult(result.Pass(), storage); |
| } |
| base::DictionaryValue* with_default_values = as_dict->DeepCopy(); |
| with_default_values->MergeDictionary(&result->settings()); |
| return UseReadResult( |
| - ValueStore::MakeReadResult(make_scoped_ptr(with_default_values))); |
| + ValueStore::MakeReadResult(make_scoped_ptr(with_default_values)), |
| + storage); |
| } |
| default: |
| @@ -234,7 +258,7 @@ bool StorageStorageAreaGetBytesInUseFunction::RunWithStorage( |
| bool StorageStorageAreaSetFunction::RunWithStorage(ValueStore* storage) { |
| base::DictionaryValue* input = NULL; |
| EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &input)); |
| - return UseWriteResult(storage->Set(ValueStore::DEFAULTS, *input)); |
| + return UseWriteResult(storage->Set(ValueStore::DEFAULTS, *input), storage); |
| } |
| void StorageStorageAreaSetFunction::GetQuotaLimitHeuristics( |
| @@ -250,14 +274,14 @@ bool StorageStorageAreaRemoveFunction::RunWithStorage(ValueStore* storage) { |
| case base::Value::TYPE_STRING: { |
| std::string as_string; |
| input->GetAsString(&as_string); |
| - return UseWriteResult(storage->Remove(as_string)); |
| + return UseWriteResult(storage->Remove(as_string), storage); |
| } |
| case base::Value::TYPE_LIST: { |
| std::vector<std::string> as_string_list; |
| AddAllStringValues(*static_cast<base::ListValue*>(input), |
| &as_string_list); |
| - return UseWriteResult(storage->Remove(as_string_list)); |
| + return UseWriteResult(storage->Remove(as_string_list), storage); |
| } |
| default: |
| @@ -272,7 +296,7 @@ void StorageStorageAreaRemoveFunction::GetQuotaLimitHeuristics( |
| } |
| bool StorageStorageAreaClearFunction::RunWithStorage(ValueStore* storage) { |
| - return UseWriteResult(storage->Clear()); |
| + return UseWriteResult(storage->Clear(), storage); |
| } |
| void StorageStorageAreaClearFunction::GetQuotaLimitHeuristics( |