| Index: content/browser/indexed_db/indexed_db_leveldb_coding.cc
|
| diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding.cc b/content/browser/indexed_db/indexed_db_leveldb_coding.cc
|
| index dd3964ab4445c0959e0d7b7e0571c7d1f8fff134..18cfed529735ddfb5c3ed7bda2950155858445c9 100644
|
| --- a/content/browser/indexed_db/indexed_db_leveldb_coding.cc
|
| +++ b/content/browser/indexed_db/indexed_db_leveldb_coding.cc
|
| @@ -44,6 +44,12 @@
|
| // <0, 0, 0, 0> => backing store schema version [SchemaVersionKey]
|
| // <0, 0, 0, 1> => maximum allocated database [MaxDatabaseIdKey]
|
| // <0, 0, 0, 2> => SerializedScriptValue version [DataVersionKey]
|
| +// <0, 0, 0, 3>
|
| +// => Blob journal
|
| +// The format of the journal is: {database_id, blobKey}*.
|
| +// If the blobKey is AllBlobsKey, the whole database should be deleted.
|
| +// [BlobJournalKey]
|
| +// <0, 0, 0, 4> => Live blob journal; same format. [LiveBlobJournalKey]
|
| // <0, 0, 0, 100, database id>
|
| // => Existence implies the database id is in the free list
|
| // [DatabaseFreeListKey]
|
| @@ -59,6 +65,7 @@
|
| // <database id, 0, 0, 2> => IDB string version data (obsolete)
|
| // <database id, 0, 0, 3> => maximum allocated object store id
|
| // <database id, 0, 0, 4> => IDB integer version (var int)
|
| +// <database id, 0, 0, 5> => blob key generator current number
|
| //
|
| //
|
| // Object store metadata: [ObjectStoreMetaDataKey]
|
| @@ -133,6 +140,14 @@
|
| // <database id, object store id, 2, user key> => "version"
|
| //
|
| //
|
| +// Blob entry table: [BlobEntryKey]
|
| +// --------------------------------
|
| +//
|
| +// The prefix is followed by a type byte and the encoded IDB primary key.
|
| +//
|
| +// <database id, object store id, 3, user key> => array of IndexedDBBlobInfo
|
| +//
|
| +//
|
| // Index data
|
| // ----------
|
| // The prefix is followed by a type byte, the encoded IDB index key, a
|
| @@ -164,8 +179,8 @@ using blink::WebIDBKeyPathTypeString;
|
| namespace content {
|
|
|
| // As most of the IndexedDBKeys and encoded values are short, we
|
| -// initialize some Vectors with a default inline buffer size to reduce
|
| -// the memory re-allocations when the Vectors are appended.
|
| +// initialize some std::vectors with a default inline buffer size to reduce
|
| +// the memory re-allocations when the std::vectors are appended.
|
| static const size_t kDefaultInlineBufferSize = 32;
|
|
|
| static const unsigned char kIndexedDBKeyNullTypeByte = 0;
|
| @@ -181,12 +196,15 @@ static const unsigned char kIndexedDBKeyPathTypeCodedByte2 = 0;
|
|
|
| static const unsigned char kObjectStoreDataIndexId = 1;
|
| static const unsigned char kExistsEntryIndexId = 2;
|
| +static const unsigned char kBlobEntryIndexId = 3;
|
|
|
| static const unsigned char kSchemaVersionTypeByte = 0;
|
| static const unsigned char kMaxDatabaseIdTypeByte = 1;
|
| static const unsigned char kDataVersionTypeByte = 2;
|
| +static const unsigned char kBlobJournalTypeByte = 3;
|
| +static const unsigned char kLiveBlobJournalTypeByte = 4;
|
| static const unsigned char kMaxSimpleGlobalMetaDataTypeByte =
|
| - 3; // Insert before this and increment.
|
| + 5; // Insert before this and increment.
|
| static const unsigned char kDatabaseFreeListTypeByte = 100;
|
| static const unsigned char kDatabaseNameTypeByte = 201;
|
|
|
| @@ -889,6 +907,14 @@ int CompareSuffix<ObjectStoreDataKey>(StringPiece* slice_a,
|
| }
|
|
|
| template <>
|
| +int CompareSuffix<BlobEntryKey>(StringPiece* slice_a,
|
| + StringPiece* slice_b,
|
| + bool only_compare_index_keys,
|
| + bool* ok) {
|
| + return CompareEncodedIDBKeys(slice_a, slice_b, ok);
|
| +}
|
| +
|
| +template <>
|
| int CompareSuffix<IndexDataKey>(StringPiece* slice_a,
|
| StringPiece* slice_b,
|
| bool only_compare_index_keys,
|
| @@ -1039,6 +1065,15 @@ int Compare(const StringPiece& a,
|
| &slice_a, &slice_b, /*only_compare_index_keys*/ false, ok);
|
| }
|
|
|
| + case KeyPrefix::BLOB_ENTRY: {
|
| + // Provide a stable ordering for invalid data.
|
| + if (slice_a.empty() || slice_b.empty())
|
| + return CompareSizes(slice_a.size(), slice_b.size());
|
| +
|
| + return CompareSuffix<BlobEntryKey>(
|
| + &slice_a, &slice_b, /*only_compare_index_keys*/ false, ok);
|
| + }
|
| +
|
| case KeyPrefix::INDEX_DATA: {
|
| // Provide a stable ordering for invalid data.
|
| if (slice_a.empty() || slice_b.empty())
|
| @@ -1240,6 +1275,8 @@ KeyPrefix::Type KeyPrefix::type() const {
|
| return OBJECT_STORE_DATA;
|
| if (index_id_ == kExistsEntryIndexId)
|
| return EXISTS_ENTRY;
|
| + if (index_id_ == kBlobEntryIndexId)
|
| + return BLOB_ENTRY;
|
| if (index_id_ >= kMinimumIndexId)
|
| return INDEX_DATA;
|
|
|
| @@ -1265,6 +1302,20 @@ std::string DataVersionKey::Encode() {
|
| return ret;
|
| }
|
|
|
| +std::string BlobJournalKey::Encode()
|
| +{
|
| + std::string ret = KeyPrefix::EncodeEmpty();
|
| + ret.push_back(kBlobJournalTypeByte);
|
| + return ret;
|
| +}
|
| +
|
| +std::string LiveBlobJournalKey::Encode()
|
| +{
|
| + std::string ret = KeyPrefix::EncodeEmpty();
|
| + ret.push_back(kLiveBlobJournalTypeByte);
|
| + return ret;
|
| +}
|
| +
|
| DatabaseFreeListKey::DatabaseFreeListKey() : database_id_(-1) {}
|
|
|
| bool DatabaseFreeListKey::Decode(StringPiece* slice,
|
| @@ -1349,6 +1400,10 @@ int DatabaseNameKey::Compare(const DatabaseNameKey& other) {
|
| return database_name_.compare(other.database_name_);
|
| }
|
|
|
| +bool DatabaseMetaDataKey::IsValidBlobKey(int64 blob_key) {
|
| + return blob_key >= kBlobKeyGeneratorInitialNumber;
|
| +}
|
| +
|
| std::string DatabaseMetaDataKey::Encode(int64 database_id,
|
| MetaDataType meta_data_type) {
|
| KeyPrefix prefix(database_id);
|
| @@ -1755,6 +1810,103 @@ scoped_ptr<IndexedDBKey> ExistsEntryKey::user_key() const {
|
|
|
| const int64 ExistsEntryKey::kSpecialIndexNumber = kExistsEntryIndexId;
|
|
|
| +bool BlobEntryKey::Decode(StringPiece* slice, BlobEntryKey* result) {
|
| + KeyPrefix prefix;
|
| + if (!KeyPrefix::Decode(slice, &prefix))
|
| + return false;
|
| + DCHECK(prefix.database_id_);
|
| + DCHECK(prefix.object_store_id_);
|
| + DCHECK_EQ(prefix.index_id_, kSpecialIndexNumber);
|
| +
|
| + if (!ExtractEncodedIDBKey(slice, &result->encoded_user_key_))
|
| + return false;
|
| + result->database_id_ = prefix.database_id_;
|
| + result->object_store_id_ = prefix.object_store_id_;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool BlobEntryKey::FromObjectStoreDataKey(StringPiece* slice,
|
| + BlobEntryKey* result) {
|
| + KeyPrefix prefix;
|
| + if (!KeyPrefix::Decode(slice, &prefix))
|
| + return false;
|
| + DCHECK(prefix.database_id_);
|
| + DCHECK(prefix.object_store_id_);
|
| + DCHECK_EQ(prefix.index_id_, ObjectStoreDataKey::kSpecialIndexNumber);
|
| +
|
| + if (!ExtractEncodedIDBKey(slice, &result->encoded_user_key_))
|
| + return false;
|
| + result->database_id_ = prefix.database_id_;
|
| + result->object_store_id_ = prefix.object_store_id_;
|
| + return true;
|
| +}
|
| +
|
| +std::string BlobEntryKey::ReencodeToObjectStoreDataKey(StringPiece* slice) {
|
| + BlobEntryKey key;
|
| + if (!Decode(slice, &key))
|
| + return std::string();
|
| +
|
| + return ObjectStoreDataKey::Encode(
|
| + key.database_id_, key.object_store_id_, key.encoded_user_key_);
|
| +}
|
| +
|
| +std::string BlobEntryKey::EncodeMinForObjectStore(int64 database_id,
|
| + int64 object_store_id) {
|
| + // Our implied encoded_user_key_ here is empty, the lowest possible key.
|
| + return Encode(database_id, object_store_id, std::string());
|
| +}
|
| +
|
| +// This isn't technically the max for this object store--it's one higher, which
|
| +// means that it's the first key /not/ in the range. That's more what we want,
|
| +// but doesn't match the terminology elsewhere in this file, which is a bit
|
| +// messy.
|
| +std::string BlobEntryKey::EncodeMaxForObjectStore(int64 database_id,
|
| + int64 object_store_id)
|
| +{
|
| + DCHECK(KeyPrefix::ValidIds(database_id, object_store_id));
|
| + KeyPrefix prefix(
|
| + KeyPrefix::CreateWithSpecialIndex(database_id, object_store_id,
|
| + kSpecialIndexNumber + 1));
|
| + return prefix.Encode();
|
| +}
|
| +
|
| +std::string BlobEntryKey::Encode() const
|
| +{
|
| + DCHECK_GT(encoded_user_key_.size(), 0UL);
|
| + return Encode(database_id_, object_store_id_, encoded_user_key_);
|
| +}
|
| +
|
| +std::string BlobEntryKey::Encode(int64 database_id,
|
| + int64 object_store_id,
|
| + const IndexedDBKey& user_key)
|
| +{
|
| + std::string encoded_key;
|
| + EncodeIDBKey(user_key, &encoded_key);
|
| + return Encode(database_id, object_store_id, encoded_key);
|
| +}
|
| +
|
| +std::string BlobEntryKey::Encode(
|
| + int64 database_id, int64 object_store_id,
|
| + const std::string& encoded_user_key) {
|
| + DCHECK(KeyPrefix::ValidIds(database_id, object_store_id));
|
| + KeyPrefix prefix(
|
| + KeyPrefix::CreateWithSpecialIndex(database_id, object_store_id,
|
| + kSpecialIndexNumber));
|
| + std::string ret = prefix.Encode();
|
| + ret.insert(ret.end(), encoded_user_key.begin(), encoded_user_key.end());
|
| + return ret;
|
| +}
|
| +
|
| +int BlobEntryKey::Compare(const BlobEntryKey& other, bool* ok)
|
| +{
|
| + DCHECK_GT(encoded_user_key_.size(), 0UL);
|
| + DCHECK_GT(other.encoded_user_key_.size(), 0UL);
|
| + return CompareEncodedIDBKeys(encoded_user_key_, other.encoded_user_key_, ok);
|
| +}
|
| +
|
| +const int64 BlobEntryKey::kSpecialIndexNumber = kBlobEntryIndexId;
|
| +
|
| IndexDataKey::IndexDataKey()
|
| : database_id_(-1),
|
| object_store_id_(-1),
|
|
|