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.
5 #include "content/browser/indexed_db/indexed_db_backing_store.h"
7 #include "base/file_util.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
13 #include "content/browser/indexed_db/indexed_db_metadata.h"
14 #include "content/browser/indexed_db/indexed_db_tracing.h"
15 #include "content/browser/indexed_db/indexed_db_value.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_transaction.h"
20 #include "content/common/indexed_db/indexed_db_key.h"
21 #include "content/common/indexed_db/indexed_db_key_path.h"
22 #include "content/common/indexed_db/indexed_db_key_range.h"
23 #include "third_party/WebKit/public/platform/WebIDBTypes.h"
24 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h"
25 #include "third_party/leveldatabase/env_chromium.h"
26 #include "webkit/common/database/database_identifier.h"
28 using base::StringPiece
;
34 static std::string
ComputeOriginIdentifier(const GURL
& origin_url
) {
35 return webkit_database::GetIdentifierFromOrigin(origin_url
) + "@1";
38 static base::FilePath
ComputeFileName(const GURL
& origin_url
) {
39 return base::FilePath()
40 .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url
))
41 .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb"));
46 static const int64 kKeyGeneratorInitialNumber
=
47 1; // From the IndexedDB specification.
49 enum IndexedDBBackingStoreErrorSource
{
50 // 0 - 2 are no longer used.
51 FIND_KEY_IN_INDEX
= 3,
52 GET_IDBDATABASE_METADATA
,
54 GET_KEY_GENERATOR_CURRENT_NUMBER
,
57 KEY_EXISTS_IN_OBJECT_STORE
,
60 GET_PRIMARY_KEY_VIA_INDEX
,
64 SET_MAX_OBJECT_STORE_ID
,
67 GET_NEW_VERSION_NUMBER
,
68 CREATE_IDBDATABASE_METADATA
,
70 TRANSACTION_COMMIT_METHOD
, // TRANSACTION_COMMIT is a WinNT.h macro
75 static void RecordInternalError(const char* type
,
76 IndexedDBBackingStoreErrorSource location
) {
78 name
.append("WebCore.IndexedDB.BackingStore.").append(type
).append("Error");
79 base::Histogram::FactoryGet(name
,
82 INTERNAL_ERROR_MAX
+ 1,
83 base::HistogramBase::kUmaTargetedHistogramFlag
)
87 // Use to signal conditions that usually indicate developer error, but
88 // could be caused by data corruption. A macro is used instead of an
89 // inline function so that the assert and log report the line number.
90 #define REPORT_ERROR(type, location) \
92 LOG(ERROR) << "IndexedDB " type " Error: " #location; \
94 RecordInternalError(type, location); \
97 #define INTERNAL_READ_ERROR(location) REPORT_ERROR("Read", location)
98 #define INTERNAL_CONSISTENCY_ERROR(location) \
99 REPORT_ERROR("Consistency", location)
100 #define INTERNAL_WRITE_ERROR(location) REPORT_ERROR("Write", location)
102 static void PutBool(LevelDBTransaction
* transaction
,
103 const StringPiece
& key
,
106 EncodeBool(value
, &buffer
);
107 transaction
->Put(key
, &buffer
);
110 // Was able to use LevelDB to read the data w/o error, but the data read was not
111 // in the expected format.
112 static leveldb::Status
InternalInconsistencyStatus() {
113 return leveldb::Status::Corruption("Internal inconsistency");
116 static leveldb::Status
InvalidDBKeyStatus() {
117 return leveldb::Status::InvalidArgument("Invalid database key ID");
120 template <typename DBOrTransaction
>
121 static leveldb::Status
GetInt(DBOrTransaction
* db
,
122 const StringPiece
& key
,
126 leveldb::Status s
= db
->Get(key
, &result
, found
);
130 return leveldb::Status::OK();
131 StringPiece
slice(result
);
132 if (DecodeInt(&slice
, found_int
) && slice
.empty())
134 return InternalInconsistencyStatus();
137 static void PutInt(LevelDBTransaction
* transaction
,
138 const StringPiece
& key
,
142 EncodeInt(value
, &buffer
);
143 transaction
->Put(key
, &buffer
);
146 template <typename DBOrTransaction
>
147 WARN_UNUSED_RESULT
static leveldb::Status
GetVarInt(DBOrTransaction
* db
,
148 const StringPiece
& key
,
152 leveldb::Status s
= db
->Get(key
, &result
, found
);
156 return leveldb::Status::OK();
157 StringPiece
slice(result
);
158 if (DecodeVarInt(&slice
, found_int
) && slice
.empty())
160 return InternalInconsistencyStatus();
163 static void PutVarInt(LevelDBTransaction
* transaction
,
164 const StringPiece
& key
,
167 EncodeVarInt(value
, &buffer
);
168 transaction
->Put(key
, &buffer
);
171 template <typename DBOrTransaction
>
172 WARN_UNUSED_RESULT
static leveldb::Status
GetString(
174 const StringPiece
& key
,
175 base::string16
* found_string
,
179 leveldb::Status s
= db
->Get(key
, &result
, found
);
183 return leveldb::Status::OK();
184 StringPiece
slice(result
);
185 if (DecodeString(&slice
, found_string
) && slice
.empty())
187 return InternalInconsistencyStatus();
190 static void PutString(LevelDBTransaction
* transaction
,
191 const StringPiece
& key
,
192 const base::string16
& value
) {
194 EncodeString(value
, &buffer
);
195 transaction
->Put(key
, &buffer
);
198 static void PutIDBKeyPath(LevelDBTransaction
* transaction
,
199 const StringPiece
& key
,
200 const IndexedDBKeyPath
& value
) {
202 EncodeIDBKeyPath(value
, &buffer
);
203 transaction
->Put(key
, &buffer
);
206 static int CompareKeys(const StringPiece
& a
, const StringPiece
& b
) {
207 return Compare(a
, b
, false /*index_keys*/);
210 static int CompareIndexKeys(const StringPiece
& a
, const StringPiece
& b
) {
211 return Compare(a
, b
, true /*index_keys*/);
214 int IndexedDBBackingStore::Comparator::Compare(const StringPiece
& a
,
215 const StringPiece
& b
) const {
216 return content::Compare(a
, b
, false /*index_keys*/);
219 const char* IndexedDBBackingStore::Comparator::Name() const {
223 // 0 - Initial version.
224 // 1 - Adds UserIntVersion to DatabaseMetaData.
225 // 2 - Adds DataVersion to to global metadata.
226 static const int64 kLatestKnownSchemaVersion
= 2;
227 WARN_UNUSED_RESULT
static bool IsSchemaKnown(LevelDBDatabase
* db
, bool* known
) {
228 int64 db_schema_version
= 0;
231 GetInt(db
, SchemaVersionKey::Encode(), &db_schema_version
, &found
);
238 if (db_schema_version
> kLatestKnownSchemaVersion
) {
243 const uint32 latest_known_data_version
=
244 blink::kSerializedScriptValueVersion
;
245 int64 db_data_version
= 0;
246 s
= GetInt(db
, DataVersionKey::Encode(), &db_data_version
, &found
);
254 if (db_data_version
> latest_known_data_version
) {
263 WARN_UNUSED_RESULT
static bool SetUpMetadata(
265 const std::string
& origin_identifier
) {
266 const uint32 latest_known_data_version
=
267 blink::kSerializedScriptValueVersion
;
268 const std::string schema_version_key
= SchemaVersionKey::Encode();
269 const std::string data_version_key
= DataVersionKey::Encode();
271 scoped_refptr
<LevelDBTransaction
> transaction
= new LevelDBTransaction(db
);
273 int64 db_schema_version
= 0;
274 int64 db_data_version
= 0;
277 GetInt(transaction
.get(), schema_version_key
, &db_schema_version
, &found
);
279 INTERNAL_READ_ERROR(SET_UP_METADATA
);
283 // Initialize new backing store.
284 db_schema_version
= kLatestKnownSchemaVersion
;
285 PutInt(transaction
.get(), schema_version_key
, db_schema_version
);
286 db_data_version
= latest_known_data_version
;
287 PutInt(transaction
.get(), data_version_key
, db_data_version
);
289 // Upgrade old backing store.
290 DCHECK_LE(db_schema_version
, kLatestKnownSchemaVersion
);
291 if (db_schema_version
< 1) {
292 db_schema_version
= 1;
293 PutInt(transaction
.get(), schema_version_key
, db_schema_version
);
294 const std::string start_key
=
295 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier
);
296 const std::string stop_key
=
297 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier
);
298 scoped_ptr
<LevelDBIterator
> it
= db
->CreateIterator();
299 for (it
->Seek(start_key
);
300 it
->IsValid() && CompareKeys(it
->Key(), stop_key
) < 0;
302 int64 database_id
= 0;
304 s
= GetInt(transaction
.get(), it
->Key(), &database_id
, &found
);
306 INTERNAL_READ_ERROR(SET_UP_METADATA
);
310 INTERNAL_CONSISTENCY_ERROR(SET_UP_METADATA
);
313 std::string int_version_key
= DatabaseMetaDataKey::Encode(
314 database_id
, DatabaseMetaDataKey::USER_INT_VERSION
);
315 PutVarInt(transaction
.get(),
317 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
);
320 if (db_schema_version
< 2) {
321 db_schema_version
= 2;
322 PutInt(transaction
.get(), schema_version_key
, db_schema_version
);
323 db_data_version
= blink::kSerializedScriptValueVersion
;
324 PutInt(transaction
.get(), data_version_key
, db_data_version
);
328 // All new values will be written using this serialization version.
330 s
= GetInt(transaction
.get(), data_version_key
, &db_data_version
, &found
);
332 INTERNAL_READ_ERROR(SET_UP_METADATA
);
336 INTERNAL_CONSISTENCY_ERROR(SET_UP_METADATA
);
339 if (db_data_version
< latest_known_data_version
) {
340 db_data_version
= latest_known_data_version
;
341 PutInt(transaction
.get(), data_version_key
, db_data_version
);
344 DCHECK_EQ(db_schema_version
, kLatestKnownSchemaVersion
);
345 DCHECK_EQ(db_data_version
, latest_known_data_version
);
347 s
= transaction
->Commit();
349 INTERNAL_WRITE_ERROR(SET_UP_METADATA
);
355 template <typename DBOrTransaction
>
356 WARN_UNUSED_RESULT
static leveldb::Status
GetMaxObjectStoreId(
359 int64
* max_object_store_id
) {
360 const std::string max_object_store_id_key
= DatabaseMetaDataKey::Encode(
361 database_id
, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID
);
362 return GetMaxObjectStoreId(db
, max_object_store_id_key
, max_object_store_id
);
365 template <typename DBOrTransaction
>
366 WARN_UNUSED_RESULT
static leveldb::Status
GetMaxObjectStoreId(
368 const std::string
& max_object_store_id_key
,
369 int64
* max_object_store_id
) {
370 *max_object_store_id
= -1;
373 GetInt(db
, max_object_store_id_key
, max_object_store_id
, &found
);
377 *max_object_store_id
= 0;
379 DCHECK_GE(*max_object_store_id
, 0);
383 class DefaultLevelDBFactory
: public LevelDBFactory
{
385 virtual leveldb::Status
OpenLevelDB(const base::FilePath
& file_name
,
386 const LevelDBComparator
* comparator
,
387 scoped_ptr
<LevelDBDatabase
>* db
,
388 bool* is_disk_full
) OVERRIDE
{
389 return LevelDBDatabase::Open(file_name
, comparator
, db
, is_disk_full
);
391 virtual leveldb::Status
DestroyLevelDB(const base::FilePath
& file_name
)
393 return LevelDBDatabase::Destroy(file_name
);
397 IndexedDBBackingStore::IndexedDBBackingStore(
398 const GURL
& origin_url
,
399 scoped_ptr
<LevelDBDatabase
> db
,
400 scoped_ptr
<LevelDBComparator
> comparator
)
401 : origin_url_(origin_url
),
402 origin_identifier_(ComputeOriginIdentifier(origin_url
)),
404 comparator_(comparator
.Pass()) {}
406 IndexedDBBackingStore::~IndexedDBBackingStore() {
407 // db_'s destructor uses comparator_. The order of destruction is important.
412 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier(
413 const std::string
& primary_key
,
415 : primary_key_(primary_key
), version_(version
) {
416 DCHECK(!primary_key
.empty());
418 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier()
419 : primary_key_(), version_(-1) {}
420 IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() {}
422 IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() {}
423 IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() {}
425 enum IndexedDBBackingStoreOpenResult
{
426 INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS
,
427 INDEXED_DB_BACKING_STORE_OPEN_SUCCESS
,
428 INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY
,
429 INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA
,
430 INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED
,
431 INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED
,
432 INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS
,
433 INDEXED_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA
,
434 INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR
,
435 INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED
,
436 INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII
,
437 INDEXED_DB_BACKING_STORE_OPEN_DISK_FULL_DEPRECATED
,
438 INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG
,
439 INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY
,
440 INDEXED_DB_BACKING_STORE_OPEN_MAX
,
444 scoped_refptr
<IndexedDBBackingStore
> IndexedDBBackingStore::Open(
445 const GURL
& origin_url
,
446 const base::FilePath
& path_base
,
447 blink::WebIDBDataLoss
* data_loss
,
448 std::string
* data_loss_message
,
450 *data_loss
= blink::WebIDBDataLossNone
;
451 DefaultLevelDBFactory leveldb_factory
;
452 return IndexedDBBackingStore::Open(origin_url
,
460 static std::string
OriginToCustomHistogramSuffix(const GURL
& origin_url
) {
461 if (origin_url
.host() == "docs.google.com")
463 return std::string();
466 static void HistogramOpenStatus(IndexedDBBackingStoreOpenResult result
,
467 const GURL
& origin_url
) {
468 UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.BackingStore.OpenStatus",
470 INDEXED_DB_BACKING_STORE_OPEN_MAX
);
471 const std::string suffix
= OriginToCustomHistogramSuffix(origin_url
);
472 // Data from the WebCore.IndexedDB.BackingStore.OpenStatus histogram is used
473 // to generate a graph. So as not to alter the meaning of that graph,
474 // continue to collect all stats there (above) but also now collect docs stats
475 // separately (below).
476 if (!suffix
.empty()) {
477 base::LinearHistogram::FactoryGet(
478 "WebCore.IndexedDB.BackingStore.OpenStatus" + suffix
,
480 INDEXED_DB_BACKING_STORE_OPEN_MAX
,
481 INDEXED_DB_BACKING_STORE_OPEN_MAX
+ 1,
482 base::HistogramBase::kUmaTargetedHistogramFlag
)->Add(result
);
486 static bool IsPathTooLong(const base::FilePath
& leveldb_dir
) {
487 int limit
= base::GetMaximumPathComponentLength(leveldb_dir
.DirName());
489 DLOG(WARNING
) << "GetMaximumPathComponentLength returned -1";
490 // In limited testing, ChromeOS returns 143, other OSes 255.
491 #if defined(OS_CHROMEOS)
497 size_t component_length
= leveldb_dir
.BaseName().value().length();
498 if (component_length
> static_cast<uint32_t>(limit
)) {
499 DLOG(WARNING
) << "Path component length (" << component_length
500 << ") exceeds maximum (" << limit
501 << ") allowed by this filesystem.";
504 const int num_buckets
= 12;
505 UMA_HISTOGRAM_CUSTOM_COUNTS(
506 "WebCore.IndexedDB.BackingStore.OverlyLargeOriginLength",
517 scoped_refptr
<IndexedDBBackingStore
> IndexedDBBackingStore::Open(
518 const GURL
& origin_url
,
519 const base::FilePath
& path_base
,
520 blink::WebIDBDataLoss
* data_loss
,
521 std::string
* data_loss_message
,
523 LevelDBFactory
* leveldb_factory
) {
524 IDB_TRACE("IndexedDBBackingStore::Open");
525 DCHECK(!path_base
.empty());
526 *data_loss
= blink::WebIDBDataLossNone
;
527 *data_loss_message
= "";
528 *is_disk_full
= false;
530 scoped_ptr
<LevelDBComparator
> comparator(new Comparator());
532 if (!IsStringASCII(path_base
.AsUTF8Unsafe())) {
533 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII
,
536 if (!base::CreateDirectory(path_base
)) {
537 LOG(ERROR
) << "Unable to create IndexedDB database path "
538 << path_base
.AsUTF8Unsafe();
539 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY
,
541 return scoped_refptr
<IndexedDBBackingStore
>();
544 const base::FilePath file_path
=
545 path_base
.Append(ComputeFileName(origin_url
));
547 if (IsPathTooLong(file_path
)) {
548 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG
,
550 return scoped_refptr
<IndexedDBBackingStore
>();
553 scoped_ptr
<LevelDBDatabase
> db
;
554 leveldb::Status status
= leveldb_factory
->OpenLevelDB(
555 file_path
, comparator
.get(), &db
, is_disk_full
);
557 DCHECK(!db
== !status
.ok());
559 if (leveldb_env::IndicatesDiskFull(status
)) {
560 *is_disk_full
= true;
561 } else if (leveldb_env::IsCorruption(status
)) {
562 *data_loss
= blink::WebIDBDataLossTotal
;
563 *data_loss_message
= leveldb_env::GetCorruptionMessage(status
);
567 bool is_schema_known
= false;
569 bool ok
= IsSchemaKnown(db
.get(), &is_schema_known
);
571 LOG(ERROR
) << "IndexedDB had IO error checking schema, treating it as "
574 INDEXED_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA
,
577 *data_loss
= blink::WebIDBDataLossTotal
;
578 *data_loss_message
= "I/O error checking schema";
579 } else if (!is_schema_known
) {
580 LOG(ERROR
) << "IndexedDB backing store had unknown schema, treating it "
581 "as failure to open";
582 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA
,
585 *data_loss
= blink::WebIDBDataLossTotal
;
586 *data_loss_message
= "Unknown schema";
590 DCHECK(status
.ok() || !is_schema_known
|| leveldb_env::IsIOError(status
) ||
591 leveldb_env::IsCorruption(status
));
594 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_SUCCESS
, origin_url
);
595 } else if (leveldb_env::IsIOError(status
)) {
596 LOG(ERROR
) << "Unable to open backing store, not trying to recover - "
597 << status
.ToString();
598 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY
, origin_url
);
599 return scoped_refptr
<IndexedDBBackingStore
>();
601 DCHECK(!is_schema_known
|| leveldb_env::IsCorruption(status
));
602 LOG(ERROR
) << "IndexedDB backing store open failed, attempting cleanup";
603 status
= leveldb_factory
->DestroyLevelDB(file_path
);
605 LOG(ERROR
) << "IndexedDB backing store cleanup failed";
606 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED
,
608 return scoped_refptr
<IndexedDBBackingStore
>();
611 LOG(ERROR
) << "IndexedDB backing store cleanup succeeded, reopening";
612 leveldb_factory
->OpenLevelDB(file_path
, comparator
.get(), &db
, NULL
);
614 LOG(ERROR
) << "IndexedDB backing store reopen after recovery failed";
615 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED
,
617 return scoped_refptr
<IndexedDBBackingStore
>();
619 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS
,
625 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR
,
627 return scoped_refptr
<IndexedDBBackingStore
>();
630 return Create(origin_url
, db
.Pass(), comparator
.Pass());
634 scoped_refptr
<IndexedDBBackingStore
> IndexedDBBackingStore::OpenInMemory(
635 const GURL
& origin_url
) {
636 DefaultLevelDBFactory leveldb_factory
;
637 return IndexedDBBackingStore::OpenInMemory(origin_url
, &leveldb_factory
);
641 scoped_refptr
<IndexedDBBackingStore
> IndexedDBBackingStore::OpenInMemory(
642 const GURL
& origin_url
,
643 LevelDBFactory
* leveldb_factory
) {
644 IDB_TRACE("IndexedDBBackingStore::OpenInMemory");
646 scoped_ptr
<LevelDBComparator
> comparator(new Comparator());
647 scoped_ptr
<LevelDBDatabase
> db
=
648 LevelDBDatabase::OpenInMemory(comparator
.get());
650 LOG(ERROR
) << "LevelDBDatabase::OpenInMemory failed.";
651 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED
,
653 return scoped_refptr
<IndexedDBBackingStore
>();
655 HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS
, origin_url
);
657 return Create(origin_url
, db
.Pass(), comparator
.Pass());
661 scoped_refptr
<IndexedDBBackingStore
> IndexedDBBackingStore::Create(
662 const GURL
& origin_url
,
663 scoped_ptr
<LevelDBDatabase
> db
,
664 scoped_ptr
<LevelDBComparator
> comparator
) {
665 // TODO(jsbell): Handle comparator name changes.
667 scoped_refptr
<IndexedDBBackingStore
> backing_store(
668 new IndexedDBBackingStore(origin_url
, db
.Pass(), comparator
.Pass()));
669 if (!SetUpMetadata(backing_store
->db_
.get(),
670 backing_store
->origin_identifier_
))
671 return scoped_refptr
<IndexedDBBackingStore
>();
673 return backing_store
;
676 std::vector
<base::string16
> IndexedDBBackingStore::GetDatabaseNames() {
677 std::vector
<base::string16
> found_names
;
678 const std::string start_key
=
679 DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_
);
680 const std::string stop_key
=
681 DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_
);
683 DCHECK(found_names
.empty());
685 scoped_ptr
<LevelDBIterator
> it
= db_
->CreateIterator();
686 for (it
->Seek(start_key
);
687 it
->IsValid() && CompareKeys(it
->Key(), stop_key
) < 0;
689 StringPiece
slice(it
->Key());
690 DatabaseNameKey database_name_key
;
691 if (!DatabaseNameKey::Decode(&slice
, &database_name_key
)) {
692 INTERNAL_CONSISTENCY_ERROR(GET_DATABASE_NAMES
);
695 found_names
.push_back(database_name_key
.database_name());
700 leveldb::Status
IndexedDBBackingStore::GetIDBDatabaseMetaData(
701 const base::string16
& name
,
702 IndexedDBDatabaseMetadata
* metadata
,
704 const std::string key
= DatabaseNameKey::Encode(origin_identifier_
, name
);
707 leveldb::Status s
= GetInt(db_
.get(), key
, &metadata
->id
, found
);
709 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA
);
713 return leveldb::Status::OK();
715 s
= GetString(db_
.get(),
716 DatabaseMetaDataKey::Encode(metadata
->id
,
717 DatabaseMetaDataKey::USER_VERSION
),
721 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA
);
725 INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA
);
726 return InternalInconsistencyStatus();
729 s
= GetVarInt(db_
.get(),
730 DatabaseMetaDataKey::Encode(
731 metadata
->id
, DatabaseMetaDataKey::USER_INT_VERSION
),
732 &metadata
->int_version
,
735 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA
);
739 INTERNAL_CONSISTENCY_ERROR(GET_IDBDATABASE_METADATA
);
740 return InternalInconsistencyStatus();
743 if (metadata
->int_version
== IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
)
744 metadata
->int_version
= IndexedDBDatabaseMetadata::NO_INT_VERSION
;
746 s
= GetMaxObjectStoreId(
747 db_
.get(), metadata
->id
, &metadata
->max_object_store_id
);
749 INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA
);
755 WARN_UNUSED_RESULT
static leveldb::Status
GetNewDatabaseId(
756 LevelDBTransaction
* transaction
,
759 int64 max_database_id
= -1;
762 GetInt(transaction
, MaxDatabaseIdKey::Encode(), &max_database_id
, &found
);
764 INTERNAL_READ_ERROR(GET_NEW_DATABASE_ID
);
770 DCHECK_GE(max_database_id
, 0);
772 int64 database_id
= max_database_id
+ 1;
773 PutInt(transaction
, MaxDatabaseIdKey::Encode(), database_id
);
774 *new_id
= database_id
;
775 return leveldb::Status::OK();
778 leveldb::Status
IndexedDBBackingStore::CreateIDBDatabaseMetaData(
779 const base::string16
& name
,
780 const base::string16
& version
,
783 scoped_refptr
<LevelDBTransaction
> transaction
=
784 new LevelDBTransaction(db_
.get());
786 leveldb::Status s
= GetNewDatabaseId(transaction
.get(), row_id
);
789 DCHECK_GE(*row_id
, 0);
791 if (int_version
== IndexedDBDatabaseMetadata::NO_INT_VERSION
)
792 int_version
= IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
;
794 PutInt(transaction
.get(),
795 DatabaseNameKey::Encode(origin_identifier_
, name
),
799 DatabaseMetaDataKey::Encode(*row_id
, DatabaseMetaDataKey::USER_VERSION
),
801 PutVarInt(transaction
.get(),
802 DatabaseMetaDataKey::Encode(*row_id
,
803 DatabaseMetaDataKey::USER_INT_VERSION
),
805 s
= transaction
->Commit();
807 INTERNAL_WRITE_ERROR(CREATE_IDBDATABASE_METADATA
);
811 bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion(
812 IndexedDBBackingStore::Transaction
* transaction
,
815 if (int_version
== IndexedDBDatabaseMetadata::NO_INT_VERSION
)
816 int_version
= IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
;
817 DCHECK_GE(int_version
, 0) << "int_version was " << int_version
;
818 PutVarInt(transaction
->transaction(),
819 DatabaseMetaDataKey::Encode(row_id
,
820 DatabaseMetaDataKey::USER_INT_VERSION
),
825 static void DeleteRange(LevelDBTransaction
* transaction
,
826 const std::string
& begin
,
827 const std::string
& end
) {
828 scoped_ptr
<LevelDBIterator
> it
= transaction
->CreateIterator();
829 for (it
->Seek(begin
); it
->IsValid() && CompareKeys(it
->Key(), end
) < 0;
831 transaction
->Remove(it
->Key());
834 leveldb::Status
IndexedDBBackingStore::DeleteDatabase(
835 const base::string16
& name
) {
836 IDB_TRACE("IndexedDBBackingStore::DeleteDatabase");
837 scoped_ptr
<LevelDBDirectTransaction
> transaction
=
838 LevelDBDirectTransaction::Create(db_
.get());
840 IndexedDBDatabaseMetadata metadata
;
841 bool success
= false;
842 leveldb::Status s
= GetIDBDatabaseMetaData(name
, &metadata
, &success
);
846 return leveldb::Status::OK();
848 const std::string start_key
= DatabaseMetaDataKey::Encode(
849 metadata
.id
, DatabaseMetaDataKey::ORIGIN_NAME
);
850 const std::string stop_key
= DatabaseMetaDataKey::Encode(
851 metadata
.id
+ 1, DatabaseMetaDataKey::ORIGIN_NAME
);
852 scoped_ptr
<LevelDBIterator
> it
= db_
->CreateIterator();
853 for (it
->Seek(start_key
);
854 it
->IsValid() && CompareKeys(it
->Key(), stop_key
) < 0;
856 transaction
->Remove(it
->Key());
858 const std::string key
= DatabaseNameKey::Encode(origin_identifier_
, name
);
859 transaction
->Remove(key
);
861 s
= transaction
->Commit();
863 INTERNAL_WRITE_ERROR(DELETE_DATABASE
);
866 db_
->Compact(start_key
, stop_key
);
870 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator
* it
,
871 const std::string
& stop_key
,
872 int64 object_store_id
,
873 int64 meta_data_type
) {
874 if (!it
->IsValid() || CompareKeys(it
->Key(), stop_key
) >= 0)
877 StringPiece
slice(it
->Key());
878 ObjectStoreMetaDataKey meta_data_key
;
879 bool ok
= ObjectStoreMetaDataKey::Decode(&slice
, &meta_data_key
);
881 if (meta_data_key
.ObjectStoreId() != object_store_id
)
883 if (meta_data_key
.MetaDataType() != meta_data_type
)
888 // TODO(jsbell): This should do some error handling rather than
889 // plowing ahead when bad data is encountered.
890 leveldb::Status
IndexedDBBackingStore::GetObjectStores(
892 IndexedDBDatabaseMetadata::ObjectStoreMap
* object_stores
) {
893 IDB_TRACE("IndexedDBBackingStore::GetObjectStores");
894 if (!KeyPrefix::IsValidDatabaseId(database_id
))
895 return InvalidDBKeyStatus();
896 const std::string start_key
=
897 ObjectStoreMetaDataKey::Encode(database_id
, 1, 0);
898 const std::string stop_key
=
899 ObjectStoreMetaDataKey::EncodeMaxKey(database_id
);
901 DCHECK(object_stores
->empty());
903 scoped_ptr
<LevelDBIterator
> it
= db_
->CreateIterator();
905 while (it
->IsValid() && CompareKeys(it
->Key(), stop_key
) < 0) {
906 StringPiece
slice(it
->Key());
907 ObjectStoreMetaDataKey meta_data_key
;
908 bool ok
= ObjectStoreMetaDataKey::Decode(&slice
, &meta_data_key
);
910 if (meta_data_key
.MetaDataType() != ObjectStoreMetaDataKey::NAME
) {
911 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES
);
912 // Possible stale metadata, but don't fail the load.
917 int64 object_store_id
= meta_data_key
.ObjectStoreId();
919 // TODO(jsbell): Do this by direct key lookup rather than iteration, to
921 base::string16 object_store_name
;
923 StringPiece
slice(it
->Value());
924 if (!DecodeString(&slice
, &object_store_name
) || !slice
.empty())
925 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES
);
929 if (!CheckObjectStoreAndMetaDataType(it
.get(),
932 ObjectStoreMetaDataKey::KEY_PATH
)) {
933 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES
);
936 IndexedDBKeyPath key_path
;
938 StringPiece
slice(it
->Value());
939 if (!DecodeIDBKeyPath(&slice
, &key_path
) || !slice
.empty())
940 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES
);
944 if (!CheckObjectStoreAndMetaDataType(
948 ObjectStoreMetaDataKey::AUTO_INCREMENT
)) {
949 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES
);
954 StringPiece
slice(it
->Value());
955 if (!DecodeBool(&slice
, &auto_increment
) || !slice
.empty())
956 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES
);
959 it
->Next(); // Is evicatble.
960 if (!CheckObjectStoreAndMetaDataType(it
.get(),
963 ObjectStoreMetaDataKey::EVICTABLE
)) {
964 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES
);
968 it
->Next(); // Last version.
969 if (!CheckObjectStoreAndMetaDataType(
973 ObjectStoreMetaDataKey::LAST_VERSION
)) {
974 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES
);
978 it
->Next(); // Maximum index id allocated.
979 if (!CheckObjectStoreAndMetaDataType(
983 ObjectStoreMetaDataKey::MAX_INDEX_ID
)) {
984 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES
);
989 StringPiece
slice(it
->Value());
990 if (!DecodeInt(&slice
, &max_index_id
) || !slice
.empty())
991 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES
);
994 it
->Next(); // [optional] has key path (is not null)
995 if (CheckObjectStoreAndMetaDataType(it
.get(),
998 ObjectStoreMetaDataKey::HAS_KEY_PATH
)) {
1001 StringPiece
slice(it
->Value());
1002 if (!DecodeBool(&slice
, &has_key_path
))
1003 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES
);
1005 // This check accounts for two layers of legacy coding:
1006 // (1) Initially, has_key_path was added to distinguish null vs. string.
1007 // (2) Later, null vs. string vs. array was stored in the key_path itself.
1008 // So this check is only relevant for string-type key_paths.
1009 if (!has_key_path
&&
1010 (key_path
.type() == blink::WebIDBKeyPathTypeString
&&
1011 !key_path
.string().empty())) {
1012 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES
);
1016 key_path
= IndexedDBKeyPath();
1020 int64 key_generator_current_number
= -1;
1021 if (CheckObjectStoreAndMetaDataType(
1025 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER
)) {
1026 StringPiece
slice(it
->Value());
1027 if (!DecodeInt(&slice
, &key_generator_current_number
) || !slice
.empty())
1028 INTERNAL_CONSISTENCY_ERROR(GET_OBJECT_STORES
);
1030 // TODO(jsbell): Return key_generator_current_number, cache in
1031 // object store, and write lazily to backing store. For now,
1032 // just assert that if it was written it was valid.
1033 DCHECK_GE(key_generator_current_number
, kKeyGeneratorInitialNumber
);
1037 IndexedDBObjectStoreMetadata
metadata(object_store_name
,
1043 GetIndexes(database_id
, object_store_id
, &metadata
.indexes
);
1046 (*object_stores
)[object_store_id
] = metadata
;
1048 return leveldb::Status::OK();
1051 WARN_UNUSED_RESULT
static leveldb::Status
SetMaxObjectStoreId(
1052 LevelDBTransaction
* transaction
,
1054 int64 object_store_id
) {
1055 const std::string max_object_store_id_key
= DatabaseMetaDataKey::Encode(
1056 database_id
, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID
);
1057 int64 max_object_store_id
= -1;
1058 leveldb::Status s
= GetMaxObjectStoreId(
1059 transaction
, max_object_store_id_key
, &max_object_store_id
);
1061 INTERNAL_READ_ERROR(SET_MAX_OBJECT_STORE_ID
);
1065 if (object_store_id
<= max_object_store_id
) {
1066 INTERNAL_CONSISTENCY_ERROR(SET_MAX_OBJECT_STORE_ID
);
1067 return InternalInconsistencyStatus();
1069 PutInt(transaction
, max_object_store_id_key
, object_store_id
);
1073 leveldb::Status
IndexedDBBackingStore::CreateObjectStore(
1074 IndexedDBBackingStore::Transaction
* transaction
,
1076 int64 object_store_id
,
1077 const base::string16
& name
,
1078 const IndexedDBKeyPath
& key_path
,
1079 bool auto_increment
) {
1080 IDB_TRACE("IndexedDBBackingStore::CreateObjectStore");
1081 if (!KeyPrefix::ValidIds(database_id
, object_store_id
))
1082 return InvalidDBKeyStatus();
1083 LevelDBTransaction
* leveldb_transaction
= transaction
->transaction();
1085 SetMaxObjectStoreId(leveldb_transaction
, database_id
, object_store_id
);
1089 const std::string name_key
= ObjectStoreMetaDataKey::Encode(
1090 database_id
, object_store_id
, ObjectStoreMetaDataKey::NAME
);
1091 const std::string key_path_key
= ObjectStoreMetaDataKey::Encode(
1092 database_id
, object_store_id
, ObjectStoreMetaDataKey::KEY_PATH
);
1093 const std::string auto_increment_key
= ObjectStoreMetaDataKey::Encode(
1094 database_id
, object_store_id
, ObjectStoreMetaDataKey::AUTO_INCREMENT
);
1095 const std::string evictable_key
= ObjectStoreMetaDataKey::Encode(
1096 database_id
, object_store_id
, ObjectStoreMetaDataKey::EVICTABLE
);
1097 const std::string last_version_key
= ObjectStoreMetaDataKey::Encode(
1098 database_id
, object_store_id
, ObjectStoreMetaDataKey::LAST_VERSION
);
1099 const std::string max_index_id_key
= ObjectStoreMetaDataKey::Encode(
1100 database_id
, object_store_id
, ObjectStoreMetaDataKey::MAX_INDEX_ID
);
1101 const std::string has_key_path_key
= ObjectStoreMetaDataKey::Encode(
1102 database_id
, object_store_id
, ObjectStoreMetaDataKey::HAS_KEY_PATH
);
1103 const std::string key_generator_current_number_key
=
1104 ObjectStoreMetaDataKey::Encode(
1107 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER
);
1108 const std::string names_key
= ObjectStoreNamesKey::Encode(database_id
, name
);
1110 PutString(leveldb_transaction
, name_key
, name
);
1111 PutIDBKeyPath(leveldb_transaction
, key_path_key
, key_path
);
1112 PutInt(leveldb_transaction
, auto_increment_key
, auto_increment
);
1113 PutInt(leveldb_transaction
, evictable_key
, false);
1114 PutInt(leveldb_transaction
, last_version_key
, 1);
1115 PutInt(leveldb_transaction
, max_index_id_key
, kMinimumIndexId
);
1116 PutBool(leveldb_transaction
, has_key_path_key
, !key_path
.IsNull());
1117 PutInt(leveldb_transaction
,
1118 key_generator_current_number_key
,
1119 kKeyGeneratorInitialNumber
);
1120 PutInt(leveldb_transaction
, names_key
, object_store_id
);
1124 leveldb::Status
IndexedDBBackingStore::DeleteObjectStore(
1125 IndexedDBBackingStore::Transaction
* transaction
,
1127 int64 object_store_id
) {
1128 IDB_TRACE("IndexedDBBackingStore::DeleteObjectStore");
1129 if (!KeyPrefix::ValidIds(database_id
, object_store_id
))
1130 return InvalidDBKeyStatus();
1131 LevelDBTransaction
* leveldb_transaction
= transaction
->transaction();
1133 base::string16 object_store_name
;
1136 GetString(leveldb_transaction
,
1137 ObjectStoreMetaDataKey::Encode(
1138 database_id
, object_store_id
, ObjectStoreMetaDataKey::NAME
),
1142 INTERNAL_READ_ERROR(DELETE_OBJECT_STORE
);
1146 INTERNAL_CONSISTENCY_ERROR(DELETE_OBJECT_STORE
);
1147 return InternalInconsistencyStatus();
1151 leveldb_transaction
,
1152 ObjectStoreMetaDataKey::Encode(database_id
, object_store_id
, 0),
1153 ObjectStoreMetaDataKey::EncodeMaxKey(database_id
, object_store_id
));
1155 leveldb_transaction
->Remove(
1156 ObjectStoreNamesKey::Encode(database_id
, object_store_name
));
1158 DeleteRange(leveldb_transaction
,
1159 IndexFreeListKey::Encode(database_id
, object_store_id
, 0),
1160 IndexFreeListKey::EncodeMaxKey(database_id
, object_store_id
));
1161 DeleteRange(leveldb_transaction
,
1162 IndexMetaDataKey::Encode(database_id
, object_store_id
, 0, 0),
1163 IndexMetaDataKey::EncodeMaxKey(database_id
, object_store_id
));
1165 return ClearObjectStore(transaction
, database_id
, object_store_id
);
1168 leveldb::Status
IndexedDBBackingStore::GetRecord(
1169 IndexedDBBackingStore::Transaction
* transaction
,
1171 int64 object_store_id
,
1172 const IndexedDBKey
& key
,
1173 IndexedDBValue
* record
) {
1174 IDB_TRACE("IndexedDBBackingStore::GetRecord");
1175 if (!KeyPrefix::ValidIds(database_id
, object_store_id
))
1176 return InvalidDBKeyStatus();
1177 LevelDBTransaction
* leveldb_transaction
= transaction
->transaction();
1179 const std::string leveldb_key
=
1180 ObjectStoreDataKey::Encode(database_id
, object_store_id
, key
);
1186 leveldb::Status s
= leveldb_transaction
->Get(leveldb_key
, &data
, &found
);
1188 INTERNAL_READ_ERROR(GET_RECORD
);
1194 INTERNAL_READ_ERROR(GET_RECORD
);
1195 return leveldb::Status::NotFound("Record contained no data");
1199 StringPiece
slice(data
);
1200 if (!DecodeVarInt(&slice
, &version
)) {
1201 INTERNAL_READ_ERROR(GET_RECORD
);
1202 return InternalInconsistencyStatus();
1205 record
->bits
= slice
.as_string();
1209 WARN_UNUSED_RESULT
static leveldb::Status
GetNewVersionNumber(
1210 LevelDBTransaction
* transaction
,
1212 int64 object_store_id
,
1213 int64
* new_version_number
) {
1214 const std::string last_version_key
= ObjectStoreMetaDataKey::Encode(
1215 database_id
, object_store_id
, ObjectStoreMetaDataKey::LAST_VERSION
);
1217 *new_version_number
= -1;
1218 int64 last_version
= -1;
1221 GetInt(transaction
, last_version_key
, &last_version
, &found
);
1223 INTERNAL_READ_ERROR(GET_NEW_VERSION_NUMBER
);
1229 DCHECK_GE(last_version
, 0);
1231 int64 version
= last_version
+ 1;
1232 PutInt(transaction
, last_version_key
, version
);
1234 // TODO(jsbell): Think about how we want to handle the overflow scenario.
1235 DCHECK(version
> last_version
);
1237 *new_version_number
= version
;
1241 leveldb::Status
IndexedDBBackingStore::PutRecord(
1242 IndexedDBBackingStore::Transaction
* transaction
,
1244 int64 object_store_id
,
1245 const IndexedDBKey
& key
,
1246 const IndexedDBValue
& value
,
1247 RecordIdentifier
* record_identifier
) {
1248 IDB_TRACE("IndexedDBBackingStore::PutRecord");
1249 if (!KeyPrefix::ValidIds(database_id
, object_store_id
))
1250 return InvalidDBKeyStatus();
1251 DCHECK(key
.IsValid());
1253 LevelDBTransaction
* leveldb_transaction
= transaction
->transaction();
1255 leveldb::Status s
= GetNewVersionNumber(
1256 leveldb_transaction
, database_id
, object_store_id
, &version
);
1259 DCHECK_GE(version
, 0);
1260 const std::string object_store_data_key
=
1261 ObjectStoreDataKey::Encode(database_id
, object_store_id
, key
);
1264 EncodeVarInt(version
, &v
);
1265 v
.append(value
.bits
);
1267 leveldb_transaction
->Put(object_store_data_key
, &v
);
1269 const std::string exists_entry_key
=
1270 ExistsEntryKey::Encode(database_id
, object_store_id
, key
);
1271 std::string version_encoded
;
1272 EncodeInt(version
, &version_encoded
);
1273 leveldb_transaction
->Put(exists_entry_key
, &version_encoded
);
1275 std::string key_encoded
;
1276 EncodeIDBKey(key
, &key_encoded
);
1277 record_identifier
->Reset(key_encoded
, version
);
1281 leveldb::Status
IndexedDBBackingStore::ClearObjectStore(
1282 IndexedDBBackingStore::Transaction
* transaction
,
1284 int64 object_store_id
) {
1285 IDB_TRACE("IndexedDBBackingStore::ClearObjectStore");
1286 if (!KeyPrefix::ValidIds(database_id
, object_store_id
))
1287 return InvalidDBKeyStatus();
1288 const std::string start_key
=
1289 KeyPrefix(database_id
, object_store_id
).Encode();
1290 const std::string stop_key
=
1291 KeyPrefix(database_id
, object_store_id
+ 1).Encode();
1293 DeleteRange(transaction
->transaction(), start_key
, stop_key
);
1294 return leveldb::Status::OK();
1297 leveldb::Status
IndexedDBBackingStore::DeleteRecord(
1298 IndexedDBBackingStore::Transaction
* transaction
,
1300 int64 object_store_id
,
1301 const RecordIdentifier
& record_identifier
) {
1302 IDB_TRACE("IndexedDBBackingStore::DeleteRecord");
1303 if (!KeyPrefix::ValidIds(database_id
, object_store_id
))
1304 return InvalidDBKeyStatus();
1305 LevelDBTransaction
* leveldb_transaction
= transaction
->transaction();
1307 const std::string object_store_data_key
= ObjectStoreDataKey::Encode(
1308 database_id
, object_store_id
, record_identifier
.primary_key());
1309 leveldb_transaction
->Remove(object_store_data_key
);
1311 const std::string exists_entry_key
= ExistsEntryKey::Encode(
1312 database_id
, object_store_id
, record_identifier
.primary_key());
1313 leveldb_transaction
->Remove(exists_entry_key
);
1314 return leveldb::Status::OK();
1317 leveldb::Status
IndexedDBBackingStore::GetKeyGeneratorCurrentNumber(
1318 IndexedDBBackingStore::Transaction
* transaction
,
1320 int64 object_store_id
,
1321 int64
* key_generator_current_number
) {
1322 if (!KeyPrefix::ValidIds(database_id
, object_store_id
))
1323 return InvalidDBKeyStatus();
1324 LevelDBTransaction
* leveldb_transaction
= transaction
->transaction();
1326 const std::string key_generator_current_number_key
=
1327 ObjectStoreMetaDataKey::Encode(
1330 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER
);
1332 *key_generator_current_number
= -1;
1337 leveldb_transaction
->Get(key_generator_current_number_key
, &data
, &found
);
1339 INTERNAL_READ_ERROR(GET_KEY_GENERATOR_CURRENT_NUMBER
);
1342 if (found
&& !data
.empty()) {
1343 StringPiece
slice(data
);
1344 if (!DecodeInt(&slice
, key_generator_current_number
) || !slice
.empty()) {
1345 INTERNAL_READ_ERROR(GET_KEY_GENERATOR_CURRENT_NUMBER
);
1346 return InternalInconsistencyStatus();
1351 // Previously, the key generator state was not stored explicitly
1352 // but derived from the maximum numeric key present in existing
1353 // data. This violates the spec as the data may be cleared but the
1354 // key generator state must be preserved.
1355 // TODO(jsbell): Fix this for all stores on database open?
1356 const std::string start_key
=
1357 ObjectStoreDataKey::Encode(database_id
, object_store_id
, MinIDBKey());
1358 const std::string stop_key
=
1359 ObjectStoreDataKey::Encode(database_id
, object_store_id
, MaxIDBKey());
1361 scoped_ptr
<LevelDBIterator
> it
= leveldb_transaction
->CreateIterator();
1362 int64 max_numeric_key
= 0;
1364 for (it
->Seek(start_key
);
1365 it
->IsValid() && CompareKeys(it
->Key(), stop_key
) < 0;
1367 StringPiece
slice(it
->Key());
1368 ObjectStoreDataKey data_key
;
1369 if (!ObjectStoreDataKey::Decode(&slice
, &data_key
)) {
1370 INTERNAL_READ_ERROR(GET_KEY_GENERATOR_CURRENT_NUMBER
);
1371 return InternalInconsistencyStatus();
1373 scoped_ptr
<IndexedDBKey
> user_key
= data_key
.user_key();
1374 if (user_key
->type() == blink::WebIDBKeyTypeNumber
) {
1375 int64 n
= static_cast<int64
>(user_key
->number());
1376 if (n
> max_numeric_key
)
1377 max_numeric_key
= n
;
1381 *key_generator_current_number
= max_numeric_key
+ 1;
1385 leveldb::Status
IndexedDBBackingStore::MaybeUpdateKeyGeneratorCurrentNumber(
1386 IndexedDBBackingStore::Transaction
* transaction
,
1388 int64 object_store_id
,
1390 bool check_current
) {
1391 if (!KeyPrefix::ValidIds(database_id
, object_store_id
))
1392 return InvalidDBKeyStatus();
1394 if (check_current
) {
1395 int64 current_number
;
1396 leveldb::Status s
= GetKeyGeneratorCurrentNumber(
1397 transaction
, database_id
, object_store_id
, ¤t_number
);
1400 if (new_number
<= current_number
)
1404 const std::string key_generator_current_number_key
=
1405 ObjectStoreMetaDataKey::Encode(
1408 ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER
);
1410 transaction
->transaction(), key_generator_current_number_key
, new_number
);
1411 return leveldb::Status::OK();
1414 leveldb::Status
IndexedDBBackingStore::KeyExistsInObjectStore(
1415 IndexedDBBackingStore::Transaction
* transaction
,
1417 int64 object_store_id
,
1418 const IndexedDBKey
& key
,
1419 RecordIdentifier
* found_record_identifier
,
1421 IDB_TRACE("IndexedDBBackingStore::KeyExistsInObjectStore");
1422 if (!KeyPrefix::ValidIds(database_id
, object_store_id
))
1423 return InvalidDBKeyStatus();
1425 const std::string leveldb_key
=
1426 ObjectStoreDataKey::Encode(database_id
, object_store_id
, key
);
1430 transaction
->transaction()->Get(leveldb_key
, &data
, found
);
1432 INTERNAL_READ_ERROR(KEY_EXISTS_IN_OBJECT_STORE
);
1436 return leveldb::Status::OK();
1438 INTERNAL_READ_ERROR(KEY_EXISTS_IN_OBJECT_STORE
);
1439 return InternalInconsistencyStatus();
1443 StringPiece
slice(data
);
1444 if (!DecodeVarInt(&slice
, &version
))
1445 return InternalInconsistencyStatus();
1447 std::string encoded_key
;
1448 EncodeIDBKey(key
, &encoded_key
);
1449 found_record_identifier
->Reset(encoded_key
, version
);
1453 static bool CheckIndexAndMetaDataKey(const LevelDBIterator
* it
,
1454 const std::string
& stop_key
,
1456 unsigned char meta_data_type
) {
1457 if (!it
->IsValid() || CompareKeys(it
->Key(), stop_key
) >= 0)
1460 StringPiece
slice(it
->Key());
1461 IndexMetaDataKey meta_data_key
;
1462 bool ok
= IndexMetaDataKey::Decode(&slice
, &meta_data_key
);
1464 if (meta_data_key
.IndexId() != index_id
)
1466 if (meta_data_key
.meta_data_type() != meta_data_type
)
1471 // TODO(jsbell): This should do some error handling rather than plowing ahead
1472 // when bad data is encountered.
1473 leveldb::Status
IndexedDBBackingStore::GetIndexes(
1475 int64 object_store_id
,
1476 IndexedDBObjectStoreMetadata::IndexMap
* indexes
) {
1477 IDB_TRACE("IndexedDBBackingStore::GetIndexes");
1478 if (!KeyPrefix::ValidIds(database_id
, object_store_id
))
1479 return InvalidDBKeyStatus();
1480 const std::string start_key
=
1481 IndexMetaDataKey::Encode(database_id
, object_store_id
, 0, 0);
1482 const std::string stop_key
=
1483 IndexMetaDataKey::Encode(database_id
, object_store_id
+ 1, 0, 0);
1485 DCHECK(indexes
->empty());
1487 scoped_ptr
<LevelDBIterator
> it
= db_
->CreateIterator();
1488 it
->Seek(start_key
);
1489 while (it
->IsValid() && CompareKeys(it
->Key(), stop_key
) < 0) {
1490 StringPiece
slice(it
->Key());
1491 IndexMetaDataKey meta_data_key
;
1492 bool ok
= IndexMetaDataKey::Decode(&slice
, &meta_data_key
);
1494 if (meta_data_key
.meta_data_type() != IndexMetaDataKey::NAME
) {
1495 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES
);
1496 // Possible stale metadata due to http://webkit.org/b/85557 but don't fail
1502 // TODO(jsbell): Do this by direct key lookup rather than iteration, to
1504 int64 index_id
= meta_data_key
.IndexId();
1505 base::string16 index_name
;
1507 StringPiece
slice(it
->Value());
1508 if (!DecodeString(&slice
, &index_name
) || !slice
.empty())
1509 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES
);
1512 it
->Next(); // unique flag
1513 if (!CheckIndexAndMetaDataKey(
1514 it
.get(), stop_key
, index_id
, IndexMetaDataKey::UNIQUE
)) {
1515 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES
);
1520 StringPiece
slice(it
->Value());
1521 if (!DecodeBool(&slice
, &index_unique
) || !slice
.empty())
1522 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES
);
1525 it
->Next(); // key_path
1526 if (!CheckIndexAndMetaDataKey(
1527 it
.get(), stop_key
, index_id
, IndexMetaDataKey::KEY_PATH
)) {
1528 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES
);
1531 IndexedDBKeyPath key_path
;
1533 StringPiece
slice(it
->Value());
1534 if (!DecodeIDBKeyPath(&slice
, &key_path
) || !slice
.empty())
1535 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES
);
1538 it
->Next(); // [optional] multi_entry flag
1539 bool index_multi_entry
= false;
1540 if (CheckIndexAndMetaDataKey(
1541 it
.get(), stop_key
, index_id
, IndexMetaDataKey::MULTI_ENTRY
)) {
1542 StringPiece
slice(it
->Value());
1543 if (!DecodeBool(&slice
, &index_multi_entry
) || !slice
.empty())
1544 INTERNAL_CONSISTENCY_ERROR(GET_INDEXES
);
1549 (*indexes
)[index_id
] = IndexedDBIndexMetadata(
1550 index_name
, index_id
, key_path
, index_unique
, index_multi_entry
);
1552 return leveldb::Status::OK();
1555 WARN_UNUSED_RESULT
static leveldb::Status
SetMaxIndexId(
1556 LevelDBTransaction
* transaction
,
1558 int64 object_store_id
,
1560 int64 max_index_id
= -1;
1561 const std::string max_index_id_key
= ObjectStoreMetaDataKey::Encode(
1562 database_id
, object_store_id
, ObjectStoreMetaDataKey::MAX_INDEX_ID
);
1565 GetInt(transaction
, max_index_id_key
, &max_index_id
, &found
);
1567 INTERNAL_READ_ERROR(SET_MAX_INDEX_ID
);
1571 max_index_id
= kMinimumIndexId
;
1573 if (index_id
<= max_index_id
) {
1574 INTERNAL_CONSISTENCY_ERROR(SET_MAX_INDEX_ID
);
1575 return InternalInconsistencyStatus();
1578 PutInt(transaction
, max_index_id_key
, index_id
);
1582 leveldb::Status
IndexedDBBackingStore::CreateIndex(
1583 IndexedDBBackingStore::Transaction
* transaction
,
1585 int64 object_store_id
,
1587 const base::string16
& name
,
1588 const IndexedDBKeyPath
& key_path
,
1590 bool is_multi_entry
) {
1591 IDB_TRACE("IndexedDBBackingStore::CreateIndex");
1592 if (!KeyPrefix::ValidIds(database_id
, object_store_id
, index_id
))
1593 return InvalidDBKeyStatus();
1594 LevelDBTransaction
* leveldb_transaction
= transaction
->transaction();
1595 leveldb::Status s
= SetMaxIndexId(
1596 leveldb_transaction
, database_id
, object_store_id
, index_id
);
1601 const std::string name_key
= IndexMetaDataKey::Encode(
1602 database_id
, object_store_id
, index_id
, IndexMetaDataKey::NAME
);
1603 const std::string unique_key
= IndexMetaDataKey::Encode(
1604 database_id
, object_store_id
, index_id
, IndexMetaDataKey::UNIQUE
);
1605 const std::string key_path_key
= IndexMetaDataKey::Encode(
1606 database_id
, object_store_id
, index_id
, IndexMetaDataKey::KEY_PATH
);
1607 const std::string multi_entry_key
= IndexMetaDataKey::Encode(
1608 database_id
, object_store_id
, index_id
, IndexMetaDataKey::MULTI_ENTRY
);
1610 PutString(leveldb_transaction
, name_key
, name
);
1611 PutBool(leveldb_transaction
, unique_key
, is_unique
);
1612 PutIDBKeyPath(leveldb_transaction
, key_path_key
, key_path
);
1613 PutBool(leveldb_transaction
, multi_entry_key
, is_multi_entry
);
1617 leveldb::Status
IndexedDBBackingStore::DeleteIndex(
1618 IndexedDBBackingStore::Transaction
* transaction
,
1620 int64 object_store_id
,
1622 IDB_TRACE("IndexedDBBackingStore::DeleteIndex");
1623 if (!KeyPrefix::ValidIds(database_id
, object_store_id
, index_id
))
1624 return InvalidDBKeyStatus();
1625 LevelDBTransaction
* leveldb_transaction
= transaction
->transaction();
1627 const std::string index_meta_data_start
=
1628 IndexMetaDataKey::Encode(database_id
, object_store_id
, index_id
, 0);
1629 const std::string index_meta_data_end
=
1630 IndexMetaDataKey::EncodeMaxKey(database_id
, object_store_id
, index_id
);
1631 DeleteRange(leveldb_transaction
, index_meta_data_start
, index_meta_data_end
);
1633 const std::string index_data_start
=
1634 IndexDataKey::EncodeMinKey(database_id
, object_store_id
, index_id
);
1635 const std::string index_data_end
=
1636 IndexDataKey::EncodeMaxKey(database_id
, object_store_id
, index_id
);
1637 DeleteRange(leveldb_transaction
, index_data_start
, index_data_end
);
1638 return leveldb::Status::OK();
1641 leveldb::Status
IndexedDBBackingStore::PutIndexDataForRecord(
1642 IndexedDBBackingStore::Transaction
* transaction
,
1644 int64 object_store_id
,
1646 const IndexedDBKey
& key
,
1647 const RecordIdentifier
& record_identifier
) {
1648 IDB_TRACE("IndexedDBBackingStore::PutIndexDataForRecord");
1649 DCHECK(key
.IsValid());
1650 if (!KeyPrefix::ValidIds(database_id
, object_store_id
, index_id
))
1651 return InvalidDBKeyStatus();
1653 std::string encoded_key
;
1654 EncodeIDBKey(key
, &encoded_key
);
1656 const std::string index_data_key
=
1657 IndexDataKey::Encode(database_id
,
1661 record_identifier
.primary_key(),
1665 EncodeVarInt(record_identifier
.version(), &data
);
1666 data
.append(record_identifier
.primary_key());
1668 transaction
->transaction()->Put(index_data_key
, &data
);
1669 return leveldb::Status::OK();
1672 static bool FindGreatestKeyLessThanOrEqual(LevelDBTransaction
* transaction
,
1673 const std::string
& target
,
1674 std::string
* found_key
) {
1675 scoped_ptr
<LevelDBIterator
> it
= transaction
->CreateIterator();
1678 if (!it
->IsValid()) {
1684 while (CompareIndexKeys(it
->Key(), target
) > 0) {
1691 *found_key
= it
->Key().as_string();
1693 // There can be several index keys that compare equal. We want the last one.
1695 } while (it
->IsValid() && !CompareIndexKeys(it
->Key(), target
));
1700 static leveldb::Status
VersionExists(LevelDBTransaction
* transaction
,
1702 int64 object_store_id
,
1704 const std::string
& encoded_primary_key
,
1706 const std::string key
=
1707 ExistsEntryKey::Encode(database_id
, object_store_id
, encoded_primary_key
);
1710 leveldb::Status s
= transaction
->Get(key
, &data
, exists
);
1712 INTERNAL_READ_ERROR(VERSION_EXISTS
);
1718 StringPiece
slice(data
);
1720 if (!DecodeInt(&slice
, &decoded
) || !slice
.empty())
1721 return InternalInconsistencyStatus();
1722 *exists
= (decoded
== version
);
1726 leveldb::Status
IndexedDBBackingStore::FindKeyInIndex(
1727 IndexedDBBackingStore::Transaction
* transaction
,
1729 int64 object_store_id
,
1731 const IndexedDBKey
& key
,
1732 std::string
* found_encoded_primary_key
,
1734 IDB_TRACE("IndexedDBBackingStore::FindKeyInIndex");
1735 DCHECK(KeyPrefix::ValidIds(database_id
, object_store_id
, index_id
));
1737 DCHECK(found_encoded_primary_key
->empty());
1740 LevelDBTransaction
* leveldb_transaction
= transaction
->transaction();
1741 const std::string leveldb_key
=
1742 IndexDataKey::Encode(database_id
, object_store_id
, index_id
, key
);
1743 scoped_ptr
<LevelDBIterator
> it
= leveldb_transaction
->CreateIterator();
1744 it
->Seek(leveldb_key
);
1748 return leveldb::Status::OK();
1749 if (CompareIndexKeys(it
->Key(), leveldb_key
) > 0)
1750 return leveldb::Status::OK();
1752 StringPiece
slice(it
->Value());
1755 if (!DecodeVarInt(&slice
, &version
)) {
1756 INTERNAL_READ_ERROR(FIND_KEY_IN_INDEX
);
1757 return InternalInconsistencyStatus();
1759 *found_encoded_primary_key
= slice
.as_string();
1761 bool exists
= false;
1762 leveldb::Status s
= VersionExists(leveldb_transaction
,
1766 *found_encoded_primary_key
,
1771 // Delete stale index data entry and continue.
1772 leveldb_transaction
->Remove(it
->Key());
1781 leveldb::Status
IndexedDBBackingStore::GetPrimaryKeyViaIndex(
1782 IndexedDBBackingStore::Transaction
* transaction
,
1784 int64 object_store_id
,
1786 const IndexedDBKey
& key
,
1787 scoped_ptr
<IndexedDBKey
>* primary_key
) {
1788 IDB_TRACE("IndexedDBBackingStore::GetPrimaryKeyViaIndex");
1789 if (!KeyPrefix::ValidIds(database_id
, object_store_id
, index_id
))
1790 return InvalidDBKeyStatus();
1793 std::string found_encoded_primary_key
;
1794 leveldb::Status s
= FindKeyInIndex(transaction
,
1799 &found_encoded_primary_key
,
1802 INTERNAL_READ_ERROR(GET_PRIMARY_KEY_VIA_INDEX
);
1807 if (!found_encoded_primary_key
.size()) {
1808 INTERNAL_READ_ERROR(GET_PRIMARY_KEY_VIA_INDEX
);
1809 return InvalidDBKeyStatus();
1812 StringPiece
slice(found_encoded_primary_key
);
1813 if (DecodeIDBKey(&slice
, primary_key
) && slice
.empty())
1816 return InvalidDBKeyStatus();
1819 leveldb::Status
IndexedDBBackingStore::KeyExistsInIndex(
1820 IndexedDBBackingStore::Transaction
* transaction
,
1822 int64 object_store_id
,
1824 const IndexedDBKey
& index_key
,
1825 scoped_ptr
<IndexedDBKey
>* found_primary_key
,
1827 IDB_TRACE("IndexedDBBackingStore::KeyExistsInIndex");
1828 if (!KeyPrefix::ValidIds(database_id
, object_store_id
, index_id
))
1829 return InvalidDBKeyStatus();
1832 std::string found_encoded_primary_key
;
1833 leveldb::Status s
= FindKeyInIndex(transaction
,
1838 &found_encoded_primary_key
,
1841 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX
);
1845 return leveldb::Status::OK();
1846 if (found_encoded_primary_key
.empty()) {
1847 INTERNAL_READ_ERROR(KEY_EXISTS_IN_INDEX
);
1848 return InvalidDBKeyStatus();
1851 StringPiece
slice(found_encoded_primary_key
);
1852 if (DecodeIDBKey(&slice
, found_primary_key
) && slice
.empty())
1855 return InvalidDBKeyStatus();
1858 IndexedDBBackingStore::Cursor::Cursor(
1859 const IndexedDBBackingStore::Cursor
* other
)
1860 : transaction_(other
->transaction_
),
1861 cursor_options_(other
->cursor_options_
),
1862 current_key_(new IndexedDBKey(*other
->current_key_
)) {
1863 if (other
->iterator_
) {
1864 iterator_
= transaction_
->CreateIterator();
1866 if (other
->iterator_
->IsValid()) {
1867 iterator_
->Seek(other
->iterator_
->Key());
1868 DCHECK(iterator_
->IsValid());
1873 IndexedDBBackingStore::Cursor::Cursor(LevelDBTransaction
* transaction
,
1874 const CursorOptions
& cursor_options
)
1875 : transaction_(transaction
), cursor_options_(cursor_options
) {}
1876 IndexedDBBackingStore::Cursor::~Cursor() {}
1878 bool IndexedDBBackingStore::Cursor::FirstSeek() {
1879 iterator_
= transaction_
->CreateIterator();
1880 if (cursor_options_
.forward
)
1881 iterator_
->Seek(cursor_options_
.low_key
);
1883 iterator_
->Seek(cursor_options_
.high_key
);
1885 return Continue(0, READY
);
1888 bool IndexedDBBackingStore::Cursor::Advance(uint32 count
) {
1896 bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey
* key
,
1897 const IndexedDBKey
* primary_key
,
1898 IteratorState next_state
) {
1899 DCHECK(!key
|| key
->IsValid());
1900 DCHECK(!primary_key
|| primary_key
->IsValid());
1902 // TODO(alecflett): avoid a copy here?
1903 IndexedDBKey previous_key
= current_key_
? *current_key_
: IndexedDBKey();
1905 bool first_iteration
= true;
1907 // When iterating with PrevNoDuplicate, spec requires that the
1908 // value we yield for each key is the first duplicate in forwards
1910 IndexedDBKey last_duplicate_key
;
1912 bool forward
= cursor_options_
.forward
;
1915 if (next_state
== SEEK
) {
1916 // TODO(jsbell): Optimize seeking for reverse cursors as well.
1917 if (first_iteration
&& key
&& forward
) {
1918 std::string leveldb_key
;
1920 leveldb_key
= EncodeKey(*key
, *primary_key
);
1922 leveldb_key
= EncodeKey(*key
);
1924 iterator_
->Seek(leveldb_key
);
1925 first_iteration
= false;
1926 } else if (forward
) {
1932 next_state
= SEEK
; // for subsequent iterations
1935 if (!iterator_
->IsValid()) {
1936 if (!forward
&& last_duplicate_key
.IsValid()) {
1937 // We need to walk forward because we hit the end of
1946 if (IsPastBounds()) {
1947 if (!forward
&& last_duplicate_key
.IsValid()) {
1948 // We need to walk forward because now we're beyond the
1949 // bounds defined by the cursor.
1957 if (!HaveEnteredRange())
1960 // The row may not load because there's a stale entry in the
1961 // index. This is not fatal.
1962 if (!LoadCurrentRow())
1967 if (primary_key
&& current_key_
->Equals(*key
) &&
1968 this->primary_key().IsLessThan(*primary_key
))
1970 if (current_key_
->IsLessThan(*key
))
1973 if (primary_key
&& key
->Equals(*current_key_
) &&
1974 primary_key
->IsLessThan(this->primary_key()))
1976 if (key
->IsLessThan(*current_key_
))
1981 if (cursor_options_
.unique
) {
1982 if (previous_key
.IsValid() && current_key_
->Equals(previous_key
)) {
1983 // We should never be able to walk forward all the way
1984 // to the previous key.
1985 DCHECK(!last_duplicate_key
.IsValid());
1990 if (!last_duplicate_key
.IsValid()) {
1991 last_duplicate_key
= *current_key_
;
1995 // We need to walk forward because we hit the boundary
1996 // between key ranges.
1997 if (!last_duplicate_key
.Equals(*current_key_
)) {
2008 DCHECK(!last_duplicate_key
.IsValid() ||
2009 (forward
&& last_duplicate_key
.Equals(*current_key_
)));
2013 bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const {
2014 if (cursor_options_
.forward
) {
2015 int compare
= CompareIndexKeys(iterator_
->Key(), cursor_options_
.low_key
);
2016 if (cursor_options_
.low_open
) {
2019 return compare
>= 0;
2021 int compare
= CompareIndexKeys(iterator_
->Key(), cursor_options_
.high_key
);
2022 if (cursor_options_
.high_open
) {
2025 return compare
<= 0;
2028 bool IndexedDBBackingStore::Cursor::IsPastBounds() const {
2029 if (cursor_options_
.forward
) {
2030 int compare
= CompareIndexKeys(iterator_
->Key(), cursor_options_
.high_key
);
2031 if (cursor_options_
.high_open
) {
2032 return compare
>= 0;
2036 int compare
= CompareIndexKeys(iterator_
->Key(), cursor_options_
.low_key
);
2037 if (cursor_options_
.low_open
) {
2038 return compare
<= 0;
2043 const IndexedDBKey
& IndexedDBBackingStore::Cursor::primary_key() const {
2044 return *current_key_
;
2047 const IndexedDBBackingStore::RecordIdentifier
&
2048 IndexedDBBackingStore::Cursor::record_identifier() const {
2049 return record_identifier_
;
2052 class ObjectStoreKeyCursorImpl
: public IndexedDBBackingStore::Cursor
{
2054 ObjectStoreKeyCursorImpl(
2055 LevelDBTransaction
* transaction
,
2056 const IndexedDBBackingStore::Cursor::CursorOptions
& cursor_options
)
2057 : IndexedDBBackingStore::Cursor(transaction
, cursor_options
) {}
2059 virtual Cursor
* Clone() OVERRIDE
{
2060 return new ObjectStoreKeyCursorImpl(this);
2063 // IndexedDBBackingStore::Cursor
2064 virtual IndexedDBValue
* value() OVERRIDE
{
2068 virtual bool LoadCurrentRow() OVERRIDE
;
2071 virtual std::string
EncodeKey(const IndexedDBKey
& key
) OVERRIDE
{
2072 return ObjectStoreDataKey::Encode(
2073 cursor_options_
.database_id
, cursor_options_
.object_store_id
, key
);
2075 virtual std::string
EncodeKey(const IndexedDBKey
& key
,
2076 const IndexedDBKey
& primary_key
) OVERRIDE
{
2078 return std::string();
2082 explicit ObjectStoreKeyCursorImpl(const ObjectStoreKeyCursorImpl
* other
)
2083 : IndexedDBBackingStore::Cursor(other
) {}
2086 bool ObjectStoreKeyCursorImpl::LoadCurrentRow() {
2087 StringPiece
slice(iterator_
->Key());
2088 ObjectStoreDataKey object_store_data_key
;
2089 if (!ObjectStoreDataKey::Decode(&slice
, &object_store_data_key
)) {
2090 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2094 current_key_
= object_store_data_key
.user_key();
2097 slice
= StringPiece(iterator_
->Value());
2098 if (!DecodeVarInt(&slice
, &version
)) {
2099 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2103 // TODO(jsbell): This re-encodes what was just decoded; try and optimize.
2104 std::string encoded_key
;
2105 EncodeIDBKey(*current_key_
, &encoded_key
);
2106 record_identifier_
.Reset(encoded_key
, version
);
2111 class ObjectStoreCursorImpl
: public IndexedDBBackingStore::Cursor
{
2113 ObjectStoreCursorImpl(
2114 LevelDBTransaction
* transaction
,
2115 const IndexedDBBackingStore::Cursor::CursorOptions
& cursor_options
)
2116 : IndexedDBBackingStore::Cursor(transaction
, cursor_options
) {}
2118 virtual Cursor
* Clone() OVERRIDE
{ return new ObjectStoreCursorImpl(this); }
2120 // IndexedDBBackingStore::Cursor
2121 virtual IndexedDBValue
* value() OVERRIDE
{ return ¤t_value_
; }
2122 virtual bool LoadCurrentRow() OVERRIDE
;
2125 virtual std::string
EncodeKey(const IndexedDBKey
& key
) OVERRIDE
{
2126 return ObjectStoreDataKey::Encode(
2127 cursor_options_
.database_id
, cursor_options_
.object_store_id
, key
);
2129 virtual std::string
EncodeKey(const IndexedDBKey
& key
,
2130 const IndexedDBKey
& primary_key
) OVERRIDE
{
2132 return std::string();
2136 explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl
* other
)
2137 : IndexedDBBackingStore::Cursor(other
),
2138 current_value_(other
->current_value_
) {}
2140 IndexedDBValue current_value_
;
2143 bool ObjectStoreCursorImpl::LoadCurrentRow() {
2144 StringPiece
key_slice(iterator_
->Key());
2145 ObjectStoreDataKey object_store_data_key
;
2146 if (!ObjectStoreDataKey::Decode(&key_slice
, &object_store_data_key
)) {
2147 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2151 current_key_
= object_store_data_key
.user_key();
2154 StringPiece value_slice
= StringPiece(iterator_
->Value());
2155 if (!DecodeVarInt(&value_slice
, &version
)) {
2156 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2160 // TODO(jsbell): This re-encodes what was just decoded; try and optimize.
2161 std::string encoded_key
;
2162 EncodeIDBKey(*current_key_
, &encoded_key
);
2163 record_identifier_
.Reset(encoded_key
, version
);
2165 current_value_
.bits
= value_slice
.as_string();
2169 class IndexKeyCursorImpl
: public IndexedDBBackingStore::Cursor
{
2172 LevelDBTransaction
* transaction
,
2173 const IndexedDBBackingStore::Cursor::CursorOptions
& cursor_options
)
2174 : IndexedDBBackingStore::Cursor(transaction
, cursor_options
) {}
2176 virtual Cursor
* Clone() OVERRIDE
{ return new IndexKeyCursorImpl(this); }
2178 // IndexedDBBackingStore::Cursor
2179 virtual IndexedDBValue
* value() OVERRIDE
{
2183 virtual const IndexedDBKey
& primary_key() const OVERRIDE
{
2184 return *primary_key_
;
2186 virtual const IndexedDBBackingStore::RecordIdentifier
& record_identifier()
2189 return record_identifier_
;
2191 virtual bool LoadCurrentRow() OVERRIDE
;
2194 virtual std::string
EncodeKey(const IndexedDBKey
& key
) OVERRIDE
{
2195 return IndexDataKey::Encode(cursor_options_
.database_id
,
2196 cursor_options_
.object_store_id
,
2197 cursor_options_
.index_id
,
2200 virtual std::string
EncodeKey(const IndexedDBKey
& key
,
2201 const IndexedDBKey
& primary_key
) OVERRIDE
{
2202 return IndexDataKey::Encode(cursor_options_
.database_id
,
2203 cursor_options_
.object_store_id
,
2204 cursor_options_
.index_id
,
2210 explicit IndexKeyCursorImpl(const IndexKeyCursorImpl
* other
)
2211 : IndexedDBBackingStore::Cursor(other
),
2212 primary_key_(new IndexedDBKey(*other
->primary_key_
)) {}
2214 scoped_ptr
<IndexedDBKey
> primary_key_
;
2217 bool IndexKeyCursorImpl::LoadCurrentRow() {
2218 StringPiece
slice(iterator_
->Key());
2219 IndexDataKey index_data_key
;
2220 if (!IndexDataKey::Decode(&slice
, &index_data_key
)) {
2221 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2225 current_key_
= index_data_key
.user_key();
2226 DCHECK(current_key_
);
2228 slice
= StringPiece(iterator_
->Value());
2229 int64 index_data_version
;
2230 if (!DecodeVarInt(&slice
, &index_data_version
)) {
2231 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2235 if (!DecodeIDBKey(&slice
, &primary_key_
) || !slice
.empty()) {
2236 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2240 std::string primary_leveldb_key
=
2241 ObjectStoreDataKey::Encode(index_data_key
.DatabaseId(),
2242 index_data_key
.ObjectStoreId(),
2247 leveldb::Status s
= transaction_
->Get(primary_leveldb_key
, &result
, &found
);
2249 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2253 transaction_
->Remove(iterator_
->Key());
2256 if (!result
.size()) {
2257 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2261 int64 object_store_data_version
;
2262 slice
= StringPiece(result
);
2263 if (!DecodeVarInt(&slice
, &object_store_data_version
)) {
2264 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2268 if (object_store_data_version
!= index_data_version
) {
2269 transaction_
->Remove(iterator_
->Key());
2276 class IndexCursorImpl
: public IndexedDBBackingStore::Cursor
{
2279 LevelDBTransaction
* transaction
,
2280 const IndexedDBBackingStore::Cursor::CursorOptions
& cursor_options
)
2281 : IndexedDBBackingStore::Cursor(transaction
, cursor_options
) {}
2283 virtual Cursor
* Clone() OVERRIDE
{ return new IndexCursorImpl(this); }
2285 // IndexedDBBackingStore::Cursor
2286 virtual IndexedDBValue
* value() OVERRIDE
{ return ¤t_value_
; }
2287 virtual const IndexedDBKey
& primary_key() const OVERRIDE
{
2288 return *primary_key_
;
2290 virtual const IndexedDBBackingStore::RecordIdentifier
& record_identifier()
2293 return record_identifier_
;
2295 virtual bool LoadCurrentRow() OVERRIDE
;
2298 virtual std::string
EncodeKey(const IndexedDBKey
& key
) OVERRIDE
{
2299 return IndexDataKey::Encode(cursor_options_
.database_id
,
2300 cursor_options_
.object_store_id
,
2301 cursor_options_
.index_id
,
2304 virtual std::string
EncodeKey(const IndexedDBKey
& key
,
2305 const IndexedDBKey
& primary_key
) OVERRIDE
{
2306 return IndexDataKey::Encode(cursor_options_
.database_id
,
2307 cursor_options_
.object_store_id
,
2308 cursor_options_
.index_id
,
2314 explicit IndexCursorImpl(const IndexCursorImpl
* other
)
2315 : IndexedDBBackingStore::Cursor(other
),
2316 primary_key_(new IndexedDBKey(*other
->primary_key_
)),
2317 current_value_(other
->current_value_
),
2318 primary_leveldb_key_(other
->primary_leveldb_key_
) {}
2320 scoped_ptr
<IndexedDBKey
> primary_key_
;
2321 IndexedDBValue current_value_
;
2322 std::string primary_leveldb_key_
;
2325 bool IndexCursorImpl::LoadCurrentRow() {
2326 StringPiece
slice(iterator_
->Key());
2327 IndexDataKey index_data_key
;
2328 if (!IndexDataKey::Decode(&slice
, &index_data_key
)) {
2329 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2333 current_key_
= index_data_key
.user_key();
2334 DCHECK(current_key_
);
2336 slice
= StringPiece(iterator_
->Value());
2337 int64 index_data_version
;
2338 if (!DecodeVarInt(&slice
, &index_data_version
)) {
2339 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2342 if (!DecodeIDBKey(&slice
, &primary_key_
)) {
2343 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2347 primary_leveldb_key_
=
2348 ObjectStoreDataKey::Encode(index_data_key
.DatabaseId(),
2349 index_data_key
.ObjectStoreId(),
2354 leveldb::Status s
= transaction_
->Get(primary_leveldb_key_
, &result
, &found
);
2356 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2360 transaction_
->Remove(iterator_
->Key());
2363 if (!result
.size()) {
2364 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2368 int64 object_store_data_version
;
2369 slice
= StringPiece(result
);
2370 if (!DecodeVarInt(&slice
, &object_store_data_version
)) {
2371 INTERNAL_READ_ERROR(LOAD_CURRENT_ROW
);
2375 if (object_store_data_version
!= index_data_version
) {
2376 transaction_
->Remove(iterator_
->Key());
2380 current_value_
.bits
= slice
.as_string();
2384 bool ObjectStoreCursorOptions(
2385 LevelDBTransaction
* transaction
,
2387 int64 object_store_id
,
2388 const IndexedDBKeyRange
& range
,
2389 indexed_db::CursorDirection direction
,
2390 IndexedDBBackingStore::Cursor::CursorOptions
* cursor_options
) {
2391 cursor_options
->database_id
= database_id
;
2392 cursor_options
->object_store_id
= object_store_id
;
2394 bool lower_bound
= range
.lower().IsValid();
2395 bool upper_bound
= range
.upper().IsValid();
2396 cursor_options
->forward
=
2397 (direction
== indexed_db::CURSOR_NEXT_NO_DUPLICATE
||
2398 direction
== indexed_db::CURSOR_NEXT
);
2399 cursor_options
->unique
= (direction
== indexed_db::CURSOR_NEXT_NO_DUPLICATE
||
2400 direction
== indexed_db::CURSOR_PREV_NO_DUPLICATE
);
2403 cursor_options
->low_key
=
2404 ObjectStoreDataKey::Encode(database_id
, object_store_id
, MinIDBKey());
2405 cursor_options
->low_open
= true; // Not included.
2407 cursor_options
->low_key
=
2408 ObjectStoreDataKey::Encode(database_id
, object_store_id
, range
.lower());
2409 cursor_options
->low_open
= range
.lowerOpen();
2413 cursor_options
->high_key
=
2414 ObjectStoreDataKey::Encode(database_id
, object_store_id
, MaxIDBKey());
2416 if (cursor_options
->forward
) {
2417 cursor_options
->high_open
= true; // Not included.
2419 // We need a key that exists.
2420 if (!FindGreatestKeyLessThanOrEqual(transaction
,
2421 cursor_options
->high_key
,
2422 &cursor_options
->high_key
))
2424 cursor_options
->high_open
= false;
2427 cursor_options
->high_key
=
2428 ObjectStoreDataKey::Encode(database_id
, object_store_id
, range
.upper());
2429 cursor_options
->high_open
= range
.upperOpen();
2431 if (!cursor_options
->forward
) {
2432 // For reverse cursors, we need a key that exists.
2433 std::string found_high_key
;
2434 if (!FindGreatestKeyLessThanOrEqual(
2435 transaction
, cursor_options
->high_key
, &found_high_key
))
2438 // If the target key should not be included, but we end up with a smaller
2439 // key, we should include that.
2440 if (cursor_options
->high_open
&&
2441 CompareIndexKeys(found_high_key
, cursor_options
->high_key
) < 0)
2442 cursor_options
->high_open
= false;
2444 cursor_options
->high_key
= found_high_key
;
2451 bool IndexCursorOptions(
2452 LevelDBTransaction
* transaction
,
2454 int64 object_store_id
,
2456 const IndexedDBKeyRange
& range
,
2457 indexed_db::CursorDirection direction
,
2458 IndexedDBBackingStore::Cursor::CursorOptions
* cursor_options
) {
2459 DCHECK(transaction
);
2460 if (!KeyPrefix::ValidIds(database_id
, object_store_id
, index_id
))
2463 cursor_options
->database_id
= database_id
;
2464 cursor_options
->object_store_id
= object_store_id
;
2465 cursor_options
->index_id
= index_id
;
2467 bool lower_bound
= range
.lower().IsValid();
2468 bool upper_bound
= range
.upper().IsValid();
2469 cursor_options
->forward
=
2470 (direction
== indexed_db::CURSOR_NEXT_NO_DUPLICATE
||
2471 direction
== indexed_db::CURSOR_NEXT
);
2472 cursor_options
->unique
= (direction
== indexed_db::CURSOR_NEXT_NO_DUPLICATE
||
2473 direction
== indexed_db::CURSOR_PREV_NO_DUPLICATE
);
2476 cursor_options
->low_key
=
2477 IndexDataKey::EncodeMinKey(database_id
, object_store_id
, index_id
);
2478 cursor_options
->low_open
= false; // Included.
2480 cursor_options
->low_key
= IndexDataKey::Encode(
2481 database_id
, object_store_id
, index_id
, range
.lower());
2482 cursor_options
->low_open
= range
.lowerOpen();
2486 cursor_options
->high_key
=
2487 IndexDataKey::EncodeMaxKey(database_id
, object_store_id
, index_id
);
2488 cursor_options
->high_open
= false; // Included.
2490 if (!cursor_options
->forward
) { // We need a key that exists.
2491 if (!FindGreatestKeyLessThanOrEqual(transaction
,
2492 cursor_options
->high_key
,
2493 &cursor_options
->high_key
))
2495 cursor_options
->high_open
= false;
2498 cursor_options
->high_key
= IndexDataKey::Encode(
2499 database_id
, object_store_id
, index_id
, range
.upper());
2500 cursor_options
->high_open
= range
.upperOpen();
2502 std::string found_high_key
;
2503 // Seek to the *last* key in the set of non-unique keys
2504 if (!FindGreatestKeyLessThanOrEqual(
2505 transaction
, cursor_options
->high_key
, &found_high_key
))
2508 // If the target key should not be included, but we end up with a smaller
2509 // key, we should include that.
2510 if (cursor_options
->high_open
&&
2511 CompareIndexKeys(found_high_key
, cursor_options
->high_key
) < 0)
2512 cursor_options
->high_open
= false;
2514 cursor_options
->high_key
= found_high_key
;
2520 scoped_ptr
<IndexedDBBackingStore::Cursor
>
2521 IndexedDBBackingStore::OpenObjectStoreCursor(
2522 IndexedDBBackingStore::Transaction
* transaction
,
2524 int64 object_store_id
,
2525 const IndexedDBKeyRange
& range
,
2526 indexed_db::CursorDirection direction
) {
2527 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreCursor");
2528 LevelDBTransaction
* leveldb_transaction
= transaction
->transaction();
2529 IndexedDBBackingStore::Cursor::CursorOptions cursor_options
;
2530 if (!ObjectStoreCursorOptions(leveldb_transaction
,
2536 return scoped_ptr
<IndexedDBBackingStore::Cursor
>();
2537 scoped_ptr
<ObjectStoreCursorImpl
> cursor(
2538 new ObjectStoreCursorImpl(leveldb_transaction
, cursor_options
));
2539 if (!cursor
->FirstSeek())
2540 return scoped_ptr
<IndexedDBBackingStore::Cursor
>();
2542 return cursor
.PassAs
<IndexedDBBackingStore::Cursor
>();
2545 scoped_ptr
<IndexedDBBackingStore::Cursor
>
2546 IndexedDBBackingStore::OpenObjectStoreKeyCursor(
2547 IndexedDBBackingStore::Transaction
* transaction
,
2549 int64 object_store_id
,
2550 const IndexedDBKeyRange
& range
,
2551 indexed_db::CursorDirection direction
) {
2552 IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor");
2553 LevelDBTransaction
* leveldb_transaction
= transaction
->transaction();
2554 IndexedDBBackingStore::Cursor::CursorOptions cursor_options
;
2555 if (!ObjectStoreCursorOptions(leveldb_transaction
,
2561 return scoped_ptr
<IndexedDBBackingStore::Cursor
>();
2562 scoped_ptr
<ObjectStoreKeyCursorImpl
> cursor(
2563 new ObjectStoreKeyCursorImpl(leveldb_transaction
, cursor_options
));
2564 if (!cursor
->FirstSeek())
2565 return scoped_ptr
<IndexedDBBackingStore::Cursor
>();
2567 return cursor
.PassAs
<IndexedDBBackingStore::Cursor
>();
2570 scoped_ptr
<IndexedDBBackingStore::Cursor
>
2571 IndexedDBBackingStore::OpenIndexKeyCursor(
2572 IndexedDBBackingStore::Transaction
* transaction
,
2574 int64 object_store_id
,
2576 const IndexedDBKeyRange
& range
,
2577 indexed_db::CursorDirection direction
) {
2578 IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor");
2579 LevelDBTransaction
* leveldb_transaction
= transaction
->transaction();
2580 IndexedDBBackingStore::Cursor::CursorOptions cursor_options
;
2581 if (!IndexCursorOptions(leveldb_transaction
,
2588 return scoped_ptr
<IndexedDBBackingStore::Cursor
>();
2589 scoped_ptr
<IndexKeyCursorImpl
> cursor(
2590 new IndexKeyCursorImpl(leveldb_transaction
, cursor_options
));
2591 if (!cursor
->FirstSeek())
2592 return scoped_ptr
<IndexedDBBackingStore::Cursor
>();
2594 return cursor
.PassAs
<IndexedDBBackingStore::Cursor
>();
2597 scoped_ptr
<IndexedDBBackingStore::Cursor
>
2598 IndexedDBBackingStore::OpenIndexCursor(
2599 IndexedDBBackingStore::Transaction
* transaction
,
2601 int64 object_store_id
,
2603 const IndexedDBKeyRange
& range
,
2604 indexed_db::CursorDirection direction
) {
2605 IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor");
2606 LevelDBTransaction
* leveldb_transaction
= transaction
->transaction();
2607 IndexedDBBackingStore::Cursor::CursorOptions cursor_options
;
2608 if (!IndexCursorOptions(leveldb_transaction
,
2615 return scoped_ptr
<IndexedDBBackingStore::Cursor
>();
2616 scoped_ptr
<IndexCursorImpl
> cursor(
2617 new IndexCursorImpl(leveldb_transaction
, cursor_options
));
2618 if (!cursor
->FirstSeek())
2619 return scoped_ptr
<IndexedDBBackingStore::Cursor
>();
2621 return cursor
.PassAs
<IndexedDBBackingStore::Cursor
>();
2624 IndexedDBBackingStore::Transaction::Transaction(
2625 IndexedDBBackingStore
* backing_store
)
2626 : backing_store_(backing_store
) {}
2628 IndexedDBBackingStore::Transaction::~Transaction() {}
2630 void IndexedDBBackingStore::Transaction::Begin() {
2631 IDB_TRACE("IndexedDBBackingStore::Transaction::Begin");
2632 DCHECK(!transaction_
.get());
2633 transaction_
= new LevelDBTransaction(backing_store_
->db_
.get());
2636 leveldb::Status
IndexedDBBackingStore::Transaction::Commit() {
2637 IDB_TRACE("IndexedDBBackingStore::Transaction::Commit");
2638 DCHECK(transaction_
.get());
2639 leveldb::Status s
= transaction_
->Commit();
2640 transaction_
= NULL
;
2642 INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD
);
2646 void IndexedDBBackingStore::Transaction::Rollback() {
2647 IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback");
2648 DCHECK(transaction_
.get());
2649 transaction_
->Rollback();
2650 transaction_
= NULL
;
2653 } // namespace content