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

Side by Side Diff: chrome/browser/safe_browsing/safe_browsing_store.cc

Issue 8349018: Safe-browsing SBAddPrefix from vector to deque. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 9 years, 2 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 (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "chrome/browser/safe_browsing/safe_browsing_store.h" 5 #include "chrome/browser/safe_browsing/safe_browsing_store.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/metrics/histogram.h" 9 #include "base/metrics/histogram.h"
10 10
11 namespace { 11 namespace {
12 12
13 // Find items matching between |subs| and |adds|, and remove them, 13 // Find items matching between |subs| and |adds|, and remove them,
14 // recording the item from |adds| in |adds_removed|. To minimize 14 // recording the item from |adds| in |adds_removed|. To minimize
15 // copies, the inputs are processing in parallel, so |subs| and |adds| 15 // copies, the inputs are processing in parallel, so |subs| and |adds|
16 // should be compatibly ordered (either by SBAddPrefixLess or 16 // should be compatibly ordered (either by SBAddPrefixLess or
17 // SBAddPrefixHashLess). 17 // SBAddPrefixHashLess).
18 // 18 //
19 // |predAS| provides add < sub, |predSA| provides sub < add, for the 19 // |predAS| provides add < sub, |predSA| provides sub < add, for the
20 // tightest compare appropriate (see calls in SBProcessSubs). 20 // tightest compare appropriate (see calls in SBProcessSubs).
21 template <class S, class A, typename PredAS, typename PredSA> 21 template <typename CS, typename CA, typename PredAS, typename PredSA>
jar (doing other things) 2011/10/21 19:10:45 I really didn't like these two letter names. The w
Scott Hess - ex-Googler 2011/10/21 23:39:32 Yeah, I just couldn't think of anything quality to
22 void KnockoutSubs(std::vector<S>* subs, 22 void KnockoutSubs(CS* subs,
23 std::vector<A>* adds, 23 CA* adds,
24 PredAS predAS, PredSA predSA, 24 PredAS predAS, PredSA predSA,
25 std::vector<A>* adds_removed) { 25 CA* adds_removed) {
26 // Keep a pair of output iterators for writing kept items. Due to 26 // Keep a pair of output iterators for writing kept items. Due to
27 // deletions, these may lag the main iterators. Using erase() on 27 // deletions, these may lag the main iterators. Using erase() on
28 // individual items would result in O(N^2) copies. Using std::list 28 // individual items would result in O(N^2) copies. Using std::list
29 // would work around that, at double or triple the memory cost. 29 // would work around that, at double or triple the memory cost.
30 typename std::vector<A>::iterator add_out = adds->begin(); 30 typename CA::iterator add_out = adds->begin();
31 typename std::vector<S>::iterator sub_out = subs->begin(); 31 typename CS::iterator sub_out = subs->begin();
32 32
33 // Current location in vectors. 33 // Current location in containers.
34 // TODO(shess): I want these to be const_iterator, but then 34 // TODO(shess): I want these to be const_iterator, but then
35 // std::copy() gets confused. Could snag a const_iterator add_end, 35 // std::copy() gets confused. Could snag a const_iterator add_end,
36 // or write an inline std::copy(), but it seems like I'm doing 36 // or write an inline std::copy(), but it seems like I'm doing
37 // something wrong. 37 // something wrong.
38 typename std::vector<A>::iterator add_iter = adds->begin(); 38 typename CA::iterator add_iter = adds->begin();
jar (doing other things) 2011/10/21 19:10:45 I'm *not* an expert on templates... but can't you
Scott Hess - ex-Googler 2011/10/21 23:39:32 I don't understand the question. Sometimes a cont
39 typename std::vector<S>::iterator sub_iter = subs->begin(); 39 typename CS::iterator sub_iter = subs->begin();
40 40
41 while (add_iter != adds->end() && sub_iter != subs->end()) { 41 while (add_iter != adds->end() && sub_iter != subs->end()) {
42 // If |*sub_iter| < |*add_iter|, retain the sub. 42 // If |*sub_iter| < |*add_iter|, retain the sub.
43 if (predSA(*sub_iter, *add_iter)) { 43 if (predSA(*sub_iter, *add_iter)) {
44 *sub_out = *sub_iter; 44 *sub_out = *sub_iter;
45 ++sub_out; 45 ++sub_out;
46 ++sub_iter; 46 ++sub_iter;
47 47
48 // If |*add_iter| < |*sub_iter|, retain the add. 48 // If |*add_iter| < |*sub_iter|, retain the add.
49 } else if (predAS(*add_iter, *sub_iter)) { 49 } else if (predAS(*add_iter, *sub_iter)) {
50 *add_out = *add_iter; 50 *add_out = *add_iter;
51 ++add_out; 51 ++add_out;
52 ++add_iter; 52 ++add_iter;
53 53
54 // Record equal items and drop them. 54 // Record equal items and drop them.
55 } else { 55 } else {
56 adds_removed->push_back(*add_iter); 56 adds_removed->push_back(*add_iter);
57 ++add_iter; 57 ++add_iter;
58 ++sub_iter; 58 ++sub_iter;
59 } 59 }
60 } 60 }
61 61
62 // Erase any leftover gap. 62 // Erase any leftover gap.
63 adds->erase(add_out, add_iter); 63 adds->erase(add_out, add_iter);
64 subs->erase(sub_out, sub_iter); 64 subs->erase(sub_out, sub_iter);
65 } 65 }
66 66
67 // Remove items in |removes| from |full_hashes|. |full_hashes| and 67 // Remove items in |removes| from |full_hashes|. |full_hashes| and
68 // |removes| should be ordered by SBAddPrefix component. 68 // |removes| should be ordered by SBAddPrefix component.
69 template <class T> 69 template <typename CT, typename CA>
70 void RemoveMatchingPrefixes(const std::vector<SBAddPrefix>& removes, 70 void RemoveMatchingPrefixes(const CA& removes, CT* full_hashes) {
71 std::vector<T>* full_hashes) {
72 // This is basically an inline of std::set_difference(). 71 // This is basically an inline of std::set_difference().
73 // Unfortunately, that algorithm requires that the two iterator 72 // Unfortunately, that algorithm requires that the two iterator
74 // pairs use the same value types. 73 // pairs use the same value types.
75 74
76 // Where to store kept items. 75 // Where to store kept items.
77 typename std::vector<T>::iterator out = full_hashes->begin(); 76 typename CT::iterator out = full_hashes->begin();
78 77
79 typename std::vector<T>::iterator hash_iter = full_hashes->begin(); 78 typename CT::iterator hash_iter = full_hashes->begin();
80 std::vector<SBAddPrefix>::const_iterator remove_iter = removes.begin(); 79 typename CA::const_iterator remove_iter = removes.begin();
81 80
82 while (hash_iter != full_hashes->end() && remove_iter != removes.end()) { 81 while (hash_iter != full_hashes->end() && remove_iter != removes.end()) {
83 // Keep items less than |*remove_iter|. 82 // Keep items less than |*remove_iter|.
84 if (SBAddPrefixLess(*hash_iter, *remove_iter)) { 83 if (SBAddPrefixLess(*hash_iter, *remove_iter)) {
85 *out = *hash_iter; 84 *out = *hash_iter;
86 ++out; 85 ++out;
87 ++hash_iter; 86 ++hash_iter;
88 87
89 // No hit for |*remove_iter|, bump it forward. 88 // No hit for |*remove_iter|, bump it forward.
90 } else if (SBAddPrefixLess(*remove_iter, *hash_iter)) { 89 } else if (SBAddPrefixLess(*remove_iter, *hash_iter)) {
91 ++remove_iter; 90 ++remove_iter;
92 91
93 // Drop equal items, there may be multiple hits. 92 // Drop equal items, there may be multiple hits.
94 } else { 93 } else {
95 do { 94 do {
96 ++hash_iter; 95 ++hash_iter;
97 } while (hash_iter != full_hashes->end() && 96 } while (hash_iter != full_hashes->end() &&
98 !SBAddPrefixLess(*remove_iter, *hash_iter)); 97 !SBAddPrefixLess(*remove_iter, *hash_iter));
99 ++remove_iter; 98 ++remove_iter;
100 } 99 }
101 } 100 }
102 101
103 // Erase any leftover gap. 102 // Erase any leftover gap.
104 full_hashes->erase(out, hash_iter); 103 full_hashes->erase(out, hash_iter);
105 } 104 }
106 105
107 // Remove deleted items (|chunk_id| in |del_set|) from the vector. 106 // Remove deleted items (|chunk_id| in |del_set|) from the container.
108 template <class T> 107 template <typename CT>
109 void RemoveDeleted(std::vector<T>* vec, const base::hash_set<int32>& del_set) { 108 void RemoveDeleted(CT* vec, const base::hash_set<int32>& del_set) {
110 DCHECK(vec); 109 DCHECK(vec);
111 110
112 // Scan through the items read, dropping the items in |del_set|. 111 // Move items from |iter| to |add_iter|, skipping items in |del_set|.
113 typename std::vector<T>::iterator add_iter = vec->begin(); 112 typename CT::iterator add_iter = vec->begin();
114 for (typename std::vector<T>::iterator iter = add_iter; 113 for (typename CT::iterator iter = add_iter;
115 iter != vec->end(); ++iter) { 114 iter != vec->end(); ++iter) {
116 if (del_set.count(iter->chunk_id) == 0) { 115 if (del_set.count(iter->chunk_id) == 0) {
117 *add_iter = *iter; 116 *add_iter = *iter;
118 ++add_iter; 117 ++add_iter;
119 } 118 }
120 } 119 }
121 vec->erase(add_iter, vec->end()); 120 vec->erase(add_iter, vec->end());
122 } 121 }
123 122
124 enum MissTypes { 123 enum MissTypes {
125 MISS_TYPE_ALL, 124 MISS_TYPE_ALL,
126 MISS_TYPE_FALSE, 125 MISS_TYPE_FALSE,
127 126
128 // Always at the end. 127 // Always at the end.
129 MISS_TYPE_MAX 128 MISS_TYPE_MAX
130 }; 129 };
131 130
132 } // namespace 131 } // namespace
133 132
134 void SBCheckPrefixMisses(const std::vector<SBAddPrefix>& add_prefixes, 133 void SBCheckPrefixMisses(const SBAddPrefixContainer& add_prefixes,
135 const std::set<SBPrefix>& prefix_misses) { 134 const std::set<SBPrefix>& prefix_misses) {
136 if (prefix_misses.empty()) 135 if (prefix_misses.empty())
137 return; 136 return;
138 137
139 // Record a hit for all prefixes which missed when sent to the 138 // Record a hit for all prefixes which missed when sent to the
140 // server. 139 // server.
141 for (size_t i = 0; i < prefix_misses.size(); ++i) { 140 for (size_t i = 0; i < prefix_misses.size(); ++i) {
142 UMA_HISTOGRAM_ENUMERATION("SB2.BloomFilterFalsePositives", 141 UMA_HISTOGRAM_ENUMERATION("SB2.BloomFilterFalsePositives",
143 MISS_TYPE_ALL, MISS_TYPE_MAX); 142 MISS_TYPE_ALL, MISS_TYPE_MAX);
144 } 143 }
145 144
146 // Collect the misses which are not present in |add_prefixes|. 145 // Collect the misses which are not present in |add_prefixes|.
147 // Since |add_prefixes| can contain multiple copies of the same 146 // Since |add_prefixes| can contain multiple copies of the same
148 // prefix, it is not sufficient to count the number of elements 147 // prefix, it is not sufficient to count the number of elements
149 // present in both collections. 148 // present in both collections.
150 std::set<SBPrefix> false_misses(prefix_misses.begin(), prefix_misses.end()); 149 std::set<SBPrefix> false_misses(prefix_misses.begin(), prefix_misses.end());
151 for (size_t i = 0; i < add_prefixes.size(); ++i) { 150 for (SBAddPrefixContainer::const_iterator iter = add_prefixes.begin();
151 iter != add_prefixes.end(); ++iter) {
152 // |erase()| on an absent element should cost like |find()|. 152 // |erase()| on an absent element should cost like |find()|.
153 false_misses.erase(add_prefixes[i].prefix); 153 false_misses.erase(iter->prefix);
154 } 154 }
155 155
156 // Record a hit for prefixes which we shouldn't have sent in the 156 // Record a hit for prefixes which we shouldn't have sent in the
157 // first place. 157 // first place.
158 for (size_t i = 0; i < false_misses.size(); ++i) { 158 for (size_t i = 0; i < false_misses.size(); ++i) {
159 UMA_HISTOGRAM_ENUMERATION("SB2.BloomFilterFalsePositives", 159 UMA_HISTOGRAM_ENUMERATION("SB2.BloomFilterFalsePositives",
160 MISS_TYPE_FALSE, MISS_TYPE_MAX); 160 MISS_TYPE_FALSE, MISS_TYPE_MAX);
161 } 161 }
162 162
163 // Divide |MISS_TYPE_FALSE| by |MISS_TYPE_ALL| to get the 163 // Divide |MISS_TYPE_FALSE| by |MISS_TYPE_ALL| to get the
164 // bloom-filter false-positive rate. 164 // bloom-filter false-positive rate.
165 } 165 }
166 166
167 void SBProcessSubs(std::vector<SBAddPrefix>* add_prefixes, 167 void SBProcessSubs(SBAddPrefixContainer* add_prefixes,
168 std::vector<SBSubPrefix>* sub_prefixes, 168 std::vector<SBSubPrefix>* sub_prefixes,
169 std::vector<SBAddFullHash>* add_full_hashes, 169 std::vector<SBAddFullHash>* add_full_hashes,
170 std::vector<SBSubFullHash>* sub_full_hashes, 170 std::vector<SBSubFullHash>* sub_full_hashes,
171 const base::hash_set<int32>& add_chunks_deleted, 171 const base::hash_set<int32>& add_chunks_deleted,
172 const base::hash_set<int32>& sub_chunks_deleted) { 172 const base::hash_set<int32>& sub_chunks_deleted) {
173 // It is possible to structure templates and template 173 // It is possible to structure templates and template
174 // specializations such that the following calls work without having 174 // specializations such that the following calls work without having
175 // to qualify things. It becomes very arbitrary, though, and less 175 // to qualify things. It becomes very arbitrary, though, and less
176 // clear how things are working. 176 // clear how things are working.
177 177
178 // Sort the inputs by the SBAddPrefix bits. 178 // Sort the inputs by the SBAddPrefix bits.
179 std::sort(add_prefixes->begin(), add_prefixes->end(), 179 std::sort(add_prefixes->begin(), add_prefixes->end(),
180 SBAddPrefixLess<SBAddPrefix,SBAddPrefix>); 180 SBAddPrefixLess<SBAddPrefix,SBAddPrefix>);
181 std::sort(sub_prefixes->begin(), sub_prefixes->end(), 181 std::sort(sub_prefixes->begin(), sub_prefixes->end(),
182 SBAddPrefixLess<SBSubPrefix,SBSubPrefix>); 182 SBAddPrefixLess<SBSubPrefix,SBSubPrefix>);
183 std::sort(add_full_hashes->begin(), add_full_hashes->end(), 183 std::sort(add_full_hashes->begin(), add_full_hashes->end(),
184 SBAddPrefixHashLess<SBAddFullHash,SBAddFullHash>); 184 SBAddPrefixHashLess<SBAddFullHash,SBAddFullHash>);
185 std::sort(sub_full_hashes->begin(), sub_full_hashes->end(), 185 std::sort(sub_full_hashes->begin(), sub_full_hashes->end(),
186 SBAddPrefixHashLess<SBSubFullHash,SBSubFullHash>); 186 SBAddPrefixHashLess<SBSubFullHash,SBSubFullHash>);
187 187
188 // Factor out the prefix subs. 188 // Factor out the prefix subs.
189 std::vector<SBAddPrefix> removed_adds; 189 SBAddPrefixContainer removed_adds;
190 KnockoutSubs(sub_prefixes, add_prefixes, 190 KnockoutSubs(sub_prefixes, add_prefixes,
191 SBAddPrefixLess<SBAddPrefix,SBSubPrefix>, 191 SBAddPrefixLess<SBAddPrefix,SBSubPrefix>,
192 SBAddPrefixLess<SBSubPrefix,SBAddPrefix>, 192 SBAddPrefixLess<SBSubPrefix,SBAddPrefix>,
193 &removed_adds); 193 &removed_adds);
194 194
195 // Remove the full-hashes corrosponding to the adds which 195 // Remove the full-hashes corrosponding to the adds which
196 // KnockoutSubs() removed. Processing these w/in KnockoutSubs() 196 // KnockoutSubs() removed. Processing these w/in KnockoutSubs()
197 // would make the code more complicated, and they are very small 197 // would make the code more complicated, and they are very small
198 // relative to the prefix lists so the gain would be modest. 198 // relative to the prefix lists so the gain would be modest.
199 RemoveMatchingPrefixes(removed_adds, add_full_hashes); 199 RemoveMatchingPrefixes(removed_adds, add_full_hashes);
(...skipping 16 matching lines...) Expand all
216 } 216 }
217 217
218 // Remove items from the deleted chunks. This is done after other 218 // Remove items from the deleted chunks. This is done after other
219 // processing to allow subs to knock out adds (and be removed) even 219 // processing to allow subs to knock out adds (and be removed) even
220 // if the add's chunk is deleted. 220 // if the add's chunk is deleted.
221 RemoveDeleted(add_prefixes, add_chunks_deleted); 221 RemoveDeleted(add_prefixes, add_chunks_deleted);
222 RemoveDeleted(sub_prefixes, sub_chunks_deleted); 222 RemoveDeleted(sub_prefixes, sub_chunks_deleted);
223 RemoveDeleted(add_full_hashes, add_chunks_deleted); 223 RemoveDeleted(add_full_hashes, add_chunks_deleted);
224 RemoveDeleted(sub_full_hashes, sub_chunks_deleted); 224 RemoveDeleted(sub_full_hashes, sub_chunks_deleted);
225 } 225 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698