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..9c402a572153443532b8badef801a13b6a3b2171 100644 |
--- a/chrome/browser/extensions/api/storage/storage_api.cc |
+++ b/chrome/browser/extensions/api/storage/storage_api.cc |
@@ -73,20 +73,30 @@ 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; |
+bool SettingsFunction::UseReadResult(ValueStore::ReadResult result, |
+ ValueStore* storage) { |
+ if (result->HasError()) { |
+ if (result->error().code == ValueStore::CORRUPTION && |
not at google - send to devlin
2014/02/14 19:35:56
result->IsCorruption()
Devlin
2014/02/18 23:55:22
Unneeded now.
|
+ !tried_restoring_storage_) { |
+ return RestoreStorageAndRetry(result->error(), storage); |
+ } |
+ error_ = result->error().message; |
return false; |
} |
- base::DictionaryValue* result = new base::DictionaryValue(); |
- result->Swap(&read_result->settings()); |
- SetResult(result); |
+ base::DictionaryValue* dict = new base::DictionaryValue(); |
not at google - send to devlin
2014/02/14 19:35:56
what was wrong with read_result vs result?
Devlin
2014/02/18 23:55:22
It was declared as |result| in the .h file (https:
|
+ dict->Swap(&result->settings()); |
+ SetResult(dict); |
return true; |
} |
-bool SettingsFunction::UseWriteResult(ValueStore::WriteResult result) { |
+bool SettingsFunction::UseWriteResult(ValueStore::WriteResult result, |
+ ValueStore* storage) { |
if (result->HasError()) { |
+ if (result->error().code == ValueStore::CORRUPTION && |
not at google - send to devlin
2014/02/14 19:35:56
ditto
Devlin
2014/02/18 23:55:22
Unneeded now.
|
+ !tried_restoring_storage_) { |
+ return RestoreStorageAndRetry(result->error(), storage); |
+ } |
error_ = result->error().message; |
return false; |
} |
@@ -102,6 +112,29 @@ bool SettingsFunction::UseWriteResult(ValueStore::WriteResult result) { |
return true; |
} |
+bool SettingsFunction::RestoreStorageAndRetry(const ValueStore::Error& error, |
+ ValueStore* storage) { |
+ DCHECK(!tried_restoring_storage_); |
+ DCHECK(error.code == ValueStore::CORRUPTION); |
+ tried_restoring_storage_ = true; |
not at google - send to devlin
2014/02/14 19:35:56
I'd rather this state be entirely handled within t
Devlin
2014/02/18 23:55:22
Done (mostly - there's not really a need for a swi
|
+ |
+ // If the corruption is on a particular key, try to restore that key and |
+ // re-run. |
+ if (error.key.get()) { |
+ if (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); |
+ |
+ // Failing that, there's nothing else we can do. |
+ error_ = error.message; |
+ return false; |
+} |
+ |
// Concrete settings functions |
namespace { |
@@ -161,32 +194,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 +269,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 +285,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 +307,7 @@ void StorageStorageAreaRemoveFunction::GetQuotaLimitHeuristics( |
} |
bool StorageStorageAreaClearFunction::RunWithStorage(ValueStore* storage) { |
- return UseWriteResult(storage->Clear()); |
+ return UseWriteResult(storage->Clear(), storage); |
} |
void StorageStorageAreaClearFunction::GetQuotaLimitHeuristics( |