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

Side by Side Diff: content/browser/indexed_db/indexed_db_backing_store.cc

Issue 15564008: Migrate the IndexedDB backend from Blink to Chromium (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update to ToT again Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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_backing_store.h"
6
7 #include <string>
8
9 #include "base/file_util.h"
10 #include "base/logging.h"
11 #include "base/metrics/histogram.h"
12 #include "base/utf_string_conversions.h"
13 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
14 #include "content/browser/indexed_db/indexed_db_metadata.h"
15 #include "content/browser/indexed_db/indexed_db_tracing.h"
16 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h"
17 #include "content/browser/indexed_db/leveldb/leveldb_database.h"
18 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
19 #include "content/browser/indexed_db/leveldb/leveldb_slice.h"
20 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
21 #include "content/common/indexed_db/indexed_db_key.h"
22 #include "content/common/indexed_db/indexed_db_key_path.h"
23 #include "content/common/indexed_db/indexed_db_key_range.h"
24 #include "third_party/WebKit/public/platform/WebIDBKey.h"
25 #include "third_party/WebKit/public/platform/WebIDBKeyPath.h"
26
27 // TODO(jsbell): Make blink push the version during the open() call.
28 static const uint32 kWireVersion = 2;
29
30 namespace content {
31
32 static const int64 kKeyGeneratorInitialNumber =
33 1; // From the IndexedDB specification.
34
35 enum IndexedDBBackingStoreErrorSource {
36 // 0 - 2 are no longer used.
37 FIND_KEY_IN_INDEX = 3,
38 GET_IDBDATABASE_METADATA,
39 GET_INDEXES,
40 GET_KEY_GENERATOR_CURRENT_NUMBER,
41 GET_OBJECT_STORES,
42 GET_RECORD,
43 KEY_EXISTS_IN_OBJECT_STORE,
44 LOAD_CURRENT_ROW,
45 SET_UP_METADATA,
46 GET_PRIMARY_KEY_VIA_INDEX,
47 KEY_EXISTS_IN_INDEX,
48 VERSION_EXISTS,
49 DELETE_OBJECT_STORE,
50 SET_MAX_OBJECT_STORE_ID,
51 SET_MAX_INDEX_ID,
52 GET_NEW_DATABASE_ID,
53 GET_NEW_VERSION_NUMBER,
54 CREATE_IDBDATABASE_METADATA,
55 DELETE_DATABASE,
56 TRANSACTION_COMMIT_METHOD, // TRANSACTION_COMMIT is a WinNT.h macro
57 INTERNAL_ERROR_MAX,
58 };
59
60 static void RecordInternalError(const char* type,
61 IndexedDBBackingStoreErrorSource location) {
62 string16 name = ASCIIToUTF16("WebCore.IndexedDB.BackingStore.") +
63 UTF8ToUTF16(type) + ASCIIToUTF16("Error");
64 base::Histogram::FactoryGet(UTF16ToUTF8(name),
65 1,
66 INTERNAL_ERROR_MAX,
67 INTERNAL_ERROR_MAX + 1,
68 base::HistogramBase::kUmaTargetedHistogramFlag)
69 ->Add(location);
70 }
71
72 // Use to signal conditions that usually indicate developer error, but
73 // could be caused by data corruption. A macro is used instead of an
74 // inline function so that the assert and log report the line number.
75 #define REPORT_ERROR(type, location) \
76 do { \
77 LOG(ERROR) << "IndexedDB " type " Error: " #location; \
78 NOTREACHED(); \
79 RecordInternalError(type, location); \
80 } while (0)
81
82 #define INTERNAL_READ_ERROR(location) REPORT_ERROR("Read", location)
83 #define INTERNAL_CONSISTENCY_ERROR(location) \
84 REPORT_ERROR("Consistency", location)
85 #define INTERNAL_WRITE_ERROR(location) REPORT_ERROR("Write", location)
86
87 static void PutBool(LevelDBTransaction* transaction,
88 const LevelDBSlice& key,
89 bool value) {
90 transaction->Put(key, EncodeBool(value));
91 }
92
93 template <typename DBOrTransaction>
94 static bool GetInt(DBOrTransaction* db,
95 const LevelDBSlice& key,
96 int64& found_int,
97 bool& found) {
98 std::vector<char> result;
99 bool ok = db->Get(key, result, found);
100 if (!ok)
101 return false;
102 if (!found)
103 return true;
104
105 found_int = DecodeInt(result.begin(), result.end());
106 return true;
107 }
108
109 static void PutInt(LevelDBTransaction* transaction,
110 const LevelDBSlice& key,
111 int64 value) {
112 DCHECK_GE(value, 0);
113 transaction->Put(key, EncodeInt(value));
114 }
115
116 template <typename DBOrTransaction>
117 WARN_UNUSED_RESULT static bool GetVarInt(DBOrTransaction* db,
118 const LevelDBSlice& key,
119 int64& found_int,
120 bool& found) {
121 std::vector<char> result;
122 bool ok = db->Get(key, result, found);
123 if (!ok)
124 return false;
125 if (!found)
126 return true;
127 if (!result.size())
128 return false;
129
130 found = DecodeVarInt(&*result.begin(), &*result.rbegin() + 1, found_int) ==
131 &*result.rbegin() + 1;
132 return true;
133 }
134
135 static void PutVarInt(LevelDBTransaction* transaction,
136 const LevelDBSlice& key,
137 int64 value) {
138 transaction->Put(key, EncodeVarInt(value));
139 }
140
141 template <typename DBOrTransaction>
142 WARN_UNUSED_RESULT static bool GetString(DBOrTransaction* db,
143 const LevelDBSlice& key,
144 string16& found_string,
145 bool& found) {
146 std::vector<char> result;
147 found = false;
148 bool ok = db->Get(key, result, found);
149 if (!ok)
150 return false;
151 if (!found)
152 return true;
153 if (!result.size()) {
154 found_string.clear();
155 return true;
156 }
157
158 found_string = DecodeString(&*result.begin(), &*result.rbegin() + 1);
159 return true;
160 }
161
162 static void PutString(LevelDBTransaction* transaction,
163 const LevelDBSlice& key,
164 const string16& value) {
165 transaction->Put(key, EncodeString(value));
166 }
167
168 static void PutIDBKeyPath(LevelDBTransaction* transaction,
169 const LevelDBSlice& key,
170 const IndexedDBKeyPath& value) {
171 transaction->Put(key, EncodeIDBKeyPath(value));
172 }
173
174 static int CompareKeys(const LevelDBSlice& a, const LevelDBSlice& b) {
175 return Compare(a, b);
176 }
177
178 static int CompareIndexKeys(const LevelDBSlice& a, const LevelDBSlice& b) {
179 return Compare(a, b, true);
180 }
181
182 class Comparator : public LevelDBComparator {
183 public:
184 virtual int Compare(const LevelDBSlice& a, const LevelDBSlice& b) const
185 OVERRIDE {
186 return content::Compare(a, b);
187 }
188 virtual const char* Name() const OVERRIDE { return "idb_cmp1"; }
189 };
190
191 // 0 - Initial version.
192 // 1 - Adds UserIntVersion to DatabaseMetaData.
193 // 2 - Adds DataVersion to to global metadata.
194 static const int64 kLatestKnownSchemaVersion = 2;
195 WARN_UNUSED_RESULT static bool IsSchemaKnown(LevelDBDatabase* db, bool* known) {
196 int64 db_schema_version = 0;
197 bool found = false;
198 bool ok = GetInt(
199 db, LevelDBSlice(SchemaVersionKey::Encode()), db_schema_version, found);
200 if (!ok)
201 return false;
202 if (!found) {
203 *known = true;
204 return true;
205 }
206 if (db_schema_version > kLatestKnownSchemaVersion) {
207 *known = false;
208 return true;
209 }
210
211 const uint32 latest_known_data_version = kWireVersion;
212 int64 db_data_version = 0;
213 ok = GetInt(
214 db, LevelDBSlice(DataVersionKey::Encode()), db_data_version, found);
215 if (!ok)
216 return false;
217 if (!found) {
218 *known = true;
219 return true;
220 }
221
222 if (db_data_version > latest_known_data_version) {
223 *known = false;
224 return true;
225 }
226
227 *known = true;
228 return true;
229 }
230
231 WARN_UNUSED_RESULT static bool SetUpMetadata(LevelDBDatabase* db,
232 const string16& origin) {
233 const uint32 latest_known_data_version = kWireVersion;
234 const std::vector<char> schema_version_key = SchemaVersionKey::Encode();
235 const std::vector<char> data_version_key = DataVersionKey::Encode();
236
237 scoped_refptr<LevelDBTransaction> transaction =
238 LevelDBTransaction::Create(db);
239
240 int64 db_schema_version = 0;
241 int64 db_data_version = 0;
242 bool found = false;
243 bool ok = GetInt(transaction.get(),
244 LevelDBSlice(schema_version_key),
245 db_schema_version,
246 found);
247 if (!ok) {
248 INTERNAL_READ_ERROR(SET_UP_METADATA);
249 return false;
250 }
251 if (!found) {
252 // Initialize new backing store.
253 db_schema_version = kLatestKnownSchemaVersion;
254 PutInt(
255 transaction.get(), LevelDBSlice(schema_version_key), db_schema_version);
256 db_data_version = latest_known_data_version;
257 PutInt(transaction.get(), LevelDBSlice(data_version_key), db_data_version);
258 } else {
259 // Upgrade old backing store.
260 DCHECK_LE(db_schema_version, kLatestKnownSchemaVersion);
261 if (db_schema_version < 1) {
262 db_schema_version = 1;
263 PutInt(transaction.get(),
264 LevelDBSlice(schema_version_key),
265 db_schema_version);
266 const std::vector<char> start_key =
267 DatabaseNameKey::EncodeMinKeyForOrigin(origin);
268 const std::vector<char> stop_key =
269 DatabaseNameKey::EncodeStopKeyForOrigin(origin);
270 scoped_ptr<LevelDBIterator> it = db->CreateIterator();
271 for (it->Seek(LevelDBSlice(start_key));
272 it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0;
273 it->Next()) {
274 int64 database_id = 0;
275 found = false;
276 bool ok = GetInt(transaction.get(), it->Key(), database_id, found);
277 if (!ok) {
278 INTERNAL_READ_ERROR(SET_UP_METADATA);
279 return false;
280 }
281 if (!found) {
282 INTERNAL_CONSISTENCY_ERROR(SET_UP_METADATA);
283 return false;
284 }
285 std::vector<char> int_version_key = DatabaseMetaDataKey::Encode(
286 database_id, DatabaseMetaDataKey::USER_INT_VERSION);
287 PutVarInt(transaction.get(),
288 LevelDBSlice(int_version_key),
289 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
290 }
291 }
292 if (db_schema_version < 2) {
293 db_schema_version = 2;
294 PutInt(transaction.get(),
295 LevelDBSlice(schema_version_key),
296 db_schema_version);
297 db_data_version = kWireVersion;
298 PutInt(
299 transaction.get(), LevelDBSlice(data_version_key), db_data_version);
300 }
301 }
302
303 // All new values will be written using this serialization version.
304 found = false;
305 ok = GetInt(transaction.get(),
306 LevelDBSlice(data_version_key),
307 db_data_version,
308 found);
309 if (!ok) {
310 INTERNAL_READ_ERROR(SET_UP_METADATA);
311 return false;
312 }
313 if (!found) {
314 INTERNAL_CONSISTENCY_ERROR(SET_UP_METADATA);
315 return false;
316 }
317 if (db_data_version < latest_known_data_version) {
318 db_data_version = latest_known_data_version;
319 PutInt(transaction.get(), LevelDBSlice(data_version_key), db_data_version);
320 }
321
322 DCHECK_EQ(db_schema_version, kLatestKnownSchemaVersion);
323 DCHECK_EQ(db_data_version, latest_known_data_version);
324
325 if (!transaction->Commit()) {
326 INTERNAL_WRITE_ERROR(SET_UP_METADATA);
327 return false;
328 }
329 return true;
330 }
331
332 template <typename DBOrTransaction>
333 WARN_UNUSED_RESULT static bool GetMaxObjectStoreId(DBOrTransaction* db,
334 int64 database_id,
335 int64& max_object_store_id) {
336 const std::vector<char> max_object_store_id_key = DatabaseMetaDataKey::Encode(
337 database_id, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID);
338 bool ok =
339 GetMaxObjectStoreId(db, max_object_store_id_key, max_object_store_id);
340 return ok;
341 }
342
343 template <typename DBOrTransaction>
344 WARN_UNUSED_RESULT static bool GetMaxObjectStoreId(
345 DBOrTransaction* db,
346 const std::vector<char>& max_object_store_id_key,
347 int64& max_object_store_id) {
348 max_object_store_id = -1;
349 bool found = false;
350 bool ok = GetInt(
351 db, LevelDBSlice(max_object_store_id_key), max_object_store_id, found);
352 if (!ok)
353 return false;
354 if (!found)
355 max_object_store_id = 0;
356
357 DCHECK_GE(max_object_store_id, 0);
358 return true;
359 }
360
361 class DefaultLevelDBFactory : public LevelDBFactory {
362 public:
363 virtual scoped_ptr<LevelDBDatabase> OpenLevelDB(
364 const base::FilePath& file_name,
365 const LevelDBComparator* comparator) OVERRIDE {
366 return LevelDBDatabase::Open(file_name, comparator);
367 }
368 virtual bool DestroyLevelDB(const base::FilePath& file_name) OVERRIDE {
369 return LevelDBDatabase::Destroy(file_name);
370 }
371 };
372
373 IndexedDBBackingStore::IndexedDBBackingStore(
374 const string16& identifier,
375 scoped_ptr<LevelDBDatabase> db,
376 scoped_ptr<LevelDBComparator> comparator)
377 : identifier_(identifier),
378 db_(db.Pass()),
379 comparator_(comparator.Pass()),
380 weak_factory_(this) {}
381
382 IndexedDBBackingStore::~IndexedDBBackingStore() {
383 // db_'s destructor uses comparator_. The order of destruction is important.
384 db_.reset();
385 comparator_.reset();
386 }
387
388 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier(
389 const std::vector<char>& primary_key,
390 int64 version)
391 : primary_key_(primary_key), version_(version) {
392 DCHECK(!primary_key.empty());
393 }
394 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier()
395 : primary_key_(), version_(-1) {}
396 IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() {}
397
398 IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() {}
399 IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() {}
400
401 enum IndexedDBLevelDBBackingStoreOpenResult {
402 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS,
403 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_SUCCESS,
404 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY,
405 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA,
406 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED,
407 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED,
408 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS,
409 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA,
410 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR,
411 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MEMORY_FAILED,
412 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII,
413 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX,
414 };
415
416 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
417 const string16& database_identifier,
418 const string16& path_base_arg,
419 const string16& file_identifier) {
420 DefaultLevelDBFactory leveldb_factory;
421 return IndexedDBBackingStore::Open(
422 database_identifier, path_base_arg, file_identifier, &leveldb_factory);
423 }
424
425 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
426 const string16& database_identifier,
427 const string16& path_base_arg,
428 const string16& file_identifier,
429 LevelDBFactory* leveldb_factory) {
430 IDB_TRACE("IndexedDBBackingStore::open");
431 DCHECK(!path_base_arg.empty());
432 string16 path_base = path_base_arg;
433
434 scoped_ptr<LevelDBComparator> comparator(new Comparator());
435 scoped_ptr<LevelDBDatabase> db;
436
437 if (!IsStringASCII(path_base)) {
438 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus",
439 1,
440 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX,
441 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1,
442 base::HistogramBase::kUmaTargetedHistogramFlag)
443 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII);
444 }
445 base::FilePath file_path_base =
446 base::FilePath::FromUTF8Unsafe(UTF16ToUTF8(path_base));
447 if (!file_util::CreateDirectory(file_path_base)) {
448 LOG(ERROR) << "Unable to create IndexedDB database path " << path_base;
449 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus",
450 1,
451 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX,
452 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1,
453 base::HistogramBase::kUmaTargetedHistogramFlag)
454 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY);
455 return scoped_refptr<IndexedDBBackingStore>();
456 }
457
458 // TODO(jsbell): Rework to use FilePath throughout.
459 base::FilePath identifier_path =
460 base::FilePath::FromUTF8Unsafe(UTF16ToUTF8(database_identifier));
461 base::FilePath file_path =
462 file_path_base.Append(identifier_path).AppendASCII(".indexeddb.leveldb");
463
464 db = leveldb_factory->OpenLevelDB(file_path, comparator.get());
465
466 if (db) {
467 bool known = false;
468 bool ok = IsSchemaKnown(db.get(), &known);
469 if (!ok) {
470 LOG(ERROR) << "IndexedDB had IO error checking schema, treating it as "
471 "failure to open";
472 base::Histogram::FactoryGet(
473 "WebCore.IndexedDB.BackingStore.OpenStatus",
474 1,
475 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX,
476 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1,
477 base::HistogramBase::kUmaTargetedHistogramFlag)
478 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_ SCHEMA);
479 db.reset();
480 } else if (!known) {
481 LOG(ERROR) << "IndexedDB backing store had unknown schema, treating it "
482 "as failure to open";
483 base::Histogram::FactoryGet(
484 "WebCore.IndexedDB.BackingStore.OpenStatus",
485 1,
486 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX,
487 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1,
488 base::HistogramBase::kUmaTargetedHistogramFlag)
489 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA);
490 db.reset();
491 }
492 }
493
494 if (db) {
495 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus",
496 1,
497 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX,
498 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1,
499 base::HistogramBase::kUmaTargetedHistogramFlag)
500 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_SUCCESS);
501 } else {
502 LOG(ERROR) << "IndexedDB backing store open failed, attempting cleanup";
503 bool success = leveldb_factory->DestroyLevelDB(file_path);
504 if (!success) {
505 LOG(ERROR) << "IndexedDB backing store cleanup failed";
506 base::Histogram::FactoryGet(
507 "WebCore.IndexedDB.BackingStore.OpenStatus",
508 1,
509 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX,
510 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1,
511 base::HistogramBase::kUmaTargetedHistogramFlag)
512 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED);
513 return scoped_refptr<IndexedDBBackingStore>();
514 }
515
516 LOG(ERROR) << "IndexedDB backing store cleanup succeeded, reopening";
517 db = leveldb_factory->OpenLevelDB(file_path, comparator.get());
518 if (!db) {
519 LOG(ERROR) << "IndexedDB backing store reopen after recovery failed";
520 base::Histogram::FactoryGet(
521 "WebCore.IndexedDB.BackingStore.OpenStatus",
522 1,
523 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX,
524 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1,
525 base::HistogramBase::kUmaTargetedHistogramFlag)
526 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED);
527 return scoped_refptr<IndexedDBBackingStore>();
528 }
529 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus",
530 1,
531 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX,
532 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1,
533 base::HistogramBase::kUmaTargetedHistogramFlag)
534 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS);
535 }
536
537 if (!db) {
538 NOTREACHED();
539 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus",
540 1,
541 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX,
542 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1,
543 base::HistogramBase::kUmaTargetedHistogramFlag)
544 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR);
545 return scoped_refptr<IndexedDBBackingStore>();
546 }
547
548 return Create(file_identifier, db.Pass(), comparator.Pass());
549 }
550
551 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
552 const string16& identifier) {
553 DefaultLevelDBFactory leveldb_factory;
554 return IndexedDBBackingStore::OpenInMemory(identifier, &leveldb_factory);
555 }
556
557 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
558 const string16& identifier,
559 LevelDBFactory* leveldb_factory) {
560 IDB_TRACE("IndexedDBBackingStore::open_in_memory");
561
562 scoped_ptr<LevelDBComparator> comparator(new Comparator());
563 scoped_ptr<LevelDBDatabase> db =
564 LevelDBDatabase::OpenInMemory(comparator.get());
565 if (!db) {
566 LOG(ERROR) << "LevelDBDatabase::open_in_memory failed.";
567 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus",
568 1,
569 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX,
570 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1,
571 base::HistogramBase::kUmaTargetedHistogramFlag)
572 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MEMORY_FAILED);
573 return scoped_refptr<IndexedDBBackingStore>();
574 }
575 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus",
576 1,
577 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX,
578 INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MAX + 1,
579 base::HistogramBase::kUmaTargetedHistogramFlag)
580 ->Add(INDEXED_DB_LEVEL_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS);
581
582 return Create(identifier, db.Pass(), comparator.Pass());
583 }
584
585 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create(
586 const string16& identifier,
587 scoped_ptr<LevelDBDatabase> db,
588 scoped_ptr<LevelDBComparator> comparator) {
589 // TODO(jsbell): Handle comparator name changes.
590 scoped_refptr<IndexedDBBackingStore> backing_store(
591 new IndexedDBBackingStore(identifier, db.Pass(), comparator.Pass()));
592
593 if (!SetUpMetadata(backing_store->db_.get(), identifier))
594 return scoped_refptr<IndexedDBBackingStore>();
595
596 return backing_store;
597 }
598
599 std::vector<string16> IndexedDBBackingStore::GetDatabaseNames() {
600 std::vector<string16> found_names;
601 const std::vector<char> start_key =
602 DatabaseNameKey::EncodeMinKeyForOrigin(identifier_);
603 const std::vector<char> stop_key =
604 DatabaseNameKey::EncodeStopKeyForOrigin(identifier_);
605
606 DCHECK(found_names.empty());
607
608 scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
609 for (it->Seek(LevelDBSlice(start_key));
610 it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0;
611 it->Next()) {
612 const char* p = it->Key().begin();
613 const char* limit = it->Key().end();
614
615 DatabaseNameKey database_name_key;
616 p = DatabaseNameKey::Decode(p, limit, &database_name_key);
617 DCHECK(p);
618
619 found_names.push_back(database_name_key.database_name());
620 }
621 return found_names;
622 }
623
624 bool IndexedDBBackingStore::GetIDBDatabaseMetaData(
625 const string16& name,
626 IndexedDBDatabaseMetadata* metadata,
627 bool& found) {
628 const std::vector<char> key = DatabaseNameKey::Encode(identifier_, name);
629 found = false;
630
631 bool ok = GetInt(db_.get(), LevelDBSlice(key), metadata->id, found);
632 if (!ok) {
633 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA);
634 return false;
635 }
636 if (!found)
637 return true;
638
639 ok = GetString(db_.get(),
640 LevelDBSlice(DatabaseMetaDataKey::Encode(
641 metadata->id, DatabaseMetaDataKey::USER_VERSION)),
642 metadata->version,
643 found);
644 if (!ok) {
645 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA);
646 return false;
647 }
648 if (!found) {
649 INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA);
650 return false;
651 }
652
653 ok = GetVarInt(db_.get(),
654 LevelDBSlice(DatabaseMetaDataKey::Encode(
655 metadata->id, DatabaseMetaDataKey::USER_INT_VERSION)),
656 metadata->int_version,
657 found);
658 if (!ok) {
659 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA);
660 return false;
661 }
662 if (!found) {
663 INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA);
664 return false;
665 }
666
667 if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION)
668 metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION;
669
670 ok = GetMaxObjectStoreId(
671 db_.get(), metadata->id, metadata->max_object_store_id);
672 if (!ok) {
673 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA);
674 return false;
675 }
676
677 return true;
678 }
679
680 WARN_UNUSED_RESULT static bool GetNewDatabaseId(LevelDBDatabase* db,
681 int64& new_id) {
682 scoped_refptr<LevelDBTransaction> transaction =
683 LevelDBTransaction::Create(db);
684
685 new_id = -1;
686 int64 max_database_id = -1;
687 bool found = false;
688 bool ok = GetInt(transaction.get(),
689 LevelDBSlice(MaxDatabaseIdKey::Encode()),
690 max_database_id,
691 found);
692 if (!ok) {
693 INTERNAL_READ_ERROR(GET_NEW_DATABASE_ID);
694 return false;
695 }
696 if (!found)
697 max_database_id = 0;
698
699 DCHECK_GE(max_database_id, 0);
700
701 int64 database_id = max_database_id + 1;
702 PutInt(
703 transaction.get(), LevelDBSlice(MaxDatabaseIdKey::Encode()), database_id);
704 if (!transaction->Commit()) {
705 INTERNAL_WRITE_ERROR(GET_NEW_DATABASE_ID);
706 return false;
707 }
708 new_id = database_id;
709 return true;
710 }
711
712 bool IndexedDBBackingStore::CreateIDBDatabaseMetaData(const string16& name,
713 const string16& version,
714 int64 int_version,
715 int64& row_id) {
716 bool ok = GetNewDatabaseId(db_.get(), row_id);
717 if (!ok)
718 return false;
719 DCHECK_GE(row_id, 0);
720
721 if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION)
722 int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
723
724 scoped_refptr<LevelDBTransaction> transaction =
725 LevelDBTransaction::Create(db_.get());
726 PutInt(transaction.get(),
727 LevelDBSlice(DatabaseNameKey::Encode(identifier_, name)),
728 row_id);
729 PutString(transaction.get(),
730 LevelDBSlice(DatabaseMetaDataKey::Encode(
731 row_id, DatabaseMetaDataKey::USER_VERSION)),
732 version);
733 PutVarInt(transaction.get(),
734 LevelDBSlice(DatabaseMetaDataKey::Encode(
735 row_id, DatabaseMetaDataKey::USER_INT_VERSION)),
736 int_version);
737 if (!transaction->Commit()) {
738 INTERNAL_WRITE_ERROR(CREATE_IDBDATABASE_METADATA);
739 return false;
740 }
741 return true;
742 }
743
744 bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion(
745 IndexedDBBackingStore::Transaction* transaction,
746 int64 row_id,
747 int64 int_version) {
748 if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION)
749 int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
750 DCHECK_GE(int_version, 0) << "int_version was " << int_version;
751 PutVarInt(Transaction::LevelDBTransactionFrom(transaction),
752 LevelDBSlice(DatabaseMetaDataKey::Encode(
753 row_id, DatabaseMetaDataKey::USER_INT_VERSION)),
754 int_version);
755 return true;
756 }
757
758 bool IndexedDBBackingStore::UpdateIDBDatabaseMetaData(
759 IndexedDBBackingStore::Transaction* transaction,
760 int64 row_id,
761 const string16& version) {
762 PutString(Transaction::LevelDBTransactionFrom(transaction),
763 LevelDBSlice(DatabaseMetaDataKey::Encode(
764 row_id, DatabaseMetaDataKey::USER_VERSION)),
765 version);
766 return true;
767 }
768
769 static void DeleteRange(LevelDBTransaction* transaction,
770 const std::vector<char>& begin,
771 const std::vector<char>& end) {
772 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator();
773 for (it->Seek(LevelDBSlice(begin));
774 it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(end)) < 0;
775 it->Next())
776 transaction->Remove(it->Key());
777 }
778
779 bool IndexedDBBackingStore::DeleteDatabase(const string16& name) {
780 IDB_TRACE("IndexedDBBackingStore::delete_database");
781 scoped_ptr<LevelDBWriteOnlyTransaction> transaction =
782 LevelDBWriteOnlyTransaction::Create(db_.get());
783
784 IndexedDBDatabaseMetadata metadata;
785 bool success = false;
786 bool ok = GetIDBDatabaseMetaData(name, &metadata, success);
787 if (!ok)
788 return false;
789 if (!success)
790 return true;
791
792 const std::vector<char> start_key = DatabaseMetaDataKey::Encode(
793 metadata.id, DatabaseMetaDataKey::ORIGIN_NAME);
794 const std::vector<char> stop_key = DatabaseMetaDataKey::Encode(
795 metadata.id + 1, DatabaseMetaDataKey::ORIGIN_NAME);
796 scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
797 for (it->Seek(LevelDBSlice(start_key));
798 it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0;
799 it->Next())
800 transaction->Remove(it->Key());
801
802 const std::vector<char> key = DatabaseNameKey::Encode(identifier_, name);
803 transaction->Remove(LevelDBSlice(key));
804
805 if (!transaction->Commit()) {
806 INTERNAL_WRITE_ERROR(DELETE_DATABASE);
807 return false;
808 }
809 return true;
810 }
811
812 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it,
813 const std::vector<char>& stop_key,
814 int64 object_store_id,
815 int64 meta_data_type) {
816 if (!it->IsValid() || CompareKeys(it->Key(), LevelDBSlice(stop_key)) >= 0)
817 return false;
818
819 ObjectStoreMetaDataKey meta_data_key;
820 const char* p = ObjectStoreMetaDataKey::Decode(
821 it->Key().begin(), it->Key().end(), &meta_data_key);
822 DCHECK(p);
823 if (meta_data_key.ObjectStoreId() != object_store_id)
824 return false;
825 if (meta_data_key.MetaDataType() != meta_data_type)
826 return false;
827 return true;
828 }
829
830 // TODO(jsbell): This should do some error handling rather than
831 // plowing ahead when bad data is encountered.
832 bool IndexedDBBackingStore::GetObjectStores(
833 int64 database_id,
834 IndexedDBDatabaseMetadata::ObjectStoreMap* object_stores) {
835 IDB_TRACE("IndexedDBBackingStore::get_object_stores");
836 if (!KeyPrefix::IsValidDatabaseId(database_id))
837 return false;
838 const std::vector<char> start_key =
839 ObjectStoreMetaDataKey::Encode(database_id, 1, 0);
840 const std::vector<char> stop_key =
841 ObjectStoreMetaDataKey::EncodeMaxKey(database_id);
842
843 DCHECK(object_stores->empty());
844
845 scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
846 it->Seek(LevelDBSlice(start_key));
847 while (it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0) {
848 const char* p = it->Key().begin();
849 const char* limit = it->Key().end();
850
851 ObjectStoreMetaDataKey meta_data_key;
852 p = ObjectStoreMetaDataKey::Decode(p, limit, &meta_data_key);
853 DCHECK(p);
854 if (meta_data_key.MetaDataType() != ObjectStoreMetaDataKey::NAME) {
855 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES);
856 // Possible stale metadata, but don't fail the load.
857 it->Next();
858 continue;
859 }
860
861 int64 object_store_id = meta_data_key.ObjectStoreId();
862
863 // TODO(jsbell): Do this by direct key lookup rather than iteration, to
864 // simplify.
865 string16 object_store_name =
866 DecodeString(it->Value().begin(), it->Value().end());
867
868 it->Next();
869 if (!CheckObjectStoreAndMetaDataType(it.get(),
870 stop_key,
871 object_store_id,
872 ObjectStoreMetaDataKey::KEY_PATH)) {
873 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES);
874 break;
875 }
876 IndexedDBKeyPath key_path =
877 DecodeIDBKeyPath(it->Value().begin(), it->Value().end());
878
879 it->Next();
880 if (!CheckObjectStoreAndMetaDataType(
881 it.get(),
882 stop_key,
883 object_store_id,
884 ObjectStoreMetaDataKey::AUTO_INCREMENT)) {
885 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES);
886 break;
887 }
888 bool auto_increment = DecodeBool(it->Value().begin(), it->Value().end());
889
890 it->Next(); // Is evicatble.
891 if (!CheckObjectStoreAndMetaDataType(it.get(),
892 stop_key,
893 object_store_id,
894 ObjectStoreMetaDataKey::EVICTABLE)) {
895 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES);
896 break;
897 }
898
899 it->Next(); // Last version.
900 if (!CheckObjectStoreAndMetaDataType(
901 it.get(),
902 stop_key,
903 object_store_id,
904 ObjectStoreMetaDataKey::LAST_VERSION)) {
905 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES);
906 break;
907 }
908
909 it->Next(); // Maximum index id allocated.
910 if (!CheckObjectStoreAndMetaDataType(
911 it.get(),
912 stop_key,
913 object_store_id,
914 ObjectStoreMetaDataKey::MAX_INDEX_ID)) {
915 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES);
916 break;
917 }
918 int64 max_index_id = DecodeInt(it->Value().begin(), it->Value().end());
919
920 it->Next(); // [optional] has key path (is not null)
921 if (CheckObjectStoreAndMetaDataType(it.get(),
922 stop_key,
923 object_store_id,
924 ObjectStoreMetaDataKey::HAS_KEY_PATH)) {
925 bool has_key_path = DecodeBool(it->Value().begin(), it->Value().end());
926 // This check accounts for two layers of legacy coding:
927 // (1) Initially, has_key_path was added to distinguish null vs. string.
928 // (2) Later, null vs. string vs. array was stored in the key_path itself.
929 // So this check is only relevant for string-type key_paths.
930 if (!has_key_path &&
931 (key_path.type() == WebKit::WebIDBKeyPath::StringType &&
932 !key_path.string().empty())) {
933 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES);
934 break;
935 }
936 if (!has_key_path)
937 key_path = IndexedDBKeyPath();
938 it->Next();
939 }
940
941 int64 key_generator_current_number = -1;
942 if (CheckObjectStoreAndMetaDataType(
943 it.get(),
944 stop_key,
945 object_store_id,
946 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER)) {
947 key_generator_current_number =
948 DecodeInt(it->Value().begin(), it->Value().end());
949 // TODO(jsbell): Return key_generator_current_number, cache in
950 // object store, and write lazily to backing store. For now,
951 // just assert that if it was written it was valid.
952 DCHECK_GE(key_generator_current_number, kKeyGeneratorInitialNumber);
953 it->Next();
954 }
955
956 IndexedDBObjectStoreMetadata metadata(object_store_name,
957 object_store_id,
958 key_path,
959 auto_increment,
960 max_index_id);
961 if (!GetIndexes(database_id, object_store_id, &metadata.indexes))
962 return false;
963 (*object_stores)[object_store_id] = metadata;
964 }
965 return true;
966 }
967
968 WARN_UNUSED_RESULT static bool SetMaxObjectStoreId(
969 LevelDBTransaction* transaction,
970 int64 database_id,
971 int64 object_store_id) {
972 const std::vector<char> max_object_store_id_key = DatabaseMetaDataKey::Encode(
973 database_id, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID);
974 int64 max_object_store_id = -1;
975 bool ok = GetMaxObjectStoreId(
976 transaction, max_object_store_id_key, max_object_store_id);
977 if (!ok) {
978 INTERNAL_READ_ERROR(SET_MAX_OBJECT_STORE_ID);
979 return false;
980 }
981
982 if (object_store_id <= max_object_store_id) {
983 INTERNAL_CONSISTENCY_ERROR(SET_MAX_OBJECT_STORE_ID);
984 return false;
985 }
986 PutInt(transaction, LevelDBSlice(max_object_store_id_key), object_store_id);
987 return true;
988 }
989
990 bool IndexedDBBackingStore::CreateObjectStore(
991 IndexedDBBackingStore::Transaction* transaction,
992 int64 database_id,
993 int64 object_store_id,
994 const string16& name,
995 const IndexedDBKeyPath& key_path,
996 bool auto_increment) {
997 IDB_TRACE("IndexedDBBackingStore::create_object_store");
998 if (!KeyPrefix::ValidIds(database_id, object_store_id))
999 return false;
1000 LevelDBTransaction* leveldb_transaction =
1001 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1002 if (!SetMaxObjectStoreId(leveldb_transaction, database_id, object_store_id))
1003 return false;
1004
1005 const std::vector<char> name_key = ObjectStoreMetaDataKey::Encode(
1006 database_id, object_store_id, ObjectStoreMetaDataKey::NAME);
1007 const std::vector<char> key_path_key = ObjectStoreMetaDataKey::Encode(
1008 database_id, object_store_id, ObjectStoreMetaDataKey::KEY_PATH);
1009 const std::vector<char> auto_increment_key = ObjectStoreMetaDataKey::Encode(
1010 database_id, object_store_id, ObjectStoreMetaDataKey::AUTO_INCREMENT);
1011 const std::vector<char> evictable_key = ObjectStoreMetaDataKey::Encode(
1012 database_id, object_store_id, ObjectStoreMetaDataKey::EVICTABLE);
1013 const std::vector<char> last_version_key = ObjectStoreMetaDataKey::Encode(
1014 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION);
1015 const std::vector<char> max_index_id_key = ObjectStoreMetaDataKey::Encode(
1016 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID);
1017 const std::vector<char> has_key_path_key = ObjectStoreMetaDataKey::Encode(
1018 database_id, object_store_id, ObjectStoreMetaDataKey::HAS_KEY_PATH);
1019 const std::vector<char> key_generator_current_number_key =
1020 ObjectStoreMetaDataKey::Encode(
1021 database_id,
1022 object_store_id,
1023 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER);
1024 const std::vector<char> names_key =
1025 ObjectStoreNamesKey::Encode(database_id, name);
1026
1027 PutString(leveldb_transaction, LevelDBSlice(name_key), name);
1028 PutIDBKeyPath(leveldb_transaction, LevelDBSlice(key_path_key), key_path);
1029 PutInt(leveldb_transaction, LevelDBSlice(auto_increment_key), auto_increment);
1030 PutInt(leveldb_transaction, LevelDBSlice(evictable_key), false);
1031 PutInt(leveldb_transaction, LevelDBSlice(last_version_key), 1);
1032 PutInt(leveldb_transaction, LevelDBSlice(max_index_id_key), kMinimumIndexId);
1033 PutBool(
1034 leveldb_transaction, LevelDBSlice(has_key_path_key), !key_path.IsNull());
1035 PutInt(leveldb_transaction,
1036 LevelDBSlice(key_generator_current_number_key),
1037 kKeyGeneratorInitialNumber);
1038 PutInt(leveldb_transaction, LevelDBSlice(names_key), object_store_id);
1039 return true;
1040 }
1041
1042 bool IndexedDBBackingStore::DeleteObjectStore(
1043 IndexedDBBackingStore::Transaction* transaction,
1044 int64 database_id,
1045 int64 object_store_id) {
1046 IDB_TRACE("IndexedDBBackingStore::delete_object_store");
1047 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1048 return false;
1049 LevelDBTransaction* leveldb_transaction =
1050 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1051
1052 string16 object_store_name;
1053 bool found = false;
1054 bool ok = GetString(
1055 leveldb_transaction,
1056 LevelDBSlice(ObjectStoreMetaDataKey::Encode(
1057 database_id, object_store_id, ObjectStoreMetaDataKey::NAME)),
1058 object_store_name,
1059 found);
1060 if (!ok) {
1061 INTERNAL_READ_ERROR(DELETE_OBJECT_STORE);
1062 return false;
1063 }
1064 if (!found) {
1065 INTERNAL_CONSISTENCY_ERROR(DELETE_OBJECT_STORE);
1066 return false;
1067 }
1068
1069 DeleteRange(
1070 leveldb_transaction,
1071 ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0),
1072 ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id));
1073
1074 leveldb_transaction->Remove(LevelDBSlice(
1075 ObjectStoreNamesKey::Encode(database_id, object_store_name)));
1076
1077 DeleteRange(leveldb_transaction,
1078 IndexFreeListKey::Encode(database_id, object_store_id, 0),
1079 IndexFreeListKey::EncodeMaxKey(database_id, object_store_id));
1080 DeleteRange(leveldb_transaction,
1081 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0),
1082 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id));
1083
1084 return ClearObjectStore(transaction, database_id, object_store_id);
1085 }
1086
1087 bool IndexedDBBackingStore::GetRecord(
1088 IndexedDBBackingStore::Transaction* transaction,
1089 int64 database_id,
1090 int64 object_store_id,
1091 const IndexedDBKey& key,
1092 std::vector<char>& record) {
1093 IDB_TRACE("IndexedDBBackingStore::get_record");
1094 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1095 return false;
1096 LevelDBTransaction* leveldb_transaction =
1097 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1098
1099 const std::vector<char> leveldb_key =
1100 ObjectStoreDataKey::Encode(database_id, object_store_id, key);
1101 std::vector<char> data;
1102
1103 record.clear();
1104
1105 bool found = false;
1106 bool ok = leveldb_transaction->Get(LevelDBSlice(leveldb_key), data, found);
1107 if (!ok) {
1108 INTERNAL_READ_ERROR(GET_RECORD);
1109 return false;
1110 }
1111 if (!found)
1112 return true;
1113 if (!data.size()) {
1114 INTERNAL_READ_ERROR(GET_RECORD);
1115 return false;
1116 }
1117
1118 int64 version;
1119 const char* p = DecodeVarInt(&*data.begin(), &*data.rbegin() + 1, version);
1120 if (!p) {
1121 INTERNAL_READ_ERROR(GET_RECORD);
1122 return false;
1123 }
1124
1125 record.insert(record.end(), p, static_cast<const char*>(&*data.rbegin()) + 1);
1126 return true;
1127 }
1128
1129 WARN_UNUSED_RESULT static bool GetNewVersionNumber(
1130 LevelDBTransaction* transaction,
1131 int64 database_id,
1132 int64 object_store_id,
1133 int64& new_version_number) {
1134 const std::vector<char> last_version_key = ObjectStoreMetaDataKey::Encode(
1135 database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION);
1136
1137 new_version_number = -1;
1138 int64 last_version = -1;
1139 bool found = false;
1140 bool ok =
1141 GetInt(transaction, LevelDBSlice(last_version_key), last_version, found);
1142 if (!ok) {
1143 INTERNAL_READ_ERROR(GET_NEW_VERSION_NUMBER);
1144 return false;
1145 }
1146 if (!found)
1147 last_version = 0;
1148
1149 DCHECK_GE(last_version, 0);
1150
1151 int64 version = last_version + 1;
1152 PutInt(transaction, LevelDBSlice(last_version_key), version);
1153
1154 DCHECK(version >
1155 last_version); // TODO(jsbell): Think about how we want to handle
1156 // the overflow scenario.
1157
1158 new_version_number = version;
1159 return true;
1160 }
1161
1162 bool IndexedDBBackingStore::PutRecord(
1163 IndexedDBBackingStore::Transaction* transaction,
1164 int64 database_id,
1165 int64 object_store_id,
1166 const IndexedDBKey& key,
1167 const std::vector<char>& value,
1168 RecordIdentifier* record_identifier) {
1169 IDB_TRACE("IndexedDBBackingStore::put_record");
1170 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1171 return false;
1172 DCHECK(key.IsValid());
1173
1174 LevelDBTransaction* leveldb_transaction =
1175 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1176 int64 version = -1;
1177 bool ok = GetNewVersionNumber(
1178 leveldb_transaction, database_id, object_store_id, version);
1179 if (!ok)
1180 return false;
1181 DCHECK_GE(version, 0);
1182 const std::vector<char> object_storedata_key =
1183 ObjectStoreDataKey::Encode(database_id, object_store_id, key);
1184
1185 std::vector<char> v(EncodeVarInt(version));
1186
1187 v.insert(v.end(), value.begin(), value.end());
1188
1189 leveldb_transaction->Put(LevelDBSlice(object_storedata_key), v);
1190
1191 const std::vector<char> exists_entry_key =
1192 ExistsEntryKey::Encode(database_id, object_store_id, key);
1193 leveldb_transaction->Put(LevelDBSlice(exists_entry_key), EncodeInt(version));
1194
1195 record_identifier->Reset(EncodeIDBKey(key), version);
1196 return true;
1197 }
1198
1199 bool IndexedDBBackingStore::ClearObjectStore(
1200 IndexedDBBackingStore::Transaction* transaction,
1201 int64 database_id,
1202 int64 object_store_id) {
1203 IDB_TRACE("IndexedDBBackingStore::clear_object_store");
1204 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1205 return false;
1206 LevelDBTransaction* leveldb_transaction =
1207 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1208 const std::vector<char> start_key =
1209 KeyPrefix(database_id, object_store_id).Encode();
1210 const std::vector<char> stop_key =
1211 KeyPrefix(database_id, object_store_id + 1).Encode();
1212
1213 DeleteRange(leveldb_transaction, start_key, stop_key);
1214 return true;
1215 }
1216
1217 bool IndexedDBBackingStore::DeleteRecord(
1218 IndexedDBBackingStore::Transaction* transaction,
1219 int64 database_id,
1220 int64 object_store_id,
1221 const RecordIdentifier& record_identifier) {
1222 IDB_TRACE("IndexedDBBackingStore::delete_record");
1223 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1224 return false;
1225 LevelDBTransaction* leveldb_transaction =
1226 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1227
1228 const std::vector<char> object_store_data_key = ObjectStoreDataKey::Encode(
1229 database_id, object_store_id, record_identifier.primary_key());
1230 leveldb_transaction->Remove(LevelDBSlice(object_store_data_key));
1231
1232 const std::vector<char> exists_entry_key = ExistsEntryKey::Encode(
1233 database_id, object_store_id, record_identifier.primary_key());
1234 leveldb_transaction->Remove(LevelDBSlice(exists_entry_key));
1235 return true;
1236 }
1237
1238 bool IndexedDBBackingStore::GetKeyGeneratorCurrentNumber(
1239 IndexedDBBackingStore::Transaction* transaction,
1240 int64 database_id,
1241 int64 object_store_id,
1242 int64& key_generator_current_number) {
1243 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1244 return false;
1245 LevelDBTransaction* leveldb_transaction =
1246 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1247
1248 const std::vector<char> key_generator_current_number_key =
1249 ObjectStoreMetaDataKey::Encode(
1250 database_id,
1251 object_store_id,
1252 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER);
1253
1254 key_generator_current_number = -1;
1255 std::vector<char> data;
1256
1257 bool found = false;
1258 bool ok = leveldb_transaction->Get(
1259 LevelDBSlice(key_generator_current_number_key), data, found);
1260 if (!ok) {
1261 INTERNAL_READ_ERROR(GET_KEY_GENERATOR_CURRENT_NUMBER);
1262 return false;
1263 }
1264 if (found) {
1265 key_generator_current_number = DecodeInt(data.begin(), data.end());
1266 } else {
1267 // Previously, the key generator state was not stored explicitly
1268 // but derived from the maximum numeric key present in existing
1269 // data. This violates the spec as the data may be cleared but the
1270 // key generator state must be preserved.
1271 // TODO(jsbell): Fix this for all stores on database open?
1272 const std::vector<char> start_key =
1273 ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey());
1274 const std::vector<char> stop_key =
1275 ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey());
1276
1277 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator();
1278 int64 max_numeric_key = 0;
1279
1280 for (it->Seek(LevelDBSlice(start_key));
1281 it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0;
1282 it->Next()) {
1283 const char* p = it->Key().begin();
1284 const char* limit = it->Key().end();
1285
1286 ObjectStoreDataKey data_key;
1287 p = ObjectStoreDataKey::Decode(p, limit, &data_key);
1288 DCHECK(p);
1289
1290 scoped_ptr<IndexedDBKey> user_key = data_key.user_key();
1291 if (user_key->type() == WebKit::WebIDBKey::NumberType) {
1292 int64 n = static_cast<int64>(user_key->number());
1293 if (n > max_numeric_key)
1294 max_numeric_key = n;
1295 }
1296 }
1297
1298 key_generator_current_number = max_numeric_key + 1;
1299 }
1300
1301 return true;
1302 }
1303
1304 bool IndexedDBBackingStore::MaybeUpdateKeyGeneratorCurrentNumber(
1305 IndexedDBBackingStore::Transaction* transaction,
1306 int64 database_id,
1307 int64 object_store_id,
1308 int64 new_number,
1309 bool check_current) {
1310 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1311 return false;
1312 LevelDBTransaction* leveldb_transaction =
1313 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1314
1315 if (check_current) {
1316 int64 current_number;
1317 bool ok = GetKeyGeneratorCurrentNumber(
1318 transaction, database_id, object_store_id, current_number);
1319 if (!ok)
1320 return false;
1321 if (new_number <= current_number)
1322 return true;
1323 }
1324
1325 const std::vector<char> key_generator_current_number_key =
1326 ObjectStoreMetaDataKey::Encode(
1327 database_id,
1328 object_store_id,
1329 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER);
1330 PutInt(leveldb_transaction,
1331 LevelDBSlice(key_generator_current_number_key),
1332 new_number);
1333 return true;
1334 }
1335
1336 bool IndexedDBBackingStore::KeyExistsInObjectStore(
1337 IndexedDBBackingStore::Transaction* transaction,
1338 int64 database_id,
1339 int64 object_store_id,
1340 const IndexedDBKey& key,
1341 RecordIdentifier* found_record_identifier,
1342 bool& found) {
1343 IDB_TRACE("IndexedDBBackingStore::key_exists_in_object_store");
1344 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1345 return false;
1346 found = false;
1347 LevelDBTransaction* leveldb_transaction =
1348 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1349 const std::vector<char> leveldb_key =
1350 ObjectStoreDataKey::Encode(database_id, object_store_id, key);
1351 std::vector<char> data;
1352
1353 bool ok = leveldb_transaction->Get(LevelDBSlice(leveldb_key), data, found);
1354 if (!ok) {
1355 INTERNAL_READ_ERROR(KEY_EXISTS_IN_OBJECT_STORE);
1356 return false;
1357 }
1358 if (!found)
1359 return true;
1360 if (!data.size()) {
1361 INTERNAL_READ_ERROR(KEY_EXISTS_IN_OBJECT_STORE);
1362 return false;
1363 }
1364
1365 int64 version;
1366 if (DecodeVarInt(&*data.begin(), &*data.rbegin() + 1, version) == 0)
1367 return false;
1368
1369 found_record_identifier->Reset(EncodeIDBKey(key), version);
1370 return true;
1371 }
1372
1373 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it,
1374 const std::vector<char>& stop_key,
1375 int64 index_id,
1376 unsigned char meta_data_type) {
1377 if (!it->IsValid() || CompareKeys(it->Key(), LevelDBSlice(stop_key)) >= 0)
1378 return false;
1379
1380 IndexMetaDataKey meta_data_key;
1381 const char* p = IndexMetaDataKey::Decode(
1382 it->Key().begin(), it->Key().end(), &meta_data_key);
1383 DCHECK(p);
1384 if (meta_data_key.IndexId() != index_id)
1385 return false;
1386 if (meta_data_key.meta_data_type() != meta_data_type)
1387 return false;
1388 return true;
1389 }
1390
1391 // TODO(jsbell): This should do some error handling rather than plowing ahead
1392 // when bad
1393 // data is encountered.
1394 bool IndexedDBBackingStore::GetIndexes(
1395 int64 database_id,
1396 int64 object_store_id,
1397 IndexedDBObjectStoreMetadata::IndexMap* indexes) {
1398 IDB_TRACE("IndexedDBBackingStore::get_indexes");
1399 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1400 return false;
1401 const std::vector<char> start_key =
1402 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0);
1403 const std::vector<char> stop_key =
1404 IndexMetaDataKey::Encode(database_id, object_store_id + 1, 0, 0);
1405
1406 DCHECK(indexes->empty());
1407
1408 scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
1409 it->Seek(LevelDBSlice(start_key));
1410 while (it->IsValid() &&
1411 CompareKeys(LevelDBSlice(it->Key()), LevelDBSlice(stop_key)) < 0) {
1412 const char* p = it->Key().begin();
1413 const char* limit = it->Key().end();
1414
1415 IndexMetaDataKey meta_data_key;
1416 p = IndexMetaDataKey::Decode(p, limit, &meta_data_key);
1417 DCHECK(p);
1418 if (meta_data_key.meta_data_type() != IndexMetaDataKey::NAME) {
1419 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES);
1420 // Possible stale metadata due to http://webkit.org/b/85557 but don't fail
1421 // the load.
1422 it->Next();
1423 continue;
1424 }
1425
1426 // TODO(jsbell): Do this by direct key lookup rather than iteration, to
1427 // simplify.
1428 int64 index_id = meta_data_key.IndexId();
1429 string16 index_name = DecodeString(it->Value().begin(), it->Value().end());
1430
1431 it->Next(); // unique flag
1432 if (!CheckIndexAndMetaDataKey(
1433 it.get(), stop_key, index_id, IndexMetaDataKey::UNIQUE)) {
1434 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES);
1435 break;
1436 }
1437 bool index_unique = DecodeBool(it->Value().begin(), it->Value().end());
1438
1439 it->Next(); // key_path
1440 if (!CheckIndexAndMetaDataKey(
1441 it.get(), stop_key, index_id, IndexMetaDataKey::KEY_PATH)) {
1442 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES);
1443 break;
1444 }
1445 IndexedDBKeyPath key_path =
1446 DecodeIDBKeyPath(it->Value().begin(), it->Value().end());
1447
1448 it->Next(); // [optional] multi_entry flag
1449 bool index_multi_entry = false;
1450 if (CheckIndexAndMetaDataKey(
1451 it.get(), stop_key, index_id, IndexMetaDataKey::MULTI_ENTRY)) {
1452 index_multi_entry = DecodeBool(it->Value().begin(), it->Value().end());
1453 it->Next();
1454 }
1455
1456 (*indexes)[index_id] = IndexedDBIndexMetadata(
1457 index_name, index_id, key_path, index_unique, index_multi_entry);
1458 }
1459 return true;
1460 }
1461
1462 WARN_UNUSED_RESULT static bool SetMaxIndexId(LevelDBTransaction* transaction,
1463 int64 database_id,
1464 int64 object_store_id,
1465 int64 index_id) {
1466 int64 max_index_id = -1;
1467 const std::vector<char> max_index_id_key = ObjectStoreMetaDataKey::Encode(
1468 database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID);
1469 bool found = false;
1470 bool ok =
1471 GetInt(transaction, LevelDBSlice(max_index_id_key), max_index_id, found);
1472 if (!ok) {
1473 INTERNAL_READ_ERROR(SET_MAX_INDEX_ID);
1474 return false;
1475 }
1476 if (!found)
1477 max_index_id = kMinimumIndexId;
1478
1479 if (index_id <= max_index_id) {
1480 INTERNAL_CONSISTENCY_ERROR(SET_MAX_INDEX_ID);
1481 return false;
1482 }
1483
1484 PutInt(transaction, LevelDBSlice(max_index_id_key), index_id);
1485 return true;
1486 }
1487
1488 bool IndexedDBBackingStore::CreateIndex(
1489 IndexedDBBackingStore::Transaction* transaction,
1490 int64 database_id,
1491 int64 object_store_id,
1492 int64 index_id,
1493 const string16& name,
1494 const IndexedDBKeyPath& key_path,
1495 bool is_unique,
1496 bool is_multi_entry) {
1497 IDB_TRACE("IndexedDBBackingStore::create_index");
1498 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
1499 return false;
1500 LevelDBTransaction* leveldb_transaction =
1501 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1502 if (!SetMaxIndexId(
1503 leveldb_transaction, database_id, object_store_id, index_id))
1504 return false;
1505
1506 const std::vector<char> name_key = IndexMetaDataKey::Encode(
1507 database_id, object_store_id, index_id, IndexMetaDataKey::NAME);
1508 const std::vector<char> unique_key = IndexMetaDataKey::Encode(
1509 database_id, object_store_id, index_id, IndexMetaDataKey::UNIQUE);
1510 const std::vector<char> key_path_key = IndexMetaDataKey::Encode(
1511 database_id, object_store_id, index_id, IndexMetaDataKey::KEY_PATH);
1512 const std::vector<char> multi_entry_key = IndexMetaDataKey::Encode(
1513 database_id, object_store_id, index_id, IndexMetaDataKey::MULTI_ENTRY);
1514
1515 PutString(leveldb_transaction, LevelDBSlice(name_key), name);
1516 PutBool(leveldb_transaction, LevelDBSlice(unique_key), is_unique);
1517 PutIDBKeyPath(leveldb_transaction, LevelDBSlice(key_path_key), key_path);
1518 PutBool(leveldb_transaction, LevelDBSlice(multi_entry_key), is_multi_entry);
1519 return true;
1520 }
1521
1522 bool IndexedDBBackingStore::DeleteIndex(
1523 IndexedDBBackingStore::Transaction* transaction,
1524 int64 database_id,
1525 int64 object_store_id,
1526 int64 index_id) {
1527 IDB_TRACE("IndexedDBBackingStore::delete_index");
1528 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
1529 return false;
1530 LevelDBTransaction* leveldb_transaction =
1531 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1532
1533 const std::vector<char> index_meta_data_start =
1534 IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0);
1535 const std::vector<char> index_meta_data_end =
1536 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
1537 DeleteRange(leveldb_transaction, index_meta_data_start, index_meta_data_end);
1538
1539 const std::vector<char> index_data_start =
1540 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id);
1541 const std::vector<char> index_data_end =
1542 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
1543 DeleteRange(leveldb_transaction, index_data_start, index_data_end);
1544 return true;
1545 }
1546
1547 bool IndexedDBBackingStore::PutIndexDataForRecord(
1548 IndexedDBBackingStore::Transaction* transaction,
1549 int64 database_id,
1550 int64 object_store_id,
1551 int64 index_id,
1552 const IndexedDBKey& key,
1553 const RecordIdentifier& record_identifier) {
1554 IDB_TRACE("IndexedDBBackingStore::put_index_data_for_record");
1555 DCHECK(key.IsValid());
1556 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
1557 return false;
1558
1559 LevelDBTransaction* leveldb_transaction =
1560 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1561 const std::vector<char> index_data_key =
1562 IndexDataKey::Encode(database_id,
1563 object_store_id,
1564 index_id,
1565 EncodeIDBKey(key),
1566 record_identifier.primary_key());
1567
1568 std::vector<char> data(EncodeVarInt(record_identifier.version()));
1569 const std::vector<char>& primary_key = record_identifier.primary_key();
1570 data.insert(data.end(), primary_key.begin(), primary_key.end());
1571
1572 leveldb_transaction->Put(LevelDBSlice(index_data_key), data);
1573 return true;
1574 }
1575
1576 static bool FindGreatestKeyLessThanOrEqual(LevelDBTransaction* transaction,
1577 const std::vector<char>& target,
1578 std::vector<char>& found_key) {
1579 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator();
1580 it->Seek(LevelDBSlice(target));
1581
1582 if (!it->IsValid()) {
1583 it->SeekToLast();
1584 if (!it->IsValid())
1585 return false;
1586 }
1587
1588 while (CompareIndexKeys(LevelDBSlice(it->Key()), LevelDBSlice(target)) > 0) {
1589 it->Prev();
1590 if (!it->IsValid())
1591 return false;
1592 }
1593
1594 do {
1595 found_key.assign(it->Key().begin(), it->Key().end());
1596
1597 // There can be several index keys that compare equal. We want the last one.
1598 it->Next();
1599 } while (it->IsValid() && !CompareIndexKeys(it->Key(), LevelDBSlice(target)));
1600
1601 return true;
1602 }
1603
1604 static bool VersionExists(LevelDBTransaction* transaction,
1605 int64 database_id,
1606 int64 object_store_id,
1607 int64 version,
1608 const std::vector<char>& encoded_primary_key,
1609 bool& exists) {
1610 const std::vector<char> key =
1611 ExistsEntryKey::Encode(database_id, object_store_id, encoded_primary_key);
1612 std::vector<char> data;
1613
1614 bool ok = transaction->Get(LevelDBSlice(key), data, exists);
1615 if (!ok) {
1616 INTERNAL_READ_ERROR(VERSION_EXISTS);
1617 return false;
1618 }
1619 if (!exists)
1620 return true;
1621
1622 exists = (DecodeInt(data.begin(), data.end()) == version);
1623 return true;
1624 }
1625
1626 bool IndexedDBBackingStore::FindKeyInIndex(
1627 IndexedDBBackingStore::Transaction* transaction,
1628 int64 database_id,
1629 int64 object_store_id,
1630 int64 index_id,
1631 const IndexedDBKey& key,
1632 std::vector<char>& found_encoded_primary_key,
1633 bool& found) {
1634 IDB_TRACE("IndexedDBBackingStore::find_key_in_index");
1635 DCHECK(KeyPrefix::ValidIds(database_id, object_store_id, index_id));
1636
1637 DCHECK(found_encoded_primary_key.empty());
1638 found = false;
1639
1640 LevelDBTransaction* leveldb_transaction =
1641 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1642 const std::vector<char> leveldb_key =
1643 IndexDataKey::Encode(database_id, object_store_id, index_id, key);
1644 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator();
1645 it->Seek(LevelDBSlice(leveldb_key));
1646
1647 for (;;) {
1648 if (!it->IsValid())
1649 return true;
1650 if (CompareIndexKeys(it->Key(), LevelDBSlice(leveldb_key)) > 0)
1651 return true;
1652
1653 int64 version;
1654 const char* p =
1655 DecodeVarInt(it->Value().begin(), it->Value().end(), version);
1656 if (!p) {
1657 INTERNAL_READ_ERROR(FIND_KEY_IN_INDEX);
1658 return false;
1659 }
1660 found_encoded_primary_key.insert(
1661 found_encoded_primary_key.end(), p, it->Value().end());
1662
1663 bool exists = false;
1664 bool ok = VersionExists(leveldb_transaction,
1665 database_id,
1666 object_store_id,
1667 version,
1668 found_encoded_primary_key,
1669 exists);
1670 if (!ok)
1671 return false;
1672 if (!exists) {
1673 // Delete stale index data entry and continue.
1674 leveldb_transaction->Remove(it->Key());
1675 it->Next();
1676 continue;
1677 }
1678 found = true;
1679 return true;
1680 }
1681 }
1682
1683 bool IndexedDBBackingStore::GetPrimaryKeyViaIndex(
1684 IndexedDBBackingStore::Transaction* transaction,
1685 int64 database_id,
1686 int64 object_store_id,
1687 int64 index_id,
1688 const IndexedDBKey& key,
1689 scoped_ptr<IndexedDBKey>* primary_key) {
1690 IDB_TRACE("IndexedDBBackingStore::get_primary_key_via_index");
1691 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
1692 return false;
1693
1694 bool found = false;
1695 std::vector<char> found_encoded_primary_key;
1696 bool ok = FindKeyInIndex(transaction,
1697 database_id,
1698 object_store_id,
1699 index_id,
1700 key,
1701 found_encoded_primary_key,
1702 found);
1703 if (!ok) {
1704 INTERNAL_READ_ERROR(GET_PRIMARY_KEY_VIA_INDEX);
1705 return false;
1706 }
1707 if (!found)
1708 return true;
1709 if (!found_encoded_primary_key.size()) {
1710 INTERNAL_READ_ERROR(GET_PRIMARY_KEY_VIA_INDEX);
1711 return false;
1712 }
1713
1714 DecodeIDBKey(&*found_encoded_primary_key.begin(),
1715 &*found_encoded_primary_key.rbegin() + 1,
1716 primary_key);
1717 return true;
1718 }
1719
1720 bool IndexedDBBackingStore::KeyExistsInIndex(
1721 IndexedDBBackingStore::Transaction* transaction,
1722 int64 database_id,
1723 int64 object_store_id,
1724 int64 index_id,
1725 const IndexedDBKey& index_key,
1726 scoped_ptr<IndexedDBKey>* found_primary_key,
1727 bool& exists) {
1728 IDB_TRACE("IndexedDBBackingStore::key_exists_in_index");
1729 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
1730 return false;
1731
1732 exists = false;
1733 std::vector<char> found_encoded_primary_key;
1734 bool ok = FindKeyInIndex(transaction,
1735 database_id,
1736 object_store_id,
1737 index_id,
1738 index_key,
1739 found_encoded_primary_key,
1740 exists);
1741 if (!ok) {
1742 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX);
1743 return false;
1744 }
1745 if (!exists)
1746 return true;
1747 if (!found_encoded_primary_key.size()) {
1748 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX);
1749 return false;
1750 }
1751
1752 DecodeIDBKey(&*found_encoded_primary_key.begin(),
1753 &*found_encoded_primary_key.rbegin() + 1,
1754 found_primary_key);
1755 return true;
1756 }
1757
1758 IndexedDBBackingStore::Cursor::Cursor(
1759 const IndexedDBBackingStore::Cursor* other)
1760 : transaction_(other->transaction_),
1761 cursor_options_(other->cursor_options_),
1762 current_key_(new IndexedDBKey(*other->current_key_)) {
1763 if (other->iterator_) {
1764 iterator_ = transaction_->CreateIterator();
1765
1766 if (other->iterator_->IsValid()) {
1767 iterator_->Seek(other->iterator_->Key());
1768 DCHECK(iterator_->IsValid());
1769 }
1770 }
1771 }
1772
1773 IndexedDBBackingStore::Cursor::Cursor(LevelDBTransaction* transaction,
1774 const CursorOptions& cursor_options)
1775 : transaction_(transaction), cursor_options_(cursor_options) {}
1776 IndexedDBBackingStore::Cursor::~Cursor() {}
1777
1778 bool IndexedDBBackingStore::Cursor::FirstSeek() {
1779 iterator_ = transaction_->CreateIterator();
1780 if (cursor_options_.forward)
1781 iterator_->Seek(LevelDBSlice(cursor_options_.low_key));
1782 else
1783 iterator_->Seek(LevelDBSlice(cursor_options_.high_key));
1784
1785 return ContinueFunction(0, READY);
1786 }
1787
1788 bool IndexedDBBackingStore::Cursor::Advance(unsigned long count) {
1789 while (count--) {
1790 if (!ContinueFunction())
1791 return false;
1792 }
1793 return true;
1794 }
1795
1796 bool IndexedDBBackingStore::Cursor::ContinueFunction(const IndexedDBKey* key,
1797 IteratorState next_state) {
1798 // TODO(alecflett): avoid a copy here?
1799 IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey();
1800
1801 bool first_iteration = true;
1802
1803 // When iterating with PrevNoDuplicate, spec requires that the
1804 // value we yield for each key is the first duplicate in forwards
1805 // order.
1806 IndexedDBKey last_duplicate_key;
1807
1808 bool forward = cursor_options_.forward;
1809
1810 for (;;) {
1811 if (next_state == SEEK) {
1812 // TODO(jsbell): Optimize seeking for reverse cursors as well.
1813 if (first_iteration && key && key->IsValid() && forward) {
1814 iterator_->Seek(LevelDBSlice(EncodeKey(*key)));
1815 first_iteration = false;
1816 } else if (forward) {
1817 iterator_->Next();
1818 } else {
1819 iterator_->Prev();
1820 }
1821 } else {
1822 next_state = SEEK; // for subsequent iterations
1823 }
1824
1825 if (!iterator_->IsValid()) {
1826 if (!forward && last_duplicate_key.IsValid()) {
1827 // We need to walk forward because we hit the end of
1828 // the data.
1829 forward = true;
1830 continue;
1831 }
1832
1833 return false;
1834 }
1835
1836 if (IsPastBounds()) {
1837 if (!forward && last_duplicate_key.IsValid()) {
1838 // We need to walk forward because now we're beyond the
1839 // bounds defined by the cursor.
1840 forward = true;
1841 continue;
1842 }
1843
1844 return false;
1845 }
1846
1847 if (!HaveEnteredRange())
1848 continue;
1849
1850 // The row may not load because there's a stale entry in the
1851 // index. This is not fatal.
1852 if (!LoadCurrentRow())
1853 continue;
1854
1855 if (key && key->IsValid()) {
1856 if (forward) {
1857 if (current_key_->IsLessThan(*key))
1858 continue;
1859 } else {
1860 if (key->IsLessThan(*current_key_))
1861 continue;
1862 }
1863 }
1864
1865 if (cursor_options_.unique) {
1866 if (previous_key.IsValid() && current_key_->IsEqual(previous_key)) {
1867 // We should never be able to walk forward all the way
1868 // to the previous key.
1869 DCHECK(!last_duplicate_key.IsValid());
1870 continue;
1871 }
1872
1873 if (!forward) {
1874 if (!last_duplicate_key.IsValid()) {
1875 last_duplicate_key = *current_key_;
1876 continue;
1877 }
1878
1879 // We need to walk forward because we hit the boundary
1880 // between key ranges.
1881 if (!last_duplicate_key.IsEqual(*current_key_)) {
1882 forward = true;
1883 continue;
1884 }
1885
1886 continue;
1887 }
1888 }
1889 break;
1890 }
1891
1892 DCHECK(!last_duplicate_key.IsValid() ||
1893 (forward && last_duplicate_key.IsEqual(*current_key_)));
1894 return true;
1895 }
1896
1897 bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const {
1898 if (cursor_options_.forward) {
1899 int compare = CompareIndexKeys(iterator_->Key(),
1900 LevelDBSlice(cursor_options_.low_key));
1901 if (cursor_options_.low_open) {
1902 return compare > 0;
1903 }
1904 return compare >= 0;
1905 }
1906 int compare = CompareIndexKeys(iterator_->Key(),
1907 LevelDBSlice(cursor_options_.high_key));
1908 if (cursor_options_.high_open) {
1909 return compare < 0;
1910 }
1911 return compare <= 0;
1912 }
1913
1914 bool IndexedDBBackingStore::Cursor::IsPastBounds() const {
1915 if (cursor_options_.forward) {
1916 int compare = CompareIndexKeys(iterator_->Key(),
1917 LevelDBSlice(cursor_options_.high_key));
1918 if (cursor_options_.high_open) {
1919 return compare >= 0;
1920 }
1921 return compare > 0;
1922 }
1923 int compare =
1924 CompareIndexKeys(iterator_->Key(), LevelDBSlice(cursor_options_.low_key));
1925 if (cursor_options_.low_open) {
1926 return compare <= 0;
1927 }
1928 return compare < 0;
1929 }
1930
1931 const IndexedDBKey& IndexedDBBackingStore::Cursor::primary_key() const {
1932 return *current_key_;
1933 }
1934
1935 const IndexedDBBackingStore::RecordIdentifier&
1936 IndexedDBBackingStore::Cursor::record_identifier() const {
1937 return record_identifier_;
1938 }
1939
1940 class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor {
1941 public:
1942 ObjectStoreKeyCursorImpl(
1943 LevelDBTransaction* transaction,
1944 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
1945 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {}
1946
1947 virtual Cursor* Clone() OVERRIDE {
1948 return new ObjectStoreKeyCursorImpl(this);
1949 }
1950
1951 // IndexedDBBackingStore::Cursor
1952 virtual std::vector<char>* Value() OVERRIDE {
1953 NOTREACHED();
1954 return NULL;
1955 }
1956 virtual bool LoadCurrentRow() OVERRIDE;
1957
1958 protected:
1959 virtual std::vector<char> EncodeKey(const IndexedDBKey& key) OVERRIDE {
1960 return ObjectStoreDataKey::Encode(
1961 cursor_options_.database_id, cursor_options_.object_store_id, key);
1962 }
1963
1964 private:
1965 explicit ObjectStoreKeyCursorImpl(const ObjectStoreKeyCursorImpl* other)
1966 : IndexedDBBackingStore::Cursor(other) {}
1967 };
1968
1969 bool ObjectStoreKeyCursorImpl::LoadCurrentRow() {
1970 const char* key_position = iterator_->Key().begin();
1971 const char* key_limit = iterator_->Key().end();
1972
1973 ObjectStoreDataKey object_store_data_key;
1974 key_position = ObjectStoreDataKey::Decode(
1975 key_position, key_limit, &object_store_data_key);
1976 if (!key_position) {
1977 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
1978 return false;
1979 }
1980
1981 current_key_ = object_store_data_key.user_key();
1982
1983 int64 version;
1984 const char* value_position = DecodeVarInt(
1985 iterator_->Value().begin(), iterator_->Value().end(), version);
1986 if (!value_position) {
1987 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
1988 return false;
1989 }
1990
1991 // TODO(jsbell): This re-encodes what was just decoded; try and optimize.
1992 record_identifier_.Reset(EncodeIDBKey(*current_key_), version);
1993
1994 return true;
1995 }
1996
1997 class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor {
1998 public:
1999 ObjectStoreCursorImpl(
2000 LevelDBTransaction* transaction,
2001 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
2002 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {}
2003
2004 virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); }
2005
2006 // IndexedDBBackingStore::Cursor
2007 virtual std::vector<char>* Value() OVERRIDE { return &current_value_; }
2008 virtual bool LoadCurrentRow() OVERRIDE;
2009
2010 protected:
2011 virtual std::vector<char> EncodeKey(const IndexedDBKey& key) OVERRIDE {
2012 return ObjectStoreDataKey::Encode(
2013 cursor_options_.database_id, cursor_options_.object_store_id, key);
2014 }
2015
2016 private:
2017 explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other)
2018 : IndexedDBBackingStore::Cursor(other),
2019 current_value_(other->current_value_) {}
2020
2021 std::vector<char> current_value_;
2022 };
2023
2024 bool ObjectStoreCursorImpl::LoadCurrentRow() {
2025 const char* key_position = iterator_->Key().begin();
2026 const char* key_limit = iterator_->Key().end();
2027
2028 ObjectStoreDataKey object_store_data_key;
2029 key_position = ObjectStoreDataKey::Decode(
2030 key_position, key_limit, &object_store_data_key);
2031 if (!key_position) {
2032 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
2033 return false;
2034 }
2035
2036 current_key_ = object_store_data_key.user_key();
2037
2038 int64 version;
2039 const char* value_position = DecodeVarInt(
2040 iterator_->Value().begin(), iterator_->Value().end(), version);
2041 if (!value_position) {
2042 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
2043 return false;
2044 }
2045
2046 // TODO(jsbell): This re-encodes what was just decoded; try and optimize.
2047 record_identifier_.Reset(EncodeIDBKey(*current_key_), version);
2048
2049 std::vector<char> value;
2050 value.insert(value.end(), value_position, iterator_->Value().end());
2051 current_value_.swap(value);
2052 return true;
2053 }
2054
2055 class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor {
2056 public:
2057 IndexKeyCursorImpl(
2058 LevelDBTransaction* transaction,
2059 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
2060 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {}
2061
2062 virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); }
2063
2064 // IndexedDBBackingStore::Cursor
2065 virtual std::vector<char>* Value() OVERRIDE {
2066 NOTREACHED();
2067 return NULL;
2068 }
2069 virtual const IndexedDBKey& primary_key() const OVERRIDE {
2070 return *primary_key_;
2071 }
2072 virtual const IndexedDBBackingStore::RecordIdentifier& RecordIdentifier()
2073 const {
2074 NOTREACHED();
2075 return record_identifier_;
2076 }
2077 virtual bool LoadCurrentRow() OVERRIDE;
2078
2079 protected:
2080 virtual std::vector<char> EncodeKey(const IndexedDBKey& key) OVERRIDE {
2081 return IndexDataKey::Encode(cursor_options_.database_id,
2082 cursor_options_.object_store_id,
2083 cursor_options_.index_id,
2084 key);
2085 }
2086
2087 private:
2088 explicit IndexKeyCursorImpl(const IndexKeyCursorImpl* other)
2089 : IndexedDBBackingStore::Cursor(other),
2090 primary_key_(new IndexedDBKey(*other->primary_key_)) {}
2091
2092 scoped_ptr<IndexedDBKey> primary_key_;
2093 };
2094
2095 bool IndexKeyCursorImpl::LoadCurrentRow() {
2096 const char* key_position = iterator_->Key().begin();
2097 const char* key_limit = iterator_->Key().end();
2098
2099 IndexDataKey index_data_key;
2100 key_position = IndexDataKey::Decode(key_position, key_limit, &index_data_key);
2101
2102 current_key_ = index_data_key.user_key();
2103 DCHECK(current_key_);
2104
2105 int64 index_data_version;
2106 const char* value_position = DecodeVarInt(
2107 iterator_->Value().begin(), iterator_->Value().end(), index_data_version);
2108 if (!value_position) {
2109 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
2110 return false;
2111 }
2112
2113 value_position =
2114 DecodeIDBKey(value_position, iterator_->Value().end(), &primary_key_);
2115 if (!value_position) {
2116 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
2117 return false;
2118 }
2119
2120 std::vector<char> primary_leveldb_key =
2121 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(),
2122 index_data_key.ObjectStoreId(),
2123 *primary_key_);
2124
2125 std::vector<char> result;
2126 bool found = false;
2127 bool ok = transaction_->Get(LevelDBSlice(primary_leveldb_key), result, found);
2128 if (!ok) {
2129 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
2130 return false;
2131 }
2132 if (!found) {
2133 transaction_->Remove(iterator_->Key());
2134 return false;
2135 }
2136 if (!result.size()) {
2137 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
2138 return false;
2139 }
2140
2141 int64 object_store_data_version;
2142 const char* t = DecodeVarInt(
2143 &*result.begin(), &*result.rbegin() + 1, object_store_data_version);
2144 if (!t) {
2145 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
2146 return false;
2147 }
2148
2149 if (object_store_data_version != index_data_version) {
2150 transaction_->Remove(iterator_->Key());
2151 return false;
2152 }
2153
2154 return true;
2155 }
2156
2157 class IndexCursorImpl : public IndexedDBBackingStore::Cursor {
2158 public:
2159 IndexCursorImpl(
2160 LevelDBTransaction* transaction,
2161 const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
2162 : IndexedDBBackingStore::Cursor(transaction, cursor_options) {}
2163
2164 virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); }
2165
2166 // IndexedDBBackingStore::Cursor
2167 virtual std::vector<char>* Value() OVERRIDE { return &current_value_; }
2168 virtual const IndexedDBKey& primary_key() const OVERRIDE {
2169 return *primary_key_;
2170 }
2171 virtual const IndexedDBBackingStore::RecordIdentifier& RecordIdentifier()
2172 const {
2173 NOTREACHED();
2174 return record_identifier_;
2175 }
2176 virtual bool LoadCurrentRow() OVERRIDE;
2177
2178 protected:
2179 virtual std::vector<char> EncodeKey(const IndexedDBKey& key) OVERRIDE {
2180 return IndexDataKey::Encode(cursor_options_.database_id,
2181 cursor_options_.object_store_id,
2182 cursor_options_.index_id,
2183 key);
2184 }
2185
2186 private:
2187 explicit IndexCursorImpl(const IndexCursorImpl* other)
2188 : IndexedDBBackingStore::Cursor(other),
2189 primary_key_(new IndexedDBKey(*other->primary_key_)),
2190 current_value_(other->current_value_),
2191 primary_leveldb_key_(other->primary_leveldb_key_) {}
2192
2193 scoped_ptr<IndexedDBKey> primary_key_;
2194 std::vector<char> current_value_;
2195 std::vector<char> primary_leveldb_key_;
2196 };
2197
2198 bool IndexCursorImpl::LoadCurrentRow() {
2199 const char* key_position = iterator_->Key().begin();
2200 const char* key_limit = iterator_->Key().end();
2201
2202 IndexDataKey index_data_key;
2203 key_position = IndexDataKey::Decode(key_position, key_limit, &index_data_key);
2204
2205 current_key_ = index_data_key.user_key();
2206 DCHECK(current_key_);
2207
2208 const char* value_position = iterator_->Value().begin();
2209 const char* value_limit = iterator_->Value().end();
2210
2211 int64 index_data_version;
2212 value_position =
2213 DecodeVarInt(value_position, value_limit, index_data_version);
2214 if (!value_position) {
2215 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
2216 return false;
2217 }
2218 value_position = DecodeIDBKey(value_position, value_limit, &primary_key_);
2219 if (!value_position) {
2220 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
2221 return false;
2222 }
2223
2224 primary_leveldb_key_ =
2225 ObjectStoreDataKey::Encode(index_data_key.DatabaseId(),
2226 index_data_key.ObjectStoreId(),
2227 *primary_key_);
2228
2229 std::vector<char> result;
2230 bool found = false;
2231 bool ok =
2232 transaction_->Get(LevelDBSlice(primary_leveldb_key_), result, found);
2233 if (!ok) {
2234 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
2235 return false;
2236 }
2237 if (!found) {
2238 transaction_->Remove(iterator_->Key());
2239 return false;
2240 }
2241 if (!result.size()) {
2242 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
2243 return false;
2244 }
2245
2246 int64 object_store_data_version;
2247 value_position = DecodeVarInt(
2248 &*result.begin(), &*result.rbegin() + 1, object_store_data_version);
2249 if (!value_position) {
2250 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW);
2251 return false;
2252 }
2253
2254 if (object_store_data_version != index_data_version) {
2255 transaction_->Remove(iterator_->Key());
2256 return false;
2257 }
2258
2259 // TODO(jsbell): Make value_position an iterator.
2260 std::vector<char> value;
2261 value.insert(value.end(),
2262 value_position,
2263 static_cast<const char*>(&*result.rbegin()) + 1);
2264 current_value_.swap(value);
2265 return true;
2266 }
2267
2268 bool ObjectStoreCursorOptions(
2269 LevelDBTransaction* transaction,
2270 int64 database_id,
2271 int64 object_store_id,
2272 const IndexedDBKeyRange& range,
2273 indexed_db::CursorDirection direction,
2274 IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) {
2275 cursor_options.database_id = database_id;
2276 cursor_options.object_store_id = object_store_id;
2277
2278 bool lower_bound = range.lower().IsValid();
2279 bool upper_bound = range.upper().IsValid();
2280 cursor_options.forward = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE ||
2281 direction == indexed_db::CURSOR_NEXT);
2282 cursor_options.unique = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE ||
2283 direction == indexed_db::CURSOR_PREV_NO_DUPLICATE);
2284
2285 if (!lower_bound) {
2286 cursor_options.low_key =
2287 ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey());
2288 cursor_options.low_open = true; // Not included.
2289 } else {
2290 cursor_options.low_key =
2291 ObjectStoreDataKey::Encode(database_id, object_store_id, range.lower());
2292 cursor_options.low_open = range.lowerOpen();
2293 }
2294
2295 if (!upper_bound) {
2296 cursor_options.high_key =
2297 ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey());
2298
2299 if (cursor_options.forward) {
2300 cursor_options.high_open = true; // Not included.
2301 } else {
2302 // We need a key that exists.
2303 if (!FindGreatestKeyLessThanOrEqual(
2304 transaction, cursor_options.high_key, cursor_options.high_key))
2305 return false;
2306 cursor_options.high_open = false;
2307 }
2308 } else {
2309 cursor_options.high_key =
2310 ObjectStoreDataKey::Encode(database_id, object_store_id, range.upper());
2311 cursor_options.high_open = range.upperOpen();
2312
2313 if (!cursor_options.forward) {
2314 // For reverse cursors, we need a key that exists.
2315 std::vector<char> found_high_key;
2316 if (!FindGreatestKeyLessThanOrEqual(
2317 transaction, cursor_options.high_key, found_high_key))
2318 return false;
2319
2320 // If the target key should not be included, but we end up with a smaller
2321 // key, we should include that.
2322 if (cursor_options.high_open &&
2323 CompareIndexKeys(LevelDBSlice(found_high_key),
2324 LevelDBSlice(cursor_options.high_key)) <
2325 0)
2326 cursor_options.high_open = false;
2327
2328 cursor_options.high_key = found_high_key;
2329 }
2330 }
2331
2332 return true;
2333 }
2334
2335 bool IndexCursorOptions(
2336 LevelDBTransaction* transaction,
2337 int64 database_id,
2338 int64 object_store_id,
2339 int64 index_id,
2340 const IndexedDBKeyRange& range,
2341 indexed_db::CursorDirection direction,
2342 IndexedDBBackingStore::Cursor::CursorOptions& cursor_options) {
2343 DCHECK(transaction);
2344 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
2345 return false;
2346
2347 cursor_options.database_id = database_id;
2348 cursor_options.object_store_id = object_store_id;
2349 cursor_options.index_id = index_id;
2350
2351 bool lower_bound = range.lower().IsValid();
2352 bool upper_bound = range.upper().IsValid();
2353 cursor_options.forward = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE ||
2354 direction == indexed_db::CURSOR_NEXT);
2355 cursor_options.unique = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE ||
2356 direction == indexed_db::CURSOR_PREV_NO_DUPLICATE);
2357
2358 if (!lower_bound) {
2359 cursor_options.low_key =
2360 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id);
2361 cursor_options.low_open = false; // Included.
2362 } else {
2363 cursor_options.low_key = IndexDataKey::Encode(
2364 database_id, object_store_id, index_id, range.lower());
2365 cursor_options.low_open = range.lowerOpen();
2366 }
2367
2368 if (!upper_bound) {
2369 cursor_options.high_key =
2370 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
2371 cursor_options.high_open = false; // Included.
2372
2373 if (!cursor_options.forward) { // We need a key that exists.
2374 if (!FindGreatestKeyLessThanOrEqual(
2375 transaction, cursor_options.high_key, cursor_options.high_key))
2376 return false;
2377 cursor_options.high_open = false;
2378 }
2379 } else {
2380 cursor_options.high_key = IndexDataKey::Encode(
2381 database_id, object_store_id, index_id, range.upper());
2382 cursor_options.high_open = range.upperOpen();
2383
2384 std::vector<char> found_high_key;
2385 if (!FindGreatestKeyLessThanOrEqual(
2386 transaction,
2387 cursor_options.high_key,
2388 found_high_key)) // Seek to the *last* key in the set of non-unique
2389 // keys.
2390 return false;
2391
2392 // If the target key should not be included, but we end up with a smaller
2393 // key, we should include that.
2394 if (cursor_options.high_open &&
2395 CompareIndexKeys(LevelDBSlice(found_high_key),
2396 LevelDBSlice(cursor_options.high_key)) <
2397 0)
2398 cursor_options.high_open = false;
2399
2400 cursor_options.high_key = found_high_key;
2401 }
2402
2403 return true;
2404 }
2405
2406 scoped_ptr<IndexedDBBackingStore::Cursor>
2407 IndexedDBBackingStore::OpenObjectStoreCursor(
2408 IndexedDBBackingStore::Transaction* transaction,
2409 int64 database_id,
2410 int64 object_store_id,
2411 const IndexedDBKeyRange& range,
2412 indexed_db::CursorDirection direction) {
2413 IDB_TRACE("IndexedDBBackingStore::open_object_store_cursor");
2414 LevelDBTransaction* leveldb_transaction =
2415 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
2416 IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
2417 if (!ObjectStoreCursorOptions(leveldb_transaction,
2418 database_id,
2419 object_store_id,
2420 range,
2421 direction,
2422 cursor_options))
2423 return scoped_ptr<IndexedDBBackingStore::Cursor>();
2424 scoped_ptr<ObjectStoreCursorImpl> cursor(
2425 new ObjectStoreCursorImpl(leveldb_transaction, cursor_options));
2426 if (!cursor->FirstSeek())
2427 return scoped_ptr<IndexedDBBackingStore::Cursor>();
2428
2429 return cursor.PassAs<IndexedDBBackingStore::Cursor>();
2430 }
2431
2432 scoped_ptr<IndexedDBBackingStore::Cursor>
2433 IndexedDBBackingStore::OpenObjectStoreKeyCursor(
2434 IndexedDBBackingStore::Transaction* transaction,
2435 int64 database_id,
2436 int64 object_store_id,
2437 const IndexedDBKeyRange& range,
2438 indexed_db::CursorDirection direction) {
2439 IDB_TRACE("IndexedDBBackingStore::open_object_store_key_cursor");
2440 LevelDBTransaction* leveldb_transaction =
2441 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
2442 IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
2443 if (!ObjectStoreCursorOptions(leveldb_transaction,
2444 database_id,
2445 object_store_id,
2446 range,
2447 direction,
2448 cursor_options))
2449 return scoped_ptr<IndexedDBBackingStore::Cursor>();
2450 scoped_ptr<ObjectStoreKeyCursorImpl> cursor(
2451 new ObjectStoreKeyCursorImpl(leveldb_transaction, cursor_options));
2452 if (!cursor->FirstSeek())
2453 return scoped_ptr<IndexedDBBackingStore::Cursor>();
2454
2455 return cursor.PassAs<IndexedDBBackingStore::Cursor>();
2456 }
2457
2458 scoped_ptr<IndexedDBBackingStore::Cursor>
2459 IndexedDBBackingStore::OpenIndexKeyCursor(
2460 IndexedDBBackingStore::Transaction* transaction,
2461 int64 database_id,
2462 int64 object_store_id,
2463 int64 index_id,
2464 const IndexedDBKeyRange& range,
2465 indexed_db::CursorDirection direction) {
2466 IDB_TRACE("IndexedDBBackingStore::open_index_key_cursor");
2467 LevelDBTransaction* leveldb_transaction =
2468 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
2469 IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
2470 if (!IndexCursorOptions(leveldb_transaction,
2471 database_id,
2472 object_store_id,
2473 index_id,
2474 range,
2475 direction,
2476 cursor_options))
2477 return scoped_ptr<IndexedDBBackingStore::Cursor>();
2478 scoped_ptr<IndexKeyCursorImpl> cursor(
2479 new IndexKeyCursorImpl(leveldb_transaction, cursor_options));
2480 if (!cursor->FirstSeek())
2481 return scoped_ptr<IndexedDBBackingStore::Cursor>();
2482
2483 return cursor.PassAs<IndexedDBBackingStore::Cursor>();
2484 }
2485
2486 scoped_ptr<IndexedDBBackingStore::Cursor>
2487 IndexedDBBackingStore::OpenIndexCursor(
2488 IndexedDBBackingStore::Transaction* transaction,
2489 int64 database_id,
2490 int64 object_store_id,
2491 int64 index_id,
2492 const IndexedDBKeyRange& range,
2493 indexed_db::CursorDirection direction) {
2494 IDB_TRACE("IndexedDBBackingStore::open_index_cursor");
2495 LevelDBTransaction* leveldb_transaction =
2496 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
2497 IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
2498 if (!IndexCursorOptions(leveldb_transaction,
2499 database_id,
2500 object_store_id,
2501 index_id,
2502 range,
2503 direction,
2504 cursor_options))
2505 return scoped_ptr<IndexedDBBackingStore::Cursor>();
2506 scoped_ptr<IndexCursorImpl> cursor(
2507 new IndexCursorImpl(leveldb_transaction, cursor_options));
2508 if (!cursor->FirstSeek())
2509 return scoped_ptr<IndexedDBBackingStore::Cursor>();
2510
2511 return cursor.PassAs<IndexedDBBackingStore::Cursor>();
2512 }
2513
2514 IndexedDBBackingStore::Transaction::Transaction(
2515 IndexedDBBackingStore* backing_store)
2516 : backing_store_(backing_store) {}
2517
2518 IndexedDBBackingStore::Transaction::~Transaction() {}
2519
2520 void IndexedDBBackingStore::Transaction::begin() {
2521 IDB_TRACE("IndexedDBBackingStore::Transaction::begin");
2522 DCHECK(!transaction_);
2523 transaction_ = LevelDBTransaction::Create(backing_store_->db_.get());
2524 }
2525
2526 bool IndexedDBBackingStore::Transaction::Commit() {
2527 IDB_TRACE("IndexedDBBackingStore::Transaction::commit");
2528 DCHECK(transaction_);
2529 bool result = transaction_->Commit();
2530 transaction_ = NULL;
2531 if (!result)
2532 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD);
2533 return result;
2534 }
2535
2536 void IndexedDBBackingStore::Transaction::Rollback() {
2537 IDB_TRACE("IndexedDBBackingStore::Transaction::rollback");
2538 DCHECK(transaction_);
2539 transaction_->Rollback();
2540 transaction_ = NULL;
2541 }
2542
2543 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/indexed_db/indexed_db_backing_store.h ('k') | content/browser/indexed_db/indexed_db_backing_store_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698