Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(311)

Side by Side Diff: components/safe_browsing_db/v4_store.cc

Issue 2151953003: PVer4: Drop hash prefixes based on the removals field in the response (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@02_iterators
Patch Set: Don't iterate over removals. Update removals comment. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/metrics/histogram_macros.h" 8 #include "base/metrics/histogram_macros.h"
9 #include "base/metrics/sparse_histogram.h" 9 #include "base/metrics/sparse_histogram.h"
10 #include "base/strings/stringprintf.h" 10 #include "base/strings/stringprintf.h"
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 } 47 }
48 48
49 // Returns the name of the temporary file used to buffer data for 49 // Returns the name of the temporary file used to buffer data for
50 // |filename|. Exported for unit tests. 50 // |filename|. Exported for unit tests.
51 const base::FilePath TemporaryFileForFilename(const base::FilePath& filename) { 51 const base::FilePath TemporaryFileForFilename(const base::FilePath& filename) {
52 return base::FilePath(filename.value() + FILE_PATH_LITERAL("_new")); 52 return base::FilePath(filename.value() + FILE_PATH_LITERAL("_new"));
53 } 53 }
54 54
55 } // namespace 55 } // namespace
56 56
57 using ::google::protobuf::RepeatedField;
58 using ::google::protobuf::RepeatedPtrField;
59 using ::google::protobuf::int32;
60
57 std::ostream& operator<<(std::ostream& os, const V4Store& store) { 61 std::ostream& operator<<(std::ostream& os, const V4Store& store) {
58 os << store.DebugString(); 62 os << store.DebugString();
59 return os; 63 return os;
60 } 64 }
61 65
62 V4Store* V4StoreFactory::CreateV4Store( 66 V4Store* V4StoreFactory::CreateV4Store(
63 const scoped_refptr<base::SequencedTaskRunner>& task_runner, 67 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
64 const base::FilePath& store_path) { 68 const base::FilePath& store_path) {
65 V4Store* new_store = new V4Store(task_runner, store_path); 69 V4Store* new_store = new V4Store(task_runner, store_path);
66 new_store->Initialize(); 70 new_store->Initialize();
(...skipping 29 matching lines...) Expand all
96 } 100 }
97 101
98 void V4Store::ApplyUpdate( 102 void V4Store::ApplyUpdate(
99 std::unique_ptr<ListUpdateResponse> response, 103 std::unique_ptr<ListUpdateResponse> response,
100 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner, 104 const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner,
101 UpdatedStoreReadyCallback callback) { 105 UpdatedStoreReadyCallback callback) {
102 std::unique_ptr<V4Store> new_store( 106 std::unique_ptr<V4Store> new_store(
103 new V4Store(this->task_runner_, this->store_path_)); 107 new V4Store(this->task_runner_, this->store_path_));
104 new_store->state_ = response->new_client_state(); 108 new_store->state_ = response->new_client_state();
105 // TODO(vakh): 109 // TODO(vakh):
106 // 1. Merge the old store and the new update in new_store. 110 // 1. Done: Merge the old store and the new update in new_store.
107 // 2. Create a ListUpdateResponse containing RICE encoded hash-prefixes and 111 // 2. Create a ListUpdateResponse containing RICE encoded hash-prefixes and
108 // response_type as FULL_UPDATE, and write that to disk. 112 // response_type as FULL_UPDATE, and write that to disk.
109 // 3. Remove this if condition after completing 1. and 2. 113 // 3. Remove this if condition after completing 1. and 2.
110 HashPrefixMap hash_prefix_map; 114 HashPrefixMap hash_prefix_map;
111 ApplyUpdateResult apply_update_result; 115 ApplyUpdateResult apply_update_result;
112 if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) { 116 if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) {
113 for (const auto& removal : response->removals()) { 117 const RepeatedField<int32>* raw_removals = nullptr;
118 size_t removals_size = response->removals_size();
119 DCHECK_LE(removals_size, 1u);
120 if (removals_size == 1) {
121 const ThreatEntrySet& removal = response->removals().Get(0);
114 // TODO(vakh): Allow other compression types. 122 // TODO(vakh): Allow other compression types.
115 // See: https://bugs.chromium.org/p/chromium/issues/detail?id=624567 123 // See: https://bugs.chromium.org/p/chromium/issues/detail?id=624567
116 DCHECK_EQ(RAW, removal.compression_type()); 124 DCHECK_EQ(RAW, removal.compression_type());
125 raw_removals = &removal.raw_indices().indices();
117 } 126 }
118 127
119 apply_update_result = UpdateHashPrefixMapFromAdditions( 128 apply_update_result = UpdateHashPrefixMapFromAdditions(
120 response->additions(), &hash_prefix_map); 129 response->additions(), &hash_prefix_map);
121 if (apply_update_result == APPLY_UPDATE_SUCCESS) { 130 if (apply_update_result == APPLY_UPDATE_SUCCESS) {
122 apply_update_result = 131 apply_update_result = new_store->MergeUpdate(
123 new_store->MergeUpdate(hash_prefix_map_, hash_prefix_map); 132 hash_prefix_map_, hash_prefix_map, raw_removals);
124 } 133 }
125 // TODO(vakh): Generate the updated ListUpdateResponse to write to disk. 134 // TODO(vakh): Generate the updated ListUpdateResponse to write to disk.
126 } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) { 135 } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) {
127 apply_update_result = UpdateHashPrefixMapFromAdditions( 136 apply_update_result = UpdateHashPrefixMapFromAdditions(
128 response->additions(), &hash_prefix_map); 137 response->additions(), &hash_prefix_map);
129 if (apply_update_result == APPLY_UPDATE_SUCCESS) { 138 if (apply_update_result == APPLY_UPDATE_SUCCESS) {
130 new_store->hash_prefix_map_ = hash_prefix_map; 139 new_store->hash_prefix_map_ = hash_prefix_map;
131 RecordStoreWriteResult(new_store->WriteToDisk(std::move(response))); 140 RecordStoreWriteResult(new_store->WriteToDisk(std::move(response)));
132 } 141 }
133 } else { 142 } else {
134 apply_update_result = UNEXPECTED_RESPONSE_TYPE_FAILURE; 143 apply_update_result = UNEXPECTED_RESPONSE_TYPE_FAILURE;
135 NOTREACHED() << "Unexpected response type: " << response->response_type(); 144 NOTREACHED() << "Unexpected response type: " << response->response_type();
136 } 145 }
137 146
138 if (apply_update_result == APPLY_UPDATE_SUCCESS) { 147 if (apply_update_result == APPLY_UPDATE_SUCCESS) {
139 // new_store is done updating, pass it to the callback. 148 // new_store is done updating, pass it to the callback.
140 callback_task_runner->PostTask( 149 callback_task_runner->PostTask(
141 FROM_HERE, base::Bind(callback, base::Passed(&new_store))); 150 FROM_HERE, base::Bind(callback, base::Passed(&new_store)));
142 } else { 151 } else {
143 // new_store failed updating. Pass a nullptr to the callback. 152 // new_store failed updating. Pass a nullptr to the callback.
144 callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr)); 153 callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr));
145 } 154 }
146 155
147 RecordApplyUpdateResult(apply_update_result); 156 RecordApplyUpdateResult(apply_update_result);
148 } 157 }
149 158
150 // static 159 // static
151 ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions( 160 ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions(
152 const ::google::protobuf::RepeatedPtrField<ThreatEntrySet>& additions, 161 const RepeatedPtrField<ThreatEntrySet>& additions,
153 HashPrefixMap* additions_map) { 162 HashPrefixMap* additions_map) {
154 for (const auto& addition : additions) { 163 for (const auto& addition : additions) {
155 // TODO(vakh): Allow other compression types. 164 // TODO(vakh): Allow other compression types.
156 // See: https://bugs.chromium.org/p/chromium/issues/detail?id=624567 165 // See: https://bugs.chromium.org/p/chromium/issues/detail?id=624567
157 DCHECK_EQ(RAW, addition.compression_type()); 166 DCHECK_EQ(RAW, addition.compression_type());
158 167
159 DCHECK(addition.has_raw_hashes()); 168 DCHECK(addition.has_raw_hashes());
160 DCHECK(addition.raw_hashes().has_raw_hashes()); 169 DCHECK(addition.raw_hashes().has_raw_hashes());
161 170
162 PrefixSize prefix_size = addition.raw_hashes().prefix_size(); 171 PrefixSize prefix_size = addition.raw_hashes().prefix_size();
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 240
232 const HashPrefixes& existing_prefixes = 241 const HashPrefixes& existing_prefixes =
233 (*prefix_map_to_update)[prefix_size]; 242 (*prefix_map_to_update)[prefix_size];
234 size_t existing_capacity = existing_prefixes.capacity(); 243 size_t existing_capacity = existing_prefixes.capacity();
235 244
236 (*prefix_map_to_update)[prefix_size].reserve(existing_capacity + 245 (*prefix_map_to_update)[prefix_size].reserve(existing_capacity +
237 prefix_length_to_add); 246 prefix_length_to_add);
238 } 247 }
239 } 248 }
240 249
241 ApplyUpdateResult V4Store::MergeUpdate(const HashPrefixMap& old_prefixes_map, 250 ApplyUpdateResult V4Store::MergeUpdate(
242 const HashPrefixMap& additions_map) { 251 const HashPrefixMap& old_prefixes_map,
252 const HashPrefixMap& additions_map,
253 const RepeatedField<int32>* raw_removals) {
243 DCHECK(hash_prefix_map_.empty()); 254 DCHECK(hash_prefix_map_.empty());
244 hash_prefix_map_.clear(); 255 hash_prefix_map_.clear();
245 ReserveSpaceInPrefixMap(old_prefixes_map, &hash_prefix_map_); 256 ReserveSpaceInPrefixMap(old_prefixes_map, &hash_prefix_map_);
246 ReserveSpaceInPrefixMap(additions_map, &hash_prefix_map_); 257 ReserveSpaceInPrefixMap(additions_map, &hash_prefix_map_);
247 258
248 IteratorMap old_iterator_map; 259 IteratorMap old_iterator_map;
249 HashPrefix next_smallest_prefix_old; 260 HashPrefix next_smallest_prefix_old;
250 InitializeIteratorMap(old_prefixes_map, &old_iterator_map); 261 InitializeIteratorMap(old_prefixes_map, &old_iterator_map);
251 bool old_has_unmerged = GetNextSmallestUnmergedPrefix( 262 bool old_has_unmerged = GetNextSmallestUnmergedPrefix(
252 old_prefixes_map, old_iterator_map, &next_smallest_prefix_old); 263 old_prefixes_map, old_iterator_map, &next_smallest_prefix_old);
253 264
254 IteratorMap additions_iterator_map; 265 IteratorMap additions_iterator_map;
255 HashPrefix next_smallest_prefix_additions; 266 HashPrefix next_smallest_prefix_additions;
256 InitializeIteratorMap(additions_map, &additions_iterator_map); 267 InitializeIteratorMap(additions_map, &additions_iterator_map);
257 bool additions_has_unmerged = GetNextSmallestUnmergedPrefix( 268 bool additions_has_unmerged = GetNextSmallestUnmergedPrefix(
258 additions_map, additions_iterator_map, &next_smallest_prefix_additions); 269 additions_map, additions_iterator_map, &next_smallest_prefix_additions);
259 270
260 // Classical merge sort. 271 // Classical merge sort.
261 // The two constructs to merge are maps: old_prefixes_map, additions_map. 272 // The two constructs to merge are maps: old_prefixes_map, additions_map.
262 // At least one of the maps still has elements that need to be merged into the 273 // At least one of the maps still has elements that need to be merged into the
263 // new store. 274 // new store.
275
276 // Keep track of the number of elements picked from the old map. This is used
277 // to determine which elements to drop based on the raw_removals. Note that
278 // picked is not the same as merged. A picked element isn't merged if its
279 // index is on the raw_removals list.
280 int total_picked_from_old = 0;
281 const int* removals_iter = raw_removals ? raw_removals->begin() : nullptr;
264 while (old_has_unmerged || additions_has_unmerged) { 282 while (old_has_unmerged || additions_has_unmerged) {
265 // If the same hash prefix appears in the existing store and the additions 283 // If the same hash prefix appears in the existing store and the additions
266 // list, something is clearly wrong. Discard the update. 284 // list, something is clearly wrong. Discard the update.
267 if (old_has_unmerged && additions_has_unmerged && 285 if (old_has_unmerged && additions_has_unmerged &&
268 next_smallest_prefix_old == next_smallest_prefix_additions) { 286 next_smallest_prefix_old == next_smallest_prefix_additions) {
269 return ADDITIONS_HAS_EXISTING_PREFIX_FAILURE; 287 return ADDITIONS_HAS_EXISTING_PREFIX_FAILURE;
270 } 288 }
271 289
272 // Select which map to pick the next hash prefix from to keep the result in 290 // Select which map to pick the next hash prefix from to keep the result in
273 // lexographically sorted order. 291 // lexographically sorted order.
274 bool pick_from_old = 292 bool pick_from_old =
275 old_has_unmerged && 293 old_has_unmerged &&
276 (!additions_has_unmerged || 294 (!additions_has_unmerged ||
277 (next_smallest_prefix_old < next_smallest_prefix_additions)); 295 (next_smallest_prefix_old < next_smallest_prefix_additions));
278 296
279 PrefixSize next_smallest_prefix_size; 297 PrefixSize next_smallest_prefix_size;
280 if (pick_from_old) { 298 if (pick_from_old) {
281 next_smallest_prefix_size = next_smallest_prefix_old.size(); 299 next_smallest_prefix_size = next_smallest_prefix_old.size();
282 300
283 // Append the smallest hash to the appropriate list.
284 hash_prefix_map_[next_smallest_prefix_size] += next_smallest_prefix_old;
285
286 // Update the iterator map, which means that we have merged one hash 301 // Update the iterator map, which means that we have merged one hash
287 // prefix of size |next_size_for_old| from the old store. 302 // prefix of size |next_size_for_old| from the old store.
288 old_iterator_map[next_smallest_prefix_size] += next_smallest_prefix_size; 303 old_iterator_map[next_smallest_prefix_size] += next_smallest_prefix_size;
289 304
305 if (!raw_removals || removals_iter == raw_removals->end() ||
306 *removals_iter != total_picked_from_old) {
307 // Append the smallest hash to the appropriate list.
308 hash_prefix_map_[next_smallest_prefix_size] += next_smallest_prefix_old;
309 } else {
310 // Element not added to new map. Move the removals iterator forward.
311 removals_iter++;
312 }
313
314 total_picked_from_old++;
315
290 // Find the next smallest unmerged element in the old store's map. 316 // Find the next smallest unmerged element in the old store's map.
291 old_has_unmerged = GetNextSmallestUnmergedPrefix( 317 old_has_unmerged = GetNextSmallestUnmergedPrefix(
292 old_prefixes_map, old_iterator_map, &next_smallest_prefix_old); 318 old_prefixes_map, old_iterator_map, &next_smallest_prefix_old);
293 } else { 319 } else {
294 next_smallest_prefix_size = next_smallest_prefix_additions.size(); 320 next_smallest_prefix_size = next_smallest_prefix_additions.size();
295 321
296 // Append the smallest hash to the appropriate list. 322 // Append the smallest hash to the appropriate list.
297 hash_prefix_map_[next_smallest_prefix_size] += 323 hash_prefix_map_[next_smallest_prefix_size] +=
298 next_smallest_prefix_additions; 324 next_smallest_prefix_additions;
299 325
300 // Update the iterator map, which means that we have merged one hash 326 // Update the iterator map, which means that we have merged one hash
301 // prefix of size |next_smallest_prefix_size| from the update. 327 // prefix of size |next_smallest_prefix_size| from the update.
302 additions_iterator_map[next_smallest_prefix_size] += 328 additions_iterator_map[next_smallest_prefix_size] +=
303 next_smallest_prefix_size; 329 next_smallest_prefix_size;
304 330
305 // Find the next smallest unmerged element in the additions map. 331 // Find the next smallest unmerged element in the additions map.
306 additions_has_unmerged = 332 additions_has_unmerged =
307 GetNextSmallestUnmergedPrefix(additions_map, additions_iterator_map, 333 GetNextSmallestUnmergedPrefix(additions_map, additions_iterator_map,
308 &next_smallest_prefix_additions); 334 &next_smallest_prefix_additions);
309 } 335 }
310 } 336 }
311 337
312 return APPLY_UPDATE_SUCCESS; 338 return (!raw_removals || removals_iter == raw_removals->end())
339 ? APPLY_UPDATE_SUCCESS
340 : REMOVALS_INDEX_TOO_LARGE;
313 } 341 }
314 342
315 StoreReadResult V4Store::ReadFromDisk() { 343 StoreReadResult V4Store::ReadFromDisk() {
316 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 344 DCHECK(task_runner_->RunsTasksOnCurrentThread());
317 345
318 std::string contents; 346 std::string contents;
319 bool read_success = base::ReadFileToString(store_path_, &contents); 347 bool read_success = base::ReadFileToString(store_path_, &contents);
320 if (!read_success) { 348 if (!read_success) {
321 return FILE_UNREADABLE_FAILURE; 349 return FILE_UNREADABLE_FAILURE;
322 } 350 }
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 419
392 if (!base::Move(new_filename, store_path_)) { 420 if (!base::Move(new_filename, store_path_)) {
393 DVLOG(1) << "store_path_: " << store_path_.value(); 421 DVLOG(1) << "store_path_: " << store_path_.value();
394 return UNABLE_TO_RENAME_FAILURE; 422 return UNABLE_TO_RENAME_FAILURE;
395 } 423 }
396 424
397 return WRITE_SUCCESS; 425 return WRITE_SUCCESS;
398 } 426 }
399 427
400 } // namespace safe_browsing 428 } // namespace safe_browsing
OLDNEW
« no previous file with comments | « components/safe_browsing_db/v4_store.h ('k') | components/safe_browsing_db/v4_store_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698