| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h" | 5 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
| 9 #include "base/location.h" | 9 #include "base/location.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 DB_INIT_IO_ERROR, | 31 DB_INIT_IO_ERROR, |
| 32 DB_INIT_FAILED, | 32 DB_INIT_FAILED, |
| 33 DB_INIT_INCOMPATIBLE, | 33 DB_INIT_INCOMPATIBLE, |
| 34 DB_INIT_BROKEN, | 34 DB_INIT_BROKEN, |
| 35 DB_INIT_OPENED_EXISTING_DB, | 35 DB_INIT_OPENED_EXISTING_DB, |
| 36 DB_INIT_CREATED_NEW_DB, | 36 DB_INIT_CREATED_NEW_DB, |
| 37 DB_INIT_REPLACED_EXISTING_DB_WITH_NEW_DB, | 37 DB_INIT_REPLACED_EXISTING_DB_WITH_NEW_DB, |
| 38 DB_INIT_MAX_VALUE, | 38 DB_INIT_MAX_VALUE, |
| 39 }; | 39 }; |
| 40 | 40 |
| 41 // Enum to describe DB validity check failure reason. |
| 42 enum CheckValidityFailureReason { |
| 43 CHECK_VALIDITY_FAILURE_INVALID_HEADER, |
| 44 CHECK_VALIDITY_FAILURE_BROKEN_ID_ENTRY, |
| 45 CHECK_VALIDITY_FAILURE_BROKEN_ENTRY, |
| 46 CHECK_VALIDITY_FAILURE_INVALID_LOCAL_ID, |
| 47 CHECK_VALIDITY_FAILURE_INVALID_PARENT_ID, |
| 48 CHECK_VALIDITY_FAILURE_BROKEN_CHILD_MAP, |
| 49 CHECK_VALIDITY_FAILURE_CHILD_ENTRY_COUNT_MISMATCH, |
| 50 CHECK_VALIDITY_FAILURE_ITERATOR_ERROR, |
| 51 CHECK_VALIDITY_FAILURE_MAX_VALUE, |
| 52 }; |
| 53 |
| 41 // The name of the DB which stores the metadata. | 54 // The name of the DB which stores the metadata. |
| 42 const base::FilePath::CharType kResourceMapDBName[] = | 55 const base::FilePath::CharType kResourceMapDBName[] = |
| 43 FILE_PATH_LITERAL("resource_metadata_resource_map.db"); | 56 FILE_PATH_LITERAL("resource_metadata_resource_map.db"); |
| 44 | 57 |
| 45 // The name of the DB which couldn't be opened, but is preserved just in case. | 58 // The name of the DB which couldn't be opened, but is preserved just in case. |
| 46 const base::FilePath::CharType kPreservedResourceMapDBName[] = | 59 const base::FilePath::CharType kPreservedResourceMapDBName[] = |
| 47 FILE_PATH_LITERAL("resource_metadata_preserved_resource_map.db"); | 60 FILE_PATH_LITERAL("resource_metadata_preserved_resource_map.db"); |
| 48 | 61 |
| 49 // The name of the DB which couldn't be opened, and was replaced with a new one. | 62 // The name of the DB which couldn't be opened, and was replaced with a new one. |
| 50 const base::FilePath::CharType kTrashedResourceMapDBName[] = | 63 const base::FilePath::CharType kTrashedResourceMapDBName[] = |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 ResourceMetadataHeader GetDefaultHeaderEntry() { | 169 ResourceMetadataHeader GetDefaultHeaderEntry() { |
| 157 ResourceMetadataHeader header; | 170 ResourceMetadataHeader header; |
| 158 header.set_version(ResourceMetadataStorage::kDBVersion); | 171 header.set_version(ResourceMetadataStorage::kDBVersion); |
| 159 return header; | 172 return header; |
| 160 } | 173 } |
| 161 | 174 |
| 162 bool MoveIfPossible(const base::FilePath& from, const base::FilePath& to) { | 175 bool MoveIfPossible(const base::FilePath& from, const base::FilePath& to) { |
| 163 return !base::PathExists(from) || base::Move(from, to); | 176 return !base::PathExists(from) || base::Move(from, to); |
| 164 } | 177 } |
| 165 | 178 |
| 179 void RecordCheckValidityFailure(CheckValidityFailureReason reason) { |
| 180 UMA_HISTOGRAM_ENUMERATION("Drive.MetadataDBValidityCheckFailureReason", |
| 181 reason, |
| 182 CHECK_VALIDITY_FAILURE_MAX_VALUE); |
| 183 } |
| 184 |
| 166 } // namespace | 185 } // namespace |
| 167 | 186 |
| 168 ResourceMetadataStorage::Iterator::Iterator(scoped_ptr<leveldb::Iterator> it) | 187 ResourceMetadataStorage::Iterator::Iterator(scoped_ptr<leveldb::Iterator> it) |
| 169 : it_(it.Pass()) { | 188 : it_(it.Pass()) { |
| 170 base::ThreadRestrictions::AssertIOAllowed(); | 189 base::ThreadRestrictions::AssertIOAllowed(); |
| 171 DCHECK(it_); | 190 DCHECK(it_); |
| 172 | 191 |
| 173 // Skip the header entry. | 192 // Skip the header entry. |
| 174 // Note: The header entry comes before all other entries because its key | 193 // Note: The header entry comes before all other entries because its key |
| 175 // starts with kDBKeyDelimeter. (i.e. '\0') | 194 // starts with kDBKeyDelimeter. (i.e. '\0') |
| (...skipping 749 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 925 // "|ID of B|" : ResourceEntry for entry B. | 944 // "|ID of B|" : ResourceEntry for entry B. |
| 926 // ... | 945 // ... |
| 927 | 946 |
| 928 // Check the header. | 947 // Check the header. |
| 929 ResourceMetadataHeader header; | 948 ResourceMetadataHeader header; |
| 930 if (!it->Valid() || | 949 if (!it->Valid() || |
| 931 it->key() != GetHeaderDBKey() || // Header entry must come first. | 950 it->key() != GetHeaderDBKey() || // Header entry must come first. |
| 932 !header.ParseFromArray(it->value().data(), it->value().size()) || | 951 !header.ParseFromArray(it->value().data(), it->value().size()) || |
| 933 header.version() != kDBVersion) { | 952 header.version() != kDBVersion) { |
| 934 DLOG(ERROR) << "Invalid header detected. version = " << header.version(); | 953 DLOG(ERROR) << "Invalid header detected. version = " << header.version(); |
| 954 RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_INVALID_HEADER); |
| 935 return false; | 955 return false; |
| 936 } | 956 } |
| 937 | 957 |
| 938 // Check all entries. | 958 // Check all entries. |
| 939 size_t num_entries_with_parent = 0; | 959 size_t num_entries_with_parent = 0; |
| 940 size_t num_child_entries = 0; | 960 size_t num_child_entries = 0; |
| 941 ResourceEntry entry; | 961 ResourceEntry entry; |
| 942 std::string serialized_entry; | 962 std::string serialized_entry; |
| 943 std::string child_id; | 963 std::string child_id; |
| 944 for (it->Next(); it->Valid(); it->Next()) { | 964 for (it->Next(); it->Valid(); it->Next()) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 955 // Resource-ID-to-local-ID mapping without entry for the local ID is ok. | 975 // Resource-ID-to-local-ID mapping without entry for the local ID is ok. |
| 956 if (status.IsNotFound()) | 976 if (status.IsNotFound()) |
| 957 continue; | 977 continue; |
| 958 // When the entry exists, its resource ID must be consistent. | 978 // When the entry exists, its resource ID must be consistent. |
| 959 const bool ok = status.ok() && | 979 const bool ok = status.ok() && |
| 960 entry.ParseFromString(serialized_entry) && | 980 entry.ParseFromString(serialized_entry) && |
| 961 !entry.resource_id().empty() && | 981 !entry.resource_id().empty() && |
| 962 leveldb::Slice(GetIdEntryKey(entry.resource_id())) == it->key(); | 982 leveldb::Slice(GetIdEntryKey(entry.resource_id())) == it->key(); |
| 963 if (!ok) { | 983 if (!ok) { |
| 964 DLOG(ERROR) << "Broken ID entry. status = " << status.ToString(); | 984 DLOG(ERROR) << "Broken ID entry. status = " << status.ToString(); |
| 985 RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_BROKEN_ID_ENTRY); |
| 965 return false; | 986 return false; |
| 966 } | 987 } |
| 967 continue; | 988 continue; |
| 968 } | 989 } |
| 969 | 990 |
| 970 // Check if stored data is broken. | 991 // Check if stored data is broken. |
| 971 if (!entry.ParseFromArray(it->value().data(), it->value().size())) { | 992 if (!entry.ParseFromArray(it->value().data(), it->value().size())) { |
| 972 DLOG(ERROR) << "Broken entry detected"; | 993 DLOG(ERROR) << "Broken entry detected"; |
| 994 RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_BROKEN_ENTRY); |
| 973 return false; | 995 return false; |
| 974 } | 996 } |
| 975 | 997 |
| 976 if (leveldb::Slice(entry.local_id()) != it->key()) { | 998 if (leveldb::Slice(entry.local_id()) != it->key()) { |
| 977 DLOG(ERROR) << "Wrong local ID."; | 999 DLOG(ERROR) << "Wrong local ID."; |
| 1000 RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_INVALID_LOCAL_ID); |
| 978 return false; | 1001 return false; |
| 979 } | 1002 } |
| 980 | 1003 |
| 981 if (!entry.parent_local_id().empty()) { | 1004 if (!entry.parent_local_id().empty()) { |
| 982 // Check if the parent entry is stored. | 1005 // Check if the parent entry is stored. |
| 983 leveldb::Status status = resource_map_->Get( | 1006 leveldb::Status status = resource_map_->Get( |
| 984 options, | 1007 options, |
| 985 leveldb::Slice(entry.parent_local_id()), | 1008 leveldb::Slice(entry.parent_local_id()), |
| 986 &serialized_entry); | 1009 &serialized_entry); |
| 987 if (!status.ok()) { | 1010 if (!status.ok()) { |
| 988 DLOG(ERROR) << "Can't get parent entry. status = " << status.ToString(); | 1011 DLOG(ERROR) << "Can't get parent entry. status = " << status.ToString(); |
| 1012 RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_INVALID_PARENT_ID); |
| 989 return false; | 1013 return false; |
| 990 } | 1014 } |
| 991 | 1015 |
| 992 // Check if parent-child relationship is stored correctly. | 1016 // Check if parent-child relationship is stored correctly. |
| 993 status = resource_map_->Get( | 1017 status = resource_map_->Get( |
| 994 options, | 1018 options, |
| 995 leveldb::Slice(GetChildEntryKey(entry.parent_local_id(), | 1019 leveldb::Slice(GetChildEntryKey(entry.parent_local_id(), |
| 996 entry.base_name())), | 1020 entry.base_name())), |
| 997 &child_id); | 1021 &child_id); |
| 998 if (!status.ok() || leveldb::Slice(child_id) != it->key()) { | 1022 if (!status.ok() || leveldb::Slice(child_id) != it->key()) { |
| 999 DLOG(ERROR) << "Child map is broken. status = " << status.ToString(); | 1023 DLOG(ERROR) << "Child map is broken. status = " << status.ToString(); |
| 1024 RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_BROKEN_CHILD_MAP); |
| 1000 return false; | 1025 return false; |
| 1001 } | 1026 } |
| 1002 ++num_entries_with_parent; | 1027 ++num_entries_with_parent; |
| 1003 } | 1028 } |
| 1004 } | 1029 } |
| 1005 if (!it->status().ok() || num_child_entries != num_entries_with_parent) { | 1030 if (!it->status().ok()) { |
| 1006 DLOG(ERROR) << "Error during checking resource map. status = " | 1031 DLOG(ERROR) << "Error during checking resource map. status = " |
| 1007 << it->status().ToString(); | 1032 << it->status().ToString(); |
| 1033 RecordCheckValidityFailure(CHECK_VALIDITY_FAILURE_ITERATOR_ERROR); |
| 1034 return false; |
| 1035 } |
| 1036 if (num_child_entries != num_entries_with_parent) { |
| 1037 DLOG(ERROR) << "Child entry count mismatch"; |
| 1038 RecordCheckValidityFailure( |
| 1039 CHECK_VALIDITY_FAILURE_CHILD_ENTRY_COUNT_MISMATCH); |
| 1008 return false; | 1040 return false; |
| 1009 } | 1041 } |
| 1010 return true; | 1042 return true; |
| 1011 } | 1043 } |
| 1012 | 1044 |
| 1013 } // namespace internal | 1045 } // namespace internal |
| 1014 } // namespace drive | 1046 } // namespace drive |
| OLD | NEW |