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 |