1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
6
7 #include <iterator>
8 #include <limits>
9 #include <sstream>
10 #include <utility>
11
12 #include "base/big_endian.h"
13 #include "base/containers/span.h"
14 #include "base/logging.h"
15 #include "base/strings/string16.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/sys_byteorder.h"
18 #include "build/build_config.h"
19 #include "components/services/storage/indexed_db/scopes/leveldb_scopes_coding.h"
20 #include "components/services/storage/indexed_db/scopes/varint_coding.h"
21
22 // See leveldb_coding_scheme.md for detailed documentation of the coding
23 // scheme implemented here.
24
25 using base::StringPiece;
26 using blink::IndexedDBKey;
27 using blink::IndexedDBKeyPath;
28
29 namespace content {
30 namespace {
ByteSwapToBE64(uint64_t x)31 inline uint64_t ByteSwapToBE64(uint64_t x) {
32 #if defined(ARCH_CPU_LITTLE_ENDIAN)
33 return base::ByteSwap(x);
34 #else
35 return x;
36 #endif
37 }
38
39 // As most of the IndexedDBKeys and encoded values are short, we
40 // initialize some std::vectors with a default inline buffer size to reduce
41 // the memory re-allocations when the std::vectors are appended.
42 const size_t kDefaultInlineBufferSize = 32;
43
44 constexpr unsigned char kIndexedDBKeyNullTypeByte = 0;
45 constexpr unsigned char kIndexedDBKeyStringTypeByte = 1;
46 constexpr unsigned char kIndexedDBKeyDateTypeByte = 2;
47 constexpr unsigned char kIndexedDBKeyNumberTypeByte = 3;
48 constexpr unsigned char kIndexedDBKeyArrayTypeByte = 4;
49 constexpr unsigned char kIndexedDBKeyMinKeyTypeByte = 5;
50 constexpr unsigned char kIndexedDBKeyBinaryTypeByte = 6;
51
52 constexpr unsigned char kIndexedDBKeyPathTypeCodedByte1 = 0;
53 constexpr unsigned char kIndexedDBKeyPathTypeCodedByte2 = 0;
54
55 constexpr unsigned char kIndexedDBKeyPathNullTypeByte = 0;
56 constexpr unsigned char kIndexedDBKeyPathStringTypeByte = 1;
57 constexpr unsigned char kIndexedDBKeyPathArrayTypeByte = 2;
58
59 constexpr unsigned char kObjectStoreDataIndexId = 1;
60 constexpr unsigned char kExistsEntryIndexId = 2;
61 constexpr unsigned char kBlobEntryIndexId = 3;
62
63 constexpr unsigned char kSchemaVersionTypeByte = 0;
64 constexpr unsigned char kMaxDatabaseIdTypeByte = 1;
65 constexpr unsigned char kDataVersionTypeByte = 2;
66 constexpr unsigned char kRecoveryBlobJournalTypeByte = 3;
67 constexpr unsigned char kActiveBlobJournalTypeByte = 4;
68 constexpr unsigned char kEarliestSweepTimeTypeByte = 5;
69 constexpr unsigned char kMaxSimpleGlobalMetaDataTypeByte =
70 6; // Insert before this and increment.
71 constexpr unsigned char kScopesPrefixByte = 50;
72 constexpr unsigned char kDatabaseFreeListTypeByte = 100;
73 constexpr unsigned char kDatabaseNameTypeByte = 201;
74
75 constexpr unsigned char kObjectStoreMetaDataTypeByte = 50;
76 constexpr unsigned char kIndexMetaDataTypeByte = 100;
77 constexpr unsigned char kObjectStoreFreeListTypeByte = 150;
78 constexpr unsigned char kIndexFreeListTypeByte = 151;
79 constexpr unsigned char kObjectStoreNamesTypeByte = 200;
80 constexpr unsigned char kIndexNamesKeyTypeByte = 201;
81
82 constexpr unsigned char kObjectMetaDataTypeMaximum = 255;
83 constexpr unsigned char kIndexMetaDataTypeMaximum = 255;
84
EncodeIntSafely(int64_t value,int64_t max,std::string * into)85 inline void EncodeIntSafely(int64_t value, int64_t max, std::string* into) {
86 DCHECK_LE(value, max);
87 return EncodeInt(value, into);
88 }
89
90 } // namespace
91
92 const unsigned char kMinimumIndexId = 30;
93
MaxIDBKey()94 std::string MaxIDBKey() {
95 std::string ret;
96 EncodeByte(kIndexedDBKeyNullTypeByte, &ret);
97 return ret;
98 }
99
MinIDBKey()100 std::string MinIDBKey() {
101 std::string ret;
102 EncodeByte(kIndexedDBKeyMinKeyTypeByte, &ret);
103 return ret;
104 }
105
EncodeByte(unsigned char value,std::string * into)106 void EncodeByte(unsigned char value, std::string* into) {
107 into->push_back(value);
108 }
109
EncodeBool(bool value,std::string * into)110 void EncodeBool(bool value, std::string* into) {
111 into->push_back(value ? 1 : 0);
112 }
113
EncodeInt(int64_t value,std::string * into)114 void EncodeInt(int64_t value, std::string* into) {
115 #ifndef NDEBUG
116 // Exercised by unit tests in debug only.
117 DCHECK_GE(value, 0);
118 #endif
119 uint64_t n = static_cast<uint64_t>(value);
120
121 do {
122 unsigned char c = n;
123 into->push_back(c);
124 n >>= 8;
125 } while (n);
126 }
127
EncodeString(const base::string16 & value,std::string * into)128 void EncodeString(const base::string16& value, std::string* into) {
129 if (value.empty())
130 return;
131 // Backing store is UTF-16BE, convert from host endianness.
132 size_t length = value.length();
133 size_t current = into->size();
134 into->resize(into->size() + length * sizeof(base::char16));
135
136 const base::char16* src = value.c_str();
137 base::char16* dst =
138 reinterpret_cast<base::char16*>(&*into->begin() + current);
139 for (unsigned i = 0; i < length; ++i)
140 *dst++ = base::HostToNet16(*src++);
141 }
142
EncodeBinary(const std::string & value,std::string * into)143 void EncodeBinary(const std::string& value, std::string* into) {
144 EncodeVarInt(value.length(), into);
145 into->append(value.begin(), value.end());
146 DCHECK(into->size() >= value.size());
147 }
148
EncodeBinary(base::span<const uint8_t> value,std::string * into)149 void EncodeBinary(base::span<const uint8_t> value, std::string* into) {
150 EncodeVarInt(value.size(), into);
151 into->append(value.begin(), value.end());
152 DCHECK(into->size() >= value.size());
153 }
154
EncodeStringWithLength(const base::string16 & value,std::string * into)155 void EncodeStringWithLength(const base::string16& value, std::string* into) {
156 EncodeVarInt(value.length(), into);
157 EncodeString(value, into);
158 }
159
EncodeDouble(double value,std::string * into)160 void EncodeDouble(double value, std::string* into) {
161 // This always has host endianness.
162 const char* p = reinterpret_cast<char*>(&value);
163 into->insert(into->end(), p, p + sizeof(value));
164 }
165
EncodeIDBKey(const IndexedDBKey & value,std::string * into)166 void EncodeIDBKey(const IndexedDBKey& value, std::string* into) {
167 size_t previous_size = into->size();
168 DCHECK(value.IsValid());
169 switch (value.type()) {
170 case blink::mojom::IDBKeyType::Array: {
171 EncodeByte(kIndexedDBKeyArrayTypeByte, into);
172 size_t length = value.array().size();
173 EncodeVarInt(length, into);
174 for (size_t i = 0; i < length; ++i)
175 EncodeIDBKey(value.array()[i], into);
176 DCHECK_GT(into->size(), previous_size);
177 return;
178 }
179 case blink::mojom::IDBKeyType::Binary:
180 EncodeByte(kIndexedDBKeyBinaryTypeByte, into);
181 EncodeBinary(value.binary(), into);
182 DCHECK_GT(into->size(), previous_size);
183 return;
184 case blink::mojom::IDBKeyType::String:
185 EncodeByte(kIndexedDBKeyStringTypeByte, into);
186 EncodeStringWithLength(value.string(), into);
187 DCHECK_GT(into->size(), previous_size);
188 return;
189 case blink::mojom::IDBKeyType::Date:
190 EncodeByte(kIndexedDBKeyDateTypeByte, into);
191 EncodeDouble(value.date(), into);
192 DCHECK_EQ(9u, static_cast<size_t>(into->size() - previous_size));
193 return;
194 case blink::mojom::IDBKeyType::Number:
195 EncodeByte(kIndexedDBKeyNumberTypeByte, into);
196 EncodeDouble(value.number(), into);
197 DCHECK_EQ(9u, static_cast<size_t>(into->size() - previous_size));
198 return;
199 case blink::mojom::IDBKeyType::None:
200 case blink::mojom::IDBKeyType::Invalid:
201 case blink::mojom::IDBKeyType::Min:
202 default:
203 NOTREACHED();
204 EncodeByte(kIndexedDBKeyNullTypeByte, into);
205 return;
206 }
207 }
208
209 #define COMPILE_ASSERT_MATCHING_VALUES(a, b) \
210 static_assert( \
211 static_cast<unsigned char>(a) == static_cast<unsigned char>(b), \
212 "Blink enum and coding byte must match.")
213
214 COMPILE_ASSERT_MATCHING_VALUES(blink::mojom::IDBKeyPathType::Null,
215 kIndexedDBKeyPathNullTypeByte);
216 COMPILE_ASSERT_MATCHING_VALUES(blink::mojom::IDBKeyPathType::String,
217 kIndexedDBKeyPathStringTypeByte);
218 COMPILE_ASSERT_MATCHING_VALUES(blink::mojom::IDBKeyPathType::Array,
219 kIndexedDBKeyPathArrayTypeByte);
220
EncodeIDBKeyPath(const IndexedDBKeyPath & value,std::string * into)221 void EncodeIDBKeyPath(const IndexedDBKeyPath& value, std::string* into) {
222 // May be typed, or may be a raw string. An invalid leading
223 // byte is used to identify typed coding. New records are
224 // always written as typed.
225 EncodeByte(kIndexedDBKeyPathTypeCodedByte1, into);
226 EncodeByte(kIndexedDBKeyPathTypeCodedByte2, into);
227 EncodeByte(static_cast<char>(value.type()), into);
228 switch (value.type()) {
229 case blink::mojom::IDBKeyPathType::Null:
230 break;
231 case blink::mojom::IDBKeyPathType::String: {
232 EncodeStringWithLength(value.string(), into);
233 break;
234 }
235 case blink::mojom::IDBKeyPathType::Array: {
236 const std::vector<base::string16>& array = value.array();
237 size_t count = array.size();
238 EncodeVarInt(count, into);
239 for (size_t i = 0; i < count; ++i) {
240 EncodeStringWithLength(array[i], into);
241 }
242 break;
243 }
244 }
245 }
246
EncodeBlobJournal(const BlobJournalType & journal,std::string * into)247 void EncodeBlobJournal(const BlobJournalType& journal, std::string* into) {
248 for (const auto& iter : journal) {
249 EncodeVarInt(iter.first, into);
250 EncodeVarInt(iter.second, into);
251 }
252 }
253
DecodeByte(StringPiece * slice,unsigned char * value)254 bool DecodeByte(StringPiece* slice, unsigned char* value) {
255 if (slice->empty())
256 return false;
257
258 *value = (*slice)[0];
259 slice->remove_prefix(1);
260 return true;
261 }
262
DecodeBool(StringPiece * slice,bool * value)263 bool DecodeBool(StringPiece* slice, bool* value) {
264 if (slice->empty())
265 return false;
266
267 *value = !!(*slice)[0];
268 slice->remove_prefix(1);
269 return true;
270 }
271
DecodeInt(StringPiece * slice,int64_t * value)272 bool DecodeInt(StringPiece* slice, int64_t* value) {
273 if (slice->empty())
274 return false;
275
276 StringPiece::const_iterator it = slice->begin();
277 int shift = 0;
278 int64_t ret = 0;
279 while (it != slice->end()) {
280 unsigned char c = *it++;
281 ret |= static_cast<int64_t>(c) << shift;
282 shift += 8;
283 }
284 *value = ret;
285 slice->remove_prefix(it - slice->begin());
286 return true;
287 }
288
DecodeString(StringPiece * slice,base::string16 * value)289 bool DecodeString(StringPiece* slice, base::string16* value) {
290 if (slice->empty()) {
291 value->clear();
292 return true;
293 }
294
295 // Backing store is UTF-16BE, convert to host endianness.
296 DCHECK(!(slice->size() % sizeof(base::char16)));
297 size_t length = slice->size() / sizeof(base::char16);
298 base::string16 decoded;
299 decoded.reserve(length);
300 const base::char16* encoded =
301 reinterpret_cast<const base::char16*>(slice->begin());
302 for (unsigned i = 0; i < length; ++i)
303 decoded.push_back(base::NetToHost16(*encoded++));
304
305 *value = decoded;
306 slice->remove_prefix(length * sizeof(base::char16));
307 return true;
308 }
309
DecodeStringWithLength(StringPiece * slice,base::string16 * value)310 bool DecodeStringWithLength(StringPiece* slice, base::string16* value) {
311 if (slice->empty())
312 return false;
313
314 int64_t length = 0;
315 if (!DecodeVarInt(slice, &length) || length < 0)
316 return false;
317 size_t bytes = length * sizeof(base::char16);
318 if (slice->size() < bytes)
319 return false;
320
321 StringPiece subpiece(slice->begin(), bytes);
322 slice->remove_prefix(bytes);
323 if (!DecodeString(&subpiece, value))
324 return false;
325
326 return true;
327 }
328
DecodeBinary(StringPiece * slice,std::string * value)329 bool DecodeBinary(StringPiece* slice, std::string* value) {
330 if (slice->empty())
331 return false;
332
333 int64_t length = 0;
334 if (!DecodeVarInt(slice, &length) || length < 0)
335 return false;
336 size_t size = length;
337 if (slice->size() < size)
338 return false;
339
340 value->assign(slice->begin(), size);
341 slice->remove_prefix(size);
342 return true;
343 }
344
DecodeBinary(StringPiece * slice,base::span<const uint8_t> * value)345 bool DecodeBinary(StringPiece* slice, base::span<const uint8_t>* value) {
346 if (slice->empty())
347 return false;
348
349 int64_t length = 0;
350 if (!DecodeVarInt(slice, &length) || length < 0)
351 return false;
352 size_t size = length;
353 if (slice->size() < size)
354 return false;
355
356 *value = base::as_bytes(base::make_span(slice->substr(0, size)));
357 slice->remove_prefix(size);
358 return true;
359 }
360
DecodeIDBKey(StringPiece * slice,std::unique_ptr<IndexedDBKey> * value)361 bool DecodeIDBKey(StringPiece* slice, std::unique_ptr<IndexedDBKey>* value) {
362 if (slice->empty())
363 return false;
364
365 unsigned char type = (*slice)[0];
366 slice->remove_prefix(1);
367
368 switch (type) {
369 case kIndexedDBKeyNullTypeByte:
370 *value = std::make_unique<IndexedDBKey>();
371 return true;
372
373 case kIndexedDBKeyArrayTypeByte: {
374 int64_t length = 0;
375 if (!DecodeVarInt(slice, &length) || length < 0)
376 return false;
377 IndexedDBKey::KeyArray array;
378 while (length--) {
379 std::unique_ptr<IndexedDBKey> key;
380 if (!DecodeIDBKey(slice, &key))
381 return false;
382 array.push_back(*key);
383 }
384 *value = std::make_unique<IndexedDBKey>(std::move(array));
385 return true;
386 }
387 case kIndexedDBKeyBinaryTypeByte: {
388 std::string binary;
389 if (!DecodeBinary(slice, &binary))
390 return false;
391 *value = std::make_unique<IndexedDBKey>(std::move(binary));
392 return true;
393 }
394 case kIndexedDBKeyStringTypeByte: {
395 base::string16 s;
396 if (!DecodeStringWithLength(slice, &s))
397 return false;
398 *value = std::make_unique<IndexedDBKey>(std::move(s));
399 return true;
400 }
401 case kIndexedDBKeyDateTypeByte: {
402 double d;
403 if (!DecodeDouble(slice, &d))
404 return false;
405 *value =
406 std::make_unique<IndexedDBKey>(d, blink::mojom::IDBKeyType::Date);
407 return true;
408 }
409 case kIndexedDBKeyNumberTypeByte: {
410 double d;
411 if (!DecodeDouble(slice, &d))
412 return false;
413 *value =
414 std::make_unique<IndexedDBKey>(d, blink::mojom::IDBKeyType::Number);
415 return true;
416 }
417 case kIndexedDBKeyMinKeyTypeByte: {
418 *value = std::make_unique<IndexedDBKey>(blink::mojom::IDBKeyType::Min);
419 return true;
420 }
421 }
422
423 NOTREACHED();
424 return false;
425 }
426
DecodeDouble(StringPiece * slice,double * value)427 bool DecodeDouble(StringPiece* slice, double* value) {
428 if (slice->size() < sizeof(*value))
429 return false;
430
431 memcpy(value, slice->begin(), sizeof(*value));
432 slice->remove_prefix(sizeof(*value));
433 return true;
434 }
435
DecodeIDBKeyPath(StringPiece * slice,IndexedDBKeyPath * value)436 bool DecodeIDBKeyPath(StringPiece* slice, IndexedDBKeyPath* value) {
437 // May be typed, or may be a raw string. An invalid leading
438 // byte sequence is used to identify typed coding. New records are
439 // always written as typed.
440 if (slice->size() < 3 || (*slice)[0] != kIndexedDBKeyPathTypeCodedByte1 ||
441 (*slice)[1] != kIndexedDBKeyPathTypeCodedByte2) {
442 base::string16 s;
443 if (!DecodeString(slice, &s))
444 return false;
445 *value = IndexedDBKeyPath(s);
446 return true;
447 }
448
449 slice->remove_prefix(2);
450 DCHECK(!slice->empty());
451 blink::mojom::IDBKeyPathType type =
452 static_cast<blink::mojom::IDBKeyPathType>((*slice)[0]);
453 slice->remove_prefix(1);
454
455 switch (type) {
456 case blink::mojom::IDBKeyPathType::Null:
457 DCHECK(slice->empty());
458 *value = IndexedDBKeyPath();
459 return true;
460 case blink::mojom::IDBKeyPathType::String: {
461 base::string16 string;
462 if (!DecodeStringWithLength(slice, &string))
463 return false;
464 DCHECK(slice->empty());
465 *value = IndexedDBKeyPath(string);
466 return true;
467 }
468 case blink::mojom::IDBKeyPathType::Array: {
469 std::vector<base::string16> array;
470 int64_t count;
471 if (!DecodeVarInt(slice, &count))
472 return false;
473 DCHECK_GE(count, 0);
474 while (count--) {
475 base::string16 string;
476 if (!DecodeStringWithLength(slice, &string))
477 return false;
478 array.push_back(string);
479 }
480 DCHECK(slice->empty());
481 *value = IndexedDBKeyPath(array);
482 return true;
483 }
484 }
485 NOTREACHED();
486 return false;
487 }
488
DecodeBlobJournal(StringPiece * slice,BlobJournalType * journal)489 bool DecodeBlobJournal(StringPiece* slice, BlobJournalType* journal) {
490 BlobJournalType output;
491 while (!slice->empty()) {
492 int64_t database_id = -1;
493 int64_t blob_number = -1;
494 if (!DecodeVarInt(slice, &database_id))
495 return false;
496 if (!KeyPrefix::IsValidDatabaseId(database_id))
497 return false;
498 if (!DecodeVarInt(slice, &blob_number))
499 return false;
500 if (!DatabaseMetaDataKey::IsValidBlobNumber(blob_number) &&
501 (blob_number != DatabaseMetaDataKey::kAllBlobsNumber)) {
502 return false;
503 }
504 output.push_back({database_id, blob_number});
505 }
506 journal->swap(output);
507 return true;
508 }
509
ConsumeEncodedIDBKey(StringPiece * slice)510 bool ConsumeEncodedIDBKey(StringPiece* slice) {
511 unsigned char type = (*slice)[0];
512 slice->remove_prefix(1);
513
514 switch (type) {
515 case kIndexedDBKeyNullTypeByte:
516 case kIndexedDBKeyMinKeyTypeByte:
517 return true;
518 case kIndexedDBKeyArrayTypeByte: {
519 int64_t length;
520 if (!DecodeVarInt(slice, &length))
521 return false;
522 while (length--) {
523 if (!ConsumeEncodedIDBKey(slice))
524 return false;
525 }
526 return true;
527 }
528 case kIndexedDBKeyBinaryTypeByte: {
529 int64_t length = 0;
530 if (!DecodeVarInt(slice, &length) || length < 0)
531 return false;
532 if (slice->size() < static_cast<size_t>(length))
533 return false;
534 slice->remove_prefix(length);
535 return true;
536 }
537 case kIndexedDBKeyStringTypeByte: {
538 int64_t length = 0;
539 if (!DecodeVarInt(slice, &length) || length < 0)
540 return false;
541 if (slice->size() < static_cast<size_t>(length) * sizeof(base::char16))
542 return false;
543 slice->remove_prefix(length * sizeof(base::char16));
544 return true;
545 }
546 case kIndexedDBKeyDateTypeByte:
547 case kIndexedDBKeyNumberTypeByte:
548 if (slice->size() < sizeof(double))
549 return false;
550 slice->remove_prefix(sizeof(double));
551 return true;
552 }
553 NOTREACHED();
554 return false;
555 }
556
ExtractEncodedIDBKey(StringPiece * slice,std::string * result)557 bool ExtractEncodedIDBKey(StringPiece* slice, std::string* result) {
558 const char* start = slice->begin();
559 if (!ConsumeEncodedIDBKey(slice))
560 return false;
561
562 if (result)
563 result->assign(start, slice->begin());
564 return true;
565 }
566
KeyTypeByteToKeyType(unsigned char type)567 static blink::mojom::IDBKeyType KeyTypeByteToKeyType(unsigned char type) {
568 switch (type) {
569 case kIndexedDBKeyNullTypeByte:
570 return blink::mojom::IDBKeyType::Invalid;
571 case kIndexedDBKeyArrayTypeByte:
572 return blink::mojom::IDBKeyType::Array;
573 case kIndexedDBKeyBinaryTypeByte:
574 return blink::mojom::IDBKeyType::Binary;
575 case kIndexedDBKeyStringTypeByte:
576 return blink::mojom::IDBKeyType::String;
577 case kIndexedDBKeyDateTypeByte:
578 return blink::mojom::IDBKeyType::Date;
579 case kIndexedDBKeyNumberTypeByte:
580 return blink::mojom::IDBKeyType::Number;
581 case kIndexedDBKeyMinKeyTypeByte:
582 return blink::mojom::IDBKeyType::Min;
583 }
584
585 NOTREACHED() << "Got invalid type " << type;
586 return blink::mojom::IDBKeyType::Invalid;
587 }
588
CompareEncodedStringsWithLength(StringPiece * slice1,StringPiece * slice2,bool * ok)589 int CompareEncodedStringsWithLength(StringPiece* slice1,
590 StringPiece* slice2,
591 bool* ok) {
592 int64_t len1, len2;
593 if (!DecodeVarInt(slice1, &len1) || !DecodeVarInt(slice2, &len2)) {
594 *ok = false;
595 return 0;
596 }
597 DCHECK_GE(len1, 0);
598 DCHECK_GE(len2, 0);
599 if (len1 < 0 || len2 < 0) {
600 *ok = false;
601 return 0;
602 }
603 DCHECK_GE(slice1->size(), len1 * sizeof(base::char16));
604 DCHECK_GE(slice2->size(), len2 * sizeof(base::char16));
605 if (slice1->size() < len1 * sizeof(base::char16) ||
606 slice2->size() < len2 * sizeof(base::char16)) {
607 *ok = false;
608 return 0;
609 }
610
611 // Extract the string data, and advance the passed slices.
612 StringPiece string1(slice1->begin(), len1 * sizeof(base::char16));
613 StringPiece string2(slice2->begin(), len2 * sizeof(base::char16));
614 slice1->remove_prefix(len1 * sizeof(base::char16));
615 slice2->remove_prefix(len2 * sizeof(base::char16));
616
617 *ok = true;
618 // Strings are UTF-16BE encoded, so a simple memcmp is sufficient.
619 return string1.compare(string2);
620 }
621
CompareEncodedBinary(StringPiece * slice1,StringPiece * slice2,bool * ok)622 int CompareEncodedBinary(StringPiece* slice1, StringPiece* slice2, bool* ok) {
623 int64_t len1, len2;
624 if (!DecodeVarInt(slice1, &len1) || !DecodeVarInt(slice2, &len2)) {
625 *ok = false;
626 return 0;
627 }
628 DCHECK_GE(len1, 0);
629 DCHECK_GE(len2, 0);
630 if (len1 < 0 || len2 < 0) {
631 *ok = false;
632 return 0;
633 }
634 size_t size1 = len1;
635 size_t size2 = len2;
636
637 DCHECK_GE(slice1->size(), size1);
638 DCHECK_GE(slice2->size(), size2);
639 if (slice1->size() < size1 || slice2->size() < size2) {
640 *ok = false;
641 return 0;
642 }
643
644 // Extract the binary data, and advance the passed slices.
645 StringPiece binary1(slice1->begin(), size1);
646 StringPiece binary2(slice2->begin(), size2);
647 slice1->remove_prefix(size1);
648 slice2->remove_prefix(size2);
649
650 *ok = true;
651 // This is the same as a memcmp()
652 return binary1.compare(binary2);
653 }
654
CompareInts(int64_t a,int64_t b)655 static int CompareInts(int64_t a, int64_t b) {
656 #ifndef NDEBUG
657 // Exercised by unit tests in debug only.
658 DCHECK_GE(a, 0);
659 DCHECK_GE(b, 0);
660 #endif
661 int64_t diff = a - b;
662 if (diff < 0)
663 return -1;
664 if (diff > 0)
665 return 1;
666 return 0;
667 }
668
CompareSizes(size_t a,size_t b)669 static inline int CompareSizes(size_t a, size_t b) {
670 if (a > b)
671 return 1;
672 if (b > a)
673 return -1;
674 return 0;
675 }
676
CompareTypes(blink::mojom::IDBKeyType a,blink::mojom::IDBKeyType b)677 static int CompareTypes(blink::mojom::IDBKeyType a,
678 blink::mojom::IDBKeyType b) {
679 return static_cast<int32_t>(b) - static_cast<int32_t>(a);
680 }
681
CompareEncodedIDBKeys(StringPiece * slice_a,StringPiece * slice_b,bool * ok)682 int CompareEncodedIDBKeys(StringPiece* slice_a,
683 StringPiece* slice_b,
684 bool* ok) {
685 DCHECK(!slice_a->empty());
686 DCHECK(!slice_b->empty());
687 *ok = true;
688 unsigned char type_a = (*slice_a)[0];
689 unsigned char type_b = (*slice_b)[0];
690 slice_a->remove_prefix(1);
691 slice_b->remove_prefix(1);
692
693 if (int x = CompareTypes(KeyTypeByteToKeyType(type_a),
694 KeyTypeByteToKeyType(type_b)))
695 return x;
696
697 switch (type_a) {
698 case kIndexedDBKeyNullTypeByte:
699 case kIndexedDBKeyMinKeyTypeByte:
700 // Null type or max type; no payload to compare.
701 return 0;
702 case kIndexedDBKeyArrayTypeByte: {
703 int64_t length_a, length_b;
704 if (!DecodeVarInt(slice_a, &length_a) ||
705 !DecodeVarInt(slice_b, &length_b)) {
706 *ok = false;
707 return 0;
708 }
709 for (int64_t i = 0; i < length_a && i < length_b; ++i) {
710 int result = CompareEncodedIDBKeys(slice_a, slice_b, ok);
711 if (!*ok || result)
712 return result;
713 }
714 return length_a - length_b;
715 }
716 case kIndexedDBKeyBinaryTypeByte:
717 return CompareEncodedBinary(slice_a, slice_b, ok);
718 case kIndexedDBKeyStringTypeByte:
719 return CompareEncodedStringsWithLength(slice_a, slice_b, ok);
720 case kIndexedDBKeyDateTypeByte:
721 case kIndexedDBKeyNumberTypeByte: {
722 double d, e;
723 if (!DecodeDouble(slice_a, &d) || !DecodeDouble(slice_b, &e)) {
724 *ok = false;
725 return 0;
726 }
727 if (d < e)
728 return -1;
729 if (d > e)
730 return 1;
731 return 0;
732 }
733 }
734
735 NOTREACHED();
736 return 0;
737 }
738
739 namespace {
740
741 template <typename KeyType>
Compare(const StringPiece & a,const StringPiece & b,bool only_compare_index_keys,bool * ok)742 int Compare(const StringPiece& a,
743 const StringPiece& b,
744 bool only_compare_index_keys,
745 bool* ok) {
746 KeyType key_a;
747 KeyType key_b;
748
749 StringPiece slice_a(a);
750 if (!KeyType::Decode(&slice_a, &key_a)) {
751 *ok = false;
752 return 0;
753 }
754 StringPiece slice_b(b);
755 if (!KeyType::Decode(&slice_b, &key_b)) {
756 *ok = false;
757 return 0;
758 }
759
760 *ok = true;
761 return key_a.Compare(key_b);
762 }
763
764 template <typename KeyType>
CompareSuffix(StringPiece * a,StringPiece * b,bool only_compare_index_keys,bool * ok)765 int CompareSuffix(StringPiece* a,
766 StringPiece* b,
767 bool only_compare_index_keys,
768 bool* ok) {
769 NOTREACHED();
770 return 0;
771 }
772
773 template <>
CompareSuffix(StringPiece * slice_a,StringPiece * slice_b,bool only_compare_index_keys,bool * ok)774 int CompareSuffix<ExistsEntryKey>(StringPiece* slice_a,
775 StringPiece* slice_b,
776 bool only_compare_index_keys,
777 bool* ok) {
778 DCHECK(!slice_a->empty());
779 DCHECK(!slice_b->empty());
780 return CompareEncodedIDBKeys(slice_a, slice_b, ok);
781 }
782
783 template <>
CompareSuffix(StringPiece * slice_a,StringPiece * slice_b,bool only_compare_index_keys,bool * ok)784 int CompareSuffix<ObjectStoreDataKey>(StringPiece* slice_a,
785 StringPiece* slice_b,
786 bool only_compare_index_keys,
787 bool* ok) {
788 return CompareEncodedIDBKeys(slice_a, slice_b, ok);
789 }
790
791 template <>
CompareSuffix(StringPiece * slice_a,StringPiece * slice_b,bool only_compare_index_keys,bool * ok)792 int CompareSuffix<BlobEntryKey>(StringPiece* slice_a,
793 StringPiece* slice_b,
794 bool only_compare_index_keys,
795 bool* ok) {
796 return CompareEncodedIDBKeys(slice_a, slice_b, ok);
797 }
798
799 template <>
CompareSuffix(StringPiece * slice_a,StringPiece * slice_b,bool only_compare_index_keys,bool * ok)800 int CompareSuffix<IndexDataKey>(StringPiece* slice_a,
801 StringPiece* slice_b,
802 bool only_compare_index_keys,
803 bool* ok) {
804 // index key
805 int result = CompareEncodedIDBKeys(slice_a, slice_b, ok);
806 if (!*ok || result)
807 return result;
808 if (only_compare_index_keys)
809 return 0;
810
811 // sequence number [optional]
812 int64_t sequence_number_a = -1;
813 int64_t sequence_number_b = -1;
814 if (!slice_a->empty() && !DecodeVarInt(slice_a, &sequence_number_a))
815 return 0;
816 if (!slice_b->empty() && !DecodeVarInt(slice_b, &sequence_number_b))
817 return 0;
818
819 if (slice_a->empty() || slice_b->empty())
820 return CompareSizes(slice_a->size(), slice_b->size());
821
822 // primary key [optional]
823 result = CompareEncodedIDBKeys(slice_a, slice_b, ok);
824 if (!*ok || result)
825 return result;
826
827 return CompareInts(sequence_number_a, sequence_number_b);
828 }
829
Compare(const StringPiece & a,const StringPiece & b,bool only_compare_index_keys,bool * ok)830 int Compare(const StringPiece& a,
831 const StringPiece& b,
832 bool only_compare_index_keys,
833 bool* ok) {
834 StringPiece slice_a(a);
835 StringPiece slice_b(b);
836 KeyPrefix prefix_a;
837 KeyPrefix prefix_b;
838 bool ok_a = KeyPrefix::Decode(&slice_a, &prefix_a);
839 bool ok_b = KeyPrefix::Decode(&slice_b, &prefix_b);
840 DCHECK(ok_a);
841 DCHECK(ok_b);
842 if (!ok_a || !ok_b) {
843 *ok = false;
844 return 0;
845 }
846
847 *ok = true;
848 if (int x = prefix_a.Compare(prefix_b))
849 return x;
850
851 switch (prefix_a.type()) {
852 case KeyPrefix::GLOBAL_METADATA: {
853 DCHECK(!slice_a.empty());
854 DCHECK(!slice_b.empty());
855
856 unsigned char type_byte_a;
857 if (!DecodeByte(&slice_a, &type_byte_a)) {
858 *ok = false;
859 return 0;
860 }
861
862 unsigned char type_byte_b;
863 if (!DecodeByte(&slice_b, &type_byte_b)) {
864 *ok = false;
865 return 0;
866 }
867
868 if (int x = type_byte_a - type_byte_b)
869 return x;
870 if (type_byte_a < kMaxSimpleGlobalMetaDataTypeByte)
871 return 0;
872
873 if (type_byte_a == kScopesPrefixByte)
874 return slice_a.compare(slice_b);
875
876 // Compare<> is used (which re-decodes the prefix) rather than an
877 // specialized CompareSuffix<> because metadata is relatively uncommon
878 // in the database.
879
880 if (type_byte_a == kDatabaseFreeListTypeByte) {
881 // TODO(jsbell): No need to pass only_compare_index_keys through here.
882 return Compare<DatabaseFreeListKey>(a, b, only_compare_index_keys, ok);
883 }
884 if (type_byte_a == kDatabaseNameTypeByte) {
885 return Compare<DatabaseNameKey>(a, b, /*only_compare_index_keys*/ false,
886 ok);
887 }
888 break;
889 }
890
891 case KeyPrefix::DATABASE_METADATA: {
892 DCHECK(!slice_a.empty());
893 DCHECK(!slice_b.empty());
894
895 unsigned char type_byte_a;
896 if (!DecodeByte(&slice_a, &type_byte_a)) {
897 *ok = false;
898 return 0;
899 }
900
901 unsigned char type_byte_b;
902 if (!DecodeByte(&slice_b, &type_byte_b)) {
903 *ok = false;
904 return 0;
905 }
906
907 if (int x = type_byte_a - type_byte_b)
908 return x;
909 if (type_byte_a < DatabaseMetaDataKey::MAX_SIMPLE_METADATA_TYPE)
910 return 0;
911
912 // Compare<> is used (which re-decodes the prefix) rather than an
913 // specialized CompareSuffix<> because metadata is relatively uncommon
914 // in the database.
915
916 if (type_byte_a == kObjectStoreMetaDataTypeByte) {
917 // TODO(jsbell): No need to pass only_compare_index_keys through here.
918 return Compare<ObjectStoreMetaDataKey>(a, b, only_compare_index_keys,
919 ok);
920 }
921 if (type_byte_a == kIndexMetaDataTypeByte) {
922 return Compare<IndexMetaDataKey>(a, b,
923 /*only_compare_index_keys*/ false, ok);
924 }
925 if (type_byte_a == kObjectStoreFreeListTypeByte) {
926 return Compare<ObjectStoreFreeListKey>(a, b, only_compare_index_keys,
927 ok);
928 }
929 if (type_byte_a == kIndexFreeListTypeByte) {
930 return Compare<IndexFreeListKey>(a, b,
931 /*only_compare_index_keys*/ false, ok);
932 }
933 if (type_byte_a == kObjectStoreNamesTypeByte) {
934 // TODO(jsbell): No need to pass only_compare_index_keys through here.
935 return Compare<ObjectStoreNamesKey>(a, b, only_compare_index_keys, ok);
936 }
937 if (type_byte_a == kIndexNamesKeyTypeByte) {
938 return Compare<IndexNamesKey>(a, b, /*only_compare_index_keys*/ false,
939 ok);
940 }
941 break;
942 }
943
944 case KeyPrefix::OBJECT_STORE_DATA: {
945 // Provide a stable ordering for invalid data.
946 if (slice_a.empty() || slice_b.empty())
947 return CompareSizes(slice_a.size(), slice_b.size());
948
949 return CompareSuffix<ObjectStoreDataKey>(
950 &slice_a, &slice_b, /*only_compare_index_keys*/ false, ok);
951 }
952
953 case KeyPrefix::EXISTS_ENTRY: {
954 // Provide a stable ordering for invalid data.
955 if (slice_a.empty() || slice_b.empty())
956 return CompareSizes(slice_a.size(), slice_b.size());
957
958 return CompareSuffix<ExistsEntryKey>(
959 &slice_a, &slice_b, /*only_compare_index_keys*/ false, ok);
960 }
961
962 case KeyPrefix::BLOB_ENTRY: {
963 // Provide a stable ordering for invalid data.
964 if (slice_a.empty() || slice_b.empty())
965 return CompareSizes(slice_a.size(), slice_b.size());
966
967 return CompareSuffix<BlobEntryKey>(&slice_a, &slice_b,
968 /*only_compare_index_keys*/ false, ok);
969 }
970
971 case KeyPrefix::INDEX_DATA: {
972 // Provide a stable ordering for invalid data.
973 if (slice_a.empty() || slice_b.empty())
974 return CompareSizes(slice_a.size(), slice_b.size());
975
976 return CompareSuffix<IndexDataKey>(&slice_a, &slice_b,
977 only_compare_index_keys, ok);
978 }
979
980 case KeyPrefix::INVALID_TYPE:
981 break;
982 }
983
984 NOTREACHED();
985 *ok = false;
986 return 0;
987 }
988
989 } // namespace
990
Compare(const StringPiece & a,const StringPiece & b,bool only_compare_index_keys)991 int Compare(const StringPiece& a,
992 const StringPiece& b,
993 bool only_compare_index_keys) {
994 bool ok;
995 int result = Compare(a, b, only_compare_index_keys, &ok);
996 // TODO(dmurph): Report this somehow. https://crbug.com/913121
997 DCHECK(ok);
998 if (!ok)
999 return 0;
1000 return result;
1001 }
1002
CompareKeys(const StringPiece & a,const StringPiece & b)1003 int CompareKeys(const StringPiece& a, const StringPiece& b) {
1004 return Compare(a, b, false /*index_keys*/);
1005 }
1006
CompareIndexKeys(const StringPiece & a,const StringPiece & b)1007 int CompareIndexKeys(const StringPiece& a, const StringPiece& b) {
1008 return Compare(a, b, true /*index_keys*/);
1009 }
1010
IndexedDBKeyToDebugString(base::StringPiece key)1011 std::string IndexedDBKeyToDebugString(base::StringPiece key) {
1012 base::StringPiece key_with_prefix_preserved = key;
1013 KeyPrefix prefix;
1014 std::stringstream result;
1015 if (!KeyPrefix::Decode(&key, &prefix)) {
1016 result << "<Error decoding key prefix>";
1017 return result.str();
1018 }
1019 result << prefix.DebugString() << ", ";
1020
1021 switch (prefix.type()) {
1022 case KeyPrefix::GLOBAL_METADATA: {
1023 unsigned char type_byte;
1024 if (!DecodeByte(&key, &type_byte)) {
1025 result << "No_Type_Byte";
1026 break;
1027 }
1028 switch (type_byte) {
1029 case kSchemaVersionTypeByte:
1030 result << "kSchemaVersionTypeByte";
1031 break;
1032 case kMaxDatabaseIdTypeByte:
1033 result << "kMaxDatabaseIdTypeByte";
1034 break;
1035 case kDataVersionTypeByte:
1036 result << "kDataVersionTypeByte";
1037 break;
1038 case kRecoveryBlobJournalTypeByte:
1039 result << "kRecoveryBlobJournalTypeByte";
1040 break;
1041 case kActiveBlobJournalTypeByte:
1042 result << "kActiveBlobJournalTypeByte";
1043 break;
1044 case kEarliestSweepTimeTypeByte:
1045 result << "kEarliestSweepTimeTypeByte";
1046 break;
1047 case kScopesPrefixByte:
1048 result << "Scopes key: "
1049 << leveldb_scopes::KeyToDebugString(base::make_span(
1050 reinterpret_cast<const uint8_t*>(key.data()),
1051 key.size()));
1052 break;
1053 case kDatabaseFreeListTypeByte: {
1054 DatabaseFreeListKey db_free_list_key;
1055 if (!DatabaseFreeListKey::Decode(&key_with_prefix_preserved,
1056 &db_free_list_key)) {
1057 result << "kDatabaseFreeListTypeByte, Invalid_Key";
1058 break;
1059 }
1060 result << db_free_list_key.DebugString();
1061 break;
1062 }
1063 case kDatabaseNameTypeByte: {
1064 DatabaseNameKey db_name_key;
1065 if (!DatabaseNameKey::Decode(&key_with_prefix_preserved,
1066 &db_name_key)) {
1067 result << "kDatabaseNameTypeByte, Invalid_Key";
1068 break;
1069 }
1070 result << db_name_key.DebugString();
1071 break;
1072 }
1073 default:
1074 result << "Invalid_metadata_type";
1075 break;
1076 }
1077 break;
1078 }
1079
1080 case KeyPrefix::DATABASE_METADATA: {
1081 unsigned char type_byte;
1082 if (!DecodeByte(&key, &type_byte)) {
1083 result << "No_Type_Byte";
1084 break;
1085 }
1086 switch (type_byte) {
1087 case DatabaseMetaDataKey::ORIGIN_NAME:
1088 result << "ORIGIN_NAME";
1089 break;
1090 case DatabaseMetaDataKey::DATABASE_NAME:
1091 result << "DATABASE_NAME";
1092 break;
1093 case DatabaseMetaDataKey::USER_STRING_VERSION:
1094 result << "USER_STRING_VERSION";
1095 break;
1096 case DatabaseMetaDataKey::MAX_OBJECT_STORE_ID:
1097 result << "MAX_OBJECT_STORE_ID";
1098 break;
1099 case DatabaseMetaDataKey::USER_VERSION:
1100 result << "USER_VERSION";
1101 break;
1102 case DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER:
1103 result << "BLOB_KEY_GENERATOR_CURRENT_NUMBER";
1104 break;
1105 case kObjectStoreMetaDataTypeByte: {
1106 ObjectStoreMetaDataKey sub_key;
1107 if (!ObjectStoreMetaDataKey::Decode(&key_with_prefix_preserved,
1108 &sub_key)) {
1109 result << "Invalid_ObjectStoreMetaDataKey";
1110 break;
1111 }
1112 result << sub_key.DebugString();
1113 break;
1114 }
1115 case kIndexMetaDataTypeByte: {
1116 IndexMetaDataKey sub_key;
1117 if (!IndexMetaDataKey::Decode(&key_with_prefix_preserved, &sub_key)) {
1118 result << "Invalid_IndexMetaDataKey";
1119 break;
1120 }
1121 result << sub_key.DebugString();
1122 break;
1123 }
1124 case kObjectStoreFreeListTypeByte: {
1125 ObjectStoreFreeListKey sub_key;
1126 if (!ObjectStoreFreeListKey::Decode(&key_with_prefix_preserved,
1127 &sub_key)) {
1128 result << "Invalid_ObjectStoreFreeListKey";
1129 break;
1130 }
1131 result << sub_key.DebugString();
1132 break;
1133 }
1134 case kIndexFreeListTypeByte: {
1135 IndexFreeListKey sub_key;
1136 if (!IndexFreeListKey::Decode(&key_with_prefix_preserved, &sub_key)) {
1137 result << "Invalid_IndexFreeListKey";
1138 break;
1139 }
1140 result << sub_key.DebugString();
1141 break;
1142 }
1143 case kObjectStoreNamesTypeByte: {
1144 ObjectStoreNamesKey sub_key;
1145 if (!ObjectStoreNamesKey::Decode(&key_with_prefix_preserved,
1146 &sub_key)) {
1147 result << "Invalid_ObjectStoreNamesKey";
1148 break;
1149 }
1150 result << sub_key.DebugString();
1151 break;
1152 } // namespace content
1153 case kIndexNamesKeyTypeByte: {
1154 IndexNamesKey sub_key;
1155 if (!IndexNamesKey::Decode(&key_with_prefix_preserved, &sub_key)) {
1156 result << "Invalid_IndexNamesKey";
1157 break;
1158 }
1159 result << sub_key.DebugString();
1160 break;
1161 }
1162 }
1163 break;
1164 }
1165 case KeyPrefix::OBJECT_STORE_DATA: {
1166 ObjectStoreDataKey sub_key;
1167 if (!ObjectStoreDataKey::Decode(&key_with_prefix_preserved, &sub_key)) {
1168 result << "Invalid_ObjectStoreDataKey";
1169 break;
1170 }
1171 result << sub_key.DebugString();
1172 break;
1173 }
1174
1175 case KeyPrefix::EXISTS_ENTRY: {
1176 ExistsEntryKey sub_key;
1177 if (!ExistsEntryKey::Decode(&key_with_prefix_preserved, &sub_key)) {
1178 result << "Invalid_ExistsEntryKey";
1179 break;
1180 }
1181 result << sub_key.DebugString();
1182 break;
1183 }
1184
1185 case KeyPrefix::BLOB_ENTRY: {
1186 BlobEntryKey sub_key;
1187 if (!BlobEntryKey::Decode(&key_with_prefix_preserved, &sub_key)) {
1188 result << "Invalid_BlobEntryKey";
1189 break;
1190 }
1191 result << sub_key.DebugString();
1192 break;
1193 }
1194
1195 case KeyPrefix::INDEX_DATA: {
1196 IndexDataKey sub_key;
1197 if (!IndexDataKey::Decode(&key_with_prefix_preserved, &sub_key)) {
1198 result << "Invalid_IndexDataKey";
1199 break;
1200 }
1201 result << sub_key.DebugString();
1202 break;
1203 }
1204
1205 case KeyPrefix::INVALID_TYPE:
1206 result << "InvalidKeyType";
1207 break;
1208 }
1209 result << "]";
1210 return result.str();
1211 }
1212
GetDatabaseLockRange(int64_t database_id)1213 ScopeLockRange GetDatabaseLockRange(int64_t database_id) {
1214 // The numbers are transformed into big-endian to make them
1215 // bytewise-comparable. Eventually, these lock ranges should just match the
1216 // leveldb keys when they are bytewise-comparable.
1217 uint64_t first[1] = {ByteSwapToBE64(static_cast<uint64_t>(database_id))};
1218 uint64_t next[1] = {ByteSwapToBE64(static_cast<uint64_t>(database_id + 1))};
1219 return {std::string(reinterpret_cast<char*>(&first), sizeof(first)),
1220 std::string(reinterpret_cast<char*>(&next), sizeof(next))};
1221 }
1222
GetObjectStoreLockRange(int64_t database_id,int64_t object_store_id)1223 ScopeLockRange GetObjectStoreLockRange(int64_t database_id,
1224 int64_t object_store_id) {
1225 // The numbers are transformed into big-endian to make them
1226 // bytewise-comparable. Eventually, these lock ranges should just match the
1227 // leveldb keys when they are bytewise-comparable.
1228 uint64_t first[2] = {ByteSwapToBE64(static_cast<uint64_t>(database_id)),
1229 ByteSwapToBE64(static_cast<uint64_t>(object_store_id))};
1230 uint64_t next[2] = {
1231 ByteSwapToBE64(static_cast<uint64_t>(database_id)),
1232 ByteSwapToBE64(static_cast<uint64_t>(object_store_id + 1))};
1233 return {std::string(reinterpret_cast<char*>(&first), sizeof(first)),
1234 std::string(reinterpret_cast<char*>(&next), sizeof(next))};
1235 }
1236
KeyPrefix()1237 KeyPrefix::KeyPrefix()
1238 : database_id_(INVALID_TYPE),
1239 object_store_id_(INVALID_TYPE),
1240 index_id_(INVALID_TYPE) {}
1241
KeyPrefix(int64_t database_id)1242 KeyPrefix::KeyPrefix(int64_t database_id)
1243 : database_id_(database_id), object_store_id_(0), index_id_(0) {
1244 DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
1245 }
1246
KeyPrefix(int64_t database_id,int64_t object_store_id)1247 KeyPrefix::KeyPrefix(int64_t database_id, int64_t object_store_id)
1248 : database_id_(database_id),
1249 object_store_id_(object_store_id),
1250 index_id_(0) {
1251 DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
1252 DCHECK(KeyPrefix::IsValidObjectStoreId(object_store_id));
1253 }
1254
KeyPrefix(int64_t database_id,int64_t object_store_id,int64_t index_id)1255 KeyPrefix::KeyPrefix(int64_t database_id,
1256 int64_t object_store_id,
1257 int64_t index_id)
1258 : database_id_(database_id),
1259 object_store_id_(object_store_id),
1260 index_id_(index_id) {
1261 DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
1262 DCHECK(KeyPrefix::IsValidObjectStoreId(object_store_id));
1263 DCHECK(KeyPrefix::IsValidIndexId(index_id));
1264 }
1265
KeyPrefix(enum Type type,int64_t database_id,int64_t object_store_id,int64_t index_id)1266 KeyPrefix::KeyPrefix(enum Type type,
1267 int64_t database_id,
1268 int64_t object_store_id,
1269 int64_t index_id)
1270 : database_id_(database_id),
1271 object_store_id_(object_store_id),
1272 index_id_(index_id) {
1273 DCHECK_EQ(type, INVALID_TYPE);
1274 DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
1275 DCHECK(KeyPrefix::IsValidObjectStoreId(object_store_id));
1276 }
1277
CreateWithSpecialIndex(int64_t database_id,int64_t object_store_id,int64_t index_id)1278 KeyPrefix KeyPrefix::CreateWithSpecialIndex(int64_t database_id,
1279 int64_t object_store_id,
1280 int64_t index_id) {
1281 DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
1282 DCHECK(KeyPrefix::IsValidObjectStoreId(object_store_id));
1283 DCHECK(index_id);
1284 return KeyPrefix(INVALID_TYPE, database_id, object_store_id, index_id);
1285 }
1286
IsValidDatabaseId(int64_t database_id)1287 bool KeyPrefix::IsValidDatabaseId(int64_t database_id) {
1288 return (database_id > 0) && (database_id < KeyPrefix::kMaxDatabaseId);
1289 }
1290
IsValidObjectStoreId(int64_t object_store_id)1291 bool KeyPrefix::IsValidObjectStoreId(int64_t object_store_id) {
1292 return (object_store_id > 0) &&
1293 (object_store_id < KeyPrefix::kMaxObjectStoreId);
1294 }
1295
IsValidIndexId(int64_t index_id)1296 bool KeyPrefix::IsValidIndexId(int64_t index_id) {
1297 return (index_id >= kMinimumIndexId) && (index_id < KeyPrefix::kMaxIndexId);
1298 }
1299
Decode(StringPiece * slice,KeyPrefix * result)1300 bool KeyPrefix::Decode(StringPiece* slice, KeyPrefix* result) {
1301 unsigned char first_byte;
1302 if (!DecodeByte(slice, &first_byte))
1303 return false;
1304
1305 size_t database_id_bytes = ((first_byte >> 5) & 0x7) + 1;
1306 size_t object_store_id_bytes = ((first_byte >> 2) & 0x7) + 1;
1307 size_t index_id_bytes = (first_byte & 0x3) + 1;
1308
1309 if (database_id_bytes + object_store_id_bytes + index_id_bytes >
1310 slice->size())
1311 return false;
1312
1313 {
1314 StringPiece tmp(slice->begin(), database_id_bytes);
1315 if (!DecodeInt(&tmp, &result->database_id_))
1316 return false;
1317 }
1318 slice->remove_prefix(database_id_bytes);
1319 {
1320 StringPiece tmp(slice->begin(), object_store_id_bytes);
1321 if (!DecodeInt(&tmp, &result->object_store_id_))
1322 return false;
1323 }
1324 slice->remove_prefix(object_store_id_bytes);
1325 {
1326 StringPiece tmp(slice->begin(), index_id_bytes);
1327 if (!DecodeInt(&tmp, &result->index_id_))
1328 return false;
1329 }
1330 slice->remove_prefix(index_id_bytes);
1331 return true;
1332 }
1333
EncodeEmpty()1334 std::string KeyPrefix::EncodeEmpty() {
1335 const std::string result(4, 0);
1336 DCHECK(EncodeInternal(0, 0, 0) == std::string(4, 0));
1337 return result;
1338 }
1339
Encode() const1340 std::string KeyPrefix::Encode() const {
1341 DCHECK(database_id_ != kInvalidId);
1342 DCHECK(object_store_id_ != kInvalidId);
1343 DCHECK(index_id_ != kInvalidId);
1344 return EncodeInternal(database_id_, object_store_id_, index_id_);
1345 }
1346
EncodeInternal(int64_t database_id,int64_t object_store_id,int64_t index_id)1347 std::string KeyPrefix::EncodeInternal(int64_t database_id,
1348 int64_t object_store_id,
1349 int64_t index_id) {
1350 std::string database_id_string;
1351 std::string object_store_id_string;
1352 std::string index_id_string;
1353
1354 EncodeIntSafely(database_id, kMaxDatabaseId, &database_id_string);
1355 EncodeIntSafely(object_store_id, kMaxObjectStoreId, &object_store_id_string);
1356 EncodeIntSafely(index_id, kMaxIndexId, &index_id_string);
1357
1358 DCHECK(database_id_string.size() <= kMaxDatabaseIdSizeBytes);
1359 DCHECK(object_store_id_string.size() <= kMaxObjectStoreIdSizeBytes);
1360 DCHECK(index_id_string.size() <= kMaxIndexIdSizeBytes);
1361
1362 unsigned char first_byte =
1363 (database_id_string.size() - 1)
1364 << (kMaxObjectStoreIdSizeBits + kMaxIndexIdSizeBits) |
1365 (object_store_id_string.size() - 1) << kMaxIndexIdSizeBits |
1366 (index_id_string.size() - 1);
1367 static_assert(kMaxDatabaseIdSizeBits + kMaxObjectStoreIdSizeBits +
1368 kMaxIndexIdSizeBits ==
1369 sizeof(first_byte) * 8,
1370 "cannot encode ids");
1371 std::string ret;
1372 ret.reserve(kDefaultInlineBufferSize);
1373 ret.push_back(first_byte);
1374 ret.append(database_id_string);
1375 ret.append(object_store_id_string);
1376 ret.append(index_id_string);
1377
1378 DCHECK_LE(ret.size(), kDefaultInlineBufferSize);
1379 return ret;
1380 }
1381
Compare(const KeyPrefix & other) const1382 int KeyPrefix::Compare(const KeyPrefix& other) const {
1383 DCHECK(database_id_ != kInvalidId);
1384 DCHECK(object_store_id_ != kInvalidId);
1385 DCHECK(index_id_ != kInvalidId);
1386
1387 if (database_id_ != other.database_id_)
1388 return CompareInts(database_id_, other.database_id_);
1389 if (object_store_id_ != other.object_store_id_)
1390 return CompareInts(object_store_id_, other.object_store_id_);
1391 if (index_id_ != other.index_id_)
1392 return CompareInts(index_id_, other.index_id_);
1393 return 0;
1394 }
1395
DebugString()1396 std::string KeyPrefix::DebugString() {
1397 std::stringstream result;
1398 result << "{";
1399 switch (type()) {
1400 case GLOBAL_METADATA:
1401 result << "GLOBAL_META";
1402 break;
1403 case DATABASE_METADATA:
1404 result << "DB_META, db: " << database_id_;
1405 break;
1406 case OBJECT_STORE_DATA:
1407 result << "OS_DATA, db: " << database_id_ << ", os: " << object_store_id_;
1408 break;
1409 case EXISTS_ENTRY:
1410 result << "EXISTS_ENTRY, db: " << database_id_
1411 << ", os: " << object_store_id_;
1412 break;
1413 case BLOB_ENTRY:
1414 result << "BLOB_ENTRY, db: " << database_id_
1415 << ", os: " << object_store_id_;
1416 break;
1417 case INDEX_DATA:
1418 result << "INDEX_DATA, db: " << database_id_
1419 << ", os: " << object_store_id_ << ", idx: " << index_id_;
1420 break;
1421 case INVALID_TYPE:
1422 result << "INVALID_TYPE";
1423 break;
1424 }
1425 result << "}";
1426 return result.str();
1427 }
1428
type() const1429 KeyPrefix::Type KeyPrefix::type() const {
1430 DCHECK(database_id_ != kInvalidId);
1431 DCHECK(object_store_id_ != kInvalidId);
1432 DCHECK(index_id_ != kInvalidId);
1433
1434 if (!database_id_)
1435 return GLOBAL_METADATA;
1436 if (!object_store_id_)
1437 return DATABASE_METADATA;
1438 if (index_id_ == kObjectStoreDataIndexId)
1439 return OBJECT_STORE_DATA;
1440 if (index_id_ == kExistsEntryIndexId)
1441 return EXISTS_ENTRY;
1442 if (index_id_ == kBlobEntryIndexId)
1443 return BLOB_ENTRY;
1444 if (index_id_ >= kMinimumIndexId)
1445 return INDEX_DATA;
1446
1447 NOTREACHED();
1448 return INVALID_TYPE;
1449 }
1450
Encode()1451 std::string SchemaVersionKey::Encode() {
1452 std::string ret = KeyPrefix::EncodeEmpty();
1453 ret.push_back(kSchemaVersionTypeByte);
1454 return ret;
1455 }
1456
Encode()1457 std::string MaxDatabaseIdKey::Encode() {
1458 std::string ret = KeyPrefix::EncodeEmpty();
1459 ret.push_back(kMaxDatabaseIdTypeByte);
1460 return ret;
1461 }
1462
Encode()1463 std::string DataVersionKey::Encode() {
1464 std::string ret = KeyPrefix::EncodeEmpty();
1465 ret.push_back(kDataVersionTypeByte);
1466 return ret;
1467 }
1468
Encode()1469 std::string RecoveryBlobJournalKey::Encode() {
1470 std::string ret = KeyPrefix::EncodeEmpty();
1471 ret.push_back(kRecoveryBlobJournalTypeByte);
1472 return ret;
1473 }
1474
Encode()1475 std::string ActiveBlobJournalKey::Encode() {
1476 std::string ret = KeyPrefix::EncodeEmpty();
1477 ret.push_back(kActiveBlobJournalTypeByte);
1478 return ret;
1479 }
1480
Encode()1481 std::string EarliestSweepKey::Encode() {
1482 std::string ret = KeyPrefix::EncodeEmpty();
1483 ret.push_back(kEarliestSweepTimeTypeByte);
1484 return ret;
1485 }
1486
Encode()1487 std::vector<uint8_t> ScopesPrefix::Encode() {
1488 std::string ret = KeyPrefix::EncodeEmpty();
1489 ret.push_back(kScopesPrefixByte);
1490 auto span = base::make_span(ret);
1491 return std::vector<uint8_t>(span.begin(), span.end());
1492 }
1493
DatabaseFreeListKey()1494 DatabaseFreeListKey::DatabaseFreeListKey() : database_id_(-1) {}
1495
Decode(StringPiece * slice,DatabaseFreeListKey * result)1496 bool DatabaseFreeListKey::Decode(StringPiece* slice,
1497 DatabaseFreeListKey* result) {
1498 KeyPrefix prefix;
1499 if (!KeyPrefix::Decode(slice, &prefix))
1500 return false;
1501 DCHECK(!prefix.database_id_);
1502 DCHECK(!prefix.object_store_id_);
1503 DCHECK(!prefix.index_id_);
1504 unsigned char type_byte = 0;
1505 if (!DecodeByte(slice, &type_byte))
1506 return false;
1507 DCHECK_EQ(type_byte, kDatabaseFreeListTypeByte);
1508 if (!DecodeVarInt(slice, &result->database_id_))
1509 return false;
1510 return true;
1511 }
1512
Encode(int64_t database_id)1513 std::string DatabaseFreeListKey::Encode(int64_t database_id) {
1514 std::string ret = KeyPrefix::EncodeEmpty();
1515 ret.push_back(kDatabaseFreeListTypeByte);
1516 EncodeVarInt(database_id, &ret);
1517 return ret;
1518 }
1519
EncodeMaxKey()1520 std::string DatabaseFreeListKey::EncodeMaxKey() {
1521 return Encode(std::numeric_limits<int64_t>::max());
1522 }
1523
DatabaseId() const1524 int64_t DatabaseFreeListKey::DatabaseId() const {
1525 DCHECK_GE(database_id_, 0);
1526 return database_id_;
1527 }
1528
Compare(const DatabaseFreeListKey & other) const1529 int DatabaseFreeListKey::Compare(const DatabaseFreeListKey& other) const {
1530 DCHECK_GE(database_id_, 0);
1531 return CompareInts(database_id_, other.database_id_);
1532 }
1533
DebugString() const1534 std::string DatabaseFreeListKey::DebugString() const {
1535 std::stringstream result;
1536 result << "DatabaseFreeListKey{db: " << database_id_ << "}";
1537 return result.str();
1538 }
1539
Decode(StringPiece * slice,DatabaseNameKey * result)1540 bool DatabaseNameKey::Decode(StringPiece* slice, DatabaseNameKey* result) {
1541 KeyPrefix prefix;
1542 if (!KeyPrefix::Decode(slice, &prefix))
1543 return false;
1544 DCHECK(!prefix.database_id_);
1545 DCHECK(!prefix.object_store_id_);
1546 DCHECK(!prefix.index_id_);
1547 unsigned char type_byte = 0;
1548 if (!DecodeByte(slice, &type_byte))
1549 return false;
1550 DCHECK_EQ(type_byte, kDatabaseNameTypeByte);
1551 if (!DecodeStringWithLength(slice, &result->origin_))
1552 return false;
1553 if (!DecodeStringWithLength(slice, &result->database_name_))
1554 return false;
1555 return true;
1556 }
1557
Encode(const std::string & origin_identifier,const base::string16 & database_name)1558 std::string DatabaseNameKey::Encode(const std::string& origin_identifier,
1559 const base::string16& database_name) {
1560 std::string ret = KeyPrefix::EncodeEmpty();
1561 ret.push_back(kDatabaseNameTypeByte);
1562 EncodeStringWithLength(base::ASCIIToUTF16(origin_identifier), &ret);
1563 EncodeStringWithLength(database_name, &ret);
1564 return ret;
1565 }
1566
EncodeMinKeyForOrigin(const std::string & origin_identifier)1567 std::string DatabaseNameKey::EncodeMinKeyForOrigin(
1568 const std::string& origin_identifier) {
1569 return Encode(origin_identifier, base::string16());
1570 }
1571
EncodeStopKeyForOrigin(const std::string & origin_identifier)1572 std::string DatabaseNameKey::EncodeStopKeyForOrigin(
1573 const std::string& origin_identifier) {
1574 // just after origin in collation order
1575 return EncodeMinKeyForOrigin(origin_identifier + '\x01');
1576 }
1577
Compare(const DatabaseNameKey & other)1578 int DatabaseNameKey::Compare(const DatabaseNameKey& other) {
1579 if (int x = origin_.compare(other.origin_))
1580 return x;
1581 return database_name_.compare(other.database_name_);
1582 }
1583
DebugString() const1584 std::string DatabaseNameKey::DebugString() const {
1585 std::stringstream result;
1586 result << "DatabaseNameKey{origin: " << origin_
1587 << ", database_name: " << database_name_ << "}";
1588 return result.str();
1589 }
1590
IsValidBlobNumber(int64_t blob_number)1591 bool DatabaseMetaDataKey::IsValidBlobNumber(int64_t blob_number) {
1592 return blob_number >= kBlobNumberGeneratorInitialNumber;
1593 }
1594
1595 const int64_t DatabaseMetaDataKey::kAllBlobsNumber = 1;
1596 const int64_t DatabaseMetaDataKey::kBlobNumberGeneratorInitialNumber = 2;
1597 const int64_t DatabaseMetaDataKey::kInvalidBlobNumber = -1;
1598
Encode(int64_t database_id,MetaDataType meta_data_type)1599 std::string DatabaseMetaDataKey::Encode(int64_t database_id,
1600 MetaDataType meta_data_type) {
1601 KeyPrefix prefix(database_id);
1602 std::string ret = prefix.Encode();
1603 ret.push_back(meta_data_type);
1604 return ret;
1605 }
1606
1607 const int64_t ObjectStoreMetaDataKey::kKeyGeneratorInitialNumber = 1;
1608
ObjectStoreMetaDataKey()1609 ObjectStoreMetaDataKey::ObjectStoreMetaDataKey()
1610 : object_store_id_(-1), meta_data_type_(0xFF) {}
1611
Decode(StringPiece * slice,ObjectStoreMetaDataKey * result)1612 bool ObjectStoreMetaDataKey::Decode(StringPiece* slice,
1613 ObjectStoreMetaDataKey* result) {
1614 KeyPrefix prefix;
1615 if (!KeyPrefix::Decode(slice, &prefix))
1616 return false;
1617 DCHECK(prefix.database_id_);
1618 DCHECK(!prefix.object_store_id_);
1619 DCHECK(!prefix.index_id_);
1620 unsigned char type_byte = 0;
1621 if (!DecodeByte(slice, &type_byte))
1622 return false;
1623 DCHECK_EQ(type_byte, kObjectStoreMetaDataTypeByte);
1624 if (!DecodeVarInt(slice, &result->object_store_id_))
1625 return false;
1626 DCHECK(result->object_store_id_);
1627 if (!DecodeByte(slice, &result->meta_data_type_))
1628 return false;
1629 return true;
1630 }
1631
Encode(int64_t database_id,int64_t object_store_id,unsigned char meta_data_type)1632 std::string ObjectStoreMetaDataKey::Encode(int64_t database_id,
1633 int64_t object_store_id,
1634 unsigned char meta_data_type) {
1635 KeyPrefix prefix(database_id);
1636 std::string ret = prefix.Encode();
1637 ret.push_back(kObjectStoreMetaDataTypeByte);
1638 EncodeVarInt(object_store_id, &ret);
1639 ret.push_back(meta_data_type);
1640 return ret;
1641 }
1642
EncodeMaxKey(int64_t database_id)1643 std::string ObjectStoreMetaDataKey::EncodeMaxKey(int64_t database_id) {
1644 return Encode(database_id, std::numeric_limits<int64_t>::max(),
1645 kObjectMetaDataTypeMaximum);
1646 }
1647
EncodeMaxKey(int64_t database_id,int64_t object_store_id)1648 std::string ObjectStoreMetaDataKey::EncodeMaxKey(int64_t database_id,
1649 int64_t object_store_id) {
1650 return Encode(database_id, object_store_id, kObjectMetaDataTypeMaximum);
1651 }
1652
ObjectStoreId() const1653 int64_t ObjectStoreMetaDataKey::ObjectStoreId() const {
1654 DCHECK_GE(object_store_id_, 0);
1655 return object_store_id_;
1656 }
MetaDataType() const1657 unsigned char ObjectStoreMetaDataKey::MetaDataType() const {
1658 return meta_data_type_;
1659 }
1660
Compare(const ObjectStoreMetaDataKey & other)1661 int ObjectStoreMetaDataKey::Compare(const ObjectStoreMetaDataKey& other) {
1662 DCHECK_GE(object_store_id_, 0);
1663 if (int x = CompareInts(object_store_id_, other.object_store_id_))
1664 return x;
1665 return meta_data_type_ - other.meta_data_type_;
1666 }
1667
DebugString() const1668 std::string ObjectStoreMetaDataKey::DebugString() const {
1669 std::stringstream result;
1670 result << "ObjectStoreMetaDataKey{os: " << object_store_id_;
1671 switch (meta_data_type_) {
1672 case NAME:
1673 result << ", NAME";
1674 break;
1675 case KEY_PATH:
1676 result << ", KEY_PATH";
1677 break;
1678 case AUTO_INCREMENT:
1679 result << ", AUTO_INCREMENT";
1680 break;
1681 case EVICTABLE:
1682 result << ", EVICTABLE";
1683 break;
1684 case LAST_VERSION:
1685 result << ", LAST_VERSION";
1686 break;
1687 case MAX_INDEX_ID:
1688 result << ", MAX_INDEX_ID";
1689 break;
1690 case HAS_KEY_PATH:
1691 result << ", HAS_KEY_PATH";
1692 break;
1693 case KEY_GENERATOR_CURRENT_NUMBER:
1694 result << ", KEY_GENERATOR_CURRENT_NUMBER";
1695 break;
1696 default:
1697 result << ", INVALID_TYPE";
1698 }
1699 result << "}";
1700 return result.str();
1701 }
1702
IndexMetaDataKey()1703 IndexMetaDataKey::IndexMetaDataKey()
1704 : object_store_id_(-1), index_id_(-1), meta_data_type_(0) {}
1705
Decode(StringPiece * slice,IndexMetaDataKey * result)1706 bool IndexMetaDataKey::Decode(StringPiece* slice, IndexMetaDataKey* result) {
1707 KeyPrefix prefix;
1708 if (!KeyPrefix::Decode(slice, &prefix))
1709 return false;
1710 DCHECK(prefix.database_id_);
1711 DCHECK(!prefix.object_store_id_);
1712 DCHECK(!prefix.index_id_);
1713 unsigned char type_byte = 0;
1714 if (!DecodeByte(slice, &type_byte))
1715 return false;
1716 DCHECK_EQ(type_byte, kIndexMetaDataTypeByte);
1717 if (!DecodeVarInt(slice, &result->object_store_id_))
1718 return false;
1719 if (!DecodeVarInt(slice, &result->index_id_))
1720 return false;
1721 if (!DecodeByte(slice, &result->meta_data_type_))
1722 return false;
1723 return true;
1724 }
1725
Encode(int64_t database_id,int64_t object_store_id,int64_t index_id,unsigned char meta_data_type)1726 std::string IndexMetaDataKey::Encode(int64_t database_id,
1727 int64_t object_store_id,
1728 int64_t index_id,
1729 unsigned char meta_data_type) {
1730 KeyPrefix prefix(database_id);
1731 std::string ret = prefix.Encode();
1732 ret.push_back(kIndexMetaDataTypeByte);
1733 EncodeVarInt(object_store_id, &ret);
1734 EncodeVarInt(index_id, &ret);
1735 EncodeByte(meta_data_type, &ret);
1736 return ret;
1737 }
1738
EncodeMaxKey(int64_t database_id,int64_t object_store_id)1739 std::string IndexMetaDataKey::EncodeMaxKey(int64_t database_id,
1740 int64_t object_store_id) {
1741 return Encode(database_id, object_store_id,
1742 std::numeric_limits<int64_t>::max(), kIndexMetaDataTypeMaximum);
1743 }
1744
EncodeMaxKey(int64_t database_id,int64_t object_store_id,int64_t index_id)1745 std::string IndexMetaDataKey::EncodeMaxKey(int64_t database_id,
1746 int64_t object_store_id,
1747 int64_t index_id) {
1748 return Encode(database_id, object_store_id, index_id,
1749 kIndexMetaDataTypeMaximum);
1750 }
1751
Compare(const IndexMetaDataKey & other)1752 int IndexMetaDataKey::Compare(const IndexMetaDataKey& other) {
1753 DCHECK_GE(object_store_id_, 0);
1754 DCHECK_GE(index_id_, 0);
1755
1756 if (int x = CompareInts(object_store_id_, other.object_store_id_))
1757 return x;
1758 if (int x = CompareInts(index_id_, other.index_id_))
1759 return x;
1760 return meta_data_type_ - other.meta_data_type_;
1761 }
1762
DebugString() const1763 std::string IndexMetaDataKey::DebugString() const {
1764 std::stringstream result;
1765 result << "IndexMetaDataKey{os: " << object_store_id_
1766 << ", idx: " << index_id_;
1767 switch (meta_data_type_) {
1768 case NAME:
1769 result << ", NAME";
1770 break;
1771 case UNIQUE:
1772 result << ", UNIQUE";
1773 break;
1774 case KEY_PATH:
1775 result << ", KEY_PATH";
1776 break;
1777 case MULTI_ENTRY:
1778 result << ", MULTI_ENTRY";
1779 break;
1780 default:
1781 result << ", INVALID_TYPE";
1782 }
1783 result << "}";
1784 return result.str();
1785 }
1786
IndexId() const1787 int64_t IndexMetaDataKey::IndexId() const {
1788 DCHECK_GE(index_id_, 0);
1789 return index_id_;
1790 }
1791
ObjectStoreFreeListKey()1792 ObjectStoreFreeListKey::ObjectStoreFreeListKey() : object_store_id_(-1) {}
1793
Decode(StringPiece * slice,ObjectStoreFreeListKey * result)1794 bool ObjectStoreFreeListKey::Decode(StringPiece* slice,
1795 ObjectStoreFreeListKey* result) {
1796 KeyPrefix prefix;
1797 if (!KeyPrefix::Decode(slice, &prefix))
1798 return false;
1799 DCHECK(prefix.database_id_);
1800 DCHECK(!prefix.object_store_id_);
1801 DCHECK(!prefix.index_id_);
1802 unsigned char type_byte = 0;
1803 if (!DecodeByte(slice, &type_byte))
1804 return false;
1805 DCHECK_EQ(type_byte, kObjectStoreFreeListTypeByte);
1806 if (!DecodeVarInt(slice, &result->object_store_id_))
1807 return false;
1808 return true;
1809 }
1810
Encode(int64_t database_id,int64_t object_store_id)1811 std::string ObjectStoreFreeListKey::Encode(int64_t database_id,
1812 int64_t object_store_id) {
1813 KeyPrefix prefix(database_id);
1814 std::string ret = prefix.Encode();
1815 ret.push_back(kObjectStoreFreeListTypeByte);
1816 EncodeVarInt(object_store_id, &ret);
1817 return ret;
1818 }
1819
EncodeMaxKey(int64_t database_id)1820 std::string ObjectStoreFreeListKey::EncodeMaxKey(int64_t database_id) {
1821 return Encode(database_id, std::numeric_limits<int64_t>::max());
1822 }
1823
ObjectStoreId() const1824 int64_t ObjectStoreFreeListKey::ObjectStoreId() const {
1825 DCHECK_GE(object_store_id_, 0);
1826 return object_store_id_;
1827 }
1828
Compare(const ObjectStoreFreeListKey & other)1829 int ObjectStoreFreeListKey::Compare(const ObjectStoreFreeListKey& other) {
1830 // TODO(jsbell): It may seem strange that we're not comparing database id's,
1831 // but that comparison will have been made earlier.
1832 // We should probably make this more clear, though...
1833 DCHECK_GE(object_store_id_, 0);
1834 return CompareInts(object_store_id_, other.object_store_id_);
1835 }
1836
DebugString() const1837 std::string ObjectStoreFreeListKey::DebugString() const {
1838 std::stringstream result;
1839 result << "ObjectStoreFreeListKey{os: " << object_store_id_ << "}";
1840 return result.str();
1841 }
1842
IndexFreeListKey()1843 IndexFreeListKey::IndexFreeListKey() : object_store_id_(-1), index_id_(-1) {}
1844
Decode(StringPiece * slice,IndexFreeListKey * result)1845 bool IndexFreeListKey::Decode(StringPiece* slice, IndexFreeListKey* result) {
1846 KeyPrefix prefix;
1847 if (!KeyPrefix::Decode(slice, &prefix))
1848 return false;
1849 DCHECK(prefix.database_id_);
1850 DCHECK(!prefix.object_store_id_);
1851 DCHECK(!prefix.index_id_);
1852 unsigned char type_byte = 0;
1853 if (!DecodeByte(slice, &type_byte))
1854 return false;
1855 DCHECK_EQ(type_byte, kIndexFreeListTypeByte);
1856 if (!DecodeVarInt(slice, &result->object_store_id_))
1857 return false;
1858 if (!DecodeVarInt(slice, &result->index_id_))
1859 return false;
1860 return true;
1861 }
1862
Encode(int64_t database_id,int64_t object_store_id,int64_t index_id)1863 std::string IndexFreeListKey::Encode(int64_t database_id,
1864 int64_t object_store_id,
1865 int64_t index_id) {
1866 KeyPrefix prefix(database_id);
1867 std::string ret = prefix.Encode();
1868 ret.push_back(kIndexFreeListTypeByte);
1869 EncodeVarInt(object_store_id, &ret);
1870 EncodeVarInt(index_id, &ret);
1871 return ret;
1872 }
1873
EncodeMaxKey(int64_t database_id,int64_t object_store_id)1874 std::string IndexFreeListKey::EncodeMaxKey(int64_t database_id,
1875 int64_t object_store_id) {
1876 return Encode(database_id, object_store_id,
1877 std::numeric_limits<int64_t>::max());
1878 }
1879
Compare(const IndexFreeListKey & other)1880 int IndexFreeListKey::Compare(const IndexFreeListKey& other) {
1881 DCHECK_GE(object_store_id_, 0);
1882 DCHECK_GE(index_id_, 0);
1883 if (int x = CompareInts(object_store_id_, other.object_store_id_))
1884 return x;
1885 return CompareInts(index_id_, other.index_id_);
1886 }
1887
DebugString() const1888 std::string IndexFreeListKey::DebugString() const {
1889 std::stringstream result;
1890 result << "IndexFreeListKey{os: " << object_store_id_
1891 << ", idx: " << index_id_ << "}";
1892 return result.str();
1893 }
1894
ObjectStoreId() const1895 int64_t IndexFreeListKey::ObjectStoreId() const {
1896 DCHECK_GE(object_store_id_, 0);
1897 return object_store_id_;
1898 }
1899
IndexId() const1900 int64_t IndexFreeListKey::IndexId() const {
1901 DCHECK_GE(index_id_, 0);
1902 return index_id_;
1903 }
1904
1905 // TODO(jsbell): We never use this to look up object store ids,
1906 // because a mapping is kept in the IndexedDBDatabase. Can the
1907 // mapping become unreliable? Can we remove this?
Decode(StringPiece * slice,ObjectStoreNamesKey * result)1908 bool ObjectStoreNamesKey::Decode(StringPiece* slice,
1909 ObjectStoreNamesKey* result) {
1910 KeyPrefix prefix;
1911 if (!KeyPrefix::Decode(slice, &prefix))
1912 return false;
1913 DCHECK(prefix.database_id_);
1914 DCHECK(!prefix.object_store_id_);
1915 DCHECK(!prefix.index_id_);
1916 unsigned char type_byte = 0;
1917 if (!DecodeByte(slice, &type_byte))
1918 return false;
1919 DCHECK_EQ(type_byte, kObjectStoreNamesTypeByte);
1920 if (!DecodeStringWithLength(slice, &result->object_store_name_))
1921 return false;
1922 return true;
1923 }
1924
Encode(int64_t database_id,const base::string16 & object_store_name)1925 std::string ObjectStoreNamesKey::Encode(
1926 int64_t database_id,
1927 const base::string16& object_store_name) {
1928 KeyPrefix prefix(database_id);
1929 std::string ret = prefix.Encode();
1930 ret.push_back(kObjectStoreNamesTypeByte);
1931 EncodeStringWithLength(object_store_name, &ret);
1932 return ret;
1933 }
1934
Compare(const ObjectStoreNamesKey & other)1935 int ObjectStoreNamesKey::Compare(const ObjectStoreNamesKey& other) {
1936 return object_store_name_.compare(other.object_store_name_);
1937 }
1938
DebugString() const1939 std::string ObjectStoreNamesKey::DebugString() const {
1940 std::stringstream result;
1941 result << "ObjectStoreNamesKey{object_store_name: " << object_store_name_
1942 << "}";
1943 return result.str();
1944 }
1945
IndexNamesKey()1946 IndexNamesKey::IndexNamesKey() : object_store_id_(-1) {}
1947
1948 // TODO(jsbell): We never use this to look up index ids, because a mapping
1949 // is kept at a higher level.
Decode(StringPiece * slice,IndexNamesKey * result)1950 bool IndexNamesKey::Decode(StringPiece* slice, IndexNamesKey* result) {
1951 KeyPrefix prefix;
1952 if (!KeyPrefix::Decode(slice, &prefix))
1953 return false;
1954 DCHECK(prefix.database_id_);
1955 DCHECK(!prefix.object_store_id_);
1956 DCHECK(!prefix.index_id_);
1957 unsigned char type_byte = 0;
1958 if (!DecodeByte(slice, &type_byte))
1959 return false;
1960 DCHECK_EQ(type_byte, kIndexNamesKeyTypeByte);
1961 if (!DecodeVarInt(slice, &result->object_store_id_))
1962 return false;
1963 if (!DecodeStringWithLength(slice, &result->index_name_))
1964 return false;
1965 return true;
1966 }
1967
Encode(int64_t database_id,int64_t object_store_id,const base::string16 & index_name)1968 std::string IndexNamesKey::Encode(int64_t database_id,
1969 int64_t object_store_id,
1970 const base::string16& index_name) {
1971 KeyPrefix prefix(database_id);
1972 std::string ret = prefix.Encode();
1973 ret.push_back(kIndexNamesKeyTypeByte);
1974 EncodeVarInt(object_store_id, &ret);
1975 EncodeStringWithLength(index_name, &ret);
1976 return ret;
1977 }
1978
Compare(const IndexNamesKey & other)1979 int IndexNamesKey::Compare(const IndexNamesKey& other) {
1980 DCHECK_GE(object_store_id_, 0);
1981 if (int x = CompareInts(object_store_id_, other.object_store_id_))
1982 return x;
1983 return index_name_.compare(other.index_name_);
1984 }
1985
DebugString() const1986 std::string IndexNamesKey::DebugString() const {
1987 std::stringstream result;
1988 result << "IndexNamesKey{os: " << object_store_id_
1989 << ", index_name: " << index_name_ << "}";
1990 return result.str();
1991 }
1992
ObjectStoreDataKey()1993 ObjectStoreDataKey::ObjectStoreDataKey() {}
~ObjectStoreDataKey()1994 ObjectStoreDataKey::~ObjectStoreDataKey() {}
1995
Decode(StringPiece * slice,ObjectStoreDataKey * result)1996 bool ObjectStoreDataKey::Decode(StringPiece* slice,
1997 ObjectStoreDataKey* result) {
1998 KeyPrefix prefix;
1999 if (!KeyPrefix::Decode(slice, &prefix))
2000 return false;
2001 DCHECK(prefix.database_id_);
2002 DCHECK(prefix.object_store_id_);
2003 DCHECK_EQ(prefix.index_id_, kSpecialIndexNumber);
2004 if (!ExtractEncodedIDBKey(slice, &result->encoded_user_key_))
2005 return false;
2006 return true;
2007 }
2008
Encode(int64_t database_id,int64_t object_store_id,const std::string encoded_user_key)2009 std::string ObjectStoreDataKey::Encode(int64_t database_id,
2010 int64_t object_store_id,
2011 const std::string encoded_user_key) {
2012 KeyPrefix prefix(KeyPrefix::CreateWithSpecialIndex(
2013 database_id, object_store_id, kSpecialIndexNumber));
2014 std::string ret = prefix.Encode();
2015 ret.append(encoded_user_key);
2016
2017 return ret;
2018 }
2019
Encode(int64_t database_id,int64_t object_store_id,const IndexedDBKey & user_key)2020 std::string ObjectStoreDataKey::Encode(int64_t database_id,
2021 int64_t object_store_id,
2022 const IndexedDBKey& user_key) {
2023 std::string encoded_key;
2024 EncodeIDBKey(user_key, &encoded_key);
2025 return Encode(database_id, object_store_id, encoded_key);
2026 }
2027
DebugString() const2028 std::string ObjectStoreDataKey::DebugString() const {
2029 std::unique_ptr<blink::IndexedDBKey> key = user_key();
2030 std::stringstream result;
2031 result << "ObjectStoreDataKey{user_key: "
2032 << (key ? key->DebugString() : "Invalid") << "}";
2033 return result.str();
2034 }
2035
user_key() const2036 std::unique_ptr<IndexedDBKey> ObjectStoreDataKey::user_key() const {
2037 std::unique_ptr<IndexedDBKey> key;
2038 StringPiece slice(encoded_user_key_);
2039 if (!DecodeIDBKey(&slice, &key)) {
2040 // TODO(jsbell): Return error.
2041 }
2042 return key;
2043 }
2044
2045 const int64_t ObjectStoreDataKey::kSpecialIndexNumber = kObjectStoreDataIndexId;
2046
ExistsEntryKey()2047 ExistsEntryKey::ExistsEntryKey() {}
~ExistsEntryKey()2048 ExistsEntryKey::~ExistsEntryKey() {}
2049
Decode(StringPiece * slice,ExistsEntryKey * result)2050 bool ExistsEntryKey::Decode(StringPiece* slice, ExistsEntryKey* result) {
2051 KeyPrefix prefix;
2052 if (!KeyPrefix::Decode(slice, &prefix))
2053 return false;
2054 DCHECK(prefix.database_id_);
2055 DCHECK(prefix.object_store_id_);
2056 DCHECK_EQ(prefix.index_id_, kSpecialIndexNumber);
2057 if (!ExtractEncodedIDBKey(slice, &result->encoded_user_key_))
2058 return false;
2059 return true;
2060 }
2061
Encode(int64_t database_id,int64_t object_store_id,const std::string & encoded_key)2062 std::string ExistsEntryKey::Encode(int64_t database_id,
2063 int64_t object_store_id,
2064 const std::string& encoded_key) {
2065 KeyPrefix prefix(KeyPrefix::CreateWithSpecialIndex(
2066 database_id, object_store_id, kSpecialIndexNumber));
2067 std::string ret = prefix.Encode();
2068 ret.append(encoded_key);
2069 return ret;
2070 }
2071
Encode(int64_t database_id,int64_t object_store_id,const IndexedDBKey & user_key)2072 std::string ExistsEntryKey::Encode(int64_t database_id,
2073 int64_t object_store_id,
2074 const IndexedDBKey& user_key) {
2075 std::string encoded_key;
2076 EncodeIDBKey(user_key, &encoded_key);
2077 return Encode(database_id, object_store_id, encoded_key);
2078 }
2079
DebugString() const2080 std::string ExistsEntryKey::DebugString() const {
2081 std::unique_ptr<blink::IndexedDBKey> key = user_key();
2082 std::stringstream result;
2083 result << "ExistsEntryKey{user_key: "
2084 << (key ? key->DebugString() : "Invalid") << "}";
2085 return result.str();
2086 }
2087
user_key() const2088 std::unique_ptr<IndexedDBKey> ExistsEntryKey::user_key() const {
2089 std::unique_ptr<IndexedDBKey> key;
2090 StringPiece slice(encoded_user_key_);
2091 if (!DecodeIDBKey(&slice, &key)) {
2092 // TODO(jsbell): Return error.
2093 }
2094 return key;
2095 }
2096
2097 const int64_t ExistsEntryKey::kSpecialIndexNumber = kExistsEntryIndexId;
2098
Decode(StringPiece * slice,BlobEntryKey * result)2099 bool BlobEntryKey::Decode(StringPiece* slice, BlobEntryKey* result) {
2100 KeyPrefix prefix;
2101 if (!KeyPrefix::Decode(slice, &prefix))
2102 return false;
2103 DCHECK(prefix.database_id_);
2104 DCHECK(prefix.object_store_id_);
2105 DCHECK_EQ(prefix.index_id_, kSpecialIndexNumber);
2106
2107 if (!ExtractEncodedIDBKey(slice, &result->encoded_user_key_))
2108 return false;
2109 result->database_id_ = prefix.database_id_;
2110 result->object_store_id_ = prefix.object_store_id_;
2111
2112 return true;
2113 }
2114
FromObjectStoreDataKey(StringPiece * slice,BlobEntryKey * result)2115 bool BlobEntryKey::FromObjectStoreDataKey(StringPiece* slice,
2116 BlobEntryKey* result) {
2117 KeyPrefix prefix;
2118 if (!KeyPrefix::Decode(slice, &prefix))
2119 return false;
2120 DCHECK(prefix.database_id_);
2121 DCHECK(prefix.object_store_id_);
2122 DCHECK_EQ(prefix.index_id_, ObjectStoreDataKey::kSpecialIndexNumber);
2123
2124 if (!ExtractEncodedIDBKey(slice, &result->encoded_user_key_))
2125 return false;
2126 result->database_id_ = prefix.database_id_;
2127 result->object_store_id_ = prefix.object_store_id_;
2128 return true;
2129 }
2130
ReencodeToObjectStoreDataKey(StringPiece * slice)2131 std::string BlobEntryKey::ReencodeToObjectStoreDataKey(StringPiece* slice) {
2132 // TODO(ericu): We could be more efficient here, since the suffix is the same.
2133 BlobEntryKey key;
2134 if (!Decode(slice, &key))
2135 return std::string();
2136
2137 return ObjectStoreDataKey::Encode(key.database_id_, key.object_store_id_,
2138 key.encoded_user_key_);
2139 }
2140
EncodeMinKeyForObjectStore(int64_t database_id,int64_t object_store_id)2141 std::string BlobEntryKey::EncodeMinKeyForObjectStore(int64_t database_id,
2142 int64_t object_store_id) {
2143 // Our implied encoded_user_key_ here is empty, the lowest possible key.
2144 return Encode(database_id, object_store_id, std::string());
2145 }
2146
EncodeStopKeyForObjectStore(int64_t database_id,int64_t object_store_id)2147 std::string BlobEntryKey::EncodeStopKeyForObjectStore(int64_t database_id,
2148 int64_t object_store_id) {
2149 DCHECK(KeyPrefix::ValidIds(database_id, object_store_id));
2150 KeyPrefix prefix(KeyPrefix::CreateWithSpecialIndex(
2151 database_id, object_store_id, kSpecialIndexNumber + 1));
2152 return prefix.Encode();
2153 }
2154
Encode() const2155 std::string BlobEntryKey::Encode() const {
2156 DCHECK(!encoded_user_key_.empty());
2157 return Encode(database_id_, object_store_id_, encoded_user_key_);
2158 }
2159
Encode(int64_t database_id,int64_t object_store_id,const IndexedDBKey & user_key)2160 std::string BlobEntryKey::Encode(int64_t database_id,
2161 int64_t object_store_id,
2162 const IndexedDBKey& user_key) {
2163 std::string encoded_key;
2164 EncodeIDBKey(user_key, &encoded_key);
2165 return Encode(database_id, object_store_id, encoded_key);
2166 }
2167
Encode(int64_t database_id,int64_t object_store_id,const std::string & encoded_user_key)2168 std::string BlobEntryKey::Encode(int64_t database_id,
2169 int64_t object_store_id,
2170 const std::string& encoded_user_key) {
2171 DCHECK(KeyPrefix::ValidIds(database_id, object_store_id));
2172 KeyPrefix prefix(KeyPrefix::CreateWithSpecialIndex(
2173 database_id, object_store_id, kSpecialIndexNumber));
2174 return prefix.Encode() + encoded_user_key;
2175 }
2176
DebugString() const2177 std::string BlobEntryKey::DebugString() const {
2178 std::stringstream result;
2179 result << "BlobEntryKey{db: " << database_id_ << "os: " << object_store_id_
2180 << ", user_key: ";
2181 std::unique_ptr<blink::IndexedDBKey> key;
2182 StringPiece slice(encoded_user_key_);
2183 if (!DecodeIDBKey(&slice, &key)) {
2184 result << "Invalid";
2185 } else {
2186 result << key->DebugString();
2187 }
2188 result << "}";
2189 return result.str();
2190 }
2191
2192 const int64_t BlobEntryKey::kSpecialIndexNumber = kBlobEntryIndexId;
2193
IndexDataKey()2194 IndexDataKey::IndexDataKey()
2195 : database_id_(-1),
2196 object_store_id_(-1),
2197 index_id_(-1),
2198 sequence_number_(-1) {}
2199
2200 IndexDataKey::IndexDataKey(IndexDataKey&& other) = default;
2201
~IndexDataKey()2202 IndexDataKey::~IndexDataKey() {}
2203
Decode(StringPiece * slice,IndexDataKey * result)2204 bool IndexDataKey::Decode(StringPiece* slice, IndexDataKey* result) {
2205 KeyPrefix prefix;
2206 if (!KeyPrefix::Decode(slice, &prefix))
2207 return false;
2208 if (prefix.database_id_ <= 0)
2209 return false;
2210 if (prefix.object_store_id_ <= 0)
2211 return false;
2212 if (prefix.index_id_ < kMinimumIndexId)
2213 return false;
2214 result->database_id_ = prefix.database_id_;
2215 result->object_store_id_ = prefix.object_store_id_;
2216 result->index_id_ = prefix.index_id_;
2217 result->sequence_number_ = -1;
2218 result->encoded_primary_key_ = MinIDBKey();
2219
2220 if (!ExtractEncodedIDBKey(slice, &result->encoded_user_key_))
2221 return false;
2222
2223 // [optional] sequence number
2224 if (slice->empty())
2225 return true;
2226 if (!DecodeVarInt(slice, &result->sequence_number_))
2227 return false;
2228
2229 // [optional] primary key
2230 if (slice->empty())
2231 return true;
2232 if (!ExtractEncodedIDBKey(slice, &result->encoded_primary_key_))
2233 return false;
2234 return true;
2235 }
2236
Encode(int64_t database_id,int64_t object_store_id,int64_t index_id,const std::string & encoded_user_key,const std::string & encoded_primary_key,int64_t sequence_number)2237 std::string IndexDataKey::Encode(int64_t database_id,
2238 int64_t object_store_id,
2239 int64_t index_id,
2240 const std::string& encoded_user_key,
2241 const std::string& encoded_primary_key,
2242 int64_t sequence_number) {
2243 KeyPrefix prefix(database_id, object_store_id, index_id);
2244 std::string ret = prefix.Encode();
2245 ret.append(encoded_user_key);
2246 EncodeVarInt(sequence_number, &ret);
2247 ret.append(encoded_primary_key);
2248 return ret;
2249 }
2250
Encode(int64_t database_id,int64_t object_store_id,int64_t index_id,const IndexedDBKey & user_key)2251 std::string IndexDataKey::Encode(int64_t database_id,
2252 int64_t object_store_id,
2253 int64_t index_id,
2254 const IndexedDBKey& user_key) {
2255 std::string encoded_key;
2256 EncodeIDBKey(user_key, &encoded_key);
2257 return Encode(database_id, object_store_id, index_id, encoded_key,
2258 MinIDBKey(), 0);
2259 }
2260
Encode(int64_t database_id,int64_t object_store_id,int64_t index_id,const IndexedDBKey & user_key,const IndexedDBKey & user_primary_key)2261 std::string IndexDataKey::Encode(int64_t database_id,
2262 int64_t object_store_id,
2263 int64_t index_id,
2264 const IndexedDBKey& user_key,
2265 const IndexedDBKey& user_primary_key) {
2266 std::string encoded_key;
2267 EncodeIDBKey(user_key, &encoded_key);
2268 std::string encoded_primary_key;
2269 EncodeIDBKey(user_primary_key, &encoded_primary_key);
2270 return Encode(database_id, object_store_id, index_id, encoded_key,
2271 encoded_primary_key, 0);
2272 }
2273
EncodeMinKey(int64_t database_id,int64_t object_store_id,int64_t index_id)2274 std::string IndexDataKey::EncodeMinKey(int64_t database_id,
2275 int64_t object_store_id,
2276 int64_t index_id) {
2277 return Encode(database_id, object_store_id, index_id, MinIDBKey(),
2278 MinIDBKey(), 0);
2279 }
2280
EncodeMaxKey(int64_t database_id,int64_t object_store_id,int64_t index_id)2281 std::string IndexDataKey::EncodeMaxKey(int64_t database_id,
2282 int64_t object_store_id,
2283 int64_t index_id) {
2284 return Encode(database_id, object_store_id, index_id, MaxIDBKey(),
2285 MaxIDBKey(), std::numeric_limits<int64_t>::max());
2286 }
2287
Encode() const2288 std::string IndexDataKey::Encode() const {
2289 return Encode(database_id_, object_store_id_, index_id_, encoded_user_key_,
2290 encoded_primary_key_, sequence_number_);
2291 }
2292
DebugString() const2293 std::string IndexDataKey::DebugString() const {
2294 std::unique_ptr<blink::IndexedDBKey> user = user_key();
2295 std::unique_ptr<blink::IndexedDBKey> primary = primary_key();
2296 std::stringstream result;
2297 result << "IndexDataKey{db: " << database_id_ << ", os: " << object_store_id_
2298 << ", idx: " << index_id_ << ", sequence_number: " << sequence_number_
2299 << ", user_key: " << (user ? user->DebugString() : "Invalid")
2300 << ", primary_key: " << (primary ? primary->DebugString() : "Invalid")
2301 << "}";
2302 return result.str();
2303 }
2304
DatabaseId() const2305 int64_t IndexDataKey::DatabaseId() const {
2306 DCHECK_GE(database_id_, 0);
2307 return database_id_;
2308 }
2309
ObjectStoreId() const2310 int64_t IndexDataKey::ObjectStoreId() const {
2311 DCHECK_GE(object_store_id_, 0);
2312 return object_store_id_;
2313 }
2314
IndexId() const2315 int64_t IndexDataKey::IndexId() const {
2316 DCHECK_GE(index_id_, 0);
2317 return index_id_;
2318 }
2319
user_key() const2320 std::unique_ptr<IndexedDBKey> IndexDataKey::user_key() const {
2321 std::unique_ptr<IndexedDBKey> key;
2322 StringPiece slice(encoded_user_key_);
2323 if (!DecodeIDBKey(&slice, &key)) {
2324 // TODO(jsbell): Return error.
2325 }
2326 return key;
2327 }
2328
primary_key() const2329 std::unique_ptr<IndexedDBKey> IndexDataKey::primary_key() const {
2330 std::unique_ptr<IndexedDBKey> key;
2331 StringPiece slice(encoded_primary_key_);
2332 if (!DecodeIDBKey(&slice, &key)) {
2333 // TODO(jsbell): Return error.
2334 }
2335 return key;
2336 }
2337
2338 } // namespace content
2339