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

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: nparker@ CR feedback 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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
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. 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) {
117 DCHECK(response->removals_size() <= 1);
118 const RepeatedField<int32>* raw_removals = nullptr;
113 for (const auto& removal : response->removals()) { 119 for (const auto& removal : response->removals()) {
Nathan Parker 2016/07/18 20:42:39 This still iterates over the loop, though you expe
vakh (use Gerrit instead) 2016/07/18 20:54:13 Done.
114 // TODO(vakh): Allow other compression types. 120 // TODO(vakh): Allow other compression types.
115 // See: https://bugs.chromium.org/p/chromium/issues/detail?id=624567 121 // See: https://bugs.chromium.org/p/chromium/issues/detail?id=624567
116 DCHECK_EQ(RAW, removal.compression_type()); 122 DCHECK_EQ(RAW, removal.compression_type());
123 raw_removals = &removal.raw_indices().indices();
117 } 124 }
118 125
119 apply_update_result = UpdateHashPrefixMapFromAdditions( 126 apply_update_result = UpdateHashPrefixMapFromAdditions(
120 response->additions(), &hash_prefix_map); 127 response->additions(), &hash_prefix_map);
121 if (apply_update_result == APPLY_UPDATE_SUCCESS) { 128 if (apply_update_result == APPLY_UPDATE_SUCCESS) {
122 apply_update_result = 129 apply_update_result = new_store->MergeUpdate(
123 new_store->MergeUpdate(hash_prefix_map_, hash_prefix_map); 130 hash_prefix_map_, hash_prefix_map, raw_removals);
124 } 131 }
125 // TODO(vakh): Generate the updated ListUpdateResponse to write to disk. 132 // TODO(vakh): Generate the updated ListUpdateResponse to write to disk.
126 } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) { 133 } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) {
127 apply_update_result = UpdateHashPrefixMapFromAdditions( 134 apply_update_result = UpdateHashPrefixMapFromAdditions(
128 response->additions(), &hash_prefix_map); 135 response->additions(), &hash_prefix_map);
129 if (apply_update_result == APPLY_UPDATE_SUCCESS) { 136 if (apply_update_result == APPLY_UPDATE_SUCCESS) {
130 new_store->hash_prefix_map_ = hash_prefix_map; 137 new_store->hash_prefix_map_ = hash_prefix_map;
131 RecordStoreWriteResult(new_store->WriteToDisk(std::move(response))); 138 RecordStoreWriteResult(new_store->WriteToDisk(std::move(response)));
132 } 139 }
133 } else { 140 } else {
134 apply_update_result = UNEXPECTED_RESPONSE_TYPE_FAILURE; 141 apply_update_result = UNEXPECTED_RESPONSE_TYPE_FAILURE;
135 NOTREACHED() << "Unexpected response type: " << response->response_type(); 142 NOTREACHED() << "Unexpected response type: " << response->response_type();
136 } 143 }
137 144
138 if (apply_update_result == APPLY_UPDATE_SUCCESS) { 145 if (apply_update_result == APPLY_UPDATE_SUCCESS) {
139 // new_store is done updating, pass it to the callback. 146 // new_store is done updating, pass it to the callback.
140 callback_task_runner->PostTask( 147 callback_task_runner->PostTask(
141 FROM_HERE, base::Bind(callback, base::Passed(&new_store))); 148 FROM_HERE, base::Bind(callback, base::Passed(&new_store)));
142 } else { 149 } else {
143 // new_store failed updating. Pass a nullptr to the callback. 150 // new_store failed updating. Pass a nullptr to the callback.
144 callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr)); 151 callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr));
145 } 152 }
146 153
147 RecordApplyUpdateResult(apply_update_result); 154 RecordApplyUpdateResult(apply_update_result);
148 } 155 }
149 156
150 // static 157 // static
151 ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions( 158 ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions(
152 const ::google::protobuf::RepeatedPtrField<ThreatEntrySet>& additions, 159 const RepeatedPtrField<ThreatEntrySet>& additions,
153 HashPrefixMap* additions_map) { 160 HashPrefixMap* additions_map) {
154 for (const auto& addition : additions) { 161 for (const auto& addition : additions) {
155 // TODO(vakh): Allow other compression types. 162 // TODO(vakh): Allow other compression types.
156 // See: https://bugs.chromium.org/p/chromium/issues/detail?id=624567 163 // See: https://bugs.chromium.org/p/chromium/issues/detail?id=624567
157 DCHECK_EQ(RAW, addition.compression_type()); 164 DCHECK_EQ(RAW, addition.compression_type());
158 165
159 DCHECK(addition.has_raw_hashes()); 166 DCHECK(addition.has_raw_hashes());
160 DCHECK(addition.raw_hashes().has_raw_hashes()); 167 DCHECK(addition.raw_hashes().has_raw_hashes());
161 168
162 PrefixSize prefix_size = addition.raw_hashes().prefix_size(); 169 PrefixSize prefix_size = addition.raw_hashes().prefix_size();
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 238
232 const HashPrefixes& existing_prefixes = 239 const HashPrefixes& existing_prefixes =
233 (*prefix_map_to_update)[prefix_size]; 240 (*prefix_map_to_update)[prefix_size];
234 size_t existing_capacity = existing_prefixes.capacity(); 241 size_t existing_capacity = existing_prefixes.capacity();
235 242
236 (*prefix_map_to_update)[prefix_size].reserve(existing_capacity + 243 (*prefix_map_to_update)[prefix_size].reserve(existing_capacity +
237 prefix_length_to_add); 244 prefix_length_to_add);
238 } 245 }
239 } 246 }
240 247
241 ApplyUpdateResult V4Store::MergeUpdate(const HashPrefixMap& old_prefixes_map, 248 ApplyUpdateResult V4Store::MergeUpdate(
242 const HashPrefixMap& additions_map) { 249 const HashPrefixMap& old_prefixes_map,
250 const HashPrefixMap& additions_map,
251 const RepeatedField<int32>* raw_removals) {
243 DCHECK(hash_prefix_map_.empty()); 252 DCHECK(hash_prefix_map_.empty());
244 hash_prefix_map_.clear(); 253 hash_prefix_map_.clear();
245 ReserveSpaceInPrefixMap(old_prefixes_map, &hash_prefix_map_); 254 ReserveSpaceInPrefixMap(old_prefixes_map, &hash_prefix_map_);
246 ReserveSpaceInPrefixMap(additions_map, &hash_prefix_map_); 255 ReserveSpaceInPrefixMap(additions_map, &hash_prefix_map_);
247 256
248 IteratorMap old_iterator_map; 257 IteratorMap old_iterator_map;
249 HashPrefix next_smallest_prefix_old; 258 HashPrefix next_smallest_prefix_old;
250 InitializeIteratorMap(old_prefixes_map, &old_iterator_map); 259 InitializeIteratorMap(old_prefixes_map, &old_iterator_map);
251 bool old_has_unmerged = GetNextSmallestUnmergedPrefix( 260 bool old_has_unmerged = GetNextSmallestUnmergedPrefix(
252 old_prefixes_map, old_iterator_map, &next_smallest_prefix_old); 261 old_prefixes_map, old_iterator_map, &next_smallest_prefix_old);
253 262
254 IteratorMap additions_iterator_map; 263 IteratorMap additions_iterator_map;
255 HashPrefix next_smallest_prefix_additions; 264 HashPrefix next_smallest_prefix_additions;
256 InitializeIteratorMap(additions_map, &additions_iterator_map); 265 InitializeIteratorMap(additions_map, &additions_iterator_map);
257 bool additions_has_unmerged = GetNextSmallestUnmergedPrefix( 266 bool additions_has_unmerged = GetNextSmallestUnmergedPrefix(
258 additions_map, additions_iterator_map, &next_smallest_prefix_additions); 267 additions_map, additions_iterator_map, &next_smallest_prefix_additions);
259 268
260 // Classical merge sort. 269 // Classical merge sort.
261 // The two constructs to merge are maps: old_prefixes_map, additions_map. 270 // 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 271 // At least one of the maps still has elements that need to be merged into the
263 // new store. 272 // new store.
273
274 // Keep track of the number of elements picked from the old map. This is used
275 // to determine which elements to drop based on the raw_removals. Note that
276 // picked is not the same as merged. A picked element isn't merged if its
277 // index is on the raw_removals list.
278 int total_picked_from_old = 0;
279 const int* removals_iter = raw_removals ? raw_removals->begin() : nullptr;
264 while (old_has_unmerged || additions_has_unmerged) { 280 while (old_has_unmerged || additions_has_unmerged) {
265 // If the same hash prefix appears in the existing store and the additions 281 // If the same hash prefix appears in the existing store and the additions
266 // list, something is clearly wrong. Discard the update. 282 // list, something is clearly wrong. Discard the update.
267 if (old_has_unmerged && additions_has_unmerged && 283 if (old_has_unmerged && additions_has_unmerged &&
268 next_smallest_prefix_old == next_smallest_prefix_additions) { 284 next_smallest_prefix_old == next_smallest_prefix_additions) {
269 return ADDITIONS_HAS_EXISTING_PREFIX_FAILURE; 285 return ADDITIONS_HAS_EXISTING_PREFIX_FAILURE;
270 } 286 }
271 287
272 // Select which map to pick the next hash prefix from to keep the result in 288 // Select which map to pick the next hash prefix from to keep the result in
273 // lexographically sorted order. 289 // lexographically sorted order.
274 bool pick_from_old = 290 bool pick_from_old =
275 old_has_unmerged && 291 old_has_unmerged &&
276 (!additions_has_unmerged || 292 (!additions_has_unmerged ||
277 (next_smallest_prefix_old < next_smallest_prefix_additions)); 293 (next_smallest_prefix_old < next_smallest_prefix_additions));
278 294
279 PrefixSize next_smallest_prefix_size; 295 PrefixSize next_smallest_prefix_size;
280 if (pick_from_old) { 296 if (pick_from_old) {
281 next_smallest_prefix_size = next_smallest_prefix_old.size(); 297 next_smallest_prefix_size = next_smallest_prefix_old.size();
282 298
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 299 // Update the iterator map, which means that we have merged one hash
287 // prefix of size |next_size_for_old| from the old store. 300 // prefix of size |next_size_for_old| from the old store.
288 old_iterator_map[next_smallest_prefix_size] += next_smallest_prefix_size; 301 old_iterator_map[next_smallest_prefix_size] += next_smallest_prefix_size;
289 302
303 if (!raw_removals || removals_iter == raw_removals->end() ||
304 *removals_iter != total_picked_from_old) {
305 // Append the smallest hash to the appropriate list.
306 hash_prefix_map_[next_smallest_prefix_size] += next_smallest_prefix_old;
307 } else {
308 // Element not added to new map. Move the removals iterator forward.
309 removals_iter++;
310 }
311
312 total_picked_from_old++;
313
290 // Find the next smallest unmerged element in the old store's map. 314 // Find the next smallest unmerged element in the old store's map.
291 old_has_unmerged = GetNextSmallestUnmergedPrefix( 315 old_has_unmerged = GetNextSmallestUnmergedPrefix(
292 old_prefixes_map, old_iterator_map, &next_smallest_prefix_old); 316 old_prefixes_map, old_iterator_map, &next_smallest_prefix_old);
293 } else { 317 } else {
294 next_smallest_prefix_size = next_smallest_prefix_additions.size(); 318 next_smallest_prefix_size = next_smallest_prefix_additions.size();
295 319
296 // Append the smallest hash to the appropriate list. 320 // Append the smallest hash to the appropriate list.
297 hash_prefix_map_[next_smallest_prefix_size] += 321 hash_prefix_map_[next_smallest_prefix_size] +=
298 next_smallest_prefix_additions; 322 next_smallest_prefix_additions;
299 323
300 // Update the iterator map, which means that we have merged one hash 324 // Update the iterator map, which means that we have merged one hash
301 // prefix of size |next_smallest_prefix_size| from the update. 325 // prefix of size |next_smallest_prefix_size| from the update.
302 additions_iterator_map[next_smallest_prefix_size] += 326 additions_iterator_map[next_smallest_prefix_size] +=
303 next_smallest_prefix_size; 327 next_smallest_prefix_size;
304 328
305 // Find the next smallest unmerged element in the additions map. 329 // Find the next smallest unmerged element in the additions map.
306 additions_has_unmerged = 330 additions_has_unmerged =
307 GetNextSmallestUnmergedPrefix(additions_map, additions_iterator_map, 331 GetNextSmallestUnmergedPrefix(additions_map, additions_iterator_map,
308 &next_smallest_prefix_additions); 332 &next_smallest_prefix_additions);
309 } 333 }
310 } 334 }
311 335
312 return APPLY_UPDATE_SUCCESS; 336 return (!raw_removals || removals_iter == raw_removals->end())
337 ? APPLY_UPDATE_SUCCESS
338 : REMOVALS_INDEX_TOO_LARGE;
313 } 339 }
314 340
315 StoreReadResult V4Store::ReadFromDisk() { 341 StoreReadResult V4Store::ReadFromDisk() {
316 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 342 DCHECK(task_runner_->RunsTasksOnCurrentThread());
317 343
318 std::string contents; 344 std::string contents;
319 bool read_success = base::ReadFileToString(store_path_, &contents); 345 bool read_success = base::ReadFileToString(store_path_, &contents);
320 if (!read_success) { 346 if (!read_success) {
321 return FILE_UNREADABLE_FAILURE; 347 return FILE_UNREADABLE_FAILURE;
322 } 348 }
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 417
392 if (!base::Move(new_filename, store_path_)) { 418 if (!base::Move(new_filename, store_path_)) {
393 DVLOG(1) << "store_path_: " << store_path_.value(); 419 DVLOG(1) << "store_path_: " << store_path_.value();
394 return UNABLE_TO_RENAME_FAILURE; 420 return UNABLE_TO_RENAME_FAILURE;
395 } 421 }
396 422
397 return WRITE_SUCCESS; 423 return WRITE_SUCCESS;
398 } 424 }
399 425
400 } // namespace safe_browsing 426 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698