OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "sync/internal_api/public/base/unique_position.h" | 5 #include "sync/internal_api/public/base/unique_position.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/rand_util.h" | |
9 #include "base/string_number_conversions.h" | 8 #include "base/string_number_conversions.h" |
10 | 9 |
11 namespace syncer { | 10 namespace syncer { |
12 | 11 |
| 12 const size_t UniquePosition::kSuffixLength = 28; |
| 13 |
13 // static. | 14 // static. |
14 bool UniquePosition::IsValidSuffix(const std::string& suffix) { | 15 bool UniquePosition::IsValidSuffix(const std::string& suffix) { |
15 // The suffix must be exactly the specified length, otherwise unique suffixes | 16 // The suffix must be exactly the specified length, otherwise unique suffixes |
16 // are not sufficient to guarantee unique positions (because prefix + suffix | 17 // are not sufficient to guarantee unique positions (because prefix + suffix |
17 // == p + refixsuffix). | 18 // == p + refixsuffix). |
18 return suffix.length() == kSuffixLength; | 19 return suffix.length() == kSuffixLength; |
19 } | 20 } |
20 | 21 |
21 // static. | 22 // static. |
22 bool UniquePosition::IsValidBytes(const std::string& bytes) { | 23 bool UniquePosition::IsValidBytes(const std::string& bytes) { |
23 return bytes.length() > kSuffixLength | 24 // The first condition ensures that our suffix uniqueness is sufficient to |
24 && bytes[bytes.length()-1] == kTerminatorByte; | 25 // guarantee position uniqueness. Otherwise, it's possible the end of some |
| 26 // prefix + some short suffix == some long suffix. |
| 27 // The second condition ensures that FindSmallerWithSuffix can always return a |
| 28 // result. |
| 29 return bytes.length() >= kSuffixLength |
| 30 && bytes[bytes.length()-1] != 0; |
25 } | 31 } |
26 | 32 |
27 // static. | 33 // static. |
28 UniquePosition UniquePosition::CreateInvalid() { | 34 UniquePosition UniquePosition::CreateInvalid() { |
29 UniquePosition pos; | 35 UniquePosition pos; |
30 DCHECK(!pos.IsValid()); | 36 DCHECK(!pos.IsValid()); |
31 return pos; | 37 return pos; |
32 } | 38 } |
33 | 39 |
34 // static. | 40 // static. |
35 UniquePosition UniquePosition::FromBytes( | 41 UniquePosition UniquePosition::FromBytes( |
36 const std::string& bytes) { | 42 const std::string& bytes) { |
37 UniquePosition result(bytes); | 43 UniquePosition result(bytes); |
38 DCHECK(result.IsValid()); | |
39 return result; | 44 return result; |
40 } | 45 } |
41 | 46 |
42 // static. | 47 // static. |
43 UniquePosition UniquePosition::FromInt64( | 48 UniquePosition UniquePosition::FromInt64( |
44 int64 x, const std::string& suffix) { | 49 int64 x, const std::string& suffix) { |
45 uint64 y = static_cast<uint64>(x); | 50 uint64 y = static_cast<uint64>(x); |
46 y ^= 0x8000000000000000ULL; // Make it non-negative. | 51 y ^= 0x8000000000000000ULL; // Make it non-negative. |
47 std::string bytes(8, 0); | 52 std::string bytes(8, 0); |
48 for (int i = 7; i >= 0; --i) { | 53 for (int i = 7; i >= 0; --i) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 const std::string& suffix) { | 91 const std::string& suffix) { |
87 DCHECK(before.IsValid()); | 92 DCHECK(before.IsValid()); |
88 DCHECK(after.IsValid()); | 93 DCHECK(after.IsValid()); |
89 DCHECK(before.LessThan(after)); | 94 DCHECK(before.LessThan(after)); |
90 DCHECK(IsValidSuffix(suffix)); | 95 DCHECK(IsValidSuffix(suffix)); |
91 const std::string& mid = | 96 const std::string& mid = |
92 FindBetweenWithSuffix(before.bytes_, after.bytes_, suffix); | 97 FindBetweenWithSuffix(before.bytes_, after.bytes_, suffix); |
93 return UniquePosition(mid, suffix); | 98 return UniquePosition(mid, suffix); |
94 } | 99 } |
95 | 100 |
96 // static. | |
97 const std::string UniquePosition::GenerateUniqueSuffix() { | |
98 return base::RandBytesAsString(kSuffixLength); | |
99 } | |
100 | |
101 // static. | |
102 const std::string UniquePosition::GenerateBookmarkSuffix( | |
103 const std::string& decoded_originator_cache_guid, | |
104 int64 numeric_originator_item_id) { | |
105 std::string result(8, 0); | |
106 | |
107 // The first 8 bytes come from the originator id. | |
108 int64 byte_iterator = numeric_originator_item_id; | |
109 for (int i = 7; i >= 0; --i) { | |
110 result[i] = static_cast<uint8>(byte_iterator); | |
111 byte_iterator >>= 8; | |
112 } | |
113 | |
114 // The next 16 bytes come from the decoded cache guid. | |
115 DCHECK_EQ(16u, decoded_originator_cache_guid.length()); | |
116 result.append(decoded_originator_cache_guid); | |
117 | |
118 return result; | |
119 } | |
120 | |
121 UniquePosition::UniquePosition() : is_valid_(false) { }; | 101 UniquePosition::UniquePosition() : is_valid_(false) { }; |
122 | 102 |
123 bool UniquePosition::LessThan(const UniquePosition& other) const { | 103 bool UniquePosition::LessThan(const UniquePosition& other) const { |
124 DCHECK(this->IsValid()); | 104 DCHECK(this->IsValid()); |
125 DCHECK(other.IsValid()); | 105 DCHECK(other.IsValid()); |
126 return bytes_ < other.bytes_; | 106 return bytes_ < other.bytes_; |
127 } | 107 } |
128 | 108 |
129 bool UniquePosition::Equals(const UniquePosition& other) const { | 109 bool UniquePosition::Equals(const UniquePosition& other) const { |
130 if (!this->IsValid() && !other.IsValid()) | 110 if (!this->IsValid() && !other.IsValid()) |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 std::string debug_string = base::HexEncode(bytes_.data(), bytes_.length()); | 143 std::string debug_string = base::HexEncode(bytes_.data(), bytes_.length()); |
164 if (!IsValid()) { | 144 if (!IsValid()) { |
165 debug_string = "INVALID[" + debug_string + "]"; | 145 debug_string = "INVALID[" + debug_string + "]"; |
166 } | 146 } |
167 return debug_string;; | 147 return debug_string;; |
168 } | 148 } |
169 | 149 |
170 std::string UniquePosition::FindSmallerWithSuffix( | 150 std::string UniquePosition::FindSmallerWithSuffix( |
171 const std::string& reference, | 151 const std::string& reference, |
172 const std::string& suffix) { | 152 const std::string& suffix) { |
173 // When comparing, we need to take into account the terminator that will be | |
174 // appended to the suffix when this is made into a UniquePosition. | |
175 const std::string suffixFF = suffix + kTerminatorByte; | |
176 std::string ret; | 153 std::string ret; |
177 | 154 |
178 // Does our suffix alone place us where we want to be? | 155 // Does our suffix alone place us where we want to be? |
179 if (suffixFF < reference) { | 156 if (suffix < reference) { |
180 return ""; | 157 return ""; |
181 } | 158 } |
182 | 159 |
183 for (size_t i = 0; i < reference.length(); ++i) { | 160 for (size_t i = 0; i < reference.length(); ++i) { |
184 const uint8 digit = reference[i]; | 161 const uint8 digit = reference[i]; |
185 if (digit != 0) { | 162 if (digit != 0) { |
186 ret.push_back(digit/2); | 163 ret.push_back(digit/2); |
187 return ret; | 164 return ret; |
188 } else { | 165 } else { |
189 ret.push_back(0); | 166 ret.push_back(0); |
190 // We failed to differentiate ourselves with this digit. But maybe the we | 167 // We failed to differentiate ourselves with this digit. But maybe the we |
191 // can append the suffix at this point and get the position we're looking | 168 // can append the suffix at this point and get the position we're looking |
192 // for that way. | 169 // for that way. |
193 if (suffixFF < reference.substr(i+1)) { | 170 if (suffix < reference.substr(i+1)) { |
194 return ret; | 171 return ret; |
195 } | 172 } |
196 } | 173 } |
197 } | 174 } |
198 | 175 |
199 // Was it 0x00 all the way to the end? Then we can't insert before it. | 176 // Was it 0x00 all the way to the end? Then we can't insert before it. |
200 // That's why we enforce that all positions should end with a max digit, | 177 // That's why we enforce that all positions should end with a max digit, |
201 // which should ensure we never end up here. | 178 // which should ensure we never end up here. |
202 NOTREACHED(); | 179 NOTREACHED(); |
203 return ""; | 180 return ""; |
204 } | 181 } |
205 | 182 |
206 // static | 183 // static |
207 std::string UniquePosition::FindGreaterWithSuffix( | 184 std::string UniquePosition::FindGreaterWithSuffix( |
208 const std::string& reference, | 185 const std::string& reference, |
209 const std::string& suffix) { | 186 const std::string& suffix) { |
210 // When comparing, we need to take into account the terminator that will be | |
211 // appended to the suffix when this is made into a UniquePosition. | |
212 const std::string suffixFF = suffix + kTerminatorByte; | |
213 | |
214 std::string ret; | 187 std::string ret; |
215 | 188 |
216 // Does our suffix alone place us where we want to be? | 189 // Does our suffix alone place us where we want to be? |
217 if (reference < suffixFF) { | 190 if (reference < suffix) { |
218 return ""; | 191 return ""; |
219 } | 192 } |
220 | 193 |
221 for (size_t i = 0; i < reference.length(); ++i) { | 194 for (size_t i = 0; i < reference.length(); ++i) { |
222 const uint8 digit = reference[i]; | 195 const uint8 digit = reference[i]; |
223 if (digit != 255) { | 196 if (digit != kuint8max) { |
224 ret.push_back((digit+256U)/2U); | 197 ret.push_back(digit + (kuint8max - digit + 1)/2); |
225 return ret; | 198 return ret; |
226 } else { | 199 } else { |
227 ret.push_back(255); | 200 ret.push_back(kuint8max); |
228 // We failed to differentiate ourselves with this digit. But maybe the we | 201 // We failed to differentiate ourselves with this digit. But maybe the we |
229 // can append the suffix at this point and get the position we're looking | 202 // can append the suffix at this point and get the position we're looking |
230 // for that way. | 203 // for that way. |
231 if (reference.substr(i+1) < suffixFF) { | 204 if (reference.substr(i+1) < suffix) { |
232 return ret; | 205 return ret; |
233 } | 206 } |
234 } | 207 } |
235 } | 208 } |
236 | 209 |
237 // Still here? Then we must increase our length in order to exceed before. | 210 // Still here? Then we must increase our length in order to exceed reference. |
238 ret.push_back(255); | 211 ret.push_back(kuint8max); |
239 | 212 |
240 DCHECK_LT(reference, ret); | 213 DCHECK_LT(reference, ret); |
241 return ret; | 214 return ret; |
242 } | 215 } |
243 | 216 |
244 // static | 217 // static |
245 std::string UniquePosition::FindBetweenWithSuffix( | 218 std::string UniquePosition::FindBetweenWithSuffix( |
246 const std::string& before, | 219 const std::string& before, |
247 const std::string& after, | 220 const std::string& after, |
248 const std::string& suffix) { | 221 const std::string& suffix) { |
249 DCHECK(IsValidSuffix(suffix)); | 222 DCHECK(IsValidSuffix(suffix)); |
250 DCHECK_NE(before, after); | 223 DCHECK_NE(before, after); |
251 DCHECK_LT(before, after); | 224 DCHECK_LT(before, after); |
252 | 225 |
253 // When comparing, we need to take into account the terminator that will be | |
254 // appended when this is made into a UniquePosition. | |
255 const std::string suffixFF = suffix + kTerminatorByte; | |
256 | |
257 std::string mid; | 226 std::string mid; |
258 | 227 |
259 // Sometimes our suffix puts us where we want to be. | 228 // Sometimes our suffix puts us where we want to be. |
260 if (before < suffixFF && suffixFF < after) { | 229 if (before < suffix && suffix < after) { |
261 return ""; | 230 return ""; |
262 } | 231 } |
263 | 232 |
264 size_t i = 0; | 233 size_t i = 0; |
265 for ( ; i < std::min(before.length(), after.length()); ++i) { | 234 for ( ; i < std::min(before.length(), after.length()); ++i) { |
266 uint8 a_digit = before[i]; | 235 uint8 a_digit = before[i]; |
267 uint8 b_digit = after[i]; | 236 uint8 b_digit = after[i]; |
268 | 237 |
269 if (b_digit - a_digit >= 2) { | 238 if (b_digit - a_digit >= 2) { |
270 mid.push_back((b_digit + a_digit) / 2U); | 239 mid.push_back(a_digit + (b_digit - a_digit)/2); |
271 return mid; | 240 return mid; |
272 } else if (a_digit == b_digit) { | 241 } else if (a_digit == b_digit) { |
273 mid.push_back(a_digit); | 242 mid.push_back(a_digit); |
274 | 243 |
275 // Both strings are equal so far. Will appending the suffix at this point | 244 // Both strings are equal so far. Will appending the suffix at this point |
276 // give us the comparison we're looking for? | 245 // give us the comparison we're looking for? |
277 if (suffixFF < before.substr(i, 0) && after.substr(i, 0) < suffixFF) { | 246 if (before.substr(i+1) < suffix && suffix < after.substr(i+1)) { |
278 return mid; | 247 return mid; |
279 } | 248 } |
280 } else { | 249 } else { |
281 DCHECK_EQ(b_digit - a_digit, 1); // Implied by above if branches. | 250 DCHECK_EQ(b_digit - a_digit, 1); // Implied by above if branches. |
282 | 251 |
283 // The two options are off by one digit. The choice of whether to round | 252 // The two options are off by one digit. The choice of whether to round |
284 // up or down here will have consequences on what we do with the remaining | 253 // up or down here will have consequences on what we do with the remaining |
285 // digits. Exploring both options is an optimization and is not required | 254 // digits. Exploring both options is an optimization and is not required |
286 // for the correctness of this algorithm. | 255 // for the correctness of this algorithm. |
287 | 256 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 // value, will make |before| < |mid|. Therefore, the following will get us a | 290 // value, will make |before| < |mid|. Therefore, the following will get us a |
322 // valid position. | 291 // valid position. |
323 | 292 |
324 mid.append(FindSmallerWithSuffix(after.substr(i), suffix)); | 293 mid.append(FindSmallerWithSuffix(after.substr(i), suffix)); |
325 return mid; | 294 return mid; |
326 } | 295 } |
327 | 296 |
328 UniquePosition::UniquePosition(const std::string& internal_rep) | 297 UniquePosition::UniquePosition(const std::string& internal_rep) |
329 : bytes_(internal_rep), | 298 : bytes_(internal_rep), |
330 is_valid_(IsValidBytes(bytes_)) { | 299 is_valid_(IsValidBytes(bytes_)) { |
331 DCHECK(IsValid()); | |
332 } | 300 } |
333 | 301 |
334 UniquePosition::UniquePosition( | 302 UniquePosition::UniquePosition( |
335 const std::string& prefix, | 303 const std::string& prefix, |
336 const std::string& suffix) | 304 const std::string& suffix) |
337 : bytes_(prefix + suffix + kTerminatorByte), | 305 : bytes_(prefix + suffix), |
338 is_valid_(IsValidBytes(bytes_)) { | 306 is_valid_(IsValidBytes(bytes_)) { |
339 DCHECK(IsValidSuffix(suffix)); | 307 DCHECK(IsValidSuffix(suffix)); |
340 DCHECK(IsValid()); | 308 DCHECK(IsValid()); |
341 } | 309 } |
342 | 310 |
343 } // namespace syncer | 311 } // namespace syncer |
OLD | NEW |