Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 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 "content/browser/indexed_db/indexed_db_leveldb_coding.h" | 5 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" |
| 6 | 6 |
| 7 #include <iterator> | 7 #include <iterator> |
| 8 #include <limits> | 8 #include <limits> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/strings/string16.h" | 11 #include "base/strings/string16.h" |
| 12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 13 #include "base/sys_byteorder.h" | 13 #include "base/sys_byteorder.h" |
| 14 #include "content/common/indexed_db/indexed_db_key.h" | 14 #include "content/common/indexed_db/indexed_db_key.h" |
| 15 #include "content/common/indexed_db/indexed_db_key_path.h" | 15 #include "content/common/indexed_db/indexed_db_key_path.h" |
| 16 | 16 |
| 17 // LevelDB Coding Scheme | 17 // See leveldb_coding_scheme.md for detailed documentation of the coding |
| 18 // ===================== | 18 // scheme implemented here. |
| 19 // | |
| 20 // LevelDB stores key/value pairs. Keys and values are strings of bytes, | |
| 21 // normally of type std::string. | |
| 22 // | |
| 23 // The keys in the backing store are variable-length tuples with different | |
| 24 // types of fields. Each key in the backing store starts with a ternary | |
| 25 // prefix: (database id, object store id, index id). For each, 0 is reserved | |
| 26 // for metadata. See KeyPrefix::Decode() for details of the prefix coding. | |
| 27 // | |
| 28 // The prefix makes sure that data for a specific database, object store, and | |
| 29 // index are grouped together. The locality is important for performance: | |
| 30 // common operations should only need a minimal number of seek operations. For | |
| 31 // example, all the metadata for a database is grouped together so that | |
| 32 // reading that metadata only requires one seek. | |
| 33 // | |
| 34 // Each key type has a class (in square brackets below) which knows how to | |
| 35 // encode, decode, and compare that key type. | |
| 36 // | |
| 37 // Strings (origins, names, etc) are encoded as UTF-16BE. | |
| 38 // | |
| 39 // | |
| 40 // Global metadata | |
| 41 // --------------- | |
| 42 // The prefix is <0, 0, 0>, followed by a metadata type byte: | |
| 43 // | |
| 44 // <0, 0, 0, 0> => backing store schema version [SchemaVersionKey] | |
| 45 // <0, 0, 0, 1> => maximum allocated database [MaxDatabaseIdKey] | |
| 46 // <0, 0, 0, 2> => SerializedScriptValue version [DataVersionKey] | |
| 47 // <0, 0, 0, 3> | |
| 48 // => Blob journal | |
| 49 // The format of the journal is: | |
| 50 // {database_id (var int), blobKey (var int)}*. | |
| 51 // If the blobKey is kAllBlobsKey, the whole database should be deleted. | |
| 52 // [BlobJournalKey] | |
| 53 // <0, 0, 0, 4> => Live blob journal; same format. [LiveBlobJournalKey] | |
| 54 // <0, 0, 0, 100, database id> | |
| 55 // => Existence implies the database id is in the free list | |
| 56 // [DatabaseFreeListKey] | |
| 57 // <0, 0, 0, 201, origin, database name> => Database id (int) [DatabaseNameKey] | |
| 58 // | |
| 59 // | |
| 60 // Database metadata: [DatabaseMetaDataKey] | |
| 61 // ---------------------------------------- | |
| 62 // The prefix is <database id, 0, 0> followed by a metadata type byte: | |
| 63 // | |
| 64 // <database id, 0, 0, 0> => origin name | |
| 65 // <database id, 0, 0, 1> => database name | |
| 66 // <database id, 0, 0, 2> => IDB string version data (obsolete) | |
| 67 // <database id, 0, 0, 3> => maximum allocated object store id | |
| 68 // <database id, 0, 0, 4> => IDB integer version (var int) | |
| 69 // <database id, 0, 0, 5> => blob key generator current number | |
| 70 // | |
| 71 // | |
| 72 // Object store metadata: [ObjectStoreMetaDataKey] | |
| 73 // ----------------------------------------------- | |
| 74 // The prefix is <database id, 0, 0>, followed by a type byte (50), then the | |
| 75 // object store id (var int), then a metadata type byte. | |
| 76 // | |
| 77 // <database id, 0, 0, 50, object store id, 0> => object store name | |
| 78 // <database id, 0, 0, 50, object store id, 1> => key path | |
| 79 // <database id, 0, 0, 50, object store id, 2> => auto increment flag | |
| 80 // <database id, 0, 0, 50, object store id, 3> => is evictable | |
| 81 // <database id, 0, 0, 50, object store id, 4> => last "version" number | |
| 82 // <database id, 0, 0, 50, object store id, 5> => maximum allocated index id | |
| 83 // <database id, 0, 0, 50, object store id, 6> => has key path flag (obsolete) | |
| 84 // <database id, 0, 0, 50, object store id, 7> => key generator current number | |
| 85 // | |
| 86 // The key path was originally just a string (#1) or null (identified by flag, | |
| 87 // #6). To support null, string, or array the coding is now identified by the | |
| 88 // leading bytes in #1 - see EncodeIDBKeyPath. | |
| 89 // | |
| 90 // The "version" field is used to weed out stale index data. Whenever new | |
| 91 // object store data is inserted, it gets a new "version" number, and new | |
| 92 // index data is written with this number. When the index is used for | |
| 93 // look-ups, entries are validated against the "exists" entries, and records | |
| 94 // with old "version" numbers are deleted when they are encountered in | |
| 95 // GetPrimaryKeyViaIndex, IndexCursorImpl::LoadCurrentRow and | |
| 96 // IndexKeyCursorImpl::LoadCurrentRow. | |
| 97 // | |
| 98 // | |
| 99 // Index metadata: [IndexMetaDataKey] | |
| 100 // ---------------------------------- | |
| 101 // The prefix is <database id, 0, 0>, followed by a type byte (100), then the | |
| 102 // object store id (var int), then the index id (var int), then a metadata | |
| 103 // type byte. | |
| 104 // | |
| 105 // <database id, 0, 0, 100, object store id, index id, 0> => index name | |
| 106 // <database id, 0, 0, 100, object store id, index id, 1> => unique flag | |
| 107 // <database id, 0, 0, 100, object store id, index id, 2> => key path | |
| 108 // <database id, 0, 0, 100, object store id, index id, 3> => multi-entry flag | |
| 109 // | |
| 110 // | |
| 111 // Other object store and index metadata | |
| 112 // ------------------------------------- | |
| 113 // The prefix is <database id, 0, 0> followed by a type byte. The object | |
| 114 // store and index id are variable length integers, the names are variable | |
| 115 // length strings. | |
| 116 // | |
| 117 // <database id, 0, 0, 150, object store id> | |
| 118 // => existence implies the object store id is in the free list | |
| 119 // [ObjectStoreFreeListKey] | |
| 120 // <database id, 0, 0, 151, object store id, index id> | |
| 121 // => existence implies the index id is in the free list [IndexFreeListKey] | |
| 122 // <database id, 0, 0, 200, object store name> | |
| 123 // => object store id [ObjectStoreNamesKey] | |
| 124 // <database id, 0, 0, 201, object store id, index name> | |
| 125 // => index id [IndexNamesKey] | |
| 126 // | |
| 127 // | |
| 128 // Object store data: [ObjectStoreDataKey] | |
| 129 // --------------------------------------- | |
| 130 // The prefix is followed by a type byte and the encoded IDB primary key. The | |
| 131 // data has a "version" prefix followed by the serialized script value. | |
| 132 // | |
| 133 // <database id, object store id, 1, user key> | |
| 134 // => "version", serialized script value | |
| 135 // | |
| 136 // | |
| 137 // "Exists" entry: [ExistsEntryKey] | |
| 138 // -------------------------------- | |
| 139 // The prefix is followed by a type byte and the encoded IDB primary key. | |
| 140 // | |
| 141 // <database id, object store id, 2, user key> => "version" | |
| 142 // | |
| 143 // | |
| 144 // Blob entry table: [BlobEntryKey] | |
| 145 // -------------------------------- | |
| 146 // | |
| 147 // The prefix is followed by a type byte and the encoded IDB primary key. | |
| 148 // | |
| 149 // <database id, object store id, 3, user key> => array of IndexedDBBlobInfo | |
| 150 // | |
| 151 // | |
| 152 // Index data | |
| 153 // ---------- | |
| 154 // The prefix is followed by a type byte, the encoded IDB index key, a | |
| 155 // "sequence" number (obsolete; var int), and the encoded IDB primary key. | |
| 156 // | |
| 157 // <database id, object store id, index id, index key, sequence number, | |
| 158 // primary key> => "version", primary key [IndexDataKey] | |
| 159 // | |
| 160 // The sequence number is obsolete; it was used to allow two entries with the | |
| 161 // same user (index) key in non-unique indexes prior to the inclusion of the | |
| 162 // primary key in the data. | |
| 163 // | |
| 164 // Note: In order to be compatible with LevelDB's Bloom filter each bit of the | |
|
cmumford
2016/02/11 00:48:31
This last sentence is omitted from the *.md file.
jsbell
2016/02/11 23:26:55
It was moved earlier.
| |
| 165 // encoded key needs to used and "not ignored" by the comparator. | |
| 166 | 19 |
| 167 using base::StringPiece; | 20 using base::StringPiece; |
| 168 using blink::WebIDBKeyType; | 21 using blink::WebIDBKeyType; |
| 169 using blink::WebIDBKeyTypeArray; | 22 using blink::WebIDBKeyTypeArray; |
| 170 using blink::WebIDBKeyTypeBinary; | 23 using blink::WebIDBKeyTypeBinary; |
| 171 using blink::WebIDBKeyTypeDate; | 24 using blink::WebIDBKeyTypeDate; |
| 172 using blink::WebIDBKeyTypeInvalid; | 25 using blink::WebIDBKeyTypeInvalid; |
| 173 using blink::WebIDBKeyTypeMin; | 26 using blink::WebIDBKeyTypeMin; |
| 174 using blink::WebIDBKeyTypeNull; | 27 using blink::WebIDBKeyTypeNull; |
| 175 using blink::WebIDBKeyTypeNumber; | 28 using blink::WebIDBKeyTypeNumber; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 190 static const unsigned char kIndexedDBKeyStringTypeByte = 1; | 43 static const unsigned char kIndexedDBKeyStringTypeByte = 1; |
| 191 static const unsigned char kIndexedDBKeyDateTypeByte = 2; | 44 static const unsigned char kIndexedDBKeyDateTypeByte = 2; |
| 192 static const unsigned char kIndexedDBKeyNumberTypeByte = 3; | 45 static const unsigned char kIndexedDBKeyNumberTypeByte = 3; |
| 193 static const unsigned char kIndexedDBKeyArrayTypeByte = 4; | 46 static const unsigned char kIndexedDBKeyArrayTypeByte = 4; |
| 194 static const unsigned char kIndexedDBKeyMinKeyTypeByte = 5; | 47 static const unsigned char kIndexedDBKeyMinKeyTypeByte = 5; |
| 195 static const unsigned char kIndexedDBKeyBinaryTypeByte = 6; | 48 static const unsigned char kIndexedDBKeyBinaryTypeByte = 6; |
| 196 | 49 |
| 197 static const unsigned char kIndexedDBKeyPathTypeCodedByte1 = 0; | 50 static const unsigned char kIndexedDBKeyPathTypeCodedByte1 = 0; |
| 198 static const unsigned char kIndexedDBKeyPathTypeCodedByte2 = 0; | 51 static const unsigned char kIndexedDBKeyPathTypeCodedByte2 = 0; |
| 199 | 52 |
| 53 static const unsigned char kIndexedDBKeyPathNullTypeByte = 0; | |
| 54 static const unsigned char kIndexedDBKeyPathStringTypeByte = 1; | |
| 55 static const unsigned char kIndexedDBKeyPathArrayTypeByte = 2; | |
| 56 | |
| 200 static const unsigned char kObjectStoreDataIndexId = 1; | 57 static const unsigned char kObjectStoreDataIndexId = 1; |
| 201 static const unsigned char kExistsEntryIndexId = 2; | 58 static const unsigned char kExistsEntryIndexId = 2; |
| 202 static const unsigned char kBlobEntryIndexId = 3; | 59 static const unsigned char kBlobEntryIndexId = 3; |
| 203 | 60 |
| 204 static const unsigned char kSchemaVersionTypeByte = 0; | 61 static const unsigned char kSchemaVersionTypeByte = 0; |
| 205 static const unsigned char kMaxDatabaseIdTypeByte = 1; | 62 static const unsigned char kMaxDatabaseIdTypeByte = 1; |
| 206 static const unsigned char kDataVersionTypeByte = 2; | 63 static const unsigned char kDataVersionTypeByte = 2; |
| 207 static const unsigned char kBlobJournalTypeByte = 3; | 64 static const unsigned char kBlobJournalTypeByte = 3; |
| 208 static const unsigned char kLiveBlobJournalTypeByte = 4; | 65 static const unsigned char kLiveBlobJournalTypeByte = 4; |
| 209 static const unsigned char kMaxSimpleGlobalMetaDataTypeByte = | 66 static const unsigned char kMaxSimpleGlobalMetaDataTypeByte = |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 346 case WebIDBKeyTypeNull: | 203 case WebIDBKeyTypeNull: |
| 347 case WebIDBKeyTypeInvalid: | 204 case WebIDBKeyTypeInvalid: |
| 348 case WebIDBKeyTypeMin: | 205 case WebIDBKeyTypeMin: |
| 349 default: | 206 default: |
| 350 NOTREACHED(); | 207 NOTREACHED(); |
| 351 EncodeByte(kIndexedDBKeyNullTypeByte, into); | 208 EncodeByte(kIndexedDBKeyNullTypeByte, into); |
| 352 return; | 209 return; |
| 353 } | 210 } |
| 354 } | 211 } |
| 355 | 212 |
| 213 #define COMPILE_ASSERT_MATCHING_VALUES(a, b) \ | |
| 214 static_assert( \ | |
| 215 static_cast<unsigned char>(a) == static_cast<unsigned char>(b), \ | |
| 216 "Blink enum and coding byte must match.") | |
| 217 | |
| 218 COMPILE_ASSERT_MATCHING_VALUES(WebIDBKeyPathTypeNull, | |
| 219 kIndexedDBKeyPathNullTypeByte); | |
| 220 COMPILE_ASSERT_MATCHING_VALUES(WebIDBKeyPathTypeString, | |
| 221 kIndexedDBKeyPathStringTypeByte); | |
| 222 COMPILE_ASSERT_MATCHING_VALUES(WebIDBKeyPathTypeArray, | |
| 223 kIndexedDBKeyPathArrayTypeByte); | |
| 224 | |
| 356 void EncodeIDBKeyPath(const IndexedDBKeyPath& value, std::string* into) { | 225 void EncodeIDBKeyPath(const IndexedDBKeyPath& value, std::string* into) { |
| 357 // May be typed, or may be a raw string. An invalid leading | 226 // May be typed, or may be a raw string. An invalid leading |
| 358 // byte is used to identify typed coding. New records are | 227 // byte is used to identify typed coding. New records are |
| 359 // always written as typed. | 228 // always written as typed. |
| 360 EncodeByte(kIndexedDBKeyPathTypeCodedByte1, into); | 229 EncodeByte(kIndexedDBKeyPathTypeCodedByte1, into); |
| 361 EncodeByte(kIndexedDBKeyPathTypeCodedByte2, into); | 230 EncodeByte(kIndexedDBKeyPathTypeCodedByte2, into); |
| 362 EncodeByte(static_cast<char>(value.type()), into); | 231 EncodeByte(static_cast<char>(value.type()), into); |
| 363 switch (value.type()) { | 232 switch (value.type()) { |
| 364 case WebIDBKeyPathTypeNull: | 233 case WebIDBKeyPathTypeNull: |
| 365 break; | 234 break; |
| (...skipping 1661 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2027 scoped_ptr<IndexedDBKey> IndexDataKey::primary_key() const { | 1896 scoped_ptr<IndexedDBKey> IndexDataKey::primary_key() const { |
| 2028 scoped_ptr<IndexedDBKey> key; | 1897 scoped_ptr<IndexedDBKey> key; |
| 2029 StringPiece slice(encoded_primary_key_); | 1898 StringPiece slice(encoded_primary_key_); |
| 2030 if (!DecodeIDBKey(&slice, &key)) { | 1899 if (!DecodeIDBKey(&slice, &key)) { |
| 2031 // TODO(jsbell): Return error. | 1900 // TODO(jsbell): Return error. |
| 2032 } | 1901 } |
| 2033 return key; | 1902 return key; |
| 2034 } | 1903 } |
| 2035 | 1904 |
| 2036 } // namespace content | 1905 } // namespace content |
| OLD | NEW |