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

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

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

Powered by Google App Engine
This is Rietveld 408576698