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

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: Accessor naming, use LevelDBSlice ctor explicitly 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 "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/metrics/histogram.h"
13 #include "base/utf_string_conversions.h"
14 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
15 #include "content/browser/indexed_db/indexed_db_metadata.h"
16 #include "content/browser/indexed_db/indexed_db_tracing.h"
17 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h"
18 #include "content/browser/indexed_db/leveldb/leveldb_database.h"
19 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
20 #include "content/browser/indexed_db/leveldb/leveldb_slice.h"
21 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
22 #include "content/common/indexed_db/indexed_db_key.h"
23 #include "content/common/indexed_db/indexed_db_key_path.h"
24 #include "content/common/indexed_db/indexed_db_key_range.h"
25 #include "third_party/WebKit/Source/Platform/chromium/public/WebIDBKeyPath.h"
26
27 // TODO: Make blink push the version during the open() call.
28 static const uint32_t kWireVersion = 2;
29
30 namespace content {
31
32 using namespace IndexedDBLevelDBCoding;
33
34 const int64_t KeyGeneratorInitialNumber =
jamesr 2013/05/21 23:56:06 constants in chromium should be named kFooBarBaz
jsbell 2013/05/22 17:54:44 Done.
35 1; // From the IndexedDB specification.
36
37 enum IndexedDBBackingStoreErrorSource {
38 // 0 - 2 are no longer used.
39 kFindKeyInIndex = 3,
jamesr 2013/05/21 23:56:06 enum values should be SHOUTY
jsbell 2013/05/22 17:54:44 Done.
40 kGetIDBDatabaseMetaData,
41 kGetIndexes,
42 kGetKeyGeneratorCurrentNumber,
43 kGetObjectStores,
44 kGetRecord,
45 kKeyExistsInObjectStore,
46 kLoadCurrentRow,
47 kSetupMetadata,
48 kGetPrimaryKeyViaIndex,
49 kKeyExistsInIndex,
50 kVersionExists,
51 kDeleteObjectStore,
52 kSetMaxObjectStoreId,
53 kSetMaxIndexId,
54 kGetNewDatabaseId,
55 kGetNewVersionNumber,
56 kCreateIDBDatabaseMetaData,
57 kDeleteDatabase,
58 kTransactionCommit,
59 kIndexedDBLevelDBBackingStoreInternalErrorMax,
60 };
61
62 static void RecordInternalError(const char* type,
63 IndexedDBBackingStoreErrorSource location) {
64 string16 name = ASCIIToUTF16("WebCore.IndexedDB.BackingStore.") +
65 UTF8ToUTF16(type) + ASCIIToUTF16("Error");
66 base::Histogram::FactoryGet(UTF16ToUTF8(name),
67 1,
68 kIndexedDBLevelDBBackingStoreInternalErrorMax,
69 kIndexedDBLevelDBBackingStoreInternalErrorMax + 1,
70 base::HistogramBase::kUmaTargetedHistogramFlag)
71 ->Add(location);
72 }
73
74 // Use to signal conditions that usually indicate developer error, but
75 // could be caused by data corruption. A macro is used instead of an
76 // inline function so that the assert and log report the line number.
77 #define REPORT_ERROR(type, location) \
78 do { \
79 LOG(ERROR) << "IndexedDB " type " Error: " #location; \
80 NOTREACHED(); \
81 RecordInternalError(type, location); \
82 } while (0)
83
84 #define INTERNAL_READ_ERROR(location) REPORT_ERROR("Read", location)
85 #define INTERNAL_CONSISTENCY_ERROR(location) \
86 REPORT_ERROR("Consistency", location)
87 #define INTERNAL_WRITE_ERROR(location) REPORT_ERROR("Write", location)
88
89 static void PutBool(LevelDBTransaction* transaction,
90 const LevelDBSlice& key,
91 bool value) {
92 transaction->Put(key, EncodeBool(value));
93 }
94
95 template <typename DBOrTransaction>
96 static bool
97 GetInt(DBOrTransaction* db,
jamesr 2013/05/21 23:56:06 seems overwrapped. did clang-format put this on a
jsbell 2013/05/22 17:54:44 Yeah, we're just letting clang-format do it's thin
jsbell 2013/05/23 21:10:49 A clang-format update appears to have addressed th
98 const LevelDBSlice& key,
99 int64_t& found_int,
100 bool& found) {
101 std::vector<char> result;
102 bool ok = db->Get(key, result, found);
103 if (!ok)
104 return false;
105 if (!found)
106 return true;
107
108 found_int = DecodeInt(result.begin(), result.end());
109 return true;
110 }
111
112 static void PutInt(LevelDBTransaction* transaction,
113 const LevelDBSlice& key,
114 int64_t value) {
115 DCHECK(value >= 0);
116 transaction->Put(key, EncodeInt(value));
117 }
118
119 template <typename DBOrTransaction>
120 WARN_UNUSED_RESULT static bool
121 GetVarInt(DBOrTransaction* db,
122 const LevelDBSlice& key,
123 int64_t& found_int,
124 bool& found) {
125 std::vector<char> result;
126 bool ok = db->Get(key, result, found);
127 if (!ok)
128 return false;
129 if (!found)
130 return true;
131
132 found = DecodeVarInt(result.begin(), result.end(), found_int) == result.end();
133 return true;
134 }
135
136 static void PutVarInt(LevelDBTransaction* transaction,
137 const LevelDBSlice& key,
138 int64_t value) {
139 transaction->Put(key, EncodeVarInt(value));
140 }
141
142 template <typename DBOrTransaction>
143 WARN_UNUSED_RESULT static bool
144 GetString(DBOrTransaction* db,
145 const LevelDBSlice& key,
146 string16& found_string,
147 bool& found) {
148 std::vector<char> result;
149 found = false;
150 bool ok = db->Get(key, result, found);
151 if (!ok)
152 return false;
153 if (!found)
154 return true;
155
156 found_string = DecodeString(&result[0], &result[0] + result.size());
157 return true;
158 }
159
160 static void PutString(LevelDBTransaction* transaction,
161 const LevelDBSlice& key,
162 const string16& value) {
163 transaction->Put(key, EncodeString(value));
164 }
165
166 static void PutIDBKeyPath(LevelDBTransaction* transaction,
167 const LevelDBSlice& key,
168 const IndexedDBKeyPath& value) {
169 transaction->Put(key, EncodeIDBKeyPath(value));
170 }
171
172 static int CompareKeys(const LevelDBSlice& a, const LevelDBSlice& b) {
173 return Compare(a, b);
174 }
175
176 static int CompareIndexKeys(const LevelDBSlice& a, const LevelDBSlice& b) {
177 return Compare(a, b, true);
178 }
179
180 class Comparator : public LevelDBComparator {
181 public:
182 virtual int Compare(const LevelDBSlice& a, const LevelDBSlice& b) const
183 OVERRIDE {
184 return IndexedDBLevelDBCoding::Compare(a, b);
185 }
186 virtual const char* Name() const OVERRIDE { return "idb_cmp1"; }
187 };
188
189 // 0 - Initial version.
190 // 1 - Adds UserIntVersion to DatabaseMetaData.
191 // 2 - Adds DataVersion to to global metadata.
192 const int64_t latest_known_schema_version = 2;
jamesr 2013/05/21 23:56:06 should be kLatest...., and probably static
jsbell 2013/05/22 17:54:44 Done.
193 WARN_UNUSED_RESULT static bool IsSchemaKnown(LevelDBDatabase* db, bool& known) {
194 int64_t db_schema_version = 0;
195 bool found = false;
196 bool ok = GetInt(
197 db, LevelDBSlice(SchemaVersionKey::Encode()), db_schema_version, found);
198 if (!ok)
199 return false;
200 if (!found) {
201 known = true;
202 return true;
203 }
204 if (db_schema_version > latest_known_schema_version) {
205 known = false;
206 return true;
207 }
208
209 const uint32_t latest_known_data_version = kWireVersion;
210 int64_t db_data_version = 0;
211 ok = GetInt(
212 db, LevelDBSlice(DataVersionKey::Encode()), db_data_version, found);
213 if (!ok)
214 return false;
215 if (!found) {
216 known = true;
217 return true;
218 }
219
220 if (db_data_version > latest_known_data_version) {
221 known = false;
222 return true;
223 }
224
225 known = true;
226 return true;
227 }
228
229 WARN_UNUSED_RESULT static bool SetUpMetadata(LevelDBDatabase* db,
230 const string16& origin) {
231 const uint32_t latest_known_data_version = kWireVersion;
232 const std::vector<char> schema_version_key = SchemaVersionKey::Encode();
233 const std::vector<char> data_version_key = DataVersionKey::Encode();
234
235 scoped_refptr<LevelDBTransaction> transaction =
236 LevelDBTransaction::Create(db);
237
238 int64_t db_schema_version = 0;
239 int64_t db_data_version = 0;
240 bool found = false;
241 bool ok = GetInt(transaction.get(),
242 LevelDBSlice(schema_version_key),
243 db_schema_version,
244 found);
245 if (!ok) {
246 INTERNAL_READ_ERROR(kSetupMetadata);
247 return false;
248 }
249 if (!found) {
250 // Initialize new backing store.
251 db_schema_version = latest_known_schema_version;
252 PutInt(
253 transaction.get(), LevelDBSlice(schema_version_key), db_schema_version);
254 db_data_version = latest_known_data_version;
255 PutInt(transaction.get(), LevelDBSlice(data_version_key), db_data_version);
256 } else {
257 // Upgrade old backing store.
258 DCHECK(db_schema_version <= latest_known_schema_version);
259 if (db_schema_version < 1) {
260 db_schema_version = 1;
261 PutInt(transaction.get(),
262 LevelDBSlice(schema_version_key),
263 db_schema_version);
264 const std::vector<char> start_key =
265 DatabaseNameKey::EncodeMinKeyForOrigin(origin);
266 const std::vector<char> stop_key =
267 DatabaseNameKey::EncodeStopKeyForOrigin(origin);
268 scoped_ptr<LevelDBIterator> it = db->CreateIterator();
269 for (it->Seek(LevelDBSlice(start_key));
270 it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0;
271 it->Next()) {
272 int64_t database_id = 0;
273 found = false;
274 bool ok = GetInt(transaction.get(), it->Key(), database_id, found);
275 if (!ok) {
276 INTERNAL_READ_ERROR(kSetupMetadata);
277 return false;
278 }
279 if (!found) {
280 INTERNAL_CONSISTENCY_ERROR(kSetupMetadata);
281 return false;
282 }
283 std::vector<char> int_version_key = DatabaseMetaDataKey::Encode(
284 database_id, DatabaseMetaDataKey::UserIntVersion);
285 PutVarInt(transaction.get(),
286 LevelDBSlice(int_version_key),
287 IndexedDBDatabaseMetadata::DefaultIntVersion);
288 }
289 }
290 if (db_schema_version < 2) {
291 db_schema_version = 2;
292 PutInt(transaction.get(),
293 LevelDBSlice(schema_version_key),
294 db_schema_version);
295 db_data_version = kWireVersion;
296 PutInt(
297 transaction.get(), LevelDBSlice(data_version_key), db_data_version);
298 }
299 }
300
301 // All new values will be written using this serialization version.
302 found = false;
303 ok = GetInt(transaction.get(),
304 LevelDBSlice(data_version_key),
305 db_data_version,
306 found);
307 if (!ok) {
308 INTERNAL_READ_ERROR(kSetupMetadata);
309 return false;
310 }
311 if (!found) {
312 INTERNAL_CONSISTENCY_ERROR(kSetupMetadata);
313 return false;
314 }
315 if (db_data_version < latest_known_data_version) {
316 db_data_version = latest_known_data_version;
317 PutInt(transaction.get(), LevelDBSlice(data_version_key), db_data_version);
318 }
319
320 DCHECK(db_schema_version == latest_known_schema_version);
321 DCHECK(db_data_version == latest_known_data_version);
322
323 if (!transaction->Commit()) {
324 INTERNAL_WRITE_ERROR(kSetupMetadata);
325 return false;
326 }
327 return true;
328 }
329
330 template <typename DBOrTransaction>
331 WARN_UNUSED_RESULT static bool
332 GetMaxObjectStoreId(DBOrTransaction* db,
333 int64_t database_id,
334 int64_t& max_object_store_id) {
335 const std::vector<char> max_object_store_id_key = DatabaseMetaDataKey::Encode(
336 database_id, DatabaseMetaDataKey::MaxObjectStoreId);
337 bool ok =
338 GetMaxObjectStoreId(db, max_object_store_id_key, max_object_store_id);
339 return ok;
340 }
341
342 template <typename DBOrTransaction>
343 WARN_UNUSED_RESULT static bool
344 GetMaxObjectStoreId(DBOrTransaction* db,
345 const std::vector<char>& max_object_store_id_key,
346 int64_t& max_object_store_id) {
347 max_object_store_id = -1;
348 bool found = false;
349 bool ok = GetInt(
350 db, LevelDBSlice(max_object_store_id_key), max_object_store_id, found);
351 if (!ok)
352 return false;
353 if (!found)
354 max_object_store_id = 0;
355
356 DCHECK(max_object_store_id >= 0);
357 return true;
358 }
359
360 class DefaultLevelDBFactory : public LevelDBFactory {
361 public:
362 virtual scoped_ptr<LevelDBDatabase> OpenLevelDB(
363 const string16& file_name,
364 const LevelDBComparator* comparator) OVERRIDE {
365 return LevelDBDatabase::Open(
366 base::FilePath::FromUTF8Unsafe(UTF16ToUTF8(file_name)), comparator);
367 }
368 virtual bool DestroyLevelDB(const string16& file_name) OVERRIDE {
369 return LevelDBDatabase::Destroy(
370 base::FilePath::FromUTF8Unsafe(UTF16ToUTF8(file_name)));
371 }
372 };
373
374 IndexedDBBackingStore::IndexedDBBackingStore(
375 const string16& identifier,
376 scoped_ptr<LevelDBDatabase> db,
377 scoped_ptr<LevelDBComparator> comparator)
378 : identifier_(identifier),
379 db_(db.Pass()),
380 comparator_(comparator.Pass()),
381 weak_factory_(this) {}
382
383 IndexedDBBackingStore::~IndexedDBBackingStore() {
384 // db_'s destructor uses comparator_. The order of destruction is important.
385 db_.reset();
386 comparator_.reset();
387 }
388
389 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier(
390 const std::vector<char>& primary_key,
391 int64_t version)
392 : primary_key_(primary_key), version_(version) {
393 DCHECK(!primary_key.empty());
394 }
395 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier()
396 : primary_key_(), version_(-1) {}
397 IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() {}
398
399 IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() {}
400 IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() {}
401
402 enum IndexedDBLevelDBBackingStoreOpenResult {
403 IndexedDBLevelDBBackingStoreOpenMemorySuccess,
jamesr 2013/05/21 23:56:06 should be SHOUTY
jsbell 2013/05/22 17:54:44 Done.
404 IndexedDBLevelDBBackingStoreOpenSuccess,
405 IndexedDBLevelDBBackingStoreOpenFailedDirectory,
406 IndexedDBLevelDBBackingStoreOpenFailedUnknownSchema,
407 IndexedDBLevelDBBackingStoreOpenCleanupDestroyFailed,
408 IndexedDBLevelDBBackingStoreOpenCleanupReopenFailed,
409 IndexedDBLevelDBBackingStoreOpenCleanupReopenSuccess,
410 IndexedDBLevelDBBackingStoreOpenFailedIOErrCheckingSchema,
411 IndexedDBLevelDBBackingStoreOpenFailedUnknownErr,
412 IndexedDBLevelDBBackingStoreOpenMemoryFailed,
413 IndexedDBLevelDBBackingStoreOpenAttemptNonASCII,
414 IndexedDBLevelDBBackingStoreOpenMax,
415 };
416
417 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
418 const string16& database_identifier,
419 const string16& path_base_arg,
420 const string16& file_identifier) {
421 DefaultLevelDBFactory leveldb_factory;
422 return IndexedDBBackingStore::Open(
423 database_identifier, path_base_arg, file_identifier, &leveldb_factory);
424 }
425
426 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
427 const string16& database_identifier,
428 const string16& path_base_arg,
429 const string16& file_identifier,
430 LevelDBFactory* leveldb_factory) {
431 IDB_TRACE("IndexedDBBackingStore::open");
432 DCHECK(!path_base_arg.empty());
433 string16 path_base = path_base_arg;
434
435 scoped_ptr<LevelDBComparator> comparator(new Comparator());
436 scoped_ptr<LevelDBDatabase> db;
437
438 if (!IsStringASCII(path_base)) {
439 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus",
440 1,
441 IndexedDBLevelDBBackingStoreOpenMax,
442 IndexedDBLevelDBBackingStoreOpenMax + 1,
443 base::HistogramBase::kUmaTargetedHistogramFlag)
444 ->Add(IndexedDBLevelDBBackingStoreOpenAttemptNonASCII);
445 }
446 base::FilePath file_path_base(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 IndexedDBLevelDBBackingStoreOpenMax,
452 IndexedDBLevelDBBackingStoreOpenMax + 1,
453 base::HistogramBase::kUmaTargetedHistogramFlag)
454 ->Add(IndexedDBLevelDBBackingStoreOpenFailedDirectory);
455 return scoped_refptr<IndexedDBBackingStore>();
456 }
457
458 base::FilePath path_utf8 = file_path_base.Append(
459 UTF16ToUTF8(database_identifier) + ".indexeddb.leveldb");
460 string16 path_utf16 = UTF8ToUTF16(path_utf8.value());
461
462 db = leveldb_factory->OpenLevelDB(path_utf16, comparator.get());
463
464 if (db) {
465 bool known = false;
466 bool ok = IsSchemaKnown(db.get(), known);
467 if (!ok) {
468 LOG(ERROR) << "IndexedDB had IO error checking schema, treating it as "
469 "failure to open";
470 base::Histogram::FactoryGet(
471 "WebCore.IndexedDB.BackingStore.OpenStatus",
472 1,
473 IndexedDBLevelDBBackingStoreOpenMax,
474 IndexedDBLevelDBBackingStoreOpenMax + 1,
475 base::HistogramBase::kUmaTargetedHistogramFlag)
476 ->Add(IndexedDBLevelDBBackingStoreOpenFailedIOErrCheckingSchema);
477 db.reset();
478 } else if (!known) {
479 LOG(ERROR) << "IndexedDB backing store had unknown schema, treating it "
480 "as failure to open";
481 base::Histogram::FactoryGet(
482 "WebCore.IndexedDB.BackingStore.OpenStatus",
483 1,
484 IndexedDBLevelDBBackingStoreOpenMax,
485 IndexedDBLevelDBBackingStoreOpenMax + 1,
486 base::HistogramBase::kUmaTargetedHistogramFlag)
487 ->Add(IndexedDBLevelDBBackingStoreOpenFailedUnknownSchema);
488 db.reset();
489 }
490 }
491
492 if (db) {
493 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus",
494 1,
495 IndexedDBLevelDBBackingStoreOpenMax,
496 IndexedDBLevelDBBackingStoreOpenMax + 1,
497 base::HistogramBase::kUmaTargetedHistogramFlag)
498 ->Add(IndexedDBLevelDBBackingStoreOpenSuccess);
499 } else {
500 LOG(ERROR) << "IndexedDB backing store open failed, attempting cleanup";
501 bool success = leveldb_factory->DestroyLevelDB(path_utf16);
502 if (!success) {
503 LOG(ERROR) << "IndexedDB backing store cleanup failed";
504 base::Histogram::FactoryGet(
505 "WebCore.IndexedDB.BackingStore.OpenStatus",
506 1,
507 IndexedDBLevelDBBackingStoreOpenMax,
508 IndexedDBLevelDBBackingStoreOpenMax + 1,
509 base::HistogramBase::kUmaTargetedHistogramFlag)
510 ->Add(IndexedDBLevelDBBackingStoreOpenCleanupDestroyFailed);
511 return scoped_refptr<IndexedDBBackingStore>();
512 }
513
514 LOG(ERROR) << "IndexedDB backing store cleanup succeeded, reopening";
515 db = leveldb_factory->OpenLevelDB(path_utf16, comparator.get());
516 if (!db) {
517 LOG(ERROR) << "IndexedDB backing store reopen after recovery failed";
518 base::Histogram::FactoryGet(
519 "WebCore.IndexedDB.BackingStore.OpenStatus",
520 1,
521 IndexedDBLevelDBBackingStoreOpenMax,
522 IndexedDBLevelDBBackingStoreOpenMax + 1,
523 base::HistogramBase::kUmaTargetedHistogramFlag)
524 ->Add(IndexedDBLevelDBBackingStoreOpenCleanupReopenFailed);
525 return scoped_refptr<IndexedDBBackingStore>();
526 }
527 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus",
528 1,
529 IndexedDBLevelDBBackingStoreOpenMax,
530 IndexedDBLevelDBBackingStoreOpenMax + 1,
531 base::HistogramBase::kUmaTargetedHistogramFlag)
532 ->Add(IndexedDBLevelDBBackingStoreOpenCleanupReopenSuccess);
533 }
534
535 if (!db) {
536 NOTREACHED();
537 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus",
538 1,
539 IndexedDBLevelDBBackingStoreOpenMax,
540 IndexedDBLevelDBBackingStoreOpenMax + 1,
541 base::HistogramBase::kUmaTargetedHistogramFlag)
542 ->Add(IndexedDBLevelDBBackingStoreOpenFailedUnknownErr);
543 return scoped_refptr<IndexedDBBackingStore>();
544 }
545
546 return Create(file_identifier, db.Pass(), comparator.Pass());
547 }
548
549 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
550 const string16& identifier) {
551 DefaultLevelDBFactory leveldb_factory;
552 return IndexedDBBackingStore::OpenInMemory(identifier, &leveldb_factory);
553 }
554
555 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
556 const string16& identifier,
557 LevelDBFactory* leveldb_factory) {
558 IDB_TRACE("IndexedDBBackingStore::open_in_memory");
559
560 scoped_ptr<LevelDBComparator> comparator(new Comparator());
561 scoped_ptr<LevelDBDatabase> db =
562 LevelDBDatabase::OpenInMemory(comparator.get());
563 if (!db) {
564 LOG(ERROR) << "LevelDBDatabase::open_in_memory failed.";
565 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus",
566 1,
567 IndexedDBLevelDBBackingStoreOpenMax,
568 IndexedDBLevelDBBackingStoreOpenMax + 1,
569 base::HistogramBase::kUmaTargetedHistogramFlag)
570 ->Add(IndexedDBLevelDBBackingStoreOpenMemoryFailed);
571 return scoped_refptr<IndexedDBBackingStore>();
572 }
573 base::Histogram::FactoryGet("WebCore.IndexedDB.BackingStore.OpenStatus",
574 1,
575 IndexedDBLevelDBBackingStoreOpenMax,
576 IndexedDBLevelDBBackingStoreOpenMax + 1,
577 base::HistogramBase::kUmaTargetedHistogramFlag)
578 ->Add(IndexedDBLevelDBBackingStoreOpenMemorySuccess);
579
580 return Create(identifier, db.Pass(), comparator.Pass());
581 }
582
583 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create(
584 const string16& identifier,
585 scoped_ptr<LevelDBDatabase> db,
586 scoped_ptr<LevelDBComparator> comparator) {
587 // TODO: Handle comparator name changes.
588 scoped_refptr<IndexedDBBackingStore> backing_store(
589 new IndexedDBBackingStore(identifier, db.Pass(), comparator.Pass()));
590
591 if (!SetUpMetadata(backing_store->db_.get(), identifier))
592 return scoped_refptr<IndexedDBBackingStore>();
593
594 return backing_store;
595 }
596
597 std::vector<string16> IndexedDBBackingStore::GetDatabaseNames() {
598 std::vector<string16> found_names;
599 const std::vector<char> start_key =
600 DatabaseNameKey::EncodeMinKeyForOrigin(identifier_);
601 const std::vector<char> stop_key =
602 DatabaseNameKey::EncodeStopKeyForOrigin(identifier_);
603
604 DCHECK(found_names.empty());
605
606 scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
607 for (it->Seek(LevelDBSlice(start_key));
608 it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0;
609 it->Next()) {
610 const char* p = it->Key().begin();
611 const char* limit = it->Key().end();
612
613 DatabaseNameKey database_name_key;
614 p = DatabaseNameKey::Decode(p, limit, &database_name_key);
615 DCHECK(p);
616
617 found_names.push_back(database_name_key.database_name());
618 }
619 return found_names;
620 }
621
622 bool IndexedDBBackingStore::GetIDBDatabaseMetaData(
623 const string16& name,
624 IndexedDBDatabaseMetadata* metadata,
625 bool& found) {
626 const std::vector<char> key = DatabaseNameKey::Encode(identifier_, name);
627 found = false;
628
629 bool ok = GetInt(db_.get(), LevelDBSlice(key), metadata->id, found);
630 if (!ok) {
631 INTERNAL_READ_ERROR(kGetIDBDatabaseMetaData);
632 return false;
633 }
634 if (!found)
635 return true;
636
637 ok = GetString(db_.get(),
638 LevelDBSlice(DatabaseMetaDataKey::Encode(
639 metadata->id, DatabaseMetaDataKey::UserVersion)),
640 metadata->version,
641 found);
642 if (!ok) {
643 INTERNAL_READ_ERROR(kGetIDBDatabaseMetaData);
644 return false;
645 }
646 if (!found) {
647 INTERNAL_CONSISTENCY_ERROR(kGetIDBDatabaseMetaData);
648 return false;
649 }
650
651 ok = GetVarInt(db_.get(),
652 LevelDBSlice(DatabaseMetaDataKey::Encode(
653 metadata->id, DatabaseMetaDataKey::UserIntVersion)),
654 metadata->int_version,
655 found);
656 if (!ok) {
657 INTERNAL_READ_ERROR(kGetIDBDatabaseMetaData);
658 return false;
659 }
660 if (!found) {
661 INTERNAL_CONSISTENCY_ERROR(kGetIDBDatabaseMetaData);
662 return false;
663 }
664
665 if (metadata->int_version == IndexedDBDatabaseMetadata::DefaultIntVersion)
666 metadata->int_version = IndexedDBDatabaseMetadata::NoIntVersion;
667
668 ok = GetMaxObjectStoreId(
669 db_.get(), metadata->id, metadata->max_object_store_id);
670 if (!ok) {
671 INTERNAL_READ_ERROR(kGetIDBDatabaseMetaData);
672 return false;
673 }
674
675 return true;
676 }
677
678 WARN_UNUSED_RESULT static bool GetNewDatabaseId(LevelDBDatabase* db,
679 int64_t& new_id) {
680 scoped_refptr<LevelDBTransaction> transaction =
681 LevelDBTransaction::Create(db);
682
683 new_id = -1;
684 int64_t max_database_id = -1;
685 bool found = false;
686 bool ok = GetInt(transaction.get(),
687 LevelDBSlice(MaxDatabaseIdKey::Encode()),
688 max_database_id,
689 found);
690 if (!ok) {
691 INTERNAL_READ_ERROR(kGetNewDatabaseId);
692 return false;
693 }
694 if (!found)
695 max_database_id = 0;
696
697 DCHECK(max_database_id >= 0);
698
699 int64_t database_id = max_database_id + 1;
700 PutInt(
701 transaction.get(), LevelDBSlice(MaxDatabaseIdKey::Encode()), database_id);
702 if (!transaction->Commit()) {
703 INTERNAL_WRITE_ERROR(kGetNewDatabaseId);
704 return false;
705 }
706 new_id = database_id;
707 return true;
708 }
709
710 bool IndexedDBBackingStore::CreateIDBDatabaseMetaData(const string16& name,
711 const string16& version,
712 int64_t int_version,
713 int64_t& row_id) {
714 bool ok = GetNewDatabaseId(db_.get(), row_id);
715 if (!ok)
716 return false;
717 DCHECK(row_id >= 0);
718
719 if (int_version == IndexedDBDatabaseMetadata::NoIntVersion)
720 int_version = IndexedDBDatabaseMetadata::DefaultIntVersion;
721
722 scoped_refptr<LevelDBTransaction> transaction =
723 LevelDBTransaction::Create(db_.get());
724 PutInt(transaction.get(),
725 LevelDBSlice(DatabaseNameKey::Encode(identifier_, name)),
726 row_id);
727 PutString(transaction.get(),
728 LevelDBSlice(DatabaseMetaDataKey::Encode(
729 row_id, DatabaseMetaDataKey::UserVersion)),
730 version);
731 PutVarInt(transaction.get(),
732 LevelDBSlice(DatabaseMetaDataKey::Encode(
733 row_id, DatabaseMetaDataKey::UserIntVersion)),
734 int_version);
735 if (!transaction->Commit()) {
736 INTERNAL_WRITE_ERROR(kCreateIDBDatabaseMetaData);
737 return false;
738 }
739 return true;
740 }
741
742 bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion(
743 IndexedDBBackingStore::Transaction* transaction,
744 int64_t row_id,
745 int64_t int_version) {
746 if (int_version == IndexedDBDatabaseMetadata::NoIntVersion)
747 int_version = IndexedDBDatabaseMetadata::DefaultIntVersion;
748 DCHECK(int_version >= 0) << "int_version was " << int_version;
749 PutVarInt(Transaction::LevelDBTransactionFrom(transaction),
750 LevelDBSlice(DatabaseMetaDataKey::Encode(
751 row_id, DatabaseMetaDataKey::UserIntVersion)),
752 int_version);
753 return true;
754 }
755
756 bool IndexedDBBackingStore::UpdateIDBDatabaseMetaData(
757 IndexedDBBackingStore::Transaction* transaction,
758 int64_t row_id,
759 const string16& version) {
760 PutString(Transaction::LevelDBTransactionFrom(transaction),
761 LevelDBSlice(DatabaseMetaDataKey::Encode(
762 row_id, DatabaseMetaDataKey::UserVersion)),
763 version);
764 return true;
765 }
766
767 static void DeleteRange(LevelDBTransaction* transaction,
768 const std::vector<char>& begin,
769 const std::vector<char>& end) {
770 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator();
771 for (it->Seek(LevelDBSlice(begin));
772 it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(end)) < 0;
773 it->Next())
774 transaction->Remove(it->Key());
775 }
776
777 bool IndexedDBBackingStore::DeleteDatabase(const string16& name) {
778 IDB_TRACE("IndexedDBBackingStore::delete_database");
779 scoped_ptr<LevelDBWriteOnlyTransaction> transaction =
780 LevelDBWriteOnlyTransaction::Create(db_.get());
781
782 IndexedDBDatabaseMetadata metadata;
783 bool success = false;
784 bool ok = GetIDBDatabaseMetaData(name, &metadata, success);
785 if (!ok)
786 return false;
787 if (!success)
788 return true;
789
790 const std::vector<char> start_key =
791 DatabaseMetaDataKey::Encode(metadata.id, DatabaseMetaDataKey::OriginName);
792 const std::vector<char> stop_key = DatabaseMetaDataKey::Encode(
793 metadata.id + 1, DatabaseMetaDataKey::OriginName);
794 scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
795 for (it->Seek(LevelDBSlice(start_key));
796 it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0;
797 it->Next())
798 transaction->Remove(it->Key());
799
800 const std::vector<char> key = DatabaseNameKey::Encode(identifier_, name);
801 transaction->Remove(LevelDBSlice(key));
802
803 if (!transaction->Commit()) {
804 INTERNAL_WRITE_ERROR(kDeleteDatabase);
805 return false;
806 }
807 return true;
808 }
809
810 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it,
811 const std::vector<char>& stop_key,
812 int64_t object_store_id,
813 int64_t meta_data_type) {
814 if (!it->IsValid() || CompareKeys(it->Key(), LevelDBSlice(stop_key)) >= 0)
815 return false;
816
817 ObjectStoreMetaDataKey meta_data_key;
818 const char* p = ObjectStoreMetaDataKey::Decode(
819 it->Key().begin(), it->Key().end(), &meta_data_key);
820 DCHECK(p);
821 if (meta_data_key.ObjectStoreId() != object_store_id)
822 return false;
823 if (meta_data_key.MetaDataType() != meta_data_type)
824 return false;
825 return true;
826 }
827
828 // TODO: This should do some error handling rather than plowing ahead when bad
829 // data is encountered.
830 bool IndexedDBBackingStore::GetObjectStores(
831 int64_t database_id,
832 IndexedDBDatabaseMetadata::ObjectStoreMap* object_stores) {
833 IDB_TRACE("IndexedDBBackingStore::get_object_stores");
834 if (!KeyPrefix::IsValidDatabaseId(database_id))
835 return false;
836 const std::vector<char> start_key =
837 ObjectStoreMetaDataKey::Encode(database_id, 1, 0);
838 const std::vector<char> stop_key =
839 ObjectStoreMetaDataKey::EncodeMaxKey(database_id);
840
841 DCHECK(object_stores->empty());
842
843 scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
844 it->Seek(LevelDBSlice(start_key));
845 while (it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0) {
846 const char* p = it->Key().begin();
847 const char* limit = it->Key().end();
848
849 ObjectStoreMetaDataKey meta_data_key;
850 p = ObjectStoreMetaDataKey::Decode(p, limit, &meta_data_key);
851 DCHECK(p);
852 if (meta_data_key.MetaDataType() != ObjectStoreMetaDataKey::Name) {
853 INTERNAL_CONSISTENCY_ERROR(kGetObjectStores);
854 // Possible stale metadata, but don't fail the load.
855 it->Next();
856 continue;
857 }
858
859 int64_t object_store_id = meta_data_key.ObjectStoreId();
860
861 // TODO: Do this by direct key lookup rather than iteration, to simplify.
862 string16 object_store_name =
863 DecodeString(it->Value().begin(), it->Value().end());
864
865 it->Next();
866 if (!CheckObjectStoreAndMetaDataType(it.get(),
867 stop_key,
868 object_store_id,
869 ObjectStoreMetaDataKey::KeyPath)) {
870 INTERNAL_CONSISTENCY_ERROR(kGetObjectStores);
871 break;
872 }
873 IndexedDBKeyPath key_path =
874 DecodeIDBKeyPath(it->Value().begin(), it->Value().end());
875
876 it->Next();
877 if (!CheckObjectStoreAndMetaDataType(
878 it.get(),
879 stop_key,
880 object_store_id,
881 ObjectStoreMetaDataKey::AutoIncrement)) {
882 INTERNAL_CONSISTENCY_ERROR(kGetObjectStores);
883 break;
884 }
885 bool auto_increment = DecodeBool(it->Value().begin(), it->Value().end());
886
887 it->Next(); // Is evicatble.
888 if (!CheckObjectStoreAndMetaDataType(it.get(),
889 stop_key,
890 object_store_id,
891 ObjectStoreMetaDataKey::Evictable)) {
892 INTERNAL_CONSISTENCY_ERROR(kGetObjectStores);
893 break;
894 }
895
896 it->Next(); // Last version.
897 if (!CheckObjectStoreAndMetaDataType(it.get(),
898 stop_key,
899 object_store_id,
900 ObjectStoreMetaDataKey::LastVersion)) {
901 INTERNAL_CONSISTENCY_ERROR(kGetObjectStores);
902 break;
903 }
904
905 it->Next(); // Maximum index id allocated.
906 if (!CheckObjectStoreAndMetaDataType(it.get(),
907 stop_key,
908 object_store_id,
909 ObjectStoreMetaDataKey::MaxIndexId)) {
910 INTERNAL_CONSISTENCY_ERROR(kGetObjectStores);
911 break;
912 }
913 int64_t max_index_id = DecodeInt(it->Value().begin(), it->Value().end());
914
915 it->Next(); // [optional] has key path (is not null)
916 if (CheckObjectStoreAndMetaDataType(it.get(),
917 stop_key,
918 object_store_id,
919 ObjectStoreMetaDataKey::HasKeyPath)) {
920 bool has_key_path = DecodeBool(it->Value().begin(), it->Value().end());
921 // This check accounts for two layers of legacy coding:
922 // (1) Initially, has_key_path was added to distinguish null vs. string.
923 // (2) Later, null vs. string vs. array was stored in the key_path itself.
924 // So this check is only relevant for string-type key_paths.
925 if (!has_key_path &&
926 (key_path.type() == WebKit::WebIDBKeyPath::StringType &&
927 !key_path.string().empty())) {
928 INTERNAL_CONSISTENCY_ERROR(kGetObjectStores);
929 break;
930 }
931 if (!has_key_path)
932 key_path = IndexedDBKeyPath();
933 it->Next();
934 }
935
936 int64_t key_generator_current_number = -1;
937 if (CheckObjectStoreAndMetaDataType(
938 it.get(),
939 stop_key,
940 object_store_id,
941 ObjectStoreMetaDataKey::KeyGeneratorCurrentNumber)) {
942 key_generator_current_number =
943 DecodeInt(it->Value().begin(), it->Value().end());
944 // TODO: Return key_generator_current_number, cache in object store, and
945 // write lazily to backing store.
946 // For now, just assert that if it was written it was valid.
947 DCHECK(key_generator_current_number >= KeyGeneratorInitialNumber);
948 it->Next();
949 }
950
951 IndexedDBObjectStoreMetadata metadata(object_store_name,
952 object_store_id,
953 key_path,
954 auto_increment,
955 max_index_id);
956 if (!GetIndexes(database_id, object_store_id, &metadata.indexes))
957 return false;
958 (*object_stores)[object_store_id] = metadata;
959 }
960 return true;
961 }
962
963 WARN_UNUSED_RESULT static bool SetMaxObjectStoreId(
964 LevelDBTransaction* transaction,
965 int64_t database_id,
966 int64_t object_store_id) {
967 const std::vector<char> max_object_store_id_key = DatabaseMetaDataKey::Encode(
968 database_id, DatabaseMetaDataKey::MaxObjectStoreId);
969 int64_t max_object_store_id = -1;
970 bool ok = GetMaxObjectStoreId(
971 transaction, max_object_store_id_key, max_object_store_id);
972 if (!ok) {
973 INTERNAL_READ_ERROR(kSetMaxObjectStoreId);
974 return false;
975 }
976
977 if (object_store_id <= max_object_store_id) {
978 INTERNAL_CONSISTENCY_ERROR(kSetMaxObjectStoreId);
979 return false;
980 }
981 PutInt(transaction, LevelDBSlice(max_object_store_id_key), object_store_id);
982 return true;
983 }
984
985 bool IndexedDBBackingStore::CreateObjectStore(
986 IndexedDBBackingStore::Transaction* transaction,
987 int64_t database_id,
988 int64_t object_store_id,
989 const string16& name,
990 const IndexedDBKeyPath& key_path,
991 bool auto_increment) {
992 IDB_TRACE("IndexedDBBackingStore::create_object_store");
993 if (!KeyPrefix::ValidIds(database_id, object_store_id))
994 return false;
995 LevelDBTransaction* leveldb_transaction =
996 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
997 if (!SetMaxObjectStoreId(leveldb_transaction, database_id, object_store_id))
998 return false;
999
1000 const std::vector<char> name_key = ObjectStoreMetaDataKey::Encode(
1001 database_id, object_store_id, ObjectStoreMetaDataKey::Name);
1002 const std::vector<char> key_path_key = ObjectStoreMetaDataKey::Encode(
1003 database_id, object_store_id, ObjectStoreMetaDataKey::KeyPath);
1004 const std::vector<char> auto_increment_key = ObjectStoreMetaDataKey::Encode(
1005 database_id, object_store_id, ObjectStoreMetaDataKey::AutoIncrement);
1006 const std::vector<char> evictable_key = ObjectStoreMetaDataKey::Encode(
1007 database_id, object_store_id, ObjectStoreMetaDataKey::Evictable);
1008 const std::vector<char> last_version_key = ObjectStoreMetaDataKey::Encode(
1009 database_id, object_store_id, ObjectStoreMetaDataKey::LastVersion);
1010 const std::vector<char> max_index_id_key = ObjectStoreMetaDataKey::Encode(
1011 database_id, object_store_id, ObjectStoreMetaDataKey::MaxIndexId);
1012 const std::vector<char> has_key_path_key = ObjectStoreMetaDataKey::Encode(
1013 database_id, object_store_id, ObjectStoreMetaDataKey::HasKeyPath);
1014 const std::vector<char> key_generator_current_number_key =
1015 ObjectStoreMetaDataKey::Encode(
1016 database_id,
1017 object_store_id,
1018 ObjectStoreMetaDataKey::KeyGeneratorCurrentNumber);
1019 const std::vector<char> names_key =
1020 ObjectStoreNamesKey::Encode(database_id, name);
1021
1022 PutString(leveldb_transaction, LevelDBSlice(name_key), name);
1023 PutIDBKeyPath(leveldb_transaction, LevelDBSlice(key_path_key), key_path);
1024 PutInt(leveldb_transaction, LevelDBSlice(auto_increment_key), auto_increment);
1025 PutInt(leveldb_transaction, LevelDBSlice(evictable_key), false);
1026 PutInt(leveldb_transaction, LevelDBSlice(last_version_key), 1);
1027 PutInt(leveldb_transaction, LevelDBSlice(max_index_id_key), MinimumIndexId);
1028 PutBool(
1029 leveldb_transaction, LevelDBSlice(has_key_path_key), !key_path.IsNull());
1030 PutInt(leveldb_transaction,
1031 LevelDBSlice(key_generator_current_number_key),
1032 KeyGeneratorInitialNumber);
1033 PutInt(leveldb_transaction, LevelDBSlice(names_key), object_store_id);
1034 return true;
1035 }
1036
1037 bool IndexedDBBackingStore::DeleteObjectStore(
1038 IndexedDBBackingStore::Transaction* transaction,
1039 int64_t database_id,
1040 int64_t object_store_id) {
1041 IDB_TRACE("IndexedDBBackingStore::delete_object_store");
1042 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1043 return false;
1044 LevelDBTransaction* leveldb_transaction =
1045 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1046
1047 string16 object_store_name;
1048 bool found = false;
1049 bool ok = GetString(
1050 leveldb_transaction,
1051 LevelDBSlice(ObjectStoreMetaDataKey::Encode(
1052 database_id, object_store_id, ObjectStoreMetaDataKey::Name)),
1053 object_store_name,
1054 found);
1055 if (!ok) {
1056 INTERNAL_READ_ERROR(kDeleteObjectStore);
1057 return false;
1058 }
1059 if (!found) {
1060 INTERNAL_CONSISTENCY_ERROR(kDeleteObjectStore);
1061 return false;
1062 }
1063
1064 DeleteRange(
1065 leveldb_transaction,
1066 ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0),
1067 ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id));
1068
1069 leveldb_transaction->Remove(LevelDBSlice(
1070 ObjectStoreNamesKey::Encode(database_id, object_store_name)));
1071
1072 DeleteRange(leveldb_transaction,
1073 IndexFreeListKey::Encode(database_id, object_store_id, 0),
1074 IndexFreeListKey::EncodeMaxKey(database_id, object_store_id));
1075 DeleteRange(leveldb_transaction,
1076 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0),
1077 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id));
1078
1079 return ClearObjectStore(transaction, database_id, object_store_id);
1080 }
1081
1082 bool IndexedDBBackingStore::GetRecord(
1083 IndexedDBBackingStore::Transaction* transaction,
1084 int64_t database_id,
1085 int64_t object_store_id,
1086 const IndexedDBKey& key,
1087 std::vector<char>& record) {
1088 IDB_TRACE("IndexedDBBackingStore::get_record");
1089 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1090 return false;
1091 LevelDBTransaction* leveldb_transaction =
1092 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1093
1094 const std::vector<char> leveldb_key =
1095 ObjectStoreDataKey::Encode(database_id, object_store_id, key);
1096 std::vector<char> data;
1097
1098 record.clear();
1099
1100 bool found = false;
1101 bool ok = leveldb_transaction->Get(LevelDBSlice(leveldb_key), data, found);
1102 if (!ok) {
1103 INTERNAL_READ_ERROR(kGetRecord);
1104 return false;
1105 }
1106 if (!found)
1107 return true;
1108
1109 int64_t version;
1110 std::vector<char>::iterator p =
1111 DecodeVarInt(data.begin(), data.end(), version);
1112 if (p == data.begin()) {
1113 INTERNAL_READ_ERROR(kGetRecord);
1114 return false;
1115 }
1116
1117 record.assign(p, data.end());
1118 return true;
1119 }
1120
1121 WARN_UNUSED_RESULT static bool GetNewVersionNumber(
1122 LevelDBTransaction* transaction,
1123 int64_t database_id,
1124 int64_t object_store_id,
1125 int64_t& new_version_number) {
1126 const std::vector<char> last_version_key = ObjectStoreMetaDataKey::Encode(
1127 database_id, object_store_id, ObjectStoreMetaDataKey::LastVersion);
1128
1129 new_version_number = -1;
1130 int64_t last_version = -1;
1131 bool found = false;
1132 bool ok =
1133 GetInt(transaction, LevelDBSlice(last_version_key), last_version, found);
1134 if (!ok) {
1135 INTERNAL_READ_ERROR(kGetNewVersionNumber);
1136 return false;
1137 }
1138 if (!found)
1139 last_version = 0;
1140
1141 DCHECK(last_version >= 0);
1142
1143 int64_t version = last_version + 1;
1144 PutInt(transaction, LevelDBSlice(last_version_key), version);
1145
1146 DCHECK(version > last_version); // TODO: Think about how we want to handle
1147 // the overflow scenario.
1148
1149 new_version_number = version;
1150 return true;
1151 }
1152
1153 bool IndexedDBBackingStore::PutRecord(
1154 IndexedDBBackingStore::Transaction* transaction,
1155 int64_t database_id,
1156 int64_t object_store_id,
1157 const IndexedDBKey& key,
1158 const std::vector<char>& value,
1159 RecordIdentifier* record_identifier) {
1160 IDB_TRACE("IndexedDBBackingStore::put_record");
1161 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1162 return false;
1163 DCHECK(key.IsValid());
1164
1165 LevelDBTransaction* leveldb_transaction =
1166 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1167 int64_t version = -1;
1168 bool ok = GetNewVersionNumber(
1169 leveldb_transaction, database_id, object_store_id, version);
1170 if (!ok)
1171 return false;
1172 DCHECK(version >= 0);
1173 const std::vector<char> object_storedata_key =
1174 ObjectStoreDataKey::Encode(database_id, object_store_id, key);
1175
1176 std::vector<char> v(EncodeVarInt(version));
1177
1178 v.insert(v.end(), value.begin(), value.end());
1179
1180 leveldb_transaction->Put(LevelDBSlice(object_storedata_key), v);
1181
1182 const std::vector<char> exists_entry_key =
1183 ExistsEntryKey::Encode(database_id, object_store_id, key);
1184 leveldb_transaction->Put(LevelDBSlice(exists_entry_key), EncodeInt(version));
1185
1186 record_identifier->Reset(EncodeIDBKey(key), version);
1187 return true;
1188 }
1189
1190 bool IndexedDBBackingStore::ClearObjectStore(
1191 IndexedDBBackingStore::Transaction* transaction,
1192 int64_t database_id,
1193 int64_t object_store_id) {
1194 IDB_TRACE("IndexedDBBackingStore::clear_object_store");
1195 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1196 return false;
1197 LevelDBTransaction* leveldb_transaction =
1198 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1199 const std::vector<char> start_key =
1200 KeyPrefix(database_id, object_store_id).Encode();
1201 const std::vector<char> stop_key =
1202 KeyPrefix(database_id, object_store_id + 1).Encode();
1203
1204 DeleteRange(leveldb_transaction, start_key, stop_key);
1205 return true;
1206 }
1207
1208 bool IndexedDBBackingStore::DeleteRecord(
1209 IndexedDBBackingStore::Transaction* transaction,
1210 int64_t database_id,
1211 int64_t object_store_id,
1212 const RecordIdentifier& record_identifier) {
1213 IDB_TRACE("IndexedDBBackingStore::delete_record");
1214 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1215 return false;
1216 LevelDBTransaction* leveldb_transaction =
1217 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1218
1219 const std::vector<char> object_store_data_key = ObjectStoreDataKey::Encode(
1220 database_id, object_store_id, record_identifier.primary_key());
1221 leveldb_transaction->Remove(LevelDBSlice(object_store_data_key));
1222
1223 const std::vector<char> exists_entry_key = ExistsEntryKey::Encode(
1224 database_id, object_store_id, record_identifier.primary_key());
1225 leveldb_transaction->Remove(LevelDBSlice(exists_entry_key));
1226 return true;
1227 }
1228
1229 bool IndexedDBBackingStore::GetKeyGeneratorCurrentNumber(
1230 IndexedDBBackingStore::Transaction* transaction,
1231 int64_t database_id,
1232 int64_t object_store_id,
1233 int64_t& key_generator_current_number) {
1234 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1235 return false;
1236 LevelDBTransaction* leveldb_transaction =
1237 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1238
1239 const std::vector<char> key_generator_current_number_key =
1240 ObjectStoreMetaDataKey::Encode(
1241 database_id,
1242 object_store_id,
1243 ObjectStoreMetaDataKey::KeyGeneratorCurrentNumber);
1244
1245 key_generator_current_number = -1;
1246 std::vector<char> data;
1247
1248 bool found = false;
1249 bool ok = leveldb_transaction->Get(
1250 LevelDBSlice(key_generator_current_number_key), data, found);
1251 if (!ok) {
1252 INTERNAL_READ_ERROR(kGetKeyGeneratorCurrentNumber);
1253 return false;
1254 }
1255 if (found) {
1256 key_generator_current_number = DecodeInt(data.begin(), data.end());
1257 } else {
1258 // Previously, the key generator state was not stored explicitly
1259 // but derived from the maximum numeric key present in existing
1260 // data. This violates the spec as the data may be cleared but the
1261 // key generator state must be preserved.
1262 const std::vector<char> start_key =
1263 ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey());
1264 const std::vector<char> stop_key =
1265 ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey());
1266
1267 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator();
1268 int64_t max_numeric_key = 0;
1269
1270 for (it->Seek(LevelDBSlice(start_key));
1271 it->IsValid() && CompareKeys(it->Key(), LevelDBSlice(stop_key)) < 0;
1272 it->Next()) {
1273 const char* p = it->Key().begin();
1274 const char* limit = it->Key().end();
1275
1276 ObjectStoreDataKey data_key;
1277 p = ObjectStoreDataKey::Decode(p, limit, &data_key);
1278 DCHECK(p);
1279
1280 scoped_ptr<IndexedDBKey> user_key = data_key.user_key();
1281 if (user_key->type() == WebKit::WebIDBKey::NumberType) {
1282 int64_t n = static_cast<int64_t>(user_key->number());
1283 if (n > max_numeric_key)
1284 max_numeric_key = n;
1285 }
1286 }
1287
1288 key_generator_current_number = max_numeric_key + 1;
1289 }
1290
1291 return key_generator_current_number;
1292 }
1293
1294 bool IndexedDBBackingStore::MaybeUpdateKeyGeneratorCurrentNumber(
1295 IndexedDBBackingStore::Transaction* transaction,
1296 int64_t database_id,
1297 int64_t object_store_id,
1298 int64_t new_number,
1299 bool check_current) {
1300 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1301 return false;
1302 LevelDBTransaction* leveldb_transaction =
1303 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1304
1305 if (check_current) {
1306 int64_t current_number;
1307 bool ok = GetKeyGeneratorCurrentNumber(
1308 transaction, database_id, object_store_id, current_number);
1309 if (!ok)
1310 return false;
1311 if (new_number <= current_number)
1312 return true;
1313 }
1314
1315 const std::vector<char> key_generator_current_number_key =
1316 ObjectStoreMetaDataKey::Encode(
1317 database_id,
1318 object_store_id,
1319 ObjectStoreMetaDataKey::KeyGeneratorCurrentNumber);
1320 PutInt(leveldb_transaction,
1321 LevelDBSlice(key_generator_current_number_key),
1322 new_number);
1323 return true;
1324 }
1325
1326 bool IndexedDBBackingStore::KeyExistsInObjectStore(
1327 IndexedDBBackingStore::Transaction* transaction,
1328 int64_t database_id,
1329 int64_t object_store_id,
1330 const IndexedDBKey& key,
1331 RecordIdentifier* found_record_identifier,
1332 bool& found) {
1333 IDB_TRACE("IndexedDBBackingStore::key_exists_in_object_store");
1334 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1335 return false;
1336 found = false;
1337 LevelDBTransaction* leveldb_transaction =
1338 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1339 const std::vector<char> leveldb_key =
1340 ObjectStoreDataKey::Encode(database_id, object_store_id, key);
1341 std::vector<char> data;
1342
1343 bool ok = leveldb_transaction->Get(LevelDBSlice(leveldb_key), data, found);
1344 if (!ok) {
1345 INTERNAL_READ_ERROR(kKeyExistsInObjectStore);
1346 return false;
1347 }
1348 if (!found)
1349 return true;
1350
1351 int64_t version;
1352 if (DecodeVarInt(data.begin(), data.end(), version) == data.begin())
1353 return false;
1354
1355 found_record_identifier->Reset(EncodeIDBKey(key), version);
1356 return true;
1357 }
1358
1359 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it,
1360 const std::vector<char>& stop_key,
1361 int64_t index_id,
1362 unsigned char meta_data_type) {
1363 if (!it->IsValid() || CompareKeys(it->Key(), LevelDBSlice(stop_key)) >= 0)
1364 return false;
1365
1366 IndexMetaDataKey meta_data_key;
1367 const char* p = IndexMetaDataKey::Decode(
1368 it->Key().begin(), it->Key().end(), &meta_data_key);
1369 DCHECK(p);
1370 if (meta_data_key.IndexId() != index_id)
1371 return false;
1372 if (meta_data_key.meta_data_type() != meta_data_type)
1373 return false;
1374 return true;
1375 }
1376
1377 // TODO: This should do some error handling rather than plowing ahead when bad
1378 // data is encountered.
1379 bool IndexedDBBackingStore::GetIndexes(
1380 int64_t database_id,
1381 int64_t object_store_id,
1382 IndexedDBObjectStoreMetadata::IndexMap* indexes) {
1383 IDB_TRACE("IndexedDBBackingStore::get_indexes");
1384 if (!KeyPrefix::ValidIds(database_id, object_store_id))
1385 return false;
1386 const std::vector<char> start_key =
1387 IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0);
1388 const std::vector<char> stop_key =
1389 IndexMetaDataKey::Encode(database_id, object_store_id + 1, 0, 0);
1390
1391 DCHECK(indexes->empty());
1392
1393 scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
1394 it->Seek(LevelDBSlice(start_key));
1395 while (it->IsValid() &&
1396 CompareKeys(LevelDBSlice(it->Key()), LevelDBSlice(stop_key)) < 0) {
1397 const char* p = it->Key().begin();
1398 const char* limit = it->Key().end();
1399
1400 IndexMetaDataKey meta_data_key;
1401 p = IndexMetaDataKey::Decode(p, limit, &meta_data_key);
1402 DCHECK(p);
1403 if (meta_data_key.meta_data_type() != IndexMetaDataKey::Name) {
1404 INTERNAL_CONSISTENCY_ERROR(kGetIndexes);
1405 // Possible stale metadata due to http://webkit.org/b/85557 but don't fail
1406 // the load.
1407 it->Next();
1408 continue;
1409 }
1410
1411 // TODO: Do this by direct key lookup rather than iteration, to simplify.
1412 int64_t index_id = meta_data_key.IndexId();
1413 string16 index_name = DecodeString(it->Value().begin(), it->Value().end());
1414
1415 it->Next(); // unique flag
1416 if (!CheckIndexAndMetaDataKey(
1417 it.get(), stop_key, index_id, IndexMetaDataKey::Unique)) {
1418 INTERNAL_CONSISTENCY_ERROR(kGetIndexes);
1419 break;
1420 }
1421 bool index_unique = DecodeBool(it->Value().begin(), it->Value().end());
1422
1423 it->Next(); // key_path
1424 if (!CheckIndexAndMetaDataKey(
1425 it.get(), stop_key, index_id, IndexMetaDataKey::KeyPath)) {
1426 INTERNAL_CONSISTENCY_ERROR(kGetIndexes);
1427 break;
1428 }
1429 IndexedDBKeyPath key_path =
1430 DecodeIDBKeyPath(it->Value().begin(), it->Value().end());
1431
1432 it->Next(); // [optional] multi_entry flag
1433 bool index_multi_entry = false;
1434 if (CheckIndexAndMetaDataKey(
1435 it.get(), stop_key, index_id, IndexMetaDataKey::MultiEntry)) {
1436 index_multi_entry = DecodeBool(it->Value().begin(), it->Value().end());
1437 it->Next();
1438 }
1439
1440 (*indexes)[index_id] = IndexedDBIndexMetadata(
1441 index_name, index_id, key_path, index_unique, index_multi_entry);
1442 }
1443 return true;
1444 }
1445
1446 WARN_UNUSED_RESULT static bool SetMaxIndexId(LevelDBTransaction* transaction,
1447 int64_t database_id,
1448 int64_t object_store_id,
1449 int64_t index_id) {
1450 int64_t max_index_id = -1;
1451 const std::vector<char> max_index_id_key = ObjectStoreMetaDataKey::Encode(
1452 database_id, object_store_id, ObjectStoreMetaDataKey::MaxIndexId);
1453 bool found = false;
1454 bool ok =
1455 GetInt(transaction, LevelDBSlice(max_index_id_key), max_index_id, found);
1456 if (!ok) {
1457 INTERNAL_READ_ERROR(kSetMaxIndexId);
1458 return false;
1459 }
1460 if (!found)
1461 max_index_id = MinimumIndexId;
1462
1463 if (index_id <= max_index_id) {
1464 INTERNAL_CONSISTENCY_ERROR(kSetMaxIndexId);
1465 return false;
1466 }
1467
1468 PutInt(transaction, LevelDBSlice(max_index_id_key), index_id);
1469 return true;
1470 }
1471
1472 bool IndexedDBBackingStore::CreateIndex(
1473 IndexedDBBackingStore::Transaction* transaction,
1474 int64_t database_id,
1475 int64_t object_store_id,
1476 int64_t index_id,
1477 const string16& name,
1478 const IndexedDBKeyPath& key_path,
1479 bool is_unique,
1480 bool is_multi_entry) {
1481 IDB_TRACE("IndexedDBBackingStore::create_index");
1482 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
1483 return false;
1484 LevelDBTransaction* leveldb_transaction =
1485 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1486 if (!SetMaxIndexId(
1487 leveldb_transaction, database_id, object_store_id, index_id))
1488 return false;
1489
1490 const std::vector<char> name_key = IndexMetaDataKey::Encode(
1491 database_id, object_store_id, index_id, IndexMetaDataKey::Name);
1492 const std::vector<char> unique_key = IndexMetaDataKey::Encode(
1493 database_id, object_store_id, index_id, IndexMetaDataKey::Unique);
1494 const std::vector<char> key_path_key = IndexMetaDataKey::Encode(
1495 database_id, object_store_id, index_id, IndexMetaDataKey::KeyPath);
1496 const std::vector<char> multi_entry_key = IndexMetaDataKey::Encode(
1497 database_id, object_store_id, index_id, IndexMetaDataKey::MultiEntry);
1498
1499 PutString(leveldb_transaction, LevelDBSlice(name_key), name);
1500 PutBool(leveldb_transaction, LevelDBSlice(unique_key), is_unique);
1501 PutIDBKeyPath(leveldb_transaction, LevelDBSlice(key_path_key), key_path);
1502 PutBool(leveldb_transaction, LevelDBSlice(multi_entry_key), is_multi_entry);
1503 return true;
1504 }
1505
1506 bool IndexedDBBackingStore::DeleteIndex(
1507 IndexedDBBackingStore::Transaction* transaction,
1508 int64_t database_id,
1509 int64_t object_store_id,
1510 int64_t index_id) {
1511 IDB_TRACE("IndexedDBBackingStore::delete_index");
1512 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
1513 return false;
1514 LevelDBTransaction* leveldb_transaction =
1515 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1516
1517 const std::vector<char> index_meta_data_start =
1518 IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0);
1519 const std::vector<char> index_meta_data_end =
1520 IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
1521 DeleteRange(leveldb_transaction, index_meta_data_start, index_meta_data_end);
1522
1523 const std::vector<char> index_data_start =
1524 IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id);
1525 const std::vector<char> index_data_end =
1526 IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
1527 DeleteRange(leveldb_transaction, index_data_start, index_data_end);
1528 return true;
1529 }
1530
1531 bool IndexedDBBackingStore::PutIndexDataForRecord(
1532 IndexedDBBackingStore::Transaction* transaction,
1533 int64_t database_id,
1534 int64_t object_store_id,
1535 int64_t index_id,
1536 const IndexedDBKey& key,
1537 const RecordIdentifier& record_identifier) {
1538 IDB_TRACE("IndexedDBBackingStore::put_index_data_for_record");
1539 DCHECK(key.IsValid());
1540 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
1541 return false;
1542
1543 LevelDBTransaction* leveldb_transaction =
1544 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1545 const std::vector<char> index_data_key =
1546 IndexDataKey::Encode(database_id,
1547 object_store_id,
1548 index_id,
1549 EncodeIDBKey(key),
1550 record_identifier.primary_key());
1551
1552 std::vector<char> data(EncodeVarInt(record_identifier.version()));
1553 const std::vector<char>& primary_key = record_identifier.primary_key();
1554 data.insert(data.end(), primary_key.begin(), primary_key.end());
1555
1556 leveldb_transaction->Put(LevelDBSlice(index_data_key), data);
1557 return true;
1558 }
1559
1560 static bool FindGreatestKeyLessThanOrEqual(LevelDBTransaction* transaction,
1561 const std::vector<char>& target,
1562 std::vector<char>& found_key) {
1563 scoped_ptr<LevelDBIterator> it = transaction->CreateIterator();
1564 it->Seek(LevelDBSlice(target));
1565
1566 if (!it->IsValid()) {
1567 it->SeekToLast();
1568 if (!it->IsValid())
1569 return false;
1570 }
1571
1572 while (CompareIndexKeys(LevelDBSlice(it->Key()), LevelDBSlice(target)) > 0) {
1573 it->Prev();
1574 if (!it->IsValid())
1575 return false;
1576 }
1577
1578 do {
1579 found_key.assign(it->Key().begin(), it->Key().end());
1580
1581 // There can be several index keys that compare equal. We want the last one.
1582 it->Next();
1583 } while (it->IsValid() && !CompareIndexKeys(it->Key(), LevelDBSlice(target)));
1584
1585 return true;
1586 }
1587
1588 static bool VersionExists(LevelDBTransaction* transaction,
1589 int64_t database_id,
1590 int64_t object_store_id,
1591 int64_t version,
1592 const std::vector<char>& encoded_primary_key,
1593 bool& exists) {
1594 const std::vector<char> key =
1595 ExistsEntryKey::Encode(database_id, object_store_id, encoded_primary_key);
1596 std::vector<char> data;
1597
1598 bool ok = transaction->Get(LevelDBSlice(key), data, exists);
1599 if (!ok) {
1600 INTERNAL_READ_ERROR(kVersionExists);
1601 return false;
1602 }
1603 if (!exists)
1604 return true;
1605
1606 exists = (DecodeInt(data.begin(), data.end()) == version);
1607 return true;
1608 }
1609
1610 bool IndexedDBBackingStore::FindKeyInIndex(
1611 IndexedDBBackingStore::Transaction* transaction,
1612 int64_t database_id,
1613 int64_t object_store_id,
1614 int64_t index_id,
1615 const IndexedDBKey& key,
1616 std::vector<char>& found_encoded_primary_key,
1617 bool& found) {
1618 IDB_TRACE("IndexedDBBackingStore::find_key_in_index");
1619 DCHECK(KeyPrefix::ValidIds(database_id, object_store_id, index_id));
1620
1621 DCHECK(found_encoded_primary_key.empty());
1622 found = false;
1623
1624 LevelDBTransaction* leveldb_transaction =
1625 IndexedDBBackingStore::Transaction::LevelDBTransactionFrom(transaction);
1626 const std::vector<char> leveldb_key =
1627 IndexDataKey::Encode(database_id, object_store_id, index_id, key);
1628 scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator();
1629 it->Seek(LevelDBSlice(leveldb_key));
1630
1631 for (;;) {
1632 if (!it->IsValid())
1633 return true;
1634 if (CompareIndexKeys(it->Key(), LevelDBSlice(leveldb_key)) > 0)
1635 return true;
1636
1637 int64_t version;
1638 const char* p =
1639 DecodeVarInt(it->Value().begin(), it->Value().end(), version);
1640 if (!p) {
1641 INTERNAL_READ_ERROR(kFindKeyInIndex);
1642 return false;
1643 }
1644 found_encoded_primary_key.insert(
1645 found_encoded_primary_key.end(), p, it->Value().end());
1646
1647 bool exists = false;
1648 bool ok = VersionExists(leveldb_transaction,
1649 database_id,
1650 object_store_id,
1651 version,
1652 found_encoded_primary_key,
1653 exists);
1654 if (!ok)
1655 return false;
1656 if (!exists) {
1657 // Delete stale index data entry and continue.
1658 leveldb_transaction->Remove(it->Key());
1659 it->Next();
1660 continue;
1661 }
1662 found = true;
1663 return true;
1664 }
1665 }
1666
1667 bool IndexedDBBackingStore::GetPrimaryKeyViaIndex(
1668 IndexedDBBackingStore::Transaction* transaction,
1669 int64_t database_id,
1670 int64_t object_store_id,
1671 int64_t index_id,
1672 const IndexedDBKey& key,
1673 scoped_ptr<IndexedDBKey>* primary_key) {
1674 IDB_TRACE("IndexedDBBackingStore::get_primary_key_via_index");
1675 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
1676 return false;
1677
1678 bool found = false;
1679 std::vector<char> found_encoded_primary_key;
1680 bool ok = FindKeyInIndex(transaction,
1681 database_id,
1682 object_store_id,
1683 index_id,
1684 key,
1685 found_encoded_primary_key,
1686 found);
1687 if (!ok) {
1688 INTERNAL_READ_ERROR(kGetPrimaryKeyViaIndex);
1689 return false;
1690 }
1691 if (found) {
1692 DecodeIDBKey(&*found_encoded_primary_key.begin(),
1693 &*found_encoded_primary_key.end(),
1694 primary_key);
1695 return true;
1696 }
1697
1698 return true;
1699 }
1700
1701 bool IndexedDBBackingStore::KeyExistsInIndex(
1702 IndexedDBBackingStore::Transaction* transaction,
1703 int64_t database_id,
1704 int64_t object_store_id,
1705 int64_t index_id,
1706 const IndexedDBKey& index_key,
1707 scoped_ptr<IndexedDBKey>* found_primary_key,
1708 bool& exists) {
1709 IDB_TRACE("IndexedDBBackingStore::key_exists_in_index");
1710 if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
1711 return false;
1712
1713 exists = false;
1714 std::vector<char> found_encoded_primary_key;
1715 bool ok = FindKeyInIndex(transaction,
1716 database_id,
1717 object_store_id,
1718 index_id,
1719 index_key,
1720 found_encoded_primary_key,
1721 exists);
1722 if (!ok) {
1723 INTERNAL_READ_ERROR(kKeyExistsInIndex);
1724 return false;
1725 }
1726 if (!exists)
1727 return true;
1728
1729 DecodeIDBKey(&*found_encoded_primary_key.begin(),
1730 &*found_encoded_primary_key.end(),
1731 found_primary_key);
1732 return true;
1733 }
1734
1735 IndexedDBBackingStore::Cursor::Cursor(
1736 const IndexedDBBackingStore::Cursor* other)
1737 : transaction_(other->transaction_),
1738 cursor_options_(other->cursor_options_),
1739 current_key_(new IndexedDBKey(*other->current_key_)) {
1740 if (other->iterator_) {
1741 iterator_ = transaction_->CreateIterator();
1742
1743 if (other->iterator_->IsValid()) {
1744 iterator_->Seek(other->iterator_->Key());
1745 DCHECK(iterator_->IsValid());
1746 }
1747 }
1748 }
1749
1750 IndexedDBBackingStore::Cursor::Cursor(LevelDBTransaction* transaction,
1751 const CursorOptions& cursor_options)
1752 : transaction_(transaction), cursor_options_(cursor_options) {}
1753 IndexedDBBackingStore::Cursor::~Cursor() {}
1754
1755 bool IndexedDBBackingStore::Cursor::FirstSeek() {
1756 iterator_ = transaction_->CreateIterator();
1757 if (cursor_options_.forward)
1758 iterator_->Seek(LevelDBSlice(cursor_options_.low_key));
1759 else
1760 iterator_->Seek(LevelDBSlice(cursor_options_.high_key));
1761
1762 return ContinueFunction(0, Ready);
1763 }
1764
1765 bool IndexedDBBackingStore::Cursor::Advance(unsigned long count) {
1766 while (count--) {
1767 if (!ContinueFunction())
1768 return false;
1769 }
1770 return true;
1771 }
1772
1773 bool IndexedDBBackingStore::Cursor::ContinueFunction(const IndexedDBKey* key,
1774 IteratorState next_state) {
1775 // TODO(alecflett): avoid a copy here?
1776 IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey();
1777
1778 bool first_iteration = true;
1779
1780 // When iterating with PrevNoDuplicate, spec requires that the
1781 // value we yield for each key is the first duplicate in forwards
1782 // order.
1783 IndexedDBKey last_duplicate_key;
1784
1785 bool forward = cursor_options_.forward;
1786
1787 for (;;) {
1788 if (next_state == Seek) {
1789 // TODO: Optimize seeking for reverse cursors as well.
1790 if (first_iteration && key && key->IsValid() && forward) {
1791 iterator_->Seek(LevelDBSlice(EncodeKey(*key)));
1792 first_iteration = false;
1793 } else if (forward) {
1794 iterator_->Next();
1795 } else {
1796 iterator_->Prev();
1797 }
1798 } else {
1799 next_state = Seek; // for subsequent iterations
1800 }
1801
1802 if (!iterator_->IsValid()) {
1803 if (!forward && last_duplicate_key.IsValid()) {
1804 // We need to walk forward because we hit the end of
1805 // the data.
1806 forward = true;
1807 continue;
1808 }
1809
1810 return false;
1811 }
1812
1813 if (IsPastBounds()) {
1814 if (!forward && last_duplicate_key.IsValid()) {
1815 // We need to walk forward because now we're beyond the
1816 // bounds defined by the cursor.
1817 forward = true;
1818 continue;
1819 }
1820
1821 return false;
1822 }
1823
1824 if (!HaveEnteredRange())
1825 continue;
1826
1827 // The row may not load because there's a stale entry in the
1828 // index. This is not fatal.
1829 if (!LoadCurrentRow())
1830 continue;
1831
1832 if (key && key->IsValid()) {
1833 if (forward) {
1834 if (current_key_->IsLessThan(*key))
1835 continue;
1836 } else {
1837 if (key->IsLessThan(*current_key_))
1838 continue;
1839 }
1840 }
1841
1842 if (cursor_options_.unique) {
1843
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;
jamesr 2013/05/21 23:56:06 odd indentation here. if this is supposed to be a
jsbell 2013/05/22 17:54:44 clang-format. Unfortunately, if you move the 0; to
jsbell 2013/05/23 21:10:49 clang-format is still wrapping before the 0 which
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 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 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