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

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

Powered by Google App Engine
This is Rietveld 408576698