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