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

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

Powered by Google App Engine
This is Rietveld 408576698