| Index: chrome/browser/sync/syncable/syncable.cc
|
| diff --git a/chrome/browser/sync/syncable/syncable.cc b/chrome/browser/sync/syncable/syncable.cc
|
| index efeecaf94440d8411742f63c28016e9bca6a3ec6..f1936e063cfce080a79cd7a2b4fc4a05221d7892 100644
|
| --- a/chrome/browser/sync/syncable/syncable.cc
|
| +++ b/chrome/browser/sync/syncable/syncable.cc
|
| @@ -14,6 +14,7 @@
|
| #include <string>
|
|
|
| #include "base/compiler_specific.h"
|
| +#include "base/debug/trace_event.h"
|
| #include "base/file_util.h"
|
| #include "base/hash_tables.h"
|
| #include "base/location.h"
|
| @@ -51,6 +52,54 @@ static const InvariantCheckLevel kInvariantCheckLevel = VERIFY_IN_MEMORY;
|
|
|
| // Max number of milliseconds to spend checking syncable entry invariants
|
| static const int kInvariantCheckMaxMs = 50;
|
| +
|
| +struct IdPtrHashFunc {
|
| + size_t operator()(const syncable::Id* id) const {
|
| + return BASE_HASH_NAMESPACE::hash<std::string>()(id->value());
|
| + }
|
| +};
|
| +
|
| +struct IdPtrCompareFunc {
|
| + bool operator()(const syncable::Id* id1, const syncable::Id* id2) const {
|
| + return *id1 == *id2;
|
| + }
|
| +};
|
| +
|
| +// This function checks to see if the given list of Metahandles has any nodes
|
| +// whose PREV_ID, PARENT_ID or NEXT_ID values refer to ID values that do not
|
| +// actually exist. Returns true on success.
|
| +//
|
| +// This function is "Unsafe" because it does not attempt to acquire any locks
|
| +// that may be protecting this list that gets passed in. The caller is
|
| +// responsible for ensuring that no one modifies this list while the function is
|
| +// running.
|
| +bool VerifyReferenceIntegrityUnsafe(const syncable::MetahandlesIndex &index) {
|
| + using namespace syncable;
|
| + typedef base::hash_set<const Id*, IdPtrHashFunc, IdPtrCompareFunc> IdsSet;
|
| +
|
| + IdsSet ids_set;
|
| + bool is_ok = true;
|
| +
|
| + ids_set.resize(index.size());
|
| + for (MetahandlesIndex::iterator it = index.begin();
|
| + it != index.end(); ++it) {
|
| + EntryKernel* entry = *it;
|
| + bool is_duplicate_id = !(ids_set.insert(&entry->ref(ID)).second);
|
| + is_ok = is_ok && !is_duplicate_id;
|
| + }
|
| +
|
| + IdsSet::iterator end = ids_set.end();
|
| + for (MetahandlesIndex::iterator it = index.begin();
|
| + it != index.end(); ++it) {
|
| + EntryKernel* entry = *it;
|
| + bool prev_exists = (ids_set.find(&(entry->ref(PREV_ID))) != end);
|
| + bool parent_exists = (ids_set.find(&(entry->ref(PARENT_ID))) != end);
|
| + bool next_exists = (ids_set.find(&(entry->ref(NEXT_ID))) != end);
|
| + is_ok = is_ok && prev_exists && parent_exists && next_exists;
|
| + }
|
| + return is_ok;
|
| +}
|
| +
|
| } // namespace
|
|
|
| using std::string;
|
| @@ -477,6 +526,10 @@ DirOpenResult Directory::OpenImpl(const FilePath& file_path,
|
| if (OPENED != result)
|
| return result;
|
|
|
| + if (!VerifyReferenceIntegrityUnsafe(metas_bucket)) {
|
| + return FAILED_LOGICAL_CORRUPTION;
|
| + }
|
| +
|
| kernel_ = new Kernel(db_path, name, info, delegate);
|
| kernel_->metahandles_index->swap(metas_bucket);
|
| InitializeIndices();
|
|
|