Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "base/base64.h" | 5 #include "base/base64.h" |
| 6 #include "base/bind.h" | 6 #include "base/bind.h" |
| 7 #include "base/files/file_util.h" | 7 #include "base/files/file_util.h" |
| 8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
| 9 #include "base/metrics/histogram_macros.h" | 9 #include "base/metrics/histogram_macros.h" |
| 10 #include "base/metrics/sparse_histogram.h" | 10 #include "base/metrics/sparse_histogram.h" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
| 13 #include "components/safe_browsing_db/v4_rice.h" | 13 #include "components/safe_browsing_db/v4_rice.h" |
| 14 #include "components/safe_browsing_db/v4_store.h" | 14 #include "components/safe_browsing_db/v4_store.h" |
| 15 #include "components/safe_browsing_db/v4_store.pb.h" | 15 #include "components/safe_browsing_db/v4_store.pb.h" |
| 16 #include "crypto/secure_hash.h" | 16 #include "crypto/secure_hash.h" |
| 17 #include "crypto/sha2.h" | 17 #include "crypto/sha2.h" |
| 18 | 18 |
| 19 using base::TimeTicks; | 19 using base::TimeTicks; |
| 20 | 20 |
| 21 namespace safe_browsing { | 21 namespace safe_browsing { |
| 22 | 22 |
| 23 namespace { | 23 namespace { |
| 24 | 24 |
| 25 // UMA related strings. | |
| 26 const char kDecodeAdditions[] = ".DecodeAdditions"; | |
|
Nathan Parker
2016/10/11 20:51:48
I think it'd be clearer to group these into suffix
vakh (use Gerrit instead)
2016/10/11 23:08:05
Done.
| |
| 27 const char kDecodeRemovals[] = ".DecodeRemovals"; | |
| 28 const char kProcessFullUpdate[] = "SafeBrowsing.V4ProcessFullUpdate"; | |
| 29 const char kProcessPartialUpdate[] = "SafeBrowsing.V4ProcessPartialUpdate"; | |
| 30 const char kReadFromDisk[] = "SafeBrowsing.V4ReadFromDisk"; | |
| 31 const char kResult[] = ".Result"; | |
| 32 const char kTime[] = ".Time"; | |
| 33 | |
| 25 const uint32_t kFileMagic = 0x600D71FE; | 34 const uint32_t kFileMagic = 0x600D71FE; |
| 26 | |
| 27 const uint32_t kFileVersion = 9; | 35 const uint32_t kFileVersion = 9; |
| 28 | 36 |
| 29 std::string GetUmaSuffixForStore(const base::FilePath& file_path) { | 37 std::string GetUmaSuffixForStore(const base::FilePath& file_path) { |
| 30 return base::StringPrintf( | 38 return base::StringPrintf( |
| 31 ".%" PRIsFP, file_path.BaseName().RemoveExtension().value().c_str()); | 39 ".%" PRIsFP, file_path.BaseName().RemoveExtension().value().c_str()); |
| 32 } | 40 } |
| 33 | 41 |
| 34 void RecordTimeWithAndWithoutStore(const std::string& metric, | 42 void RecordTimeWithAndWithoutSuffix(const std::string& metric, |
| 35 base::TimeDelta time, | 43 base::TimeDelta time, |
| 36 const base::FilePath& file_path) { | 44 const base::FilePath& file_path) { |
| 37 // The histograms below are a modified expansion of the | 45 // The histograms below are a modified expansion of the |
| 38 // UMA_HISTOGRAM_LONG_TIMES macro adapted to allow for a dynamically suffixed | 46 // UMA_HISTOGRAM_LONG_TIMES macro adapted to allow for a dynamically suffixed |
| 39 // histogram name. | 47 // histogram name. |
| 40 // Note: The factory creates and owns the histogram. | 48 // Note: The factory creates and owns the histogram. |
| 41 const int kBucketCount = 100; | 49 const int kBucketCount = 100; |
| 42 base::HistogramBase* histogram = base::Histogram::FactoryTimeGet( | 50 base::HistogramBase* histogram = base::Histogram::FactoryTimeGet( |
| 43 metric, base::TimeDelta::FromMilliseconds(1), | 51 metric + kTime, base::TimeDelta::FromMilliseconds(1), |
| 44 base::TimeDelta::FromMinutes(1), kBucketCount, | 52 base::TimeDelta::FromMinutes(1), kBucketCount, |
| 45 base::HistogramBase::kUmaTargetedHistogramFlag); | 53 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 46 if (histogram) { | 54 if (histogram) { |
| 47 histogram->AddTime(time); | 55 histogram->AddTime(time); |
| 48 } | 56 } |
| 49 | 57 |
| 50 std::string suffix = GetUmaSuffixForStore(file_path); | 58 std::string suffix = GetUmaSuffixForStore(file_path); |
| 51 base::HistogramBase* histogram_suffix = base::Histogram::FactoryTimeGet( | 59 base::HistogramBase* histogram_suffix = base::Histogram::FactoryTimeGet( |
| 52 metric + suffix, base::TimeDelta::FromMilliseconds(1), | 60 metric + suffix + kTime, base::TimeDelta::FromMilliseconds(1), |
| 53 base::TimeDelta::FromMinutes(1), kBucketCount, | 61 base::TimeDelta::FromMinutes(1), kBucketCount, |
| 54 base::HistogramBase::kUmaTargetedHistogramFlag); | 62 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 55 if (histogram_suffix) { | 63 if (histogram_suffix) { |
| 56 histogram_suffix->AddTime(time); | 64 histogram_suffix->AddTime(time); |
| 57 } | 65 } |
| 58 } | 66 } |
| 59 | 67 |
| 68 void RecordEnumWithAndWithoutSuffix(const std::string& metric, | |
| 69 int32_t value, | |
| 70 int32_t maximum, | |
| 71 const base::FilePath& file_path) { | |
| 72 // The histograms below are an expansion of the UMA_HISTOGRAM_ENUMERATION | |
| 73 // macro adapted to allow for a dynamically suffixed histogram name. | |
| 74 // Note: The factory creates and owns the histogram. | |
| 75 base::HistogramBase* histogram = base::LinearHistogram::FactoryGet( | |
| 76 metric + kResult, 1, maximum, maximum + 1, | |
| 77 base::HistogramBase::kUmaTargetedHistogramFlag); | |
| 78 if (histogram) { | |
| 79 histogram->Add(value); | |
| 80 } | |
| 81 | |
| 82 std::string suffix = GetUmaSuffixForStore(file_path); | |
| 83 base::HistogramBase* histogram_suffix = base::LinearHistogram::FactoryGet( | |
| 84 metric + suffix + kResult, 1, maximum, maximum + 1, | |
| 85 base::HistogramBase::kUmaTargetedHistogramFlag); | |
| 86 if (histogram_suffix) { | |
| 87 histogram_suffix->Add(value); | |
| 88 } | |
| 89 } | |
| 90 | |
| 60 void RecordAddUnlumpedHashesTime(base::TimeDelta time) { | 91 void RecordAddUnlumpedHashesTime(base::TimeDelta time) { |
| 61 UMA_HISTOGRAM_LONG_TIMES("SafeBrowsing.V4AddUnlumpedHashesTime", time); | 92 UMA_HISTOGRAM_LONG_TIMES("SafeBrowsing.V4AddUnlumpedHashes.Time", time); |
|
Nathan Parker
2016/10/11 20:51:48
Should this one also vary by store name?
vakh (use Gerrit instead)
2016/10/11 23:08:05
No, I intend to delete this histogram actually.
I'
| |
| 62 } | 93 } |
| 63 | 94 |
| 64 void RecordApplyUpdateResult(ApplyUpdateResult result) { | 95 void RecordApplyUpdateResult(const std::string& base_metric, |
| 65 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4ApplyUpdateResult", result, | 96 ApplyUpdateResult result, |
| 66 APPLY_UPDATE_RESULT_MAX); | 97 const base::FilePath& file_path) { |
| 98 RecordEnumWithAndWithoutSuffix(base_metric + ".ApplyUpdate", result, | |
|
Nathan Parker
2016/10/11 20:51:48
use a const string here too?
vakh (use Gerrit instead)
2016/10/11 23:08:05
Only used in this one place so defined inline.
| |
| 99 APPLY_UPDATE_RESULT_MAX, file_path); | |
| 67 } | 100 } |
| 68 | 101 |
| 69 void RecordApplyUpdateResultWhenReadingFromDisk(ApplyUpdateResult result) { | 102 void RecordDecodeAdditionsResult(const std::string& base_metric, |
| 70 UMA_HISTOGRAM_ENUMERATION( | 103 V4DecodeResult result, |
| 71 "SafeBrowsing.V4ApplyUpdateResultWhenReadingFromDisk", result, | 104 const base::FilePath& file_path) { |
| 72 APPLY_UPDATE_RESULT_MAX); | 105 RecordEnumWithAndWithoutSuffix(base_metric + kDecodeAdditions, result, |
| 106 DECODE_RESULT_MAX, file_path); | |
| 73 } | 107 } |
| 74 | 108 |
| 75 void RecordDecodeAdditionsResult(V4DecodeResult result) { | 109 void RecordDecodeAdditionsTime(const std::string& base_metric, |
| 76 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4DecodeAdditionsResult", result, | 110 base::TimeDelta time, |
| 77 DECODE_RESULT_MAX); | 111 const base::FilePath& file_path) { |
| 112 RecordTimeWithAndWithoutSuffix(base_metric + kDecodeAdditions, time, | |
| 113 file_path); | |
| 78 } | 114 } |
| 79 | 115 |
| 80 void RecordDecodeAdditionsTime(base::TimeDelta time, | 116 void RecordDecodeRemovalsResult(const std::string& base_metric, |
| 81 const base::FilePath& file_path) { | 117 V4DecodeResult result, |
| 82 RecordTimeWithAndWithoutStore("SafeBrowsing.V4DecodeAdditionsTime", time, | 118 const base::FilePath& file_path) { |
| 83 file_path); | 119 RecordEnumWithAndWithoutSuffix(base_metric + kDecodeRemovals, result, |
| 120 DECODE_RESULT_MAX, file_path); | |
| 84 } | 121 } |
| 85 | 122 |
| 86 void RecordDecodeRemovalsResult(V4DecodeResult result) { | 123 void RecordDecodeRemovalsTime(const std::string& base_metric, |
| 87 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4DecodeRemovalsResult", result, | 124 base::TimeDelta time, |
| 88 DECODE_RESULT_MAX); | 125 const base::FilePath& file_path) { |
| 126 RecordTimeWithAndWithoutSuffix(base_metric + kDecodeRemovals, time, | |
| 127 file_path); | |
| 89 } | 128 } |
| 90 | 129 |
| 91 void RecordDecodeRemovalsTime(base::TimeDelta time, | 130 void RecordMergeUpdateTime(const std::string& base_metric, |
| 92 const base::FilePath& file_path) { | 131 base::TimeDelta time, |
| 93 RecordTimeWithAndWithoutStore("SafeBrowsing.V4DecodeRemovalsTime", time, | |
| 94 file_path); | |
| 95 } | |
| 96 | |
| 97 void RecordMergeUpdateTime(base::TimeDelta time, | |
| 98 const base::FilePath& file_path) { | 132 const base::FilePath& file_path) { |
| 99 RecordTimeWithAndWithoutStore("SafeBrowsing.V4MergeUpdateTime", time, | 133 RecordTimeWithAndWithoutSuffix(base_metric + ".MergeUpdate", time, file_path); |
|
Nathan Parker
2016/10/11 20:51:48
And here too? Or, are you just using constants for
vakh (use Gerrit instead)
2016/10/11 23:08:05
Yup, except kProcessFullUpdate but defining it at
| |
| 100 file_path); | |
| 101 } | |
| 102 | |
| 103 void RecordProcessFullUpdateTime(base::TimeDelta time, | |
| 104 const base::FilePath& file_path) { | |
| 105 RecordTimeWithAndWithoutStore("SafeBrowsing.V4ProcessFullUpdateTime", time, | |
| 106 file_path); | |
| 107 } | |
| 108 | |
| 109 void RecordProcessPartialUpdateTime(base::TimeDelta time, | |
| 110 const base::FilePath& file_path) { | |
| 111 RecordTimeWithAndWithoutStore("SafeBrowsing.V4ProcessPartialUpdateTime", time, | |
| 112 file_path); | |
| 113 } | |
| 114 | |
| 115 void RecordReadFromDiskTime(base::TimeDelta time, | |
| 116 const base::FilePath& file_path) { | |
| 117 RecordTimeWithAndWithoutStore("SafeBrowsing.V4ReadFromDiskTime", time, | |
| 118 file_path); | |
| 119 } | 134 } |
| 120 | 135 |
| 121 void RecordStoreReadResult(StoreReadResult result) { | 136 void RecordStoreReadResult(StoreReadResult result) { |
| 122 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4StoreReadResult", result, | 137 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4StoreRead.Result", result, |
| 123 STORE_READ_RESULT_MAX); | 138 STORE_READ_RESULT_MAX); |
| 124 } | 139 } |
| 125 | 140 |
| 126 void RecordStoreWriteResult(StoreWriteResult result) { | 141 void RecordStoreWriteResult(StoreWriteResult result) { |
| 127 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4StoreWriteResult", result, | 142 UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4StoreWrite.Result", result, |
| 128 STORE_WRITE_RESULT_MAX); | 143 STORE_WRITE_RESULT_MAX); |
| 129 } | 144 } |
| 130 | 145 |
| 131 // Returns the name of the temporary file used to buffer data for | 146 // Returns the name of the temporary file used to buffer data for |
| 132 // |filename|. Exported for unit tests. | 147 // |filename|. Exported for unit tests. |
| 133 const base::FilePath TemporaryFileForFilename(const base::FilePath& filename) { | 148 const base::FilePath TemporaryFileForFilename(const base::FilePath& filename) { |
| 134 return base::FilePath(filename.value() + FILE_PATH_LITERAL("_new")); | 149 return base::FilePath(filename.value() + FILE_PATH_LITERAL("_new")); |
| 135 } | 150 } |
| 136 | 151 |
| 137 } // namespace | 152 } // namespace |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 store_path_.value().c_str(), state_base64.c_str()); | 190 store_path_.value().c_str(), state_base64.c_str()); |
| 176 } | 191 } |
| 177 | 192 |
| 178 void V4Store::Reset() { | 193 void V4Store::Reset() { |
| 179 expected_checksum_.clear(); | 194 expected_checksum_.clear(); |
| 180 hash_prefix_map_.clear(); | 195 hash_prefix_map_.clear(); |
| 181 state_ = ""; | 196 state_ = ""; |
| 182 } | 197 } |
| 183 | 198 |
| 184 ApplyUpdateResult V4Store::ProcessPartialUpdateAndWriteToDisk( | 199 ApplyUpdateResult V4Store::ProcessPartialUpdateAndWriteToDisk( |
| 200 const std::string& metric, | |
| 185 const HashPrefixMap& hash_prefix_map_old, | 201 const HashPrefixMap& hash_prefix_map_old, |
| 186 std::unique_ptr<ListUpdateResponse> response) { | 202 std::unique_ptr<ListUpdateResponse> response) { |
| 187 DCHECK(response->has_response_type()); | 203 DCHECK(response->has_response_type()); |
| 188 DCHECK_EQ(ListUpdateResponse::PARTIAL_UPDATE, response->response_type()); | 204 DCHECK_EQ(ListUpdateResponse::PARTIAL_UPDATE, response->response_type()); |
| 189 | 205 |
| 190 TimeTicks before = TimeTicks::Now(); | 206 TimeTicks before = TimeTicks::Now(); |
| 191 ApplyUpdateResult result = ProcessUpdate(hash_prefix_map_old, response); | 207 ApplyUpdateResult result = |
| 208 ProcessUpdate(metric, hash_prefix_map_old, response); | |
| 192 if (result == APPLY_UPDATE_SUCCESS) { | 209 if (result == APPLY_UPDATE_SUCCESS) { |
| 193 RecordProcessPartialUpdateTime(TimeTicks::Now() - before, store_path_); | 210 RecordTimeWithAndWithoutSuffix(metric, TimeTicks::Now() - before, |
| 211 store_path_); | |
| 194 // TODO(vakh): Create a ListUpdateResponse containing RICE encoded | 212 // TODO(vakh): Create a ListUpdateResponse containing RICE encoded |
| 195 // hash prefixes and response_type as FULL_UPDATE, and write that to disk. | 213 // hash prefixes and response_type as FULL_UPDATE, and write that to disk. |
| 196 } | 214 } |
| 197 return result; | 215 return result; |
| 198 } | 216 } |
| 199 | 217 |
| 200 ApplyUpdateResult V4Store::ProcessFullUpdateAndWriteToDisk( | 218 ApplyUpdateResult V4Store::ProcessFullUpdateAndWriteToDisk( |
| 219 const std::string& metric, | |
| 201 std::unique_ptr<ListUpdateResponse> response) { | 220 std::unique_ptr<ListUpdateResponse> response) { |
| 202 TimeTicks before = TimeTicks::Now(); | 221 TimeTicks before = TimeTicks::Now(); |
| 203 ApplyUpdateResult result = ProcessFullUpdate(response); | 222 ApplyUpdateResult result = ProcessFullUpdate(metric, response); |
| 204 if (result == APPLY_UPDATE_SUCCESS) { | 223 if (result == APPLY_UPDATE_SUCCESS) { |
| 205 RecordProcessFullUpdateTime(TimeTicks::Now() - before, store_path_); | 224 RecordTimeWithAndWithoutSuffix(metric, TimeTicks::Now() - before, |
| 225 store_path_); | |
| 206 RecordStoreWriteResult(WriteToDisk(std::move(response))); | 226 RecordStoreWriteResult(WriteToDisk(std::move(response))); |
| 207 } | 227 } |
| 208 return result; | 228 return result; |
| 209 } | 229 } |
| 210 | 230 |
| 211 ApplyUpdateResult V4Store::ProcessFullUpdate( | 231 ApplyUpdateResult V4Store::ProcessFullUpdate( |
| 232 const std::string& metric, | |
| 212 const std::unique_ptr<ListUpdateResponse>& response) { | 233 const std::unique_ptr<ListUpdateResponse>& response) { |
| 213 DCHECK(response->has_response_type()); | 234 DCHECK(response->has_response_type()); |
| 214 DCHECK_EQ(ListUpdateResponse::FULL_UPDATE, response->response_type()); | 235 DCHECK_EQ(ListUpdateResponse::FULL_UPDATE, response->response_type()); |
| 215 // TODO(vakh): For a full update, we don't need to process the update in | 236 // TODO(vakh): For a full update, we don't need to process the update in |
| 216 // lexographical order to store it, but we do need to do that for calculating | 237 // lexographical order to store it, but we do need to do that for calculating |
| 217 // checksum. It might save some CPU cycles to store the full update as-is and | 238 // checksum. It might save some CPU cycles to store the full update as-is and |
| 218 // walk the list of hash prefixes in lexographical order only for checksum | 239 // walk the list of hash prefixes in lexographical order only for checksum |
| 219 // calculation. | 240 // calculation. |
| 220 return ProcessUpdate(HashPrefixMap(), response); | 241 return ProcessUpdate(metric, HashPrefixMap(), response); |
| 221 } | 242 } |
| 222 | 243 |
| 223 ApplyUpdateResult V4Store::ProcessUpdate( | 244 ApplyUpdateResult V4Store::ProcessUpdate( |
| 245 const std::string& metric, | |
| 224 const HashPrefixMap& hash_prefix_map_old, | 246 const HashPrefixMap& hash_prefix_map_old, |
| 225 const std::unique_ptr<ListUpdateResponse>& response) { | 247 const std::unique_ptr<ListUpdateResponse>& response) { |
| 226 const RepeatedField<int32>* raw_removals = nullptr; | 248 const RepeatedField<int32>* raw_removals = nullptr; |
| 227 RepeatedField<int32> rice_removals; | 249 RepeatedField<int32> rice_removals; |
| 228 size_t removals_size = response->removals_size(); | 250 size_t removals_size = response->removals_size(); |
| 229 DCHECK_LE(removals_size, 1u); | 251 DCHECK_LE(removals_size, 1u); |
| 230 if (removals_size == 1) { | 252 if (removals_size == 1) { |
| 231 const ThreatEntrySet& removal = response->removals().Get(0); | 253 const ThreatEntrySet& removal = response->removals().Get(0); |
| 232 const CompressionType compression_type = removal.compression_type(); | 254 const CompressionType compression_type = removal.compression_type(); |
| 233 if (compression_type == RAW) { | 255 if (compression_type == RAW) { |
| 234 raw_removals = &removal.raw_indices().indices(); | 256 raw_removals = &removal.raw_indices().indices(); |
| 235 } else if (compression_type == RICE) { | 257 } else if (compression_type == RICE) { |
| 236 DCHECK(removal.has_rice_indices()); | 258 DCHECK(removal.has_rice_indices()); |
| 237 | 259 |
| 238 const RiceDeltaEncoding& rice_indices = removal.rice_indices(); | 260 const RiceDeltaEncoding& rice_indices = removal.rice_indices(); |
| 239 TimeTicks before = TimeTicks::Now(); | 261 TimeTicks before = TimeTicks::Now(); |
| 240 V4DecodeResult decode_result = V4RiceDecoder::DecodeIntegers( | 262 V4DecodeResult decode_result = V4RiceDecoder::DecodeIntegers( |
| 241 rice_indices.first_value(), rice_indices.rice_parameter(), | 263 rice_indices.first_value(), rice_indices.rice_parameter(), |
| 242 rice_indices.num_entries(), rice_indices.encoded_data(), | 264 rice_indices.num_entries(), rice_indices.encoded_data(), |
| 243 &rice_removals); | 265 &rice_removals); |
| 244 | 266 |
| 245 RecordDecodeRemovalsResult(decode_result); | 267 RecordDecodeRemovalsResult(metric, decode_result, store_path_); |
| 246 if (decode_result != DECODE_SUCCESS) { | 268 if (decode_result != DECODE_SUCCESS) { |
| 247 return RICE_DECODING_FAILURE; | 269 return RICE_DECODING_FAILURE; |
| 248 } | 270 } |
| 249 RecordDecodeRemovalsTime(TimeTicks::Now() - before, store_path_); | 271 RecordDecodeRemovalsTime(metric, TimeTicks::Now() - before, store_path_); |
| 250 raw_removals = &rice_removals; | 272 raw_removals = &rice_removals; |
| 251 } else { | 273 } else { |
| 252 NOTREACHED() << "Unexpected compression_type type: " << compression_type; | 274 NOTREACHED() << "Unexpected compression_type type: " << compression_type; |
| 253 return UNEXPECTED_COMPRESSION_TYPE_REMOVALS_FAILURE; | 275 return UNEXPECTED_COMPRESSION_TYPE_REMOVALS_FAILURE; |
| 254 } | 276 } |
| 255 } | 277 } |
| 256 | 278 |
| 257 HashPrefixMap hash_prefix_map; | 279 HashPrefixMap hash_prefix_map; |
| 258 ApplyUpdateResult apply_update_result = | 280 ApplyUpdateResult apply_update_result = UpdateHashPrefixMapFromAdditions( |
| 259 UpdateHashPrefixMapFromAdditions(response->additions(), &hash_prefix_map); | 281 metric, response->additions(), &hash_prefix_map); |
| 260 if (apply_update_result != APPLY_UPDATE_SUCCESS) { | 282 if (apply_update_result != APPLY_UPDATE_SUCCESS) { |
| 261 return apply_update_result; | 283 return apply_update_result; |
| 262 } | 284 } |
| 263 | 285 |
| 264 std::string expected_checksum; | 286 std::string expected_checksum; |
| 265 if (response->has_checksum() && response->checksum().has_sha256()) { | 287 if (response->has_checksum() && response->checksum().has_sha256()) { |
| 266 expected_checksum = response->checksum().sha256(); | 288 expected_checksum = response->checksum().sha256(); |
| 267 } | 289 } |
| 268 | 290 |
| 269 TimeTicks before = TimeTicks::Now(); | 291 TimeTicks before = TimeTicks::Now(); |
| 270 apply_update_result = MergeUpdate(hash_prefix_map_old, hash_prefix_map, | 292 apply_update_result = MergeUpdate(hash_prefix_map_old, hash_prefix_map, |
| 271 raw_removals, expected_checksum); | 293 raw_removals, expected_checksum); |
| 272 if (apply_update_result != APPLY_UPDATE_SUCCESS) { | 294 if (apply_update_result != APPLY_UPDATE_SUCCESS) { |
| 273 return apply_update_result; | 295 return apply_update_result; |
| 274 } | 296 } |
| 275 RecordMergeUpdateTime(TimeTicks::Now() - before, store_path_); | 297 RecordMergeUpdateTime(metric, TimeTicks::Now() - before, store_path_); |
| 276 | 298 |
| 277 state_ = response->new_client_state(); | 299 state_ = response->new_client_state(); |
| 278 return APPLY_UPDATE_SUCCESS; | 300 return APPLY_UPDATE_SUCCESS; |
| 279 } | 301 } |
| 280 | 302 |
| 281 void V4Store::ApplyUpdate( | 303 void V4Store::ApplyUpdate( |
| 282 std::unique_ptr<ListUpdateResponse> response, | 304 std::unique_ptr<ListUpdateResponse> response, |
| 283 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, | 305 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, |
| 284 UpdatedStoreReadyCallback callback) { | 306 UpdatedStoreReadyCallback callback) { |
| 285 std::unique_ptr<V4Store> new_store( | 307 std::unique_ptr<V4Store> new_store(new V4Store(task_runner_, store_path_)); |
| 286 new V4Store(this->task_runner_, this->store_path_)); | |
| 287 ApplyUpdateResult apply_update_result; | 308 ApplyUpdateResult apply_update_result; |
| 309 std::string metric; | |
| 288 if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) { | 310 if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) { |
| 311 metric = kProcessPartialUpdate; | |
| 289 apply_update_result = new_store->ProcessPartialUpdateAndWriteToDisk( | 312 apply_update_result = new_store->ProcessPartialUpdateAndWriteToDisk( |
| 290 hash_prefix_map_, std::move(response)); | 313 metric, hash_prefix_map_, std::move(response)); |
| 291 } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) { | 314 } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) { |
| 315 metric = kProcessFullUpdate; | |
| 292 apply_update_result = | 316 apply_update_result = |
| 293 new_store->ProcessFullUpdateAndWriteToDisk(std::move(response)); | 317 new_store->ProcessFullUpdateAndWriteToDisk(metric, std::move(response)); |
| 294 } else { | 318 } else { |
| 295 apply_update_result = UNEXPECTED_RESPONSE_TYPE_FAILURE; | 319 apply_update_result = UNEXPECTED_RESPONSE_TYPE_FAILURE; |
| 296 NOTREACHED() << "Failure: Unexpected response type: " | 320 NOTREACHED() << "Failure: Unexpected response type: " |
| 297 << response->response_type(); | 321 << response->response_type(); |
| 298 } | 322 } |
| 299 | 323 |
| 300 if (apply_update_result == APPLY_UPDATE_SUCCESS) { | 324 if (apply_update_result == APPLY_UPDATE_SUCCESS) { |
| 301 // new_store is done updating, pass it to the callback. | 325 // new_store is done updating, pass it to the callback. |
| 302 callback_task_runner->PostTask( | 326 callback_task_runner->PostTask( |
| 303 FROM_HERE, base::Bind(callback, base::Passed(&new_store))); | 327 FROM_HERE, base::Bind(callback, base::Passed(&new_store))); |
| 304 } else { | 328 } else { |
| 305 DVLOG(1) << "Failure: ApplyUpdate: reason: " << apply_update_result | 329 DVLOG(1) << "Failure: ApplyUpdate: reason: " << apply_update_result |
| 306 << "; store: " << *this; | 330 << "; store: " << *this; |
| 307 // new_store failed updating. Pass a nullptr to the callback. | 331 // new_store failed updating. Pass a nullptr to the callback. |
| 308 callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr)); | 332 callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr)); |
| 309 } | 333 } |
| 310 | 334 |
| 311 RecordApplyUpdateResult(apply_update_result); | 335 RecordApplyUpdateResult(metric, apply_update_result, store_path_); |
| 312 } | 336 } |
| 313 | 337 |
| 314 ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions( | 338 ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions( |
| 339 const std::string& metric, | |
| 315 const RepeatedPtrField<ThreatEntrySet>& additions, | 340 const RepeatedPtrField<ThreatEntrySet>& additions, |
| 316 HashPrefixMap* additions_map) { | 341 HashPrefixMap* additions_map) { |
| 317 for (const auto& addition : additions) { | 342 for (const auto& addition : additions) { |
| 318 ApplyUpdateResult apply_update_result = APPLY_UPDATE_SUCCESS; | 343 ApplyUpdateResult apply_update_result = APPLY_UPDATE_SUCCESS; |
| 319 const CompressionType compression_type = addition.compression_type(); | 344 const CompressionType compression_type = addition.compression_type(); |
| 320 if (compression_type == RAW) { | 345 if (compression_type == RAW) { |
| 321 DCHECK(addition.has_raw_hashes()); | 346 DCHECK(addition.has_raw_hashes()); |
| 322 DCHECK(addition.raw_hashes().has_raw_hashes()); | 347 DCHECK(addition.raw_hashes().has_raw_hashes()); |
| 323 | 348 |
| 324 apply_update_result = | 349 apply_update_result = |
| 325 AddUnlumpedHashes(addition.raw_hashes().prefix_size(), | 350 AddUnlumpedHashes(addition.raw_hashes().prefix_size(), |
| 326 addition.raw_hashes().raw_hashes(), additions_map); | 351 addition.raw_hashes().raw_hashes(), additions_map); |
| 327 } else if (compression_type == RICE) { | 352 } else if (compression_type == RICE) { |
| 328 DCHECK(addition.has_rice_hashes()); | 353 DCHECK(addition.has_rice_hashes()); |
| 329 | 354 |
| 330 const RiceDeltaEncoding& rice_hashes = addition.rice_hashes(); | 355 const RiceDeltaEncoding& rice_hashes = addition.rice_hashes(); |
| 331 std::vector<uint32_t> raw_hashes; | 356 std::vector<uint32_t> raw_hashes; |
| 332 TimeTicks before = TimeTicks::Now(); | 357 TimeTicks before = TimeTicks::Now(); |
| 333 V4DecodeResult decode_result = V4RiceDecoder::DecodePrefixes( | 358 V4DecodeResult decode_result = V4RiceDecoder::DecodePrefixes( |
| 334 rice_hashes.first_value(), rice_hashes.rice_parameter(), | 359 rice_hashes.first_value(), rice_hashes.rice_parameter(), |
| 335 rice_hashes.num_entries(), rice_hashes.encoded_data(), &raw_hashes); | 360 rice_hashes.num_entries(), rice_hashes.encoded_data(), &raw_hashes); |
| 336 RecordDecodeAdditionsResult(decode_result); | 361 RecordDecodeAdditionsResult(metric, decode_result, store_path_); |
| 337 if (decode_result != DECODE_SUCCESS) { | 362 if (decode_result != DECODE_SUCCESS) { |
| 338 return RICE_DECODING_FAILURE; | 363 return RICE_DECODING_FAILURE; |
| 339 } else { | 364 } else { |
| 340 RecordDecodeAdditionsTime(TimeTicks::Now() - before, store_path_); | 365 RecordDecodeAdditionsTime(metric, TimeTicks::Now() - before, |
| 366 store_path_); | |
| 341 char* raw_hashes_start = reinterpret_cast<char*>(raw_hashes.data()); | 367 char* raw_hashes_start = reinterpret_cast<char*>(raw_hashes.data()); |
| 342 size_t raw_hashes_size = sizeof(uint32_t) * raw_hashes.size(); | 368 size_t raw_hashes_size = sizeof(uint32_t) * raw_hashes.size(); |
| 343 | 369 |
| 344 // Rice-Golomb encoding is used to send compressed compressed 4-byte | 370 // Rice-Golomb encoding is used to send compressed compressed 4-byte |
| 345 // hash prefixes. Hash prefixes longer than 4 bytes will not be | 371 // hash prefixes. Hash prefixes longer than 4 bytes will not be |
| 346 // compressed, and will be served in raw format instead. | 372 // compressed, and will be served in raw format instead. |
| 347 // Source: https://developers.google.com/safe-browsing/v4/compression | 373 // Source: https://developers.google.com/safe-browsing/v4/compression |
| 348 const PrefixSize kPrefixSize = 4; | 374 const PrefixSize kPrefixSize = 4; |
| 349 apply_update_result = AddUnlumpedHashes(kPrefixSize, raw_hashes_start, | 375 apply_update_result = AddUnlumpedHashes(kPrefixSize, raw_hashes_start, |
| 350 raw_hashes_size, additions_map); | 376 raw_hashes_size, additions_map); |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 620 if (file_format.version_number() != kFileVersion) { | 646 if (file_format.version_number() != kFileVersion) { |
| 621 return FILE_VERSION_INCOMPATIBLE_FAILURE; | 647 return FILE_VERSION_INCOMPATIBLE_FAILURE; |
| 622 } | 648 } |
| 623 | 649 |
| 624 if (!file_format.has_list_update_response()) { | 650 if (!file_format.has_list_update_response()) { |
| 625 return HASH_PREFIX_INFO_MISSING_FAILURE; | 651 return HASH_PREFIX_INFO_MISSING_FAILURE; |
| 626 } | 652 } |
| 627 | 653 |
| 628 std::unique_ptr<ListUpdateResponse> response(new ListUpdateResponse); | 654 std::unique_ptr<ListUpdateResponse> response(new ListUpdateResponse); |
| 629 response->Swap(file_format.mutable_list_update_response()); | 655 response->Swap(file_format.mutable_list_update_response()); |
| 630 ApplyUpdateResult apply_update_result = ProcessFullUpdate(response); | 656 ApplyUpdateResult apply_update_result = |
| 631 RecordApplyUpdateResultWhenReadingFromDisk(apply_update_result); | 657 ProcessFullUpdate(kReadFromDisk, response); |
| 658 RecordApplyUpdateResult(kReadFromDisk, apply_update_result, store_path_); | |
| 632 if (apply_update_result != APPLY_UPDATE_SUCCESS) { | 659 if (apply_update_result != APPLY_UPDATE_SUCCESS) { |
| 633 hash_prefix_map_.clear(); | 660 hash_prefix_map_.clear(); |
| 634 return HASH_PREFIX_MAP_GENERATION_FAILURE; | 661 return HASH_PREFIX_MAP_GENERATION_FAILURE; |
| 635 } | 662 } |
| 636 RecordReadFromDiskTime(TimeTicks::Now() - before, store_path_); | 663 RecordTimeWithAndWithoutSuffix(kReadFromDisk, TimeTicks::Now() - before, |
| 664 store_path_); | |
| 637 | 665 |
| 638 return READ_SUCCESS; | 666 return READ_SUCCESS; |
| 639 } | 667 } |
| 640 | 668 |
| 641 StoreWriteResult V4Store::WriteToDisk( | 669 StoreWriteResult V4Store::WriteToDisk( |
| 642 std::unique_ptr<ListUpdateResponse> response) const { | 670 std::unique_ptr<ListUpdateResponse> response) const { |
| 643 // Do not write partial updates to the disk. | 671 // Do not write partial updates to the disk. |
| 644 // After merging the updates, the ListUpdateResponse passed to this method | 672 // After merging the updates, the ListUpdateResponse passed to this method |
| 645 // should be a FULL_UPDATE. | 673 // should be a FULL_UPDATE. |
| 646 if (!response->has_response_type() || | 674 if (!response->has_response_type() || |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 743 | 771 |
| 744 // Find the next smallest unmerged element in the map. | 772 // Find the next smallest unmerged element in the map. |
| 745 has_unmerged = GetNextSmallestUnmergedPrefix(hash_prefix_map_, iterator_map, | 773 has_unmerged = GetNextSmallestUnmergedPrefix(hash_prefix_map_, iterator_map, |
| 746 &next_smallest_prefix); | 774 &next_smallest_prefix); |
| 747 } | 775 } |
| 748 | 776 |
| 749 char checksum[crypto::kSHA256Length]; | 777 char checksum[crypto::kSHA256Length]; |
| 750 checksum_ctx->Finish(checksum, sizeof(checksum)); | 778 checksum_ctx->Finish(checksum, sizeof(checksum)); |
| 751 for (size_t i = 0; i < crypto::kSHA256Length; i++) { | 779 for (size_t i = 0; i < crypto::kSHA256Length; i++) { |
| 752 if (checksum[i] != expected_checksum_[i]) { | 780 if (checksum[i] != expected_checksum_[i]) { |
| 753 RecordApplyUpdateResultWhenReadingFromDisk(CHECKSUM_MISMATCH_FAILURE); | 781 RecordApplyUpdateResult(kReadFromDisk, CHECKSUM_MISMATCH_FAILURE, |
| 782 store_path_); | |
| 754 #if DCHECK_IS_ON() | 783 #if DCHECK_IS_ON() |
| 755 std::string checksum_b64, expected_checksum_b64; | 784 std::string checksum_b64, expected_checksum_b64; |
| 756 base::Base64Encode(base::StringPiece(checksum, arraysize(checksum)), | 785 base::Base64Encode(base::StringPiece(checksum, arraysize(checksum)), |
| 757 &checksum_b64); | 786 &checksum_b64); |
| 758 base::Base64Encode(expected_checksum_, &expected_checksum_b64); | 787 base::Base64Encode(expected_checksum_, &expected_checksum_b64); |
| 759 DVLOG(1) << "Failure: Checksum mismatch: calculated: " << checksum_b64 | 788 DVLOG(1) << "Failure: Checksum mismatch: calculated: " << checksum_b64 |
| 760 << "; expected: " << expected_checksum_b64 | 789 << "; expected: " << expected_checksum_b64 |
| 761 << "; store: " << *this; | 790 << "; store: " << *this; |
| 762 #endif | 791 #endif |
| 763 return false; | 792 return false; |
| 764 } | 793 } |
| 765 } | 794 } |
| 766 return true; | 795 return true; |
| 767 } | 796 } |
| 768 | 797 |
| 769 } // namespace safe_browsing | 798 } // namespace safe_browsing |
| OLD | NEW |