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 |