Home | History | Annotate | Download | only in indexed_db
      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 "base/file_util.h"
      8 #include "base/files/file_path.h"
      9 #include "base/format_macros.h"
     10 #include "base/json/json_reader.h"
     11 #include "base/json/json_writer.h"
     12 #include "base/logging.h"
     13 #include "base/metrics/histogram.h"
     14 #include "base/strings/string_util.h"
     15 #include "base/strings/stringprintf.h"
     16 #include "base/strings/utf_string_conversions.h"
     17 #include "content/browser/child_process_security_policy_impl.h"
     18 #include "content/browser/indexed_db/indexed_db_blob_info.h"
     19 #include "content/browser/indexed_db/indexed_db_class_factory.h"
     20 #include "content/browser/indexed_db/indexed_db_database_error.h"
     21 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
     22 #include "content/browser/indexed_db/indexed_db_metadata.h"
     23 #include "content/browser/indexed_db/indexed_db_tracing.h"
     24 #include "content/browser/indexed_db/indexed_db_value.h"
     25 #include "content/browser/indexed_db/leveldb/leveldb_comparator.h"
     26 #include "content/browser/indexed_db/leveldb/leveldb_database.h"
     27 #include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
     28 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
     29 #include "content/common/indexed_db/indexed_db_key.h"
     30 #include "content/common/indexed_db/indexed_db_key_path.h"
     31 #include "content/common/indexed_db/indexed_db_key_range.h"
     32 #include "content/public/browser/browser_thread.h"
     33 #include "net/url_request/url_request_context.h"
     34 #include "third_party/WebKit/public/platform/WebIDBTypes.h"
     35 #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h"
     36 #include "third_party/leveldatabase/env_chromium.h"
     37 #include "webkit/browser/blob/blob_data_handle.h"
     38 #include "webkit/browser/fileapi/file_stream_writer.h"
     39 #include "webkit/browser/fileapi/file_writer_delegate.h"
     40 #include "webkit/browser/fileapi/local_file_stream_writer.h"
     41 #include "webkit/common/database/database_identifier.h"
     42 
     43 using base::FilePath;
     44 using base::StringPiece;
     45 using fileapi::FileWriterDelegate;
     46 
     47 namespace content {
     48 
     49 namespace {
     50 
     51 FilePath GetBlobDirectoryName(const FilePath& pathBase, int64 database_id) {
     52   return pathBase.AppendASCII(base::StringPrintf("%" PRIx64, database_id));
     53 }
     54 
     55 FilePath GetBlobDirectoryNameForKey(const FilePath& pathBase,
     56                                     int64 database_id,
     57                                     int64 key) {
     58   FilePath path = GetBlobDirectoryName(pathBase, database_id);
     59   path = path.AppendASCII(base::StringPrintf(
     60       "%02x", static_cast<int>(key & 0x000000000000ff00) >> 8));
     61   return path;
     62 }
     63 
     64 FilePath GetBlobFileNameForKey(const FilePath& pathBase,
     65                                int64 database_id,
     66                                int64 key) {
     67   FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key);
     68   path = path.AppendASCII(base::StringPrintf("%" PRIx64, key));
     69   return path;
     70 }
     71 
     72 bool MakeIDBBlobDirectory(const FilePath& pathBase,
     73                           int64 database_id,
     74                           int64 key) {
     75   FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key);
     76   return base::CreateDirectory(path);
     77 }
     78 
     79 static std::string ComputeOriginIdentifier(const GURL& origin_url) {
     80   return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1";
     81 }
     82 
     83 static base::FilePath ComputeFileName(const GURL& origin_url) {
     84   return base::FilePath()
     85       .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url))
     86       .AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb"));
     87 }
     88 
     89 static base::FilePath ComputeBlobPath(const GURL& origin_url) {
     90   return base::FilePath()
     91       .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url))
     92       .AddExtension(FILE_PATH_LITERAL(".indexeddb.blob"));
     93 }
     94 
     95 static base::FilePath ComputeCorruptionFileName(const GURL& origin_url) {
     96   return ComputeFileName(origin_url)
     97       .Append(FILE_PATH_LITERAL("corruption_info.json"));
     98 }
     99 
    100 }  // namespace
    101 
    102 static const int64 kKeyGeneratorInitialNumber =
    103     1;  // From the IndexedDB specification.
    104 
    105 enum IndexedDBBackingStoreErrorSource {
    106   // 0 - 2 are no longer used.
    107   FIND_KEY_IN_INDEX = 3,
    108   GET_IDBDATABASE_METADATA,
    109   GET_INDEXES,
    110   GET_KEY_GENERATOR_CURRENT_NUMBER,
    111   GET_OBJECT_STORES,
    112   GET_RECORD,
    113   KEY_EXISTS_IN_OBJECT_STORE,
    114   LOAD_CURRENT_ROW,
    115   SET_UP_METADATA,
    116   GET_PRIMARY_KEY_VIA_INDEX,
    117   KEY_EXISTS_IN_INDEX,
    118   VERSION_EXISTS,
    119   DELETE_OBJECT_STORE,
    120   SET_MAX_OBJECT_STORE_ID,
    121   SET_MAX_INDEX_ID,
    122   GET_NEW_DATABASE_ID,
    123   GET_NEW_VERSION_NUMBER,
    124   CREATE_IDBDATABASE_METADATA,
    125   DELETE_DATABASE,
    126   TRANSACTION_COMMIT_METHOD,  // TRANSACTION_COMMIT is a WinNT.h macro
    127   GET_DATABASE_NAMES,
    128   DELETE_INDEX,
    129   CLEAR_OBJECT_STORE,
    130   READ_BLOB_JOURNAL,
    131   DECODE_BLOB_JOURNAL,
    132   GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER,
    133   GET_BLOB_INFO_FOR_RECORD,
    134   INTERNAL_ERROR_MAX,
    135 };
    136 
    137 static void RecordInternalError(const char* type,
    138                                 IndexedDBBackingStoreErrorSource location) {
    139   std::string name;
    140   name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error");
    141   base::Histogram::FactoryGet(name,
    142                               1,
    143                               INTERNAL_ERROR_MAX,
    144                               INTERNAL_ERROR_MAX + 1,
    145                               base::HistogramBase::kUmaTargetedHistogramFlag)
    146       ->Add(location);
    147 }
    148 
    149 // Use to signal conditions caused by data corruption.
    150 // A macro is used instead of an inline function so that the assert and log
    151 // report the line number.
    152 #define REPORT_ERROR(type, location)                      \
    153   do {                                                    \
    154     LOG(ERROR) << "IndexedDB " type " Error: " #location; \
    155     RecordInternalError(type, location);                  \
    156   } while (0)
    157 
    158 #define INTERNAL_READ_ERROR(location) REPORT_ERROR("Read", location)
    159 #define INTERNAL_CONSISTENCY_ERROR(location) \
    160   REPORT_ERROR("Consistency", location)
    161 #define INTERNAL_WRITE_ERROR(location) REPORT_ERROR("Write", location)
    162 
    163 // Use to signal conditions that usually indicate developer error, but
    164 // could be caused by data corruption.  A macro is used instead of an
    165 // inline function so that the assert and log report the line number.
    166 // TODO(cmumford): Improve test coverage so that all error conditions are
    167 // "tested" and then delete this macro.
    168 #define REPORT_ERROR_UNTESTED(type, location)             \
    169   do {                                                    \
    170     LOG(ERROR) << "IndexedDB " type " Error: " #location; \
    171     NOTREACHED();                                         \
    172     RecordInternalError(type, location);                  \
    173   } while (0)
    174 
    175 #define INTERNAL_READ_ERROR_UNTESTED(location) \
    176   REPORT_ERROR_UNTESTED("Read", location)
    177 #define INTERNAL_CONSISTENCY_ERROR_UNTESTED(location) \
    178   REPORT_ERROR_UNTESTED("Consistency", location)
    179 #define INTERNAL_WRITE_ERROR_UNTESTED(location) \
    180   REPORT_ERROR_UNTESTED("Write", location)
    181 
    182 static void PutBool(LevelDBTransaction* transaction,
    183                     const StringPiece& key,
    184                     bool value) {
    185   std::string buffer;
    186   EncodeBool(value, &buffer);
    187   transaction->Put(key, &buffer);
    188 }
    189 
    190 // Was able to use LevelDB to read the data w/o error, but the data read was not
    191 // in the expected format.
    192 static leveldb::Status InternalInconsistencyStatus() {
    193   return leveldb::Status::Corruption("Internal inconsistency");
    194 }
    195 
    196 static leveldb::Status InvalidDBKeyStatus() {
    197   return leveldb::Status::InvalidArgument("Invalid database key ID");
    198 }
    199 
    200 static leveldb::Status IOErrorStatus() {
    201   return leveldb::Status::IOError("IO Error");
    202 }
    203 
    204 template <typename DBOrTransaction>
    205 static leveldb::Status GetInt(DBOrTransaction* db,
    206                               const StringPiece& key,
    207                               int64* found_int,
    208                               bool* found) {
    209   std::string result;
    210   leveldb::Status s = db->Get(key, &result, found);
    211   if (!s.ok())
    212     return s;
    213   if (!*found)
    214     return leveldb::Status::OK();
    215   StringPiece slice(result);
    216   if (DecodeInt(&slice, found_int) && slice.empty())
    217     return s;
    218   return InternalInconsistencyStatus();
    219 }
    220 
    221 static void PutInt(LevelDBTransaction* transaction,
    222                    const StringPiece& key,
    223                    int64 value) {
    224   DCHECK_GE(value, 0);
    225   std::string buffer;
    226   EncodeInt(value, &buffer);
    227   transaction->Put(key, &buffer);
    228 }
    229 
    230 template <typename DBOrTransaction>
    231 WARN_UNUSED_RESULT static leveldb::Status GetVarInt(DBOrTransaction* db,
    232                                                     const StringPiece& key,
    233                                                     int64* found_int,
    234                                                     bool* found) {
    235   std::string result;
    236   leveldb::Status s = db->Get(key, &result, found);
    237   if (!s.ok())
    238     return s;
    239   if (!*found)
    240     return leveldb::Status::OK();
    241   StringPiece slice(result);
    242   if (DecodeVarInt(&slice, found_int) && slice.empty())
    243     return s;
    244   return InternalInconsistencyStatus();
    245 }
    246 
    247 static void PutVarInt(LevelDBTransaction* transaction,
    248                       const StringPiece& key,
    249                       int64 value) {
    250   std::string buffer;
    251   EncodeVarInt(value, &buffer);
    252   transaction->Put(key, &buffer);
    253 }
    254 
    255 template <typename DBOrTransaction>
    256 WARN_UNUSED_RESULT static leveldb::Status GetString(
    257     DBOrTransaction* db,
    258     const StringPiece& key,
    259     base::string16* found_string,
    260     bool* found) {
    261   std::string result;
    262   *found = false;
    263   leveldb::Status s = db->Get(key, &result, found);
    264   if (!s.ok())
    265     return s;
    266   if (!*found)
    267     return leveldb::Status::OK();
    268   StringPiece slice(result);
    269   if (DecodeString(&slice, found_string) && slice.empty())
    270     return s;
    271   return InternalInconsistencyStatus();
    272 }
    273 
    274 static void PutString(LevelDBTransaction* transaction,
    275                       const StringPiece& key,
    276                       const base::string16& value) {
    277   std::string buffer;
    278   EncodeString(value, &buffer);
    279   transaction->Put(key, &buffer);
    280 }
    281 
    282 static void PutIDBKeyPath(LevelDBTransaction* transaction,
    283                           const StringPiece& key,
    284                           const IndexedDBKeyPath& value) {
    285   std::string buffer;
    286   EncodeIDBKeyPath(value, &buffer);
    287   transaction->Put(key, &buffer);
    288 }
    289 
    290 static int CompareKeys(const StringPiece& a, const StringPiece& b) {
    291   return Compare(a, b, false /*index_keys*/);
    292 }
    293 
    294 static int CompareIndexKeys(const StringPiece& a, const StringPiece& b) {
    295   return Compare(a, b, true /*index_keys*/);
    296 }
    297 
    298 int IndexedDBBackingStore::Comparator::Compare(const StringPiece& a,
    299                                                const StringPiece& b) const {
    300   return content::Compare(a, b, false /*index_keys*/);
    301 }
    302 
    303 const char* IndexedDBBackingStore::Comparator::Name() const {
    304   return "idb_cmp1";
    305 }
    306 
    307 // 0 - Initial version.
    308 // 1 - Adds UserIntVersion to DatabaseMetaData.
    309 // 2 - Adds DataVersion to to global metadata.
    310 // 3 - Adds metadata needed for blob support.
    311 static const int64 kLatestKnownSchemaVersion = 3;
    312 WARN_UNUSED_RESULT static bool IsSchemaKnown(LevelDBDatabase* db, bool* known) {
    313   int64 db_schema_version = 0;
    314   bool found = false;
    315   leveldb::Status s =
    316       GetInt(db, SchemaVersionKey::Encode(), &db_schema_version, &found);
    317   if (!s.ok())
    318     return false;
    319   if (!found) {
    320     *known = true;
    321     return true;
    322   }
    323   if (db_schema_version > kLatestKnownSchemaVersion) {
    324     *known = false;
    325     return true;
    326   }
    327 
    328   const uint32 latest_known_data_version =
    329       blink::kSerializedScriptValueVersion;
    330   int64 db_data_version = 0;
    331   s = GetInt(db, DataVersionKey::Encode(), &db_data_version, &found);
    332   if (!s.ok())
    333     return false;
    334   if (!found) {
    335     *known = true;
    336     return true;
    337   }
    338 
    339   if (db_data_version > latest_known_data_version) {
    340     *known = false;
    341     return true;
    342   }
    343 
    344   *known = true;
    345   return true;
    346 }
    347 
    348 // TODO(ericu): Move this down into the member section of this file.  I'm
    349 // leaving it here for this CL as it's easier to see the diffs in place.
    350 WARN_UNUSED_RESULT bool IndexedDBBackingStore::SetUpMetadata() {
    351   const uint32 latest_known_data_version =
    352       blink::kSerializedScriptValueVersion;
    353   const std::string schema_version_key = SchemaVersionKey::Encode();
    354   const std::string data_version_key = DataVersionKey::Encode();
    355 
    356   scoped_refptr<LevelDBTransaction> transaction =
    357       IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
    358 
    359   int64 db_schema_version = 0;
    360   int64 db_data_version = 0;
    361   bool found = false;
    362   leveldb::Status s =
    363       GetInt(transaction.get(), schema_version_key, &db_schema_version, &found);
    364   if (!s.ok()) {
    365     INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA);
    366     return false;
    367   }
    368   if (!found) {
    369     // Initialize new backing store.
    370     db_schema_version = kLatestKnownSchemaVersion;
    371     PutInt(transaction.get(), schema_version_key, db_schema_version);
    372     db_data_version = latest_known_data_version;
    373     PutInt(transaction.get(), data_version_key, db_data_version);
    374     // If a blob directory already exists for this database, blow it away.  It's
    375     // leftover from a partially-purged previous generation of data.
    376     if (!base::DeleteFile(blob_path_, true)) {
    377       INTERNAL_WRITE_ERROR_UNTESTED(SET_UP_METADATA);
    378       return false;
    379     }
    380   } else {
    381     // Upgrade old backing store.
    382     DCHECK_LE(db_schema_version, kLatestKnownSchemaVersion);
    383     if (db_schema_version < 1) {
    384       db_schema_version = 1;
    385       PutInt(transaction.get(), schema_version_key, db_schema_version);
    386       const std::string start_key =
    387           DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_);
    388       const std::string stop_key =
    389           DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_);
    390       scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
    391       for (s = it->Seek(start_key);
    392            s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0;
    393            s = it->Next()) {
    394         int64 database_id = 0;
    395         found = false;
    396         s = GetInt(transaction.get(), it->Key(), &database_id, &found);
    397         if (!s.ok()) {
    398           INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA);
    399           return false;
    400         }
    401         if (!found) {
    402           INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_UP_METADATA);
    403           return false;
    404         }
    405         std::string int_version_key = DatabaseMetaDataKey::Encode(
    406             database_id, DatabaseMetaDataKey::USER_INT_VERSION);
    407         PutVarInt(transaction.get(),
    408                   int_version_key,
    409                   IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
    410       }
    411     }
    412     if (s.ok() && db_schema_version < 2) {
    413       db_schema_version = 2;
    414       PutInt(transaction.get(), schema_version_key, db_schema_version);
    415       db_data_version = blink::kSerializedScriptValueVersion;
    416       PutInt(transaction.get(), data_version_key, db_data_version);
    417     }
    418     if (db_schema_version < 3) {
    419       db_schema_version = 3;
    420       if (!base::DeleteFile(blob_path_, true)) {
    421         INTERNAL_WRITE_ERROR_UNTESTED(SET_UP_METADATA);
    422         return false;
    423       }
    424     }
    425   }
    426 
    427   if (!s.ok()) {
    428     INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA);
    429     return false;
    430   }
    431 
    432   // All new values will be written using this serialization version.
    433   found = false;
    434   s = GetInt(transaction.get(), data_version_key, &db_data_version, &found);
    435   if (!s.ok()) {
    436     INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA);
    437     return false;
    438   }
    439   if (!found) {
    440     INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_UP_METADATA);
    441     return false;
    442   }
    443   if (db_data_version < latest_known_data_version) {
    444     db_data_version = latest_known_data_version;
    445     PutInt(transaction.get(), data_version_key, db_data_version);
    446   }
    447 
    448   DCHECK_EQ(db_schema_version, kLatestKnownSchemaVersion);
    449   DCHECK_EQ(db_data_version, latest_known_data_version);
    450 
    451   s = transaction->Commit();
    452   if (!s.ok()) {
    453     INTERNAL_WRITE_ERROR_UNTESTED(SET_UP_METADATA);
    454     return false;
    455   }
    456   return true;
    457 }
    458 
    459 template <typename DBOrTransaction>
    460 WARN_UNUSED_RESULT static leveldb::Status GetMaxObjectStoreId(
    461     DBOrTransaction* db,
    462     int64 database_id,
    463     int64* max_object_store_id) {
    464   const std::string max_object_store_id_key = DatabaseMetaDataKey::Encode(
    465       database_id, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID);
    466   return GetMaxObjectStoreId(db, max_object_store_id_key, max_object_store_id);
    467 }
    468 
    469 template <typename DBOrTransaction>
    470 WARN_UNUSED_RESULT static leveldb::Status GetMaxObjectStoreId(
    471     DBOrTransaction* db,
    472     const std::string& max_object_store_id_key,
    473     int64* max_object_store_id) {
    474   *max_object_store_id = -1;
    475   bool found = false;
    476   leveldb::Status s =
    477       GetInt(db, max_object_store_id_key, max_object_store_id, &found);
    478   if (!s.ok())
    479     return s;
    480   if (!found)
    481     *max_object_store_id = 0;
    482 
    483   DCHECK_GE(*max_object_store_id, 0);
    484   return s;
    485 }
    486 
    487 class DefaultLevelDBFactory : public LevelDBFactory {
    488  public:
    489   DefaultLevelDBFactory() {}
    490   virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name,
    491                                       const LevelDBComparator* comparator,
    492                                       scoped_ptr<LevelDBDatabase>* db,
    493                                       bool* is_disk_full) OVERRIDE {
    494     return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full);
    495   }
    496   virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name)
    497       OVERRIDE {
    498     return LevelDBDatabase::Destroy(file_name);
    499   }
    500 
    501  private:
    502   DISALLOW_COPY_AND_ASSIGN(DefaultLevelDBFactory);
    503 };
    504 
    505 static bool GetBlobKeyGeneratorCurrentNumber(
    506     LevelDBTransaction* leveldb_transaction,
    507     int64 database_id,
    508     int64* blob_key_generator_current_number) {
    509   const std::string key_gen_key = DatabaseMetaDataKey::Encode(
    510       database_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER);
    511 
    512   // Default to initial number if not found.
    513   int64 cur_number = DatabaseMetaDataKey::kBlobKeyGeneratorInitialNumber;
    514   std::string data;
    515 
    516   bool found = false;
    517   bool ok = leveldb_transaction->Get(key_gen_key, &data, &found).ok();
    518   if (!ok) {
    519     INTERNAL_READ_ERROR_UNTESTED(GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER);
    520     return false;
    521   }
    522   if (found) {
    523     StringPiece slice(data);
    524     if (!DecodeVarInt(&slice, &cur_number) || !slice.empty() ||
    525         !DatabaseMetaDataKey::IsValidBlobKey(cur_number)) {
    526       INTERNAL_READ_ERROR_UNTESTED(GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER);
    527       return false;
    528     }
    529   }
    530   *blob_key_generator_current_number = cur_number;
    531   return true;
    532 }
    533 
    534 static bool UpdateBlobKeyGeneratorCurrentNumber(
    535     LevelDBTransaction* leveldb_transaction,
    536     int64 database_id,
    537     int64 blob_key_generator_current_number) {
    538 #ifndef NDEBUG
    539   int64 old_number;
    540   if (!GetBlobKeyGeneratorCurrentNumber(
    541           leveldb_transaction, database_id, &old_number))
    542     return false;
    543   DCHECK_LT(old_number, blob_key_generator_current_number);
    544 #endif
    545   DCHECK(
    546       DatabaseMetaDataKey::IsValidBlobKey(blob_key_generator_current_number));
    547   const std::string key = DatabaseMetaDataKey::Encode(
    548       database_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER);
    549 
    550   PutVarInt(leveldb_transaction, key, blob_key_generator_current_number);
    551   return true;
    552 }
    553 
    554 // TODO(ericu): Error recovery. If we persistently can't read the
    555 // blob journal, the safe thing to do is to clear it and leak the blobs,
    556 // though that may be costly. Still, database/directory deletion should always
    557 // clean things up, and we can write an fsck that will do a full correction if
    558 // need be.
    559 template <typename T>
    560 static leveldb::Status GetBlobJournal(const StringPiece& leveldb_key,
    561                                       T* leveldb_transaction,
    562                                       BlobJournalType* journal) {
    563   std::string data;
    564   bool found = false;
    565   leveldb::Status s = leveldb_transaction->Get(leveldb_key, &data, &found);
    566   if (!s.ok()) {
    567     INTERNAL_READ_ERROR_UNTESTED(READ_BLOB_JOURNAL);
    568     return s;
    569   }
    570   journal->clear();
    571   if (!found || !data.size())
    572     return leveldb::Status::OK();
    573   StringPiece slice(data);
    574   if (!DecodeBlobJournal(&slice, journal)) {
    575     INTERNAL_READ_ERROR_UNTESTED(DECODE_BLOB_JOURNAL);
    576     s = InternalInconsistencyStatus();
    577   }
    578   return s;
    579 }
    580 
    581 static void ClearBlobJournal(LevelDBTransaction* leveldb_transaction,
    582                              const std::string& level_db_key) {
    583   leveldb_transaction->Remove(level_db_key);
    584 }
    585 
    586 static void UpdatePrimaryJournalWithBlobList(
    587     LevelDBTransaction* leveldb_transaction,
    588     const BlobJournalType& journal) {
    589   const std::string leveldb_key = BlobJournalKey::Encode();
    590   std::string data;
    591   EncodeBlobJournal(journal, &data);
    592   leveldb_transaction->Put(leveldb_key, &data);
    593 }
    594 
    595 static void UpdateLiveBlobJournalWithBlobList(
    596     LevelDBTransaction* leveldb_transaction,
    597     const BlobJournalType& journal) {
    598   const std::string leveldb_key = LiveBlobJournalKey::Encode();
    599   std::string data;
    600   EncodeBlobJournal(journal, &data);
    601   leveldb_transaction->Put(leveldb_key, &data);
    602 }
    603 
    604 static leveldb::Status MergeBlobsIntoLiveBlobJournal(
    605     LevelDBTransaction* leveldb_transaction,
    606     const BlobJournalType& journal) {
    607   BlobJournalType old_journal;
    608   const std::string key = LiveBlobJournalKey::Encode();
    609   leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &old_journal);
    610   if (!s.ok())
    611     return s;
    612 
    613   old_journal.insert(old_journal.end(), journal.begin(), journal.end());
    614 
    615   UpdateLiveBlobJournalWithBlobList(leveldb_transaction, old_journal);
    616   return leveldb::Status::OK();
    617 }
    618 
    619 static void UpdateBlobJournalWithDatabase(
    620     LevelDBDirectTransaction* leveldb_transaction,
    621     int64 database_id) {
    622   BlobJournalType journal;
    623   journal.push_back(
    624       std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey));
    625   const std::string key = BlobJournalKey::Encode();
    626   std::string data;
    627   EncodeBlobJournal(journal, &data);
    628   leveldb_transaction->Put(key, &data);
    629 }
    630 
    631 static leveldb::Status MergeDatabaseIntoLiveBlobJournal(
    632     LevelDBDirectTransaction* leveldb_transaction,
    633     int64 database_id) {
    634   BlobJournalType journal;
    635   const std::string key = LiveBlobJournalKey::Encode();
    636   leveldb::Status s = GetBlobJournal(key, leveldb_transaction, &journal);
    637   if (!s.ok())
    638     return s;
    639   journal.push_back(
    640       std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey));
    641   std::string data;
    642   EncodeBlobJournal(journal, &data);
    643   leveldb_transaction->Put(key, &data);
    644   return leveldb::Status::OK();
    645 }
    646 
    647 // Blob Data is encoded as a series of:
    648 //   { is_file [bool], key [int64 as varInt],
    649 //     type [string-with-length, may be empty],
    650 //     (for Blobs only) size [int64 as varInt]
    651 //     (for Files only) fileName [string-with-length]
    652 //   }
    653 // There is no length field; just read until you run out of data.
    654 static std::string EncodeBlobData(
    655     const std::vector<IndexedDBBlobInfo*>& blob_info) {
    656   std::string ret;
    657   std::vector<IndexedDBBlobInfo*>::const_iterator iter;
    658   for (iter = blob_info.begin(); iter != blob_info.end(); ++iter) {
    659     const IndexedDBBlobInfo& info = **iter;
    660     EncodeBool(info.is_file(), &ret);
    661     EncodeVarInt(info.key(), &ret);
    662     EncodeStringWithLength(info.type(), &ret);
    663     if (info.is_file())
    664       EncodeStringWithLength(info.file_name(), &ret);
    665     else
    666       EncodeVarInt(info.size(), &ret);
    667   }
    668   return ret;
    669 }
    670 
    671 static bool DecodeBlobData(const std::string& data,
    672                            std::vector<IndexedDBBlobInfo>* output) {
    673   std::vector<IndexedDBBlobInfo> ret;
    674   output->clear();
    675   StringPiece slice(data);
    676   while (!slice.empty()) {
    677     bool is_file;
    678     int64 key;
    679     base::string16 type;
    680     int64 size;
    681     base::string16 file_name;
    682 
    683     if (!DecodeBool(&slice, &is_file))
    684       return false;
    685     if (!DecodeVarInt(&slice, &key) ||
    686         !DatabaseMetaDataKey::IsValidBlobKey(key))
    687       return false;
    688     if (!DecodeStringWithLength(&slice, &type))
    689       return false;
    690     if (is_file) {
    691       if (!DecodeStringWithLength(&slice, &file_name))
    692         return false;
    693       ret.push_back(IndexedDBBlobInfo(key, type, file_name));
    694     } else {
    695       if (!DecodeVarInt(&slice, &size) || size < 0)
    696         return false;
    697       ret.push_back(IndexedDBBlobInfo(type, static_cast<uint64>(size), key));
    698     }
    699   }
    700   output->swap(ret);
    701 
    702   return true;
    703 }
    704 
    705 IndexedDBBackingStore::IndexedDBBackingStore(
    706     IndexedDBFactory* indexed_db_factory,
    707     const GURL& origin_url,
    708     const base::FilePath& blob_path,
    709     net::URLRequestContext* request_context,
    710     scoped_ptr<LevelDBDatabase> db,
    711     scoped_ptr<LevelDBComparator> comparator,
    712     base::TaskRunner* task_runner)
    713     : indexed_db_factory_(indexed_db_factory),
    714       origin_url_(origin_url),
    715       blob_path_(blob_path),
    716       origin_identifier_(ComputeOriginIdentifier(origin_url)),
    717       request_context_(request_context),
    718       task_runner_(task_runner),
    719       db_(db.Pass()),
    720       comparator_(comparator.Pass()),
    721       active_blob_registry_(this) {
    722 }
    723 
    724 IndexedDBBackingStore::~IndexedDBBackingStore() {
    725   if (!blob_path_.empty() && !child_process_ids_granted_.empty()) {
    726     ChildProcessSecurityPolicyImpl* policy =
    727         ChildProcessSecurityPolicyImpl::GetInstance();
    728     std::set<int>::const_iterator iter;
    729     for (iter = child_process_ids_granted_.begin();
    730          iter != child_process_ids_granted_.end();
    731          ++iter) {
    732       policy->RevokeAllPermissionsForFile(*iter, blob_path_);
    733     }
    734   }
    735   STLDeleteContainerPairSecondPointers(incognito_blob_map_.begin(),
    736                                        incognito_blob_map_.end());
    737   // db_'s destructor uses comparator_. The order of destruction is important.
    738   db_.reset();
    739   comparator_.reset();
    740 }
    741 
    742 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier(
    743     const std::string& primary_key,
    744     int64 version)
    745     : primary_key_(primary_key), version_(version) {
    746   DCHECK(!primary_key.empty());
    747 }
    748 IndexedDBBackingStore::RecordIdentifier::RecordIdentifier()
    749     : primary_key_(), version_(-1) {}
    750 IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() {}
    751 
    752 IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() {}
    753 IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() {}
    754 
    755 enum IndexedDBBackingStoreOpenResult {
    756   INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS,
    757   INDEXED_DB_BACKING_STORE_OPEN_SUCCESS,
    758   INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY,
    759   INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA,
    760   INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED,
    761   INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED,
    762   INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS,
    763   INDEXED_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA,
    764   INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR,
    765   INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED,
    766   INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII,
    767   INDEXED_DB_BACKING_STORE_OPEN_DISK_FULL_DEPRECATED,
    768   INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG,
    769   INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY,
    770   INDEXED_DB_BACKING_STORE_OPEN_FAILED_PRIOR_CORRUPTION,
    771   INDEXED_DB_BACKING_STORE_OPEN_FAILED_CLEANUP_JOURNAL_ERROR,
    772   INDEXED_DB_BACKING_STORE_OPEN_MAX,
    773 };
    774 
    775 // static
    776 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
    777     IndexedDBFactory* indexed_db_factory,
    778     const GURL& origin_url,
    779     const base::FilePath& path_base,
    780     net::URLRequestContext* request_context,
    781     blink::WebIDBDataLoss* data_loss,
    782     std::string* data_loss_message,
    783     bool* disk_full,
    784     base::TaskRunner* task_runner,
    785     bool clean_journal) {
    786   *data_loss = blink::WebIDBDataLossNone;
    787   DefaultLevelDBFactory leveldb_factory;
    788   return IndexedDBBackingStore::Open(indexed_db_factory,
    789                                      origin_url,
    790                                      path_base,
    791                                      request_context,
    792                                      data_loss,
    793                                      data_loss_message,
    794                                      disk_full,
    795                                      &leveldb_factory,
    796                                      task_runner,
    797                                      clean_journal);
    798 }
    799 
    800 static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) {
    801   if (origin_url.host() == "docs.google.com")
    802     return ".Docs";
    803   return std::string();
    804 }
    805 
    806 static void HistogramOpenStatus(IndexedDBBackingStoreOpenResult result,
    807                                 const GURL& origin_url) {
    808   UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.BackingStore.OpenStatus",
    809                             result,
    810                             INDEXED_DB_BACKING_STORE_OPEN_MAX);
    811   const std::string suffix = OriginToCustomHistogramSuffix(origin_url);
    812   // Data from the WebCore.IndexedDB.BackingStore.OpenStatus histogram is used
    813   // to generate a graph. So as not to alter the meaning of that graph,
    814   // continue to collect all stats there (above) but also now collect docs stats
    815   // separately (below).
    816   if (!suffix.empty()) {
    817     base::LinearHistogram::FactoryGet(
    818         "WebCore.IndexedDB.BackingStore.OpenStatus" + suffix,
    819         1,
    820         INDEXED_DB_BACKING_STORE_OPEN_MAX,
    821         INDEXED_DB_BACKING_STORE_OPEN_MAX + 1,
    822         base::HistogramBase::kUmaTargetedHistogramFlag)->Add(result);
    823   }
    824 }
    825 
    826 static bool IsPathTooLong(const base::FilePath& leveldb_dir) {
    827   int limit = base::GetMaximumPathComponentLength(leveldb_dir.DirName());
    828   if (limit == -1) {
    829     DLOG(WARNING) << "GetMaximumPathComponentLength returned -1";
    830     // In limited testing, ChromeOS returns 143, other OSes 255.
    831 #if defined(OS_CHROMEOS)
    832     limit = 143;
    833 #else
    834     limit = 255;
    835 #endif
    836   }
    837   size_t component_length = leveldb_dir.BaseName().value().length();
    838   if (component_length > static_cast<uint32_t>(limit)) {
    839     DLOG(WARNING) << "Path component length (" << component_length
    840                   << ") exceeds maximum (" << limit
    841                   << ") allowed by this filesystem.";
    842     const int min = 140;
    843     const int max = 300;
    844     const int num_buckets = 12;
    845     UMA_HISTOGRAM_CUSTOM_COUNTS(
    846         "WebCore.IndexedDB.BackingStore.OverlyLargeOriginLength",
    847         component_length,
    848         min,
    849         max,
    850         num_buckets);
    851     return true;
    852   }
    853   return false;
    854 }
    855 
    856 leveldb::Status IndexedDBBackingStore::DestroyBackingStore(
    857     const base::FilePath& path_base,
    858     const GURL& origin_url) {
    859   const base::FilePath file_path =
    860       path_base.Append(ComputeFileName(origin_url));
    861   DefaultLevelDBFactory leveldb_factory;
    862   return leveldb_factory.DestroyLevelDB(file_path);
    863 }
    864 
    865 bool IndexedDBBackingStore::ReadCorruptionInfo(const base::FilePath& path_base,
    866                                                const GURL& origin_url,
    867                                                std::string& message) {
    868   const base::FilePath info_path =
    869       path_base.Append(ComputeCorruptionFileName(origin_url));
    870 
    871   if (IsPathTooLong(info_path))
    872     return false;
    873 
    874   const int64 max_json_len = 4096;
    875   int64 file_size(0);
    876   if (!GetFileSize(info_path, &file_size) || file_size > max_json_len)
    877     return false;
    878   if (!file_size) {
    879     NOTREACHED();
    880     return false;
    881   }
    882 
    883   base::File file(info_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
    884   bool success = false;
    885   if (file.IsValid()) {
    886     std::vector<char> bytes(file_size);
    887     if (file_size == file.Read(0, &bytes[0], file_size)) {
    888       std::string input_js(&bytes[0], file_size);
    889       base::JSONReader reader;
    890       scoped_ptr<base::Value> val(reader.ReadToValue(input_js));
    891       if (val && val->GetType() == base::Value::TYPE_DICTIONARY) {
    892         base::DictionaryValue* dict_val =
    893             static_cast<base::DictionaryValue*>(val.get());
    894         success = dict_val->GetString("message", &message);
    895       }
    896     }
    897     file.Close();
    898   }
    899 
    900   base::DeleteFile(info_path, false);
    901 
    902   return success;
    903 }
    904 
    905 bool IndexedDBBackingStore::RecordCorruptionInfo(
    906     const base::FilePath& path_base,
    907     const GURL& origin_url,
    908     const std::string& message) {
    909   const base::FilePath info_path =
    910       path_base.Append(ComputeCorruptionFileName(origin_url));
    911   if (IsPathTooLong(info_path))
    912     return false;
    913 
    914   base::DictionaryValue root_dict;
    915   root_dict.SetString("message", message);
    916   std::string output_js;
    917   base::JSONWriter::Write(&root_dict, &output_js);
    918 
    919   base::File file(info_path,
    920                   base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
    921   if (!file.IsValid())
    922     return false;
    923   int written = file.Write(0, output_js.c_str(), output_js.length());
    924   return size_t(written) == output_js.length();
    925 }
    926 
    927 // static
    928 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
    929     IndexedDBFactory* indexed_db_factory,
    930     const GURL& origin_url,
    931     const base::FilePath& path_base,
    932     net::URLRequestContext* request_context,
    933     blink::WebIDBDataLoss* data_loss,
    934     std::string* data_loss_message,
    935     bool* is_disk_full,
    936     LevelDBFactory* leveldb_factory,
    937     base::TaskRunner* task_runner,
    938     bool clean_journal) {
    939   IDB_TRACE("IndexedDBBackingStore::Open");
    940   DCHECK(!path_base.empty());
    941   *data_loss = blink::WebIDBDataLossNone;
    942   *data_loss_message = "";
    943   *is_disk_full = false;
    944 
    945   scoped_ptr<LevelDBComparator> comparator(new Comparator());
    946 
    947   if (!base::IsStringASCII(path_base.AsUTF8Unsafe())) {
    948     HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII,
    949                         origin_url);
    950   }
    951   if (!base::CreateDirectory(path_base)) {
    952     LOG(ERROR) << "Unable to create IndexedDB database path "
    953                << path_base.AsUTF8Unsafe();
    954     HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY,
    955                         origin_url);
    956     return scoped_refptr<IndexedDBBackingStore>();
    957   }
    958 
    959   const base::FilePath file_path =
    960       path_base.Append(ComputeFileName(origin_url));
    961   const base::FilePath blob_path =
    962       path_base.Append(ComputeBlobPath(origin_url));
    963 
    964   if (IsPathTooLong(file_path)) {
    965     HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG,
    966                         origin_url);
    967     return scoped_refptr<IndexedDBBackingStore>();
    968   }
    969 
    970   scoped_ptr<LevelDBDatabase> db;
    971   leveldb::Status status = leveldb_factory->OpenLevelDB(
    972       file_path, comparator.get(), &db, is_disk_full);
    973 
    974   DCHECK(!db == !status.ok());
    975   if (!status.ok()) {
    976     if (leveldb_env::IndicatesDiskFull(status)) {
    977       *is_disk_full = true;
    978     } else if (leveldb_env::IsCorruption(status)) {
    979       *data_loss = blink::WebIDBDataLossTotal;
    980       *data_loss_message = leveldb_env::GetCorruptionMessage(status);
    981     }
    982   }
    983 
    984   bool is_schema_known = false;
    985   if (db) {
    986     std::string corruption_message;
    987     if (ReadCorruptionInfo(path_base, origin_url, corruption_message)) {
    988       LOG(ERROR) << "IndexedDB recovering from a corrupted (and deleted) "
    989                     "database.";
    990       HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_PRIOR_CORRUPTION,
    991                           origin_url);
    992       db.reset();
    993       *data_loss = blink::WebIDBDataLossTotal;
    994       *data_loss_message =
    995           "IndexedDB (database was corrupt): " + corruption_message;
    996     } else if (!IsSchemaKnown(db.get(), &is_schema_known)) {
    997       LOG(ERROR) << "IndexedDB had IO error checking schema, treating it as "
    998                     "failure to open";
    999       HistogramOpenStatus(
   1000           INDEXED_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA,
   1001           origin_url);
   1002       db.reset();
   1003       *data_loss = blink::WebIDBDataLossTotal;
   1004       *data_loss_message = "I/O error checking schema";
   1005     } else if (!is_schema_known) {
   1006       LOG(ERROR) << "IndexedDB backing store had unknown schema, treating it "
   1007                     "as failure to open";
   1008       HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA,
   1009                           origin_url);
   1010       db.reset();
   1011       *data_loss = blink::WebIDBDataLossTotal;
   1012       *data_loss_message = "Unknown schema";
   1013     }
   1014   }
   1015 
   1016   DCHECK(status.ok() || !is_schema_known || leveldb_env::IsIOError(status) ||
   1017          leveldb_env::IsCorruption(status));
   1018 
   1019   if (db) {
   1020     HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_SUCCESS, origin_url);
   1021   } else if (leveldb_env::IsIOError(status)) {
   1022     LOG(ERROR) << "Unable to open backing store, not trying to recover - "
   1023                << status.ToString();
   1024     HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, origin_url);
   1025     return scoped_refptr<IndexedDBBackingStore>();
   1026   } else {
   1027     DCHECK(!is_schema_known || leveldb_env::IsCorruption(status));
   1028     LOG(ERROR) << "IndexedDB backing store open failed, attempting cleanup";
   1029     status = leveldb_factory->DestroyLevelDB(file_path);
   1030     if (!status.ok()) {
   1031       LOG(ERROR) << "IndexedDB backing store cleanup failed";
   1032       HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED,
   1033                           origin_url);
   1034       return scoped_refptr<IndexedDBBackingStore>();
   1035     }
   1036 
   1037     LOG(ERROR) << "IndexedDB backing store cleanup succeeded, reopening";
   1038     leveldb_factory->OpenLevelDB(file_path, comparator.get(), &db, NULL);
   1039     if (!db) {
   1040       LOG(ERROR) << "IndexedDB backing store reopen after recovery failed";
   1041       HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED,
   1042                           origin_url);
   1043       return scoped_refptr<IndexedDBBackingStore>();
   1044     }
   1045     HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS,
   1046                         origin_url);
   1047   }
   1048 
   1049   if (!db) {
   1050     NOTREACHED();
   1051     HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_ERR,
   1052                         origin_url);
   1053     return scoped_refptr<IndexedDBBackingStore>();
   1054   }
   1055 
   1056   scoped_refptr<IndexedDBBackingStore> backing_store =
   1057       Create(indexed_db_factory,
   1058              origin_url,
   1059              blob_path,
   1060              request_context,
   1061              db.Pass(),
   1062              comparator.Pass(),
   1063              task_runner);
   1064 
   1065   if (clean_journal && backing_store &&
   1066       !backing_store->CleanUpBlobJournal(LiveBlobJournalKey::Encode()).ok()) {
   1067     HistogramOpenStatus(
   1068         INDEXED_DB_BACKING_STORE_OPEN_FAILED_CLEANUP_JOURNAL_ERROR, origin_url);
   1069     return scoped_refptr<IndexedDBBackingStore>();
   1070   }
   1071   return backing_store;
   1072 }
   1073 
   1074 // static
   1075 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
   1076     const GURL& origin_url,
   1077     base::TaskRunner* task_runner) {
   1078   DefaultLevelDBFactory leveldb_factory;
   1079   return IndexedDBBackingStore::OpenInMemory(
   1080       origin_url, &leveldb_factory, task_runner);
   1081 }
   1082 
   1083 // static
   1084 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
   1085     const GURL& origin_url,
   1086     LevelDBFactory* leveldb_factory,
   1087     base::TaskRunner* task_runner) {
   1088   IDB_TRACE("IndexedDBBackingStore::OpenInMemory");
   1089 
   1090   scoped_ptr<LevelDBComparator> comparator(new Comparator());
   1091   scoped_ptr<LevelDBDatabase> db =
   1092       LevelDBDatabase::OpenInMemory(comparator.get());
   1093   if (!db) {
   1094     LOG(ERROR) << "LevelDBDatabase::OpenInMemory failed.";
   1095     HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED,
   1096                         origin_url);
   1097     return scoped_refptr<IndexedDBBackingStore>();
   1098   }
   1099   HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, origin_url);
   1100 
   1101   return Create(NULL /* indexed_db_factory */,
   1102                 origin_url,
   1103                 base::FilePath(),
   1104                 NULL /* request_context */,
   1105                 db.Pass(),
   1106                 comparator.Pass(),
   1107                 task_runner);
   1108 }
   1109 
   1110 // static
   1111 scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create(
   1112     IndexedDBFactory* indexed_db_factory,
   1113     const GURL& origin_url,
   1114     const base::FilePath& blob_path,
   1115     net::URLRequestContext* request_context,
   1116     scoped_ptr<LevelDBDatabase> db,
   1117     scoped_ptr<LevelDBComparator> comparator,
   1118     base::TaskRunner* task_runner) {
   1119   // TODO(jsbell): Handle comparator name changes.
   1120   scoped_refptr<IndexedDBBackingStore> backing_store(
   1121       new IndexedDBBackingStore(indexed_db_factory,
   1122                                 origin_url,
   1123                                 blob_path,
   1124                                 request_context,
   1125                                 db.Pass(),
   1126                                 comparator.Pass(),
   1127                                 task_runner));
   1128   if (!backing_store->SetUpMetadata())
   1129     return scoped_refptr<IndexedDBBackingStore>();
   1130 
   1131   return backing_store;
   1132 }
   1133 
   1134 void IndexedDBBackingStore::GrantChildProcessPermissions(int child_process_id) {
   1135   if (!child_process_ids_granted_.count(child_process_id)) {
   1136     child_process_ids_granted_.insert(child_process_id);
   1137     ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
   1138         child_process_id, blob_path_);
   1139   }
   1140 }
   1141 
   1142 std::vector<base::string16> IndexedDBBackingStore::GetDatabaseNames(
   1143     leveldb::Status* s) {
   1144   *s = leveldb::Status::OK();
   1145   std::vector<base::string16> found_names;
   1146   const std::string start_key =
   1147       DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_);
   1148   const std::string stop_key =
   1149       DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_);
   1150 
   1151   DCHECK(found_names.empty());
   1152 
   1153   scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
   1154   for (*s = it->Seek(start_key);
   1155        s->ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0;
   1156        *s = it->Next()) {
   1157     StringPiece slice(it->Key());
   1158     DatabaseNameKey database_name_key;
   1159     if (!DatabaseNameKey::Decode(&slice, &database_name_key) ||
   1160         !slice.empty()) {
   1161       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_DATABASE_NAMES);
   1162       continue;
   1163     }
   1164     found_names.push_back(database_name_key.database_name());
   1165   }
   1166 
   1167   if (!s->ok())
   1168     INTERNAL_READ_ERROR_UNTESTED(GET_DATABASE_NAMES);
   1169 
   1170   return found_names;
   1171 }
   1172 
   1173 leveldb::Status IndexedDBBackingStore::GetIDBDatabaseMetaData(
   1174     const base::string16& name,
   1175     IndexedDBDatabaseMetadata* metadata,
   1176     bool* found) {
   1177   const std::string key = DatabaseNameKey::Encode(origin_identifier_, name);
   1178   *found = false;
   1179 
   1180   leveldb::Status s = GetInt(db_.get(), key, &metadata->id, found);
   1181   if (!s.ok()) {
   1182     INTERNAL_READ_ERROR(GET_IDBDATABASE_METADATA);
   1183     return s;
   1184   }
   1185   if (!*found)
   1186     return leveldb::Status::OK();
   1187 
   1188   s = GetString(db_.get(),
   1189                 DatabaseMetaDataKey::Encode(metadata->id,
   1190                                             DatabaseMetaDataKey::USER_VERSION),
   1191                 &metadata->version,
   1192                 found);
   1193   if (!s.ok()) {
   1194     INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
   1195     return s;
   1196   }
   1197   if (!*found) {
   1198     INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
   1199     return InternalInconsistencyStatus();
   1200   }
   1201 
   1202   s = GetVarInt(db_.get(),
   1203                 DatabaseMetaDataKey::Encode(
   1204                     metadata->id, DatabaseMetaDataKey::USER_INT_VERSION),
   1205                 &metadata->int_version,
   1206                 found);
   1207   if (!s.ok()) {
   1208     INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
   1209     return s;
   1210   }
   1211   if (!*found) {
   1212     INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
   1213     return InternalInconsistencyStatus();
   1214   }
   1215 
   1216   if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION)
   1217     metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION;
   1218 
   1219   s = GetMaxObjectStoreId(
   1220       db_.get(), metadata->id, &metadata->max_object_store_id);
   1221   if (!s.ok()) {
   1222     INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
   1223   }
   1224 
   1225   // We don't cache this, we just check it if it's there.
   1226   int64 blob_key_generator_current_number =
   1227       DatabaseMetaDataKey::kInvalidBlobKey;
   1228 
   1229   s = GetVarInt(
   1230       db_.get(),
   1231       DatabaseMetaDataKey::Encode(
   1232           metadata->id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER),
   1233       &blob_key_generator_current_number,
   1234       found);
   1235   if (!s.ok()) {
   1236     INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
   1237     return s;
   1238   }
   1239   if (!*found) {
   1240     // This database predates blob support.
   1241     *found = true;
   1242   } else if (!DatabaseMetaDataKey::IsValidBlobKey(
   1243                  blob_key_generator_current_number)) {
   1244     INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
   1245     return InternalInconsistencyStatus();
   1246   }
   1247 
   1248   return s;
   1249 }
   1250 
   1251 WARN_UNUSED_RESULT static leveldb::Status GetNewDatabaseId(
   1252     LevelDBTransaction* transaction,
   1253     int64* new_id) {
   1254   *new_id = -1;
   1255   int64 max_database_id = -1;
   1256   bool found = false;
   1257   leveldb::Status s =
   1258       GetInt(transaction, MaxDatabaseIdKey::Encode(), &max_database_id, &found);
   1259   if (!s.ok()) {
   1260     INTERNAL_READ_ERROR_UNTESTED(GET_NEW_DATABASE_ID);
   1261     return s;
   1262   }
   1263   if (!found)
   1264     max_database_id = 0;
   1265 
   1266   DCHECK_GE(max_database_id, 0);
   1267 
   1268   int64 database_id = max_database_id + 1;
   1269   PutInt(transaction, MaxDatabaseIdKey::Encode(), database_id);
   1270   *new_id = database_id;
   1271   return leveldb::Status::OK();
   1272 }
   1273 
   1274 leveldb::Status IndexedDBBackingStore::CreateIDBDatabaseMetaData(
   1275     const base::string16& name,
   1276     const base::string16& version,
   1277     int64 int_version,
   1278     int64* row_id) {
   1279   scoped_refptr<LevelDBTransaction> transaction =
   1280       IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
   1281 
   1282   leveldb::Status s = GetNewDatabaseId(transaction.get(), row_id);
   1283   if (!s.ok())
   1284     return s;
   1285   DCHECK_GE(*row_id, 0);
   1286 
   1287   if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION)
   1288     int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
   1289 
   1290   PutInt(transaction.get(),
   1291          DatabaseNameKey::Encode(origin_identifier_, name),
   1292          *row_id);
   1293   PutString(
   1294       transaction.get(),
   1295       DatabaseMetaDataKey::Encode(*row_id, DatabaseMetaDataKey::USER_VERSION),
   1296       version);
   1297   PutVarInt(transaction.get(),
   1298             DatabaseMetaDataKey::Encode(*row_id,
   1299                                         DatabaseMetaDataKey::USER_INT_VERSION),
   1300             int_version);
   1301   PutVarInt(
   1302       transaction.get(),
   1303       DatabaseMetaDataKey::Encode(
   1304           *row_id, DatabaseMetaDataKey::BLOB_KEY_GENERATOR_CURRENT_NUMBER),
   1305       DatabaseMetaDataKey::kBlobKeyGeneratorInitialNumber);
   1306 
   1307   s = transaction->Commit();
   1308   if (!s.ok())
   1309     INTERNAL_WRITE_ERROR_UNTESTED(CREATE_IDBDATABASE_METADATA);
   1310   return s;
   1311 }
   1312 
   1313 bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion(
   1314     IndexedDBBackingStore::Transaction* transaction,
   1315     int64 row_id,
   1316     int64 int_version) {
   1317   if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION)
   1318     int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
   1319   DCHECK_GE(int_version, 0) << "int_version was " << int_version;
   1320   PutVarInt(transaction->transaction(),
   1321             DatabaseMetaDataKey::Encode(row_id,
   1322                                         DatabaseMetaDataKey::USER_INT_VERSION),
   1323             int_version);
   1324   return true;
   1325 }
   1326 
   1327 // If you're deleting a range that contains user keys that have blob info, this
   1328 // won't clean up the blobs.
   1329 static leveldb::Status DeleteRangeBasic(LevelDBTransaction* transaction,
   1330                                         const std::string& begin,
   1331                                         const std::string& end,
   1332                                         bool upper_open) {
   1333   scoped_ptr<LevelDBIterator> it = transaction->CreateIterator();
   1334   leveldb::Status s;
   1335   for (s = it->Seek(begin); s.ok() && it->IsValid() &&
   1336                                 (upper_open ? CompareKeys(it->Key(), end) < 0
   1337                                             : CompareKeys(it->Key(), end) <= 0);
   1338        s = it->Next())
   1339     transaction->Remove(it->Key());
   1340   return s;
   1341 }
   1342 
   1343 static leveldb::Status DeleteBlobsInRange(
   1344     IndexedDBBackingStore::Transaction* transaction,
   1345     int64 database_id,
   1346     int64 object_store_id,
   1347     const std::string& start_key,
   1348     const std::string& end_key,
   1349     bool upper_open) {
   1350   scoped_ptr<LevelDBIterator> it = transaction->transaction()->CreateIterator();
   1351   leveldb::Status s = it->Seek(start_key);
   1352   for (; s.ok() && it->IsValid() &&
   1353              (upper_open ? CompareKeys(it->Key(), end_key) < 0
   1354                          : CompareKeys(it->Key(), end_key) <= 0);
   1355        s = it->Next()) {
   1356     StringPiece key_piece(it->Key());
   1357     std::string user_key =
   1358         BlobEntryKey::ReencodeToObjectStoreDataKey(&key_piece);
   1359     if (!user_key.size()) {
   1360       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
   1361       return InternalInconsistencyStatus();
   1362     }
   1363     transaction->PutBlobInfo(
   1364         database_id, object_store_id, user_key, NULL, NULL);
   1365   }
   1366   return s;
   1367 }
   1368 
   1369 static leveldb::Status DeleteBlobsInObjectStore(
   1370     IndexedDBBackingStore::Transaction* transaction,
   1371     int64 database_id,
   1372     int64 object_store_id) {
   1373   std::string start_key, stop_key;
   1374   start_key =
   1375       BlobEntryKey::EncodeMinKeyForObjectStore(database_id, object_store_id);
   1376   stop_key =
   1377       BlobEntryKey::EncodeStopKeyForObjectStore(database_id, object_store_id);
   1378   return DeleteBlobsInRange(
   1379       transaction, database_id, object_store_id, start_key, stop_key, true);
   1380 }
   1381 
   1382 leveldb::Status IndexedDBBackingStore::DeleteDatabase(
   1383     const base::string16& name) {
   1384   IDB_TRACE("IndexedDBBackingStore::DeleteDatabase");
   1385   scoped_ptr<LevelDBDirectTransaction> transaction =
   1386       LevelDBDirectTransaction::Create(db_.get());
   1387 
   1388   leveldb::Status s;
   1389   s = CleanUpBlobJournal(BlobJournalKey::Encode());
   1390   if (!s.ok())
   1391     return s;
   1392 
   1393   IndexedDBDatabaseMetadata metadata;
   1394   bool success = false;
   1395   s = GetIDBDatabaseMetaData(name, &metadata, &success);
   1396   if (!s.ok())
   1397     return s;
   1398   if (!success)
   1399     return leveldb::Status::OK();
   1400 
   1401   const std::string start_key = DatabaseMetaDataKey::Encode(
   1402       metadata.id, DatabaseMetaDataKey::ORIGIN_NAME);
   1403   const std::string stop_key = DatabaseMetaDataKey::Encode(
   1404       metadata.id + 1, DatabaseMetaDataKey::ORIGIN_NAME);
   1405   scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
   1406   for (s = it->Seek(start_key);
   1407        s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0;
   1408        s = it->Next())
   1409     transaction->Remove(it->Key());
   1410   if (!s.ok()) {
   1411     INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE);
   1412     return s;
   1413   }
   1414 
   1415   const std::string key = DatabaseNameKey::Encode(origin_identifier_, name);
   1416   transaction->Remove(key);
   1417 
   1418   bool need_cleanup = false;
   1419   if (active_blob_registry()->MarkDeletedCheckIfUsed(
   1420           metadata.id, DatabaseMetaDataKey::kAllBlobsKey)) {
   1421     s = MergeDatabaseIntoLiveBlobJournal(transaction.get(), metadata.id);
   1422     if (!s.ok())
   1423       return s;
   1424   } else {
   1425     UpdateBlobJournalWithDatabase(transaction.get(), metadata.id);
   1426     need_cleanup = true;
   1427   }
   1428 
   1429   s = transaction->Commit();
   1430   if (!s.ok()) {
   1431     INTERNAL_WRITE_ERROR_UNTESTED(DELETE_DATABASE);
   1432     return s;
   1433   }
   1434 
   1435   if (need_cleanup)
   1436     CleanUpBlobJournal(BlobJournalKey::Encode());
   1437 
   1438   db_->Compact(start_key, stop_key);
   1439   return s;
   1440 }
   1441 
   1442 static bool CheckObjectStoreAndMetaDataType(const LevelDBIterator* it,
   1443                                             const std::string& stop_key,
   1444                                             int64 object_store_id,
   1445                                             int64 meta_data_type) {
   1446   if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0)
   1447     return false;
   1448 
   1449   StringPiece slice(it->Key());
   1450   ObjectStoreMetaDataKey meta_data_key;
   1451   bool ok =
   1452       ObjectStoreMetaDataKey::Decode(&slice, &meta_data_key) && slice.empty();
   1453   DCHECK(ok);
   1454   if (meta_data_key.ObjectStoreId() != object_store_id)
   1455     return false;
   1456   if (meta_data_key.MetaDataType() != meta_data_type)
   1457     return false;
   1458   return ok;
   1459 }
   1460 
   1461 // TODO(jsbell): This should do some error handling rather than
   1462 // plowing ahead when bad data is encountered.
   1463 leveldb::Status IndexedDBBackingStore::GetObjectStores(
   1464     int64 database_id,
   1465     IndexedDBDatabaseMetadata::ObjectStoreMap* object_stores) {
   1466   IDB_TRACE("IndexedDBBackingStore::GetObjectStores");
   1467   if (!KeyPrefix::IsValidDatabaseId(database_id))
   1468     return InvalidDBKeyStatus();
   1469   const std::string start_key =
   1470       ObjectStoreMetaDataKey::Encode(database_id, 1, 0);
   1471   const std::string stop_key =
   1472       ObjectStoreMetaDataKey::EncodeMaxKey(database_id);
   1473 
   1474   DCHECK(object_stores->empty());
   1475 
   1476   scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
   1477   leveldb::Status s = it->Seek(start_key);
   1478   while (s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0) {
   1479     StringPiece slice(it->Key());
   1480     ObjectStoreMetaDataKey meta_data_key;
   1481     bool ok =
   1482         ObjectStoreMetaDataKey::Decode(&slice, &meta_data_key) && slice.empty();
   1483     DCHECK(ok);
   1484     if (!ok || meta_data_key.MetaDataType() != ObjectStoreMetaDataKey::NAME) {
   1485       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
   1486       // Possible stale metadata, but don't fail the load.
   1487       s = it->Next();
   1488       if (!s.ok())
   1489         break;
   1490       continue;
   1491     }
   1492 
   1493     int64 object_store_id = meta_data_key.ObjectStoreId();
   1494 
   1495     // TODO(jsbell): Do this by direct key lookup rather than iteration, to
   1496     // simplify.
   1497     base::string16 object_store_name;
   1498     {
   1499       StringPiece slice(it->Value());
   1500       if (!DecodeString(&slice, &object_store_name) || !slice.empty())
   1501         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
   1502     }
   1503 
   1504     s = it->Next();
   1505     if (!s.ok())
   1506       break;
   1507     if (!CheckObjectStoreAndMetaDataType(it.get(),
   1508                                          stop_key,
   1509                                          object_store_id,
   1510                                          ObjectStoreMetaDataKey::KEY_PATH)) {
   1511       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
   1512       break;
   1513     }
   1514     IndexedDBKeyPath key_path;
   1515     {
   1516       StringPiece slice(it->Value());
   1517       if (!DecodeIDBKeyPath(&slice, &key_path) || !slice.empty())
   1518         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
   1519     }
   1520 
   1521     s = it->Next();
   1522     if (!s.ok())
   1523       break;
   1524     if (!CheckObjectStoreAndMetaDataType(
   1525              it.get(),
   1526              stop_key,
   1527              object_store_id,
   1528              ObjectStoreMetaDataKey::AUTO_INCREMENT)) {
   1529       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
   1530       break;
   1531     }
   1532     bool auto_increment;
   1533     {
   1534       StringPiece slice(it->Value());
   1535       if (!DecodeBool(&slice, &auto_increment) || !slice.empty())
   1536         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
   1537     }
   1538 
   1539     s = it->Next();  // Is evictable.
   1540     if (!s.ok())
   1541       break;
   1542     if (!CheckObjectStoreAndMetaDataType(it.get(),
   1543                                          stop_key,
   1544                                          object_store_id,
   1545                                          ObjectStoreMetaDataKey::EVICTABLE)) {
   1546       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
   1547       break;
   1548     }
   1549 
   1550     s = it->Next();  // Last version.
   1551     if (!s.ok())
   1552       break;
   1553     if (!CheckObjectStoreAndMetaDataType(
   1554              it.get(),
   1555              stop_key,
   1556              object_store_id,
   1557              ObjectStoreMetaDataKey::LAST_VERSION)) {
   1558       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
   1559       break;
   1560     }
   1561 
   1562     s = it->Next();  // Maximum index id allocated.
   1563     if (!s.ok())
   1564       break;
   1565     if (!CheckObjectStoreAndMetaDataType(
   1566              it.get(),
   1567              stop_key,
   1568              object_store_id,
   1569              ObjectStoreMetaDataKey::MAX_INDEX_ID)) {
   1570       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
   1571       break;
   1572     }
   1573     int64 max_index_id;
   1574     {
   1575       StringPiece slice(it->Value());
   1576       if (!DecodeInt(&slice, &max_index_id) || !slice.empty())
   1577         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
   1578     }
   1579 
   1580     s = it->Next();  // [optional] has key path (is not null)
   1581     if (!s.ok())
   1582       break;
   1583     if (CheckObjectStoreAndMetaDataType(it.get(),
   1584                                         stop_key,
   1585                                         object_store_id,
   1586                                         ObjectStoreMetaDataKey::HAS_KEY_PATH)) {
   1587       bool has_key_path;
   1588       {
   1589         StringPiece slice(it->Value());
   1590         if (!DecodeBool(&slice, &has_key_path))
   1591           INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
   1592       }
   1593       // This check accounts for two layers of legacy coding:
   1594       // (1) Initially, has_key_path was added to distinguish null vs. string.
   1595       // (2) Later, null vs. string vs. array was stored in the key_path itself.
   1596       // So this check is only relevant for string-type key_paths.
   1597       if (!has_key_path &&
   1598           (key_path.type() == blink::WebIDBKeyPathTypeString &&
   1599            !key_path.string().empty())) {
   1600         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
   1601         break;
   1602       }
   1603       if (!has_key_path)
   1604         key_path = IndexedDBKeyPath();
   1605       s = it->Next();
   1606       if (!s.ok())
   1607         break;
   1608     }
   1609 
   1610     int64 key_generator_current_number = -1;
   1611     if (CheckObjectStoreAndMetaDataType(
   1612             it.get(),
   1613             stop_key,
   1614             object_store_id,
   1615             ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER)) {
   1616       StringPiece slice(it->Value());
   1617       if (!DecodeInt(&slice, &key_generator_current_number) || !slice.empty())
   1618         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_OBJECT_STORES);
   1619 
   1620       // TODO(jsbell): Return key_generator_current_number, cache in
   1621       // object store, and write lazily to backing store.  For now,
   1622       // just assert that if it was written it was valid.
   1623       DCHECK_GE(key_generator_current_number, kKeyGeneratorInitialNumber);
   1624       s = it->Next();
   1625       if (!s.ok())
   1626         break;
   1627     }
   1628 
   1629     IndexedDBObjectStoreMetadata metadata(object_store_name,
   1630                                           object_store_id,
   1631                                           key_path,
   1632                                           auto_increment,
   1633                                           max_index_id);
   1634     s = GetIndexes(database_id, object_store_id, &metadata.indexes);
   1635     if (!s.ok())
   1636       break;
   1637     (*object_stores)[object_store_id] = metadata;
   1638   }
   1639 
   1640   if (!s.ok())
   1641     INTERNAL_READ_ERROR_UNTESTED(GET_OBJECT_STORES);
   1642 
   1643   return s;
   1644 }
   1645 
   1646 WARN_UNUSED_RESULT static leveldb::Status SetMaxObjectStoreId(
   1647     LevelDBTransaction* transaction,
   1648     int64 database_id,
   1649     int64 object_store_id) {
   1650   const std::string max_object_store_id_key = DatabaseMetaDataKey::Encode(
   1651       database_id, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID);
   1652   int64 max_object_store_id = -1;
   1653   leveldb::Status s = GetMaxObjectStoreId(
   1654       transaction, max_object_store_id_key, &max_object_store_id);
   1655   if (!s.ok()) {
   1656     INTERNAL_READ_ERROR_UNTESTED(SET_MAX_OBJECT_STORE_ID);
   1657     return s;
   1658   }
   1659 
   1660   if (object_store_id <= max_object_store_id) {
   1661     INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_MAX_OBJECT_STORE_ID);
   1662     return InternalInconsistencyStatus();
   1663   }
   1664   PutInt(transaction, max_object_store_id_key, object_store_id);
   1665   return s;
   1666 }
   1667 
   1668 void IndexedDBBackingStore::Compact() { db_->CompactAll(); }
   1669 
   1670 leveldb::Status IndexedDBBackingStore::CreateObjectStore(
   1671     IndexedDBBackingStore::Transaction* transaction,
   1672     int64 database_id,
   1673     int64 object_store_id,
   1674     const base::string16& name,
   1675     const IndexedDBKeyPath& key_path,
   1676     bool auto_increment) {
   1677   IDB_TRACE("IndexedDBBackingStore::CreateObjectStore");
   1678   if (!KeyPrefix::ValidIds(database_id, object_store_id))
   1679     return InvalidDBKeyStatus();
   1680   LevelDBTransaction* leveldb_transaction = transaction->transaction();
   1681   leveldb::Status s =
   1682       SetMaxObjectStoreId(leveldb_transaction, database_id, object_store_id);
   1683   if (!s.ok())
   1684     return s;
   1685 
   1686   const std::string name_key = ObjectStoreMetaDataKey::Encode(
   1687       database_id, object_store_id, ObjectStoreMetaDataKey::NAME);
   1688   const std::string key_path_key = ObjectStoreMetaDataKey::Encode(
   1689       database_id, object_store_id, ObjectStoreMetaDataKey::KEY_PATH);
   1690   const std::string auto_increment_key = ObjectStoreMetaDataKey::Encode(
   1691       database_id, object_store_id, ObjectStoreMetaDataKey::AUTO_INCREMENT);
   1692   const std::string evictable_key = ObjectStoreMetaDataKey::Encode(
   1693       database_id, object_store_id, ObjectStoreMetaDataKey::EVICTABLE);
   1694   const std::string last_version_key = ObjectStoreMetaDataKey::Encode(
   1695       database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION);
   1696   const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode(
   1697       database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID);
   1698   const std::string has_key_path_key = ObjectStoreMetaDataKey::Encode(
   1699       database_id, object_store_id, ObjectStoreMetaDataKey::HAS_KEY_PATH);
   1700   const std::string key_generator_current_number_key =
   1701       ObjectStoreMetaDataKey::Encode(
   1702           database_id,
   1703           object_store_id,
   1704           ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER);
   1705   const std::string names_key = ObjectStoreNamesKey::Encode(database_id, name);
   1706 
   1707   PutString(leveldb_transaction, name_key, name);
   1708   PutIDBKeyPath(leveldb_transaction, key_path_key, key_path);
   1709   PutInt(leveldb_transaction, auto_increment_key, auto_increment);
   1710   PutInt(leveldb_transaction, evictable_key, false);
   1711   PutInt(leveldb_transaction, last_version_key, 1);
   1712   PutInt(leveldb_transaction, max_index_id_key, kMinimumIndexId);
   1713   PutBool(leveldb_transaction, has_key_path_key, !key_path.IsNull());
   1714   PutInt(leveldb_transaction,
   1715          key_generator_current_number_key,
   1716          kKeyGeneratorInitialNumber);
   1717   PutInt(leveldb_transaction, names_key, object_store_id);
   1718   return s;
   1719 }
   1720 
   1721 leveldb::Status IndexedDBBackingStore::DeleteObjectStore(
   1722     IndexedDBBackingStore::Transaction* transaction,
   1723     int64 database_id,
   1724     int64 object_store_id) {
   1725   IDB_TRACE("IndexedDBBackingStore::DeleteObjectStore");
   1726   if (!KeyPrefix::ValidIds(database_id, object_store_id))
   1727     return InvalidDBKeyStatus();
   1728   LevelDBTransaction* leveldb_transaction = transaction->transaction();
   1729 
   1730   base::string16 object_store_name;
   1731   bool found = false;
   1732   leveldb::Status s =
   1733       GetString(leveldb_transaction,
   1734                 ObjectStoreMetaDataKey::Encode(
   1735                     database_id, object_store_id, ObjectStoreMetaDataKey::NAME),
   1736                 &object_store_name,
   1737                 &found);
   1738   if (!s.ok()) {
   1739     INTERNAL_READ_ERROR_UNTESTED(DELETE_OBJECT_STORE);
   1740     return s;
   1741   }
   1742   if (!found) {
   1743     INTERNAL_CONSISTENCY_ERROR_UNTESTED(DELETE_OBJECT_STORE);
   1744     return InternalInconsistencyStatus();
   1745   }
   1746 
   1747   s = DeleteBlobsInObjectStore(transaction, database_id, object_store_id);
   1748   if (!s.ok()) {
   1749     INTERNAL_CONSISTENCY_ERROR_UNTESTED(DELETE_OBJECT_STORE);
   1750     return s;
   1751   }
   1752 
   1753   s = DeleteRangeBasic(
   1754       leveldb_transaction,
   1755       ObjectStoreMetaDataKey::Encode(database_id, object_store_id, 0),
   1756       ObjectStoreMetaDataKey::EncodeMaxKey(database_id, object_store_id),
   1757       true);
   1758 
   1759   if (s.ok()) {
   1760     leveldb_transaction->Remove(
   1761         ObjectStoreNamesKey::Encode(database_id, object_store_name));
   1762 
   1763     s = DeleteRangeBasic(
   1764         leveldb_transaction,
   1765         IndexFreeListKey::Encode(database_id, object_store_id, 0),
   1766         IndexFreeListKey::EncodeMaxKey(database_id, object_store_id),
   1767         true);
   1768   }
   1769 
   1770   if (s.ok()) {
   1771     s = DeleteRangeBasic(
   1772         leveldb_transaction,
   1773         IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0),
   1774         IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id),
   1775         true);
   1776   }
   1777 
   1778   if (!s.ok()) {
   1779     INTERNAL_WRITE_ERROR_UNTESTED(DELETE_OBJECT_STORE);
   1780     return s;
   1781   }
   1782 
   1783   return ClearObjectStore(transaction, database_id, object_store_id);
   1784 }
   1785 
   1786 leveldb::Status IndexedDBBackingStore::GetRecord(
   1787     IndexedDBBackingStore::Transaction* transaction,
   1788     int64 database_id,
   1789     int64 object_store_id,
   1790     const IndexedDBKey& key,
   1791     IndexedDBValue* record) {
   1792   IDB_TRACE("IndexedDBBackingStore::GetRecord");
   1793   if (!KeyPrefix::ValidIds(database_id, object_store_id))
   1794     return InvalidDBKeyStatus();
   1795   LevelDBTransaction* leveldb_transaction = transaction->transaction();
   1796 
   1797   const std::string leveldb_key =
   1798       ObjectStoreDataKey::Encode(database_id, object_store_id, key);
   1799   std::string data;
   1800 
   1801   record->clear();
   1802 
   1803   bool found = false;
   1804   leveldb::Status s = leveldb_transaction->Get(leveldb_key, &data, &found);
   1805   if (!s.ok()) {
   1806     INTERNAL_READ_ERROR(GET_RECORD);
   1807     return s;
   1808   }
   1809   if (!found)
   1810     return s;
   1811   if (data.empty()) {
   1812     INTERNAL_READ_ERROR_UNTESTED(GET_RECORD);
   1813     return leveldb::Status::NotFound("Record contained no data");
   1814   }
   1815 
   1816   int64 version;
   1817   StringPiece slice(data);
   1818   if (!DecodeVarInt(&slice, &version)) {
   1819     INTERNAL_READ_ERROR_UNTESTED(GET_RECORD);
   1820     return InternalInconsistencyStatus();
   1821   }
   1822 
   1823   record->bits = slice.as_string();
   1824   return transaction->GetBlobInfoForRecord(database_id, leveldb_key, record);
   1825 }
   1826 
   1827 WARN_UNUSED_RESULT static leveldb::Status GetNewVersionNumber(
   1828     LevelDBTransaction* transaction,
   1829     int64 database_id,
   1830     int64 object_store_id,
   1831     int64* new_version_number) {
   1832   const std::string last_version_key = ObjectStoreMetaDataKey::Encode(
   1833       database_id, object_store_id, ObjectStoreMetaDataKey::LAST_VERSION);
   1834 
   1835   *new_version_number = -1;
   1836   int64 last_version = -1;
   1837   bool found = false;
   1838   leveldb::Status s =
   1839       GetInt(transaction, last_version_key, &last_version, &found);
   1840   if (!s.ok()) {
   1841     INTERNAL_READ_ERROR_UNTESTED(GET_NEW_VERSION_NUMBER);
   1842     return s;
   1843   }
   1844   if (!found)
   1845     last_version = 0;
   1846 
   1847   DCHECK_GE(last_version, 0);
   1848 
   1849   int64 version = last_version + 1;
   1850   PutInt(transaction, last_version_key, version);
   1851 
   1852   // TODO(jsbell): Think about how we want to handle the overflow scenario.
   1853   DCHECK(version > last_version);
   1854 
   1855   *new_version_number = version;
   1856   return s;
   1857 }
   1858 
   1859 leveldb::Status IndexedDBBackingStore::PutRecord(
   1860     IndexedDBBackingStore::Transaction* transaction,
   1861     int64 database_id,
   1862     int64 object_store_id,
   1863     const IndexedDBKey& key,
   1864     IndexedDBValue& value,
   1865     ScopedVector<webkit_blob::BlobDataHandle>* handles,
   1866     RecordIdentifier* record_identifier) {
   1867   IDB_TRACE("IndexedDBBackingStore::PutRecord");
   1868   if (!KeyPrefix::ValidIds(database_id, object_store_id))
   1869     return InvalidDBKeyStatus();
   1870   DCHECK(key.IsValid());
   1871 
   1872   LevelDBTransaction* leveldb_transaction = transaction->transaction();
   1873   int64 version = -1;
   1874   leveldb::Status s = GetNewVersionNumber(
   1875       leveldb_transaction, database_id, object_store_id, &version);
   1876   if (!s.ok())
   1877     return s;
   1878   DCHECK_GE(version, 0);
   1879   const std::string object_store_data_key =
   1880       ObjectStoreDataKey::Encode(database_id, object_store_id, key);
   1881 
   1882   std::string v;
   1883   EncodeVarInt(version, &v);
   1884   v.append(value.bits);
   1885 
   1886   leveldb_transaction->Put(object_store_data_key, &v);
   1887   s = transaction->PutBlobInfoIfNeeded(database_id,
   1888                                        object_store_id,
   1889                                        object_store_data_key,
   1890                                        &value.blob_info,
   1891                                        handles);
   1892   if (!s.ok())
   1893     return s;
   1894   DCHECK(!handles->size());
   1895 
   1896   const std::string exists_entry_key =
   1897       ExistsEntryKey::Encode(database_id, object_store_id, key);
   1898   std::string version_encoded;
   1899   EncodeInt(version, &version_encoded);
   1900   leveldb_transaction->Put(exists_entry_key, &version_encoded);
   1901 
   1902   std::string key_encoded;
   1903   EncodeIDBKey(key, &key_encoded);
   1904   record_identifier->Reset(key_encoded, version);
   1905   return s;
   1906 }
   1907 
   1908 leveldb::Status IndexedDBBackingStore::ClearObjectStore(
   1909     IndexedDBBackingStore::Transaction* transaction,
   1910     int64 database_id,
   1911     int64 object_store_id) {
   1912   IDB_TRACE("IndexedDBBackingStore::ClearObjectStore");
   1913   if (!KeyPrefix::ValidIds(database_id, object_store_id))
   1914     return InvalidDBKeyStatus();
   1915   const std::string start_key =
   1916       KeyPrefix(database_id, object_store_id).Encode();
   1917   const std::string stop_key =
   1918       KeyPrefix(database_id, object_store_id + 1).Encode();
   1919 
   1920   leveldb::Status s =
   1921       DeleteRangeBasic(transaction->transaction(), start_key, stop_key, true);
   1922   if (!s.ok()) {
   1923     INTERNAL_WRITE_ERROR(CLEAR_OBJECT_STORE);
   1924     return s;
   1925   }
   1926   return DeleteBlobsInObjectStore(transaction, database_id, object_store_id);
   1927 }
   1928 
   1929 leveldb::Status IndexedDBBackingStore::DeleteRecord(
   1930     IndexedDBBackingStore::Transaction* transaction,
   1931     int64 database_id,
   1932     int64 object_store_id,
   1933     const RecordIdentifier& record_identifier) {
   1934   IDB_TRACE("IndexedDBBackingStore::DeleteRecord");
   1935   if (!KeyPrefix::ValidIds(database_id, object_store_id))
   1936     return InvalidDBKeyStatus();
   1937   LevelDBTransaction* leveldb_transaction = transaction->transaction();
   1938 
   1939   const std::string object_store_data_key = ObjectStoreDataKey::Encode(
   1940       database_id, object_store_id, record_identifier.primary_key());
   1941   leveldb_transaction->Remove(object_store_data_key);
   1942   leveldb::Status s = transaction->PutBlobInfoIfNeeded(
   1943       database_id, object_store_id, object_store_data_key, NULL, NULL);
   1944   if (!s.ok())
   1945     return s;
   1946 
   1947   const std::string exists_entry_key = ExistsEntryKey::Encode(
   1948       database_id, object_store_id, record_identifier.primary_key());
   1949   leveldb_transaction->Remove(exists_entry_key);
   1950   return leveldb::Status::OK();
   1951 }
   1952 
   1953 leveldb::Status IndexedDBBackingStore::DeleteRange(
   1954     IndexedDBBackingStore::Transaction* transaction,
   1955     int64 database_id,
   1956     int64 object_store_id,
   1957     const IndexedDBKeyRange& key_range) {
   1958   leveldb::Status s;
   1959   scoped_ptr<IndexedDBBackingStore::Cursor> start_cursor =
   1960       OpenObjectStoreCursor(transaction,
   1961                             database_id,
   1962                             object_store_id,
   1963                             key_range,
   1964                             indexed_db::CURSOR_NEXT,
   1965                             &s);
   1966   if (!s.ok())
   1967     return s;
   1968   if (!start_cursor)
   1969     return leveldb::Status::OK();  // Empty range == delete success.
   1970 
   1971   scoped_ptr<IndexedDBBackingStore::Cursor> end_cursor =
   1972       OpenObjectStoreCursor(transaction,
   1973                             database_id,
   1974                             object_store_id,
   1975                             key_range,
   1976                             indexed_db::CURSOR_PREV,
   1977                             &s);
   1978 
   1979   if (!s.ok())
   1980     return s;
   1981   if (!end_cursor)
   1982     return leveldb::Status::OK();  // Empty range == delete success.
   1983 
   1984   BlobEntryKey start_blob_key, end_blob_key;
   1985 
   1986   std::string start_key = ObjectStoreDataKey::Encode(
   1987       database_id, object_store_id, start_cursor->key());
   1988   base::StringPiece start_key_piece(start_key);
   1989   if (!BlobEntryKey::FromObjectStoreDataKey(&start_key_piece, &start_blob_key))
   1990     return InternalInconsistencyStatus();
   1991   std::string stop_key = ObjectStoreDataKey::Encode(
   1992       database_id, object_store_id, end_cursor->key());
   1993   base::StringPiece stop_key_piece(stop_key);
   1994   if (!BlobEntryKey::FromObjectStoreDataKey(&stop_key_piece, &end_blob_key))
   1995     return InternalInconsistencyStatus();
   1996 
   1997   s = DeleteBlobsInRange(transaction,
   1998                          database_id,
   1999                          object_store_id,
   2000                          start_blob_key.Encode(),
   2001                          end_blob_key.Encode(),
   2002                          false);
   2003   if (!s.ok())
   2004     return s;
   2005   s = DeleteRangeBasic(transaction->transaction(), start_key, stop_key, false);
   2006   if (!s.ok())
   2007     return s;
   2008   start_key =
   2009       ExistsEntryKey::Encode(database_id, object_store_id, start_cursor->key());
   2010   stop_key =
   2011       ExistsEntryKey::Encode(database_id, object_store_id, end_cursor->key());
   2012   return DeleteRangeBasic(
   2013       transaction->transaction(), start_key, stop_key, false);
   2014 }
   2015 
   2016 leveldb::Status IndexedDBBackingStore::GetKeyGeneratorCurrentNumber(
   2017     IndexedDBBackingStore::Transaction* transaction,
   2018     int64 database_id,
   2019     int64 object_store_id,
   2020     int64* key_generator_current_number) {
   2021   if (!KeyPrefix::ValidIds(database_id, object_store_id))
   2022     return InvalidDBKeyStatus();
   2023   LevelDBTransaction* leveldb_transaction = transaction->transaction();
   2024 
   2025   const std::string key_generator_current_number_key =
   2026       ObjectStoreMetaDataKey::Encode(
   2027           database_id,
   2028           object_store_id,
   2029           ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER);
   2030 
   2031   *key_generator_current_number = -1;
   2032   std::string data;
   2033 
   2034   bool found = false;
   2035   leveldb::Status s =
   2036       leveldb_transaction->Get(key_generator_current_number_key, &data, &found);
   2037   if (!s.ok()) {
   2038     INTERNAL_READ_ERROR_UNTESTED(GET_KEY_GENERATOR_CURRENT_NUMBER);
   2039     return s;
   2040   }
   2041   if (found && !data.empty()) {
   2042     StringPiece slice(data);
   2043     if (!DecodeInt(&slice, key_generator_current_number) || !slice.empty()) {
   2044       INTERNAL_READ_ERROR_UNTESTED(GET_KEY_GENERATOR_CURRENT_NUMBER);
   2045       return InternalInconsistencyStatus();
   2046     }
   2047     return s;
   2048   }
   2049 
   2050   // Previously, the key generator state was not stored explicitly
   2051   // but derived from the maximum numeric key present in existing
   2052   // data. This violates the spec as the data may be cleared but the
   2053   // key generator state must be preserved.
   2054   // TODO(jsbell): Fix this for all stores on database open?
   2055   const std::string start_key =
   2056       ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey());
   2057   const std::string stop_key =
   2058       ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey());
   2059 
   2060   scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator();
   2061   int64 max_numeric_key = 0;
   2062 
   2063   for (s = it->Seek(start_key);
   2064        s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0;
   2065        s = it->Next()) {
   2066     StringPiece slice(it->Key());
   2067     ObjectStoreDataKey data_key;
   2068     if (!ObjectStoreDataKey::Decode(&slice, &data_key) || !slice.empty()) {
   2069       INTERNAL_READ_ERROR_UNTESTED(GET_KEY_GENERATOR_CURRENT_NUMBER);
   2070       return InternalInconsistencyStatus();
   2071     }
   2072     scoped_ptr<IndexedDBKey> user_key = data_key.user_key();
   2073     if (user_key->type() == blink::WebIDBKeyTypeNumber) {
   2074       int64 n = static_cast<int64>(user_key->number());
   2075       if (n > max_numeric_key)
   2076         max_numeric_key = n;
   2077     }
   2078   }
   2079 
   2080   if (s.ok())
   2081     *key_generator_current_number = max_numeric_key + 1;
   2082   else
   2083     INTERNAL_READ_ERROR_UNTESTED(GET_KEY_GENERATOR_CURRENT_NUMBER);
   2084 
   2085   return s;
   2086 }
   2087 
   2088 leveldb::Status IndexedDBBackingStore::MaybeUpdateKeyGeneratorCurrentNumber(
   2089     IndexedDBBackingStore::Transaction* transaction,
   2090     int64 database_id,
   2091     int64 object_store_id,
   2092     int64 new_number,
   2093     bool check_current) {
   2094   if (!KeyPrefix::ValidIds(database_id, object_store_id))
   2095     return InvalidDBKeyStatus();
   2096 
   2097   if (check_current) {
   2098     int64 current_number;
   2099     leveldb::Status s = GetKeyGeneratorCurrentNumber(
   2100         transaction, database_id, object_store_id, &current_number);
   2101     if (!s.ok())
   2102       return s;
   2103     if (new_number <= current_number)
   2104       return s;
   2105   }
   2106 
   2107   const std::string key_generator_current_number_key =
   2108       ObjectStoreMetaDataKey::Encode(
   2109           database_id,
   2110           object_store_id,
   2111           ObjectStoreMetaDataKey::KEY_GENERATOR_CURRENT_NUMBER);
   2112   PutInt(
   2113       transaction->transaction(), key_generator_current_number_key, new_number);
   2114   return leveldb::Status::OK();
   2115 }
   2116 
   2117 leveldb::Status IndexedDBBackingStore::KeyExistsInObjectStore(
   2118     IndexedDBBackingStore::Transaction* transaction,
   2119     int64 database_id,
   2120     int64 object_store_id,
   2121     const IndexedDBKey& key,
   2122     RecordIdentifier* found_record_identifier,
   2123     bool* found) {
   2124   IDB_TRACE("IndexedDBBackingStore::KeyExistsInObjectStore");
   2125   if (!KeyPrefix::ValidIds(database_id, object_store_id))
   2126     return InvalidDBKeyStatus();
   2127   *found = false;
   2128   const std::string leveldb_key =
   2129       ObjectStoreDataKey::Encode(database_id, object_store_id, key);
   2130   std::string data;
   2131 
   2132   leveldb::Status s =
   2133       transaction->transaction()->Get(leveldb_key, &data, found);
   2134   if (!s.ok()) {
   2135     INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_OBJECT_STORE);
   2136     return s;
   2137   }
   2138   if (!*found)
   2139     return leveldb::Status::OK();
   2140   if (!data.size()) {
   2141     INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_OBJECT_STORE);
   2142     return InternalInconsistencyStatus();
   2143   }
   2144 
   2145   int64 version;
   2146   StringPiece slice(data);
   2147   if (!DecodeVarInt(&slice, &version))
   2148     return InternalInconsistencyStatus();
   2149 
   2150   std::string encoded_key;
   2151   EncodeIDBKey(key, &encoded_key);
   2152   found_record_identifier->Reset(encoded_key, version);
   2153   return s;
   2154 }
   2155 
   2156 class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl
   2157     : public IndexedDBBackingStore::Transaction::ChainedBlobWriter {
   2158  public:
   2159   typedef IndexedDBBackingStore::Transaction::WriteDescriptorVec
   2160       WriteDescriptorVec;
   2161   ChainedBlobWriterImpl(
   2162       int64 database_id,
   2163       IndexedDBBackingStore* backing_store,
   2164       WriteDescriptorVec& blobs,
   2165       scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback)
   2166       : waiting_for_callback_(false),
   2167         database_id_(database_id),
   2168         backing_store_(backing_store),
   2169         callback_(callback),
   2170         aborted_(false) {
   2171     blobs_.swap(blobs);
   2172     iter_ = blobs_.begin();
   2173     backing_store->task_runner()->PostTask(
   2174         FROM_HERE, base::Bind(&ChainedBlobWriterImpl::WriteNextFile, this));
   2175   }
   2176 
   2177   virtual void set_delegate(scoped_ptr<FileWriterDelegate> delegate) OVERRIDE {
   2178     delegate_.reset(delegate.release());
   2179   }
   2180 
   2181   virtual void ReportWriteCompletion(bool succeeded,
   2182                                      int64 bytes_written) OVERRIDE {
   2183     DCHECK(waiting_for_callback_);
   2184     DCHECK(!succeeded || bytes_written >= 0);
   2185     waiting_for_callback_ = false;
   2186     if (delegate_.get())  // Only present for Blob, not File.
   2187       content::BrowserThread::DeleteSoon(
   2188           content::BrowserThread::IO, FROM_HERE, delegate_.release());
   2189     if (aborted_) {
   2190       self_ref_ = NULL;
   2191       return;
   2192     }
   2193     if (iter_->size() != -1 && iter_->size() != bytes_written)
   2194       succeeded = false;
   2195     if (succeeded) {
   2196       ++iter_;
   2197       WriteNextFile();
   2198     } else {
   2199       callback_->Run(false);
   2200     }
   2201   }
   2202 
   2203   virtual void Abort() OVERRIDE {
   2204     if (!waiting_for_callback_)
   2205       return;
   2206     self_ref_ = this;
   2207     aborted_ = true;
   2208   }
   2209 
   2210  private:
   2211   virtual ~ChainedBlobWriterImpl() {}
   2212 
   2213   void WriteNextFile() {
   2214     DCHECK(!waiting_for_callback_);
   2215     DCHECK(!aborted_);
   2216     if (iter_ == blobs_.end()) {
   2217       DCHECK(!self_ref_);
   2218       callback_->Run(true);
   2219       return;
   2220     } else {
   2221       if (!backing_store_->WriteBlobFile(database_id_, *iter_, this)) {
   2222         callback_->Run(false);
   2223         return;
   2224       }
   2225       waiting_for_callback_ = true;
   2226     }
   2227   }
   2228 
   2229   bool waiting_for_callback_;
   2230   scoped_refptr<ChainedBlobWriterImpl> self_ref_;
   2231   WriteDescriptorVec blobs_;
   2232   WriteDescriptorVec::const_iterator iter_;
   2233   int64 database_id_;
   2234   IndexedDBBackingStore* backing_store_;
   2235   scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback_;
   2236   scoped_ptr<FileWriterDelegate> delegate_;
   2237   bool aborted_;
   2238 
   2239   DISALLOW_COPY_AND_ASSIGN(ChainedBlobWriterImpl);
   2240 };
   2241 
   2242 class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback,
   2243                           public base::RefCounted<LocalWriteClosure> {
   2244  public:
   2245   LocalWriteClosure(IndexedDBBackingStore::Transaction::ChainedBlobWriter*
   2246                         chained_blob_writer,
   2247                     base::TaskRunner* task_runner)
   2248       : chained_blob_writer_(chained_blob_writer),
   2249         task_runner_(task_runner),
   2250         bytes_written_(0) {}
   2251 
   2252   void Run(base::File::Error rv,
   2253            int64 bytes,
   2254            FileWriterDelegate::WriteProgressStatus write_status) {
   2255     DCHECK_GE(bytes, 0);
   2256     bytes_written_ += bytes;
   2257     if (write_status == FileWriterDelegate::SUCCESS_IO_PENDING)
   2258       return;  // We don't care about progress events.
   2259     if (rv == base::File::FILE_OK) {
   2260       DCHECK_EQ(write_status, FileWriterDelegate::SUCCESS_COMPLETED);
   2261     } else {
   2262       DCHECK(write_status == FileWriterDelegate::ERROR_WRITE_STARTED ||
   2263              write_status == FileWriterDelegate::ERROR_WRITE_NOT_STARTED);
   2264     }
   2265     task_runner_->PostTask(
   2266         FROM_HERE,
   2267         base::Bind(&LocalWriteClosure::callBlobCallbackOnIDBTaskRunner,
   2268                    this,
   2269                    write_status == FileWriterDelegate::SUCCESS_COMPLETED));
   2270   }
   2271 
   2272   void writeBlobToFileOnIOThread(const FilePath& file_path,
   2273                                  const GURL& blob_url,
   2274                                  net::URLRequestContext* request_context) {
   2275     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
   2276     scoped_ptr<fileapi::FileStreamWriter> writer(
   2277         fileapi::FileStreamWriter::CreateForLocalFile(
   2278             task_runner_, file_path, 0,
   2279             fileapi::FileStreamWriter::CREATE_NEW_FILE));
   2280     scoped_ptr<FileWriterDelegate> delegate(
   2281         new FileWriterDelegate(writer.Pass(),
   2282                                FileWriterDelegate::FLUSH_ON_COMPLETION));
   2283 
   2284     DCHECK(blob_url.is_valid());
   2285     scoped_ptr<net::URLRequest> blob_request(request_context->CreateRequest(
   2286         blob_url, net::DEFAULT_PRIORITY, delegate.get(), NULL));
   2287 
   2288     delegate->Start(blob_request.Pass(),
   2289                     base::Bind(&LocalWriteClosure::Run, this));
   2290     chained_blob_writer_->set_delegate(delegate.Pass());
   2291   }
   2292 
   2293  private:
   2294   virtual ~LocalWriteClosure() {}
   2295   friend class base::RefCounted<LocalWriteClosure>;
   2296 
   2297   void callBlobCallbackOnIDBTaskRunner(bool succeeded) {
   2298     DCHECK(task_runner_->RunsTasksOnCurrentThread());
   2299     chained_blob_writer_->ReportWriteCompletion(succeeded, bytes_written_);
   2300   }
   2301 
   2302   IndexedDBBackingStore::Transaction::ChainedBlobWriter* chained_blob_writer_;
   2303   base::TaskRunner* task_runner_;
   2304   int64 bytes_written_;
   2305 
   2306   DISALLOW_COPY_AND_ASSIGN(LocalWriteClosure);
   2307 };
   2308 
   2309 bool IndexedDBBackingStore::WriteBlobFile(
   2310     int64 database_id,
   2311     const Transaction::WriteDescriptor& descriptor,
   2312     Transaction::ChainedBlobWriter* chained_blob_writer) {
   2313 
   2314   if (!MakeIDBBlobDirectory(blob_path_, database_id, descriptor.key()))
   2315     return false;
   2316 
   2317   FilePath path = GetBlobFileName(database_id, descriptor.key());
   2318 
   2319   if (descriptor.is_file()) {
   2320     DCHECK(!descriptor.file_path().empty());
   2321     if (!base::CopyFile(descriptor.file_path(), path))
   2322       return false;
   2323 
   2324     base::File::Info info;
   2325     if (base::GetFileInfo(descriptor.file_path(), &info)) {
   2326       if (descriptor.size() != -1) {
   2327         if (descriptor.size() != info.size)
   2328           return false;
   2329         // The round-trip can be lossy; round to nearest millisecond.
   2330         int64 delta = (descriptor.last_modified() -
   2331             info.last_modified).InMilliseconds();
   2332         if (std::abs(delta) > 1)
   2333           return false;
   2334       }
   2335       if (!base::TouchFile(path, info.last_accessed, info.last_modified)) {
   2336         // TODO(ericu): Complain quietly; timestamp's probably not vital.
   2337       }
   2338     } else {
   2339       // TODO(ericu): Complain quietly; timestamp's probably not vital.
   2340     }
   2341 
   2342     task_runner_->PostTask(
   2343         FROM_HERE,
   2344         base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion,
   2345                    chained_blob_writer,
   2346                    true,
   2347                    info.size));
   2348   } else {
   2349     DCHECK(descriptor.url().is_valid());
   2350     scoped_refptr<LocalWriteClosure> write_closure(
   2351         new LocalWriteClosure(chained_blob_writer, task_runner_));
   2352     content::BrowserThread::PostTask(
   2353         content::BrowserThread::IO,
   2354         FROM_HERE,
   2355         base::Bind(&LocalWriteClosure::writeBlobToFileOnIOThread,
   2356                    write_closure.get(),
   2357                    path,
   2358                    descriptor.url(),
   2359                    request_context_));
   2360   }
   2361   return true;
   2362 }
   2363 
   2364 void IndexedDBBackingStore::ReportBlobUnused(int64 database_id,
   2365                                              int64 blob_key) {
   2366   DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
   2367   bool all_blobs = blob_key == DatabaseMetaDataKey::kAllBlobsKey;
   2368   DCHECK(all_blobs || DatabaseMetaDataKey::IsValidBlobKey(blob_key));
   2369   scoped_refptr<LevelDBTransaction> transaction =
   2370       IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
   2371 
   2372   std::string live_blob_key = LiveBlobJournalKey::Encode();
   2373   BlobJournalType live_blob_journal;
   2374   if (!GetBlobJournal(live_blob_key, transaction.get(), &live_blob_journal)
   2375            .ok())
   2376     return;
   2377   DCHECK(live_blob_journal.size());
   2378 
   2379   std::string primary_key = BlobJournalKey::Encode();
   2380   BlobJournalType primary_journal;
   2381   if (!GetBlobJournal(primary_key, transaction.get(), &primary_journal).ok())
   2382     return;
   2383 
   2384   // There are several cases to handle.  If blob_key is kAllBlobsKey, we want to
   2385   // remove all entries with database_id from the live_blob journal and add only
   2386   // kAllBlobsKey to the primary journal.  Otherwise if IsValidBlobKey(blob_key)
   2387   // and we hit kAllBlobsKey for the right database_id in the journal, we leave
   2388   // the kAllBlobsKey entry in the live_blob journal but add the specific blob
   2389   // to the primary.  Otherwise if IsValidBlobKey(blob_key) and we find a
   2390   // matching (database_id, blob_key) tuple, we should move it to the primary
   2391   // journal.
   2392   BlobJournalType new_live_blob_journal;
   2393   for (BlobJournalType::iterator journal_iter = live_blob_journal.begin();
   2394        journal_iter != live_blob_journal.end();
   2395        ++journal_iter) {
   2396     int64 current_database_id = journal_iter->first;
   2397     int64 current_blob_key = journal_iter->second;
   2398     bool current_all_blobs =
   2399         current_blob_key == DatabaseMetaDataKey::kAllBlobsKey;
   2400     DCHECK(KeyPrefix::IsValidDatabaseId(current_database_id) ||
   2401            current_all_blobs);
   2402     if (current_database_id == database_id &&
   2403         (all_blobs || current_all_blobs || blob_key == current_blob_key)) {
   2404       if (!all_blobs) {
   2405         primary_journal.push_back(
   2406             std::make_pair(database_id, current_blob_key));
   2407         if (current_all_blobs)
   2408           new_live_blob_journal.push_back(*journal_iter);
   2409         new_live_blob_journal.insert(new_live_blob_journal.end(),
   2410                                      ++journal_iter,
   2411                                      live_blob_journal.end());  // All the rest.
   2412         break;
   2413       }
   2414     } else {
   2415       new_live_blob_journal.push_back(*journal_iter);
   2416     }
   2417   }
   2418   if (all_blobs) {
   2419     primary_journal.push_back(
   2420         std::make_pair(database_id, DatabaseMetaDataKey::kAllBlobsKey));
   2421   }
   2422   UpdatePrimaryJournalWithBlobList(transaction.get(), primary_journal);
   2423   UpdateLiveBlobJournalWithBlobList(transaction.get(), new_live_blob_journal);
   2424   transaction->Commit();
   2425   // We could just do the deletions/cleaning here, but if there are a lot of
   2426   // blobs about to be garbage collected, it'd be better to wait and do them all
   2427   // at once.
   2428   StartJournalCleaningTimer();
   2429 }
   2430 
   2431 // The this reference is a raw pointer that's declared Unretained inside the
   2432 // timer code, so this won't confuse IndexedDBFactory's check for
   2433 // HasLastBackingStoreReference.  It's safe because if the backing store is
   2434 // deleted, the timer will automatically be canceled on destruction.
   2435 void IndexedDBBackingStore::StartJournalCleaningTimer() {
   2436   journal_cleaning_timer_.Start(
   2437       FROM_HERE,
   2438       base::TimeDelta::FromSeconds(5),
   2439       this,
   2440       &IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn);
   2441 }
   2442 
   2443 // This assumes a file path of dbId/second-to-LSB-of-counter/counter.
   2444 FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) {
   2445   return GetBlobFileNameForKey(blob_path_, database_id, key);
   2446 }
   2447 
   2448 static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it,
   2449                                      const std::string& stop_key,
   2450                                      int64 index_id,
   2451                                      unsigned char meta_data_type) {
   2452   if (!it->IsValid() || CompareKeys(it->Key(), stop_key) >= 0)
   2453     return false;
   2454 
   2455   StringPiece slice(it->Key());
   2456   IndexMetaDataKey meta_data_key;
   2457   bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key);
   2458   DCHECK(ok);
   2459   if (meta_data_key.IndexId() != index_id)
   2460     return false;
   2461   if (meta_data_key.meta_data_type() != meta_data_type)
   2462     return false;
   2463   return true;
   2464 }
   2465 
   2466 // TODO(jsbell): This should do some error handling rather than plowing ahead
   2467 // when bad data is encountered.
   2468 leveldb::Status IndexedDBBackingStore::GetIndexes(
   2469     int64 database_id,
   2470     int64 object_store_id,
   2471     IndexedDBObjectStoreMetadata::IndexMap* indexes) {
   2472   IDB_TRACE("IndexedDBBackingStore::GetIndexes");
   2473   if (!KeyPrefix::ValidIds(database_id, object_store_id))
   2474     return InvalidDBKeyStatus();
   2475   const std::string start_key =
   2476       IndexMetaDataKey::Encode(database_id, object_store_id, 0, 0);
   2477   const std::string stop_key =
   2478       IndexMetaDataKey::Encode(database_id, object_store_id + 1, 0, 0);
   2479 
   2480   DCHECK(indexes->empty());
   2481 
   2482   scoped_ptr<LevelDBIterator> it = db_->CreateIterator();
   2483   leveldb::Status s = it->Seek(start_key);
   2484   while (s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0) {
   2485     StringPiece slice(it->Key());
   2486     IndexMetaDataKey meta_data_key;
   2487     bool ok = IndexMetaDataKey::Decode(&slice, &meta_data_key);
   2488     DCHECK(ok);
   2489     if (meta_data_key.meta_data_type() != IndexMetaDataKey::NAME) {
   2490       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
   2491       // Possible stale metadata due to http://webkit.org/b/85557 but don't fail
   2492       // the load.
   2493       s = it->Next();
   2494       if (!s.ok())
   2495         break;
   2496       continue;
   2497     }
   2498 
   2499     // TODO(jsbell): Do this by direct key lookup rather than iteration, to
   2500     // simplify.
   2501     int64 index_id = meta_data_key.IndexId();
   2502     base::string16 index_name;
   2503     {
   2504       StringPiece slice(it->Value());
   2505       if (!DecodeString(&slice, &index_name) || !slice.empty())
   2506         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
   2507     }
   2508 
   2509     s = it->Next();  // unique flag
   2510     if (!s.ok())
   2511       break;
   2512     if (!CheckIndexAndMetaDataKey(
   2513              it.get(), stop_key, index_id, IndexMetaDataKey::UNIQUE)) {
   2514       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
   2515       break;
   2516     }
   2517     bool index_unique;
   2518     {
   2519       StringPiece slice(it->Value());
   2520       if (!DecodeBool(&slice, &index_unique) || !slice.empty())
   2521         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
   2522     }
   2523 
   2524     s = it->Next();  // key_path
   2525     if (!s.ok())
   2526       break;
   2527     if (!CheckIndexAndMetaDataKey(
   2528              it.get(), stop_key, index_id, IndexMetaDataKey::KEY_PATH)) {
   2529       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
   2530       break;
   2531     }
   2532     IndexedDBKeyPath key_path;
   2533     {
   2534       StringPiece slice(it->Value());
   2535       if (!DecodeIDBKeyPath(&slice, &key_path) || !slice.empty())
   2536         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
   2537     }
   2538 
   2539     s = it->Next();  // [optional] multi_entry flag
   2540     if (!s.ok())
   2541       break;
   2542     bool index_multi_entry = false;
   2543     if (CheckIndexAndMetaDataKey(
   2544             it.get(), stop_key, index_id, IndexMetaDataKey::MULTI_ENTRY)) {
   2545       StringPiece slice(it->Value());
   2546       if (!DecodeBool(&slice, &index_multi_entry) || !slice.empty())
   2547         INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_INDEXES);
   2548 
   2549       s = it->Next();
   2550       if (!s.ok())
   2551         break;
   2552     }
   2553 
   2554     (*indexes)[index_id] = IndexedDBIndexMetadata(
   2555         index_name, index_id, key_path, index_unique, index_multi_entry);
   2556   }
   2557 
   2558   if (!s.ok())
   2559     INTERNAL_READ_ERROR_UNTESTED(GET_INDEXES);
   2560 
   2561   return s;
   2562 }
   2563 
   2564 bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) {
   2565   FilePath fileName = GetBlobFileName(database_id, key);
   2566   return base::DeleteFile(fileName, false);
   2567 }
   2568 
   2569 bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) {
   2570   FilePath dirName = GetBlobDirectoryName(blob_path_, database_id);
   2571   return base::DeleteFile(dirName, true);
   2572 }
   2573 
   2574 leveldb::Status IndexedDBBackingStore::CleanUpBlobJournal(
   2575     const std::string& level_db_key) {
   2576   scoped_refptr<LevelDBTransaction> journal_transaction =
   2577       IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
   2578   BlobJournalType journal;
   2579   leveldb::Status s =
   2580       GetBlobJournal(level_db_key, journal_transaction.get(), &journal);
   2581   if (!s.ok())
   2582     return s;
   2583   if (!journal.size())
   2584     return leveldb::Status::OK();
   2585   BlobJournalType::iterator journal_iter;
   2586   for (journal_iter = journal.begin(); journal_iter != journal.end();
   2587        ++journal_iter) {
   2588     int64 database_id = journal_iter->first;
   2589     int64 blob_key = journal_iter->second;
   2590     DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
   2591     if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) {
   2592       if (!RemoveBlobDirectory(database_id))
   2593         return IOErrorStatus();
   2594     } else {
   2595       DCHECK(DatabaseMetaDataKey::IsValidBlobKey(blob_key));
   2596       if (!RemoveBlobFile(database_id, blob_key))
   2597         return IOErrorStatus();
   2598     }
   2599   }
   2600   ClearBlobJournal(journal_transaction.get(), level_db_key);
   2601   return journal_transaction->Commit();
   2602 }
   2603 
   2604 leveldb::Status IndexedDBBackingStore::Transaction::GetBlobInfoForRecord(
   2605     int64 database_id,
   2606     const std::string& object_store_data_key,
   2607     IndexedDBValue* value) {
   2608   BlobChangeRecord* change_record = NULL;
   2609   BlobChangeMap::const_iterator blob_iter =
   2610       blob_change_map_.find(object_store_data_key);
   2611   if (blob_iter != blob_change_map_.end()) {
   2612     change_record = blob_iter->second;
   2613   } else {
   2614     blob_iter = incognito_blob_map_.find(object_store_data_key);
   2615     if (blob_iter != incognito_blob_map_.end())
   2616       change_record = blob_iter->second;
   2617   }
   2618   if (change_record) {
   2619     // Either we haven't written the blob to disk yet or we're in incognito
   2620     // mode, so we have to send back the one they sent us.  This change record
   2621     // includes the original UUID.
   2622     value->blob_info = change_record->blob_info();
   2623     return leveldb::Status::OK();
   2624   }
   2625 
   2626   BlobEntryKey blob_entry_key;
   2627   StringPiece leveldb_key_piece(object_store_data_key);
   2628   if (!BlobEntryKey::FromObjectStoreDataKey(&leveldb_key_piece,
   2629                                             &blob_entry_key)) {
   2630     NOTREACHED();
   2631     return InternalInconsistencyStatus();
   2632   }
   2633   scoped_ptr<LevelDBIterator> it = transaction()->CreateIterator();
   2634   std::string encoded_key = blob_entry_key.Encode();
   2635   leveldb::Status s = it->Seek(encoded_key);
   2636   if (!s.ok())
   2637     return s;
   2638   if (it->IsValid() && CompareKeys(it->Key(), encoded_key) == 0) {
   2639     if (!DecodeBlobData(it->Value().as_string(), &value->blob_info)) {
   2640       INTERNAL_READ_ERROR(GET_BLOB_INFO_FOR_RECORD);
   2641       return InternalInconsistencyStatus();
   2642     }
   2643     std::vector<IndexedDBBlobInfo>::iterator iter;
   2644     for (iter = value->blob_info.begin(); iter != value->blob_info.end();
   2645          ++iter) {
   2646       iter->set_file_path(
   2647           backing_store_->GetBlobFileName(database_id, iter->key()));
   2648       iter->set_mark_used_callback(
   2649           backing_store_->active_blob_registry()->GetAddBlobRefCallback(
   2650               database_id, iter->key()));
   2651       iter->set_release_callback(
   2652           backing_store_->active_blob_registry()->GetFinalReleaseCallback(
   2653               database_id, iter->key()));
   2654       if (iter->is_file()) {
   2655         base::File::Info info;
   2656         if (base::GetFileInfo(iter->file_path(), &info)) {
   2657           // This should always work, but it isn't fatal if it doesn't; it just
   2658           // means a potential slow synchronous call from the renderer later.
   2659           iter->set_last_modified(info.last_modified);
   2660           iter->set_size(info.size);
   2661         }
   2662       }
   2663     }
   2664   }
   2665   return leveldb::Status::OK();
   2666 }
   2667 
   2668 void IndexedDBBackingStore::CleanPrimaryJournalIgnoreReturn() {
   2669   CleanUpBlobJournal(BlobJournalKey::Encode());
   2670 }
   2671 
   2672 WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId(
   2673     LevelDBTransaction* transaction,
   2674     int64 database_id,
   2675     int64 object_store_id,
   2676     int64 index_id) {
   2677   int64 max_index_id = -1;
   2678   const std::string max_index_id_key = ObjectStoreMetaDataKey::Encode(
   2679       database_id, object_store_id, ObjectStoreMetaDataKey::MAX_INDEX_ID);
   2680   bool found = false;
   2681   leveldb::Status s =
   2682       GetInt(transaction, max_index_id_key, &max_index_id, &found);
   2683   if (!s.ok()) {
   2684     INTERNAL_READ_ERROR_UNTESTED(SET_MAX_INDEX_ID);
   2685     return s;
   2686   }
   2687   if (!found)
   2688     max_index_id = kMinimumIndexId;
   2689 
   2690   if (index_id <= max_index_id) {
   2691     INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_MAX_INDEX_ID);
   2692     return InternalInconsistencyStatus();
   2693   }
   2694 
   2695   PutInt(transaction, max_index_id_key, index_id);
   2696   return s;
   2697 }
   2698 
   2699 leveldb::Status IndexedDBBackingStore::CreateIndex(
   2700     IndexedDBBackingStore::Transaction* transaction,
   2701     int64 database_id,
   2702     int64 object_store_id,
   2703     int64 index_id,
   2704     const base::string16& name,
   2705     const IndexedDBKeyPath& key_path,
   2706     bool is_unique,
   2707     bool is_multi_entry) {
   2708   IDB_TRACE("IndexedDBBackingStore::CreateIndex");
   2709   if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
   2710     return InvalidDBKeyStatus();
   2711   LevelDBTransaction* leveldb_transaction = transaction->transaction();
   2712   leveldb::Status s = SetMaxIndexId(
   2713       leveldb_transaction, database_id, object_store_id, index_id);
   2714 
   2715   if (!s.ok())
   2716     return s;
   2717 
   2718   const std::string name_key = IndexMetaDataKey::Encode(
   2719       database_id, object_store_id, index_id, IndexMetaDataKey::NAME);
   2720   const std::string unique_key = IndexMetaDataKey::Encode(
   2721       database_id, object_store_id, index_id, IndexMetaDataKey::UNIQUE);
   2722   const std::string key_path_key = IndexMetaDataKey::Encode(
   2723       database_id, object_store_id, index_id, IndexMetaDataKey::KEY_PATH);
   2724   const std::string multi_entry_key = IndexMetaDataKey::Encode(
   2725       database_id, object_store_id, index_id, IndexMetaDataKey::MULTI_ENTRY);
   2726 
   2727   PutString(leveldb_transaction, name_key, name);
   2728   PutBool(leveldb_transaction, unique_key, is_unique);
   2729   PutIDBKeyPath(leveldb_transaction, key_path_key, key_path);
   2730   PutBool(leveldb_transaction, multi_entry_key, is_multi_entry);
   2731   return s;
   2732 }
   2733 
   2734 leveldb::Status IndexedDBBackingStore::DeleteIndex(
   2735     IndexedDBBackingStore::Transaction* transaction,
   2736     int64 database_id,
   2737     int64 object_store_id,
   2738     int64 index_id) {
   2739   IDB_TRACE("IndexedDBBackingStore::DeleteIndex");
   2740   if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
   2741     return InvalidDBKeyStatus();
   2742   LevelDBTransaction* leveldb_transaction = transaction->transaction();
   2743 
   2744   const std::string index_meta_data_start =
   2745       IndexMetaDataKey::Encode(database_id, object_store_id, index_id, 0);
   2746   const std::string index_meta_data_end =
   2747       IndexMetaDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
   2748   leveldb::Status s = DeleteRangeBasic(
   2749       leveldb_transaction, index_meta_data_start, index_meta_data_end, true);
   2750 
   2751   if (s.ok()) {
   2752     const std::string index_data_start =
   2753         IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id);
   2754     const std::string index_data_end =
   2755         IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
   2756     s = DeleteRangeBasic(
   2757         leveldb_transaction, index_data_start, index_data_end, true);
   2758   }
   2759 
   2760   if (!s.ok())
   2761     INTERNAL_WRITE_ERROR_UNTESTED(DELETE_INDEX);
   2762 
   2763   return s;
   2764 }
   2765 
   2766 leveldb::Status IndexedDBBackingStore::PutIndexDataForRecord(
   2767     IndexedDBBackingStore::Transaction* transaction,
   2768     int64 database_id,
   2769     int64 object_store_id,
   2770     int64 index_id,
   2771     const IndexedDBKey& key,
   2772     const RecordIdentifier& record_identifier) {
   2773   IDB_TRACE("IndexedDBBackingStore::PutIndexDataForRecord");
   2774   DCHECK(key.IsValid());
   2775   if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
   2776     return InvalidDBKeyStatus();
   2777 
   2778   std::string encoded_key;
   2779   EncodeIDBKey(key, &encoded_key);
   2780 
   2781   const std::string index_data_key =
   2782       IndexDataKey::Encode(database_id,
   2783                            object_store_id,
   2784                            index_id,
   2785                            encoded_key,
   2786                            record_identifier.primary_key(),
   2787                            0);
   2788 
   2789   std::string data;
   2790   EncodeVarInt(record_identifier.version(), &data);
   2791   data.append(record_identifier.primary_key());
   2792 
   2793   transaction->transaction()->Put(index_data_key, &data);
   2794   return leveldb::Status::OK();
   2795 }
   2796 
   2797 static bool FindGreatestKeyLessThanOrEqual(LevelDBTransaction* transaction,
   2798                                            const std::string& target,
   2799                                            std::string* found_key,
   2800                                            leveldb::Status& s) {
   2801   scoped_ptr<LevelDBIterator> it = transaction->CreateIterator();
   2802   s = it->Seek(target);
   2803   if (!s.ok())
   2804     return false;
   2805 
   2806   if (!it->IsValid()) {
   2807     s = it->SeekToLast();
   2808     if (!s.ok() || !it->IsValid())
   2809       return false;
   2810   }
   2811 
   2812   while (CompareIndexKeys(it->Key(), target) > 0) {
   2813     s = it->Prev();
   2814     if (!s.ok() || !it->IsValid())
   2815       return false;
   2816   }
   2817 
   2818   do {
   2819     *found_key = it->Key().as_string();
   2820 
   2821     // There can be several index keys that compare equal. We want the last one.
   2822     s = it->Next();
   2823   } while (s.ok() && it->IsValid() && !CompareIndexKeys(it->Key(), target));
   2824 
   2825   return true;
   2826 }
   2827 
   2828 static leveldb::Status VersionExists(LevelDBTransaction* transaction,
   2829                                      int64 database_id,
   2830                                      int64 object_store_id,
   2831                                      int64 version,
   2832                                      const std::string& encoded_primary_key,
   2833                                      bool* exists) {
   2834   const std::string key =
   2835       ExistsEntryKey::Encode(database_id, object_store_id, encoded_primary_key);
   2836   std::string data;
   2837 
   2838   leveldb::Status s = transaction->Get(key, &data, exists);
   2839   if (!s.ok()) {
   2840     INTERNAL_READ_ERROR_UNTESTED(VERSION_EXISTS);
   2841     return s;
   2842   }
   2843   if (!*exists)
   2844     return s;
   2845 
   2846   StringPiece slice(data);
   2847   int64 decoded;
   2848   if (!DecodeInt(&slice, &decoded) || !slice.empty())
   2849     return InternalInconsistencyStatus();
   2850   *exists = (decoded == version);
   2851   return s;
   2852 }
   2853 
   2854 leveldb::Status IndexedDBBackingStore::FindKeyInIndex(
   2855     IndexedDBBackingStore::Transaction* transaction,
   2856     int64 database_id,
   2857     int64 object_store_id,
   2858     int64 index_id,
   2859     const IndexedDBKey& key,
   2860     std::string* found_encoded_primary_key,
   2861     bool* found) {
   2862   IDB_TRACE("IndexedDBBackingStore::FindKeyInIndex");
   2863   DCHECK(KeyPrefix::ValidIds(database_id, object_store_id, index_id));
   2864 
   2865   DCHECK(found_encoded_primary_key->empty());
   2866   *found = false;
   2867 
   2868   LevelDBTransaction* leveldb_transaction = transaction->transaction();
   2869   const std::string leveldb_key =
   2870       IndexDataKey::Encode(database_id, object_store_id, index_id, key);
   2871   scoped_ptr<LevelDBIterator> it = leveldb_transaction->CreateIterator();
   2872   leveldb::Status s = it->Seek(leveldb_key);
   2873   if (!s.ok()) {
   2874     INTERNAL_READ_ERROR_UNTESTED(FIND_KEY_IN_INDEX);
   2875     return s;
   2876   }
   2877 
   2878   for (;;) {
   2879     if (!it->IsValid())
   2880       return leveldb::Status::OK();
   2881     if (CompareIndexKeys(it->Key(), leveldb_key) > 0)
   2882       return leveldb::Status::OK();
   2883 
   2884     StringPiece slice(it->Value());
   2885 
   2886     int64 version;
   2887     if (!DecodeVarInt(&slice, &version)) {
   2888       INTERNAL_READ_ERROR_UNTESTED(FIND_KEY_IN_INDEX);
   2889       return InternalInconsistencyStatus();
   2890     }
   2891     *found_encoded_primary_key = slice.as_string();
   2892 
   2893     bool exists = false;
   2894     s = VersionExists(leveldb_transaction,
   2895                       database_id,
   2896                       object_store_id,
   2897                       version,
   2898                       *found_encoded_primary_key,
   2899                       &exists);
   2900     if (!s.ok())
   2901       return s;
   2902     if (!exists) {
   2903       // Delete stale index data entry and continue.
   2904       leveldb_transaction->Remove(it->Key());
   2905       s = it->Next();
   2906       continue;
   2907     }
   2908     *found = true;
   2909     return s;
   2910   }
   2911 }
   2912 
   2913 leveldb::Status IndexedDBBackingStore::GetPrimaryKeyViaIndex(
   2914     IndexedDBBackingStore::Transaction* transaction,
   2915     int64 database_id,
   2916     int64 object_store_id,
   2917     int64 index_id,
   2918     const IndexedDBKey& key,
   2919     scoped_ptr<IndexedDBKey>* primary_key) {
   2920   IDB_TRACE("IndexedDBBackingStore::GetPrimaryKeyViaIndex");
   2921   if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
   2922     return InvalidDBKeyStatus();
   2923 
   2924   bool found = false;
   2925   std::string found_encoded_primary_key;
   2926   leveldb::Status s = FindKeyInIndex(transaction,
   2927                                      database_id,
   2928                                      object_store_id,
   2929                                      index_id,
   2930                                      key,
   2931                                      &found_encoded_primary_key,
   2932                                      &found);
   2933   if (!s.ok()) {
   2934     INTERNAL_READ_ERROR_UNTESTED(GET_PRIMARY_KEY_VIA_INDEX);
   2935     return s;
   2936   }
   2937   if (!found)
   2938     return s;
   2939   if (!found_encoded_primary_key.size()) {
   2940     INTERNAL_READ_ERROR_UNTESTED(GET_PRIMARY_KEY_VIA_INDEX);
   2941     return InvalidDBKeyStatus();
   2942   }
   2943 
   2944   StringPiece slice(found_encoded_primary_key);
   2945   if (DecodeIDBKey(&slice, primary_key) && slice.empty())
   2946     return s;
   2947   else
   2948     return InvalidDBKeyStatus();
   2949 }
   2950 
   2951 leveldb::Status IndexedDBBackingStore::KeyExistsInIndex(
   2952     IndexedDBBackingStore::Transaction* transaction,
   2953     int64 database_id,
   2954     int64 object_store_id,
   2955     int64 index_id,
   2956     const IndexedDBKey& index_key,
   2957     scoped_ptr<IndexedDBKey>* found_primary_key,
   2958     bool* exists) {
   2959   IDB_TRACE("IndexedDBBackingStore::KeyExistsInIndex");
   2960   if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
   2961     return InvalidDBKeyStatus();
   2962 
   2963   *exists = false;
   2964   std::string found_encoded_primary_key;
   2965   leveldb::Status s = FindKeyInIndex(transaction,
   2966                                      database_id,
   2967                                      object_store_id,
   2968                                      index_id,
   2969                                      index_key,
   2970                                      &found_encoded_primary_key,
   2971                                      exists);
   2972   if (!s.ok()) {
   2973     INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_INDEX);
   2974     return s;
   2975   }
   2976   if (!*exists)
   2977     return leveldb::Status::OK();
   2978   if (found_encoded_primary_key.empty()) {
   2979     INTERNAL_READ_ERROR_UNTESTED(KEY_EXISTS_IN_INDEX);
   2980     return InvalidDBKeyStatus();
   2981   }
   2982 
   2983   StringPiece slice(found_encoded_primary_key);
   2984   if (DecodeIDBKey(&slice, found_primary_key) && slice.empty())
   2985     return s;
   2986   else
   2987     return InvalidDBKeyStatus();
   2988 }
   2989 
   2990 IndexedDBBackingStore::Cursor::Cursor(
   2991     const IndexedDBBackingStore::Cursor* other)
   2992     : backing_store_(other->backing_store_),
   2993       transaction_(other->transaction_),
   2994       database_id_(other->database_id_),
   2995       cursor_options_(other->cursor_options_),
   2996       current_key_(new IndexedDBKey(*other->current_key_)) {
   2997   if (other->iterator_) {
   2998     iterator_ = transaction_->transaction()->CreateIterator();
   2999 
   3000     if (other->iterator_->IsValid()) {
   3001       leveldb::Status s = iterator_->Seek(other->iterator_->Key());
   3002       // TODO(cmumford): Handle this error (crbug.com/363397)
   3003       DCHECK(iterator_->IsValid());
   3004     }
   3005   }
   3006 }
   3007 
   3008 IndexedDBBackingStore::Cursor::Cursor(
   3009     scoped_refptr<IndexedDBBackingStore> backing_store,
   3010     IndexedDBBackingStore::Transaction* transaction,
   3011     int64 database_id,
   3012     const CursorOptions& cursor_options)
   3013     : backing_store_(backing_store),
   3014       transaction_(transaction),
   3015       database_id_(database_id),
   3016       cursor_options_(cursor_options) {
   3017 }
   3018 IndexedDBBackingStore::Cursor::~Cursor() {}
   3019 
   3020 bool IndexedDBBackingStore::Cursor::FirstSeek(leveldb::Status* s) {
   3021   iterator_ = transaction_->transaction()->CreateIterator();
   3022   if (cursor_options_.forward)
   3023     *s = iterator_->Seek(cursor_options_.low_key);
   3024   else
   3025     *s = iterator_->Seek(cursor_options_.high_key);
   3026   if (!s->ok())
   3027     return false;
   3028 
   3029   return Continue(0, READY, s);
   3030 }
   3031 
   3032 bool IndexedDBBackingStore::Cursor::Advance(uint32 count, leveldb::Status* s) {
   3033   *s = leveldb::Status::OK();
   3034   while (count--) {
   3035     if (!Continue(s))
   3036       return false;
   3037   }
   3038   return true;
   3039 }
   3040 
   3041 bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key,
   3042                                              const IndexedDBKey* primary_key,
   3043                                              IteratorState next_state,
   3044                                              leveldb::Status* s) {
   3045   DCHECK(!key || key->IsValid());
   3046   DCHECK(!primary_key || primary_key->IsValid());
   3047   *s = leveldb::Status::OK();
   3048 
   3049   // TODO(alecflett): avoid a copy here?
   3050   IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey();
   3051 
   3052   bool first_iteration = true;
   3053 
   3054   // When iterating with PrevNoDuplicate, spec requires that the
   3055   // value we yield for each key is the first duplicate in forwards
   3056   // order.
   3057   IndexedDBKey last_duplicate_key;
   3058 
   3059   bool forward = cursor_options_.forward;
   3060 
   3061   for (;;) {
   3062     if (next_state == SEEK) {
   3063       // TODO(jsbell): Optimize seeking for reverse cursors as well.
   3064       if (first_iteration && key && forward) {
   3065         std::string leveldb_key;
   3066         if (primary_key) {
   3067           leveldb_key = EncodeKey(*key, *primary_key);
   3068         } else {
   3069           leveldb_key = EncodeKey(*key);
   3070         }
   3071         *s = iterator_->Seek(leveldb_key);
   3072         first_iteration = false;
   3073       } else if (forward) {
   3074         *s = iterator_->Next();
   3075       } else {
   3076         *s = iterator_->Prev();
   3077       }
   3078       if (!s->ok())
   3079         return false;
   3080     } else {
   3081       next_state = SEEK;  // for subsequent iterations
   3082     }
   3083 
   3084     if (!iterator_->IsValid()) {
   3085       if (!forward && last_duplicate_key.IsValid()) {
   3086         // We need to walk forward because we hit the end of
   3087         // the data.
   3088         forward = true;
   3089         continue;
   3090       }
   3091 
   3092       return false;
   3093     }
   3094 
   3095     if (IsPastBounds()) {
   3096       if (!forward && last_duplicate_key.IsValid()) {
   3097         // We need to walk forward because now we're beyond the
   3098         // bounds defined by the cursor.
   3099         forward = true;
   3100         continue;
   3101       }
   3102 
   3103       return false;
   3104     }
   3105 
   3106     if (!HaveEnteredRange())
   3107       continue;
   3108 
   3109     // The row may not load because there's a stale entry in the
   3110     // index. This is not fatal.
   3111     if (!LoadCurrentRow())
   3112       continue;
   3113 
   3114     if (key) {
   3115       if (forward) {
   3116         if (primary_key && current_key_->Equals(*key) &&
   3117             this->primary_key().IsLessThan(*primary_key))
   3118           continue;
   3119         if (current_key_->IsLessThan(*key))
   3120           continue;
   3121       } else {
   3122         if (primary_key && key->Equals(*current_key_) &&
   3123             primary_key->IsLessThan(this->primary_key()))
   3124           continue;
   3125         if (key->IsLessThan(*current_key_))
   3126           continue;
   3127       }
   3128     }
   3129 
   3130     if (cursor_options_.unique) {
   3131       if (previous_key.IsValid() && current_key_->Equals(previous_key)) {
   3132         // We should never be able to walk forward all the way
   3133         // to the previous key.
   3134         DCHECK(!last_duplicate_key.IsValid());
   3135         continue;
   3136       }
   3137 
   3138       if (!forward) {
   3139         if (!last_duplicate_key.IsValid()) {
   3140           last_duplicate_key = *current_key_;
   3141           continue;
   3142         }
   3143 
   3144         // We need to walk forward because we hit the boundary
   3145         // between key ranges.
   3146         if (!last_duplicate_key.Equals(*current_key_)) {
   3147           forward = true;
   3148           continue;
   3149         }
   3150 
   3151         continue;
   3152       }
   3153     }
   3154     break;
   3155   }
   3156 
   3157   DCHECK(!last_duplicate_key.IsValid() ||
   3158          (forward && last_duplicate_key.Equals(*current_key_)));
   3159   return true;
   3160 }
   3161 
   3162 bool IndexedDBBackingStore::Cursor::HaveEnteredRange() const {
   3163   if (cursor_options_.forward) {
   3164     int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key);
   3165     if (cursor_options_.low_open) {
   3166       return compare > 0;
   3167     }
   3168     return compare >= 0;
   3169   }
   3170   int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.high_key);
   3171   if (cursor_options_.high_open) {
   3172     return compare < 0;
   3173   }
   3174   return compare <= 0;
   3175 }
   3176 
   3177 bool IndexedDBBackingStore::Cursor::IsPastBounds() const {
   3178   if (cursor_options_.forward) {
   3179     int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.high_key);
   3180     if (cursor_options_.high_open) {
   3181       return compare >= 0;
   3182     }
   3183     return compare > 0;
   3184   }
   3185   int compare = CompareIndexKeys(iterator_->Key(), cursor_options_.low_key);
   3186   if (cursor_options_.low_open) {
   3187     return compare <= 0;
   3188   }
   3189   return compare < 0;
   3190 }
   3191 
   3192 const IndexedDBKey& IndexedDBBackingStore::Cursor::primary_key() const {
   3193   return *current_key_;
   3194 }
   3195 
   3196 const IndexedDBBackingStore::RecordIdentifier&
   3197 IndexedDBBackingStore::Cursor::record_identifier() const {
   3198   return record_identifier_;
   3199 }
   3200 
   3201 class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor {
   3202  public:
   3203   ObjectStoreKeyCursorImpl(
   3204       scoped_refptr<IndexedDBBackingStore> backing_store,
   3205       IndexedDBBackingStore::Transaction* transaction,
   3206       int64 database_id,
   3207       const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
   3208       : IndexedDBBackingStore::Cursor(backing_store,
   3209                                       transaction,
   3210                                       database_id,
   3211                                       cursor_options) {}
   3212 
   3213   virtual Cursor* Clone() OVERRIDE {
   3214     return new ObjectStoreKeyCursorImpl(this);
   3215   }
   3216 
   3217   // IndexedDBBackingStore::Cursor
   3218   virtual IndexedDBValue* value() OVERRIDE {
   3219     NOTREACHED();
   3220     return NULL;
   3221   }
   3222   virtual bool LoadCurrentRow() OVERRIDE;
   3223 
   3224  protected:
   3225   virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
   3226     return ObjectStoreDataKey::Encode(
   3227         cursor_options_.database_id, cursor_options_.object_store_id, key);
   3228   }
   3229   virtual std::string EncodeKey(const IndexedDBKey& key,
   3230                                 const IndexedDBKey& primary_key) OVERRIDE {
   3231     NOTREACHED();
   3232     return std::string();
   3233   }
   3234 
   3235  private:
   3236   explicit ObjectStoreKeyCursorImpl(const ObjectStoreKeyCursorImpl* other)
   3237       : IndexedDBBackingStore::Cursor(other) {}
   3238 
   3239   DISALLOW_COPY_AND_ASSIGN(ObjectStoreKeyCursorImpl);
   3240 };
   3241 
   3242 bool ObjectStoreKeyCursorImpl::LoadCurrentRow() {
   3243   StringPiece slice(iterator_->Key());
   3244   ObjectStoreDataKey object_store_data_key;
   3245   if (!ObjectStoreDataKey::Decode(&slice, &object_store_data_key)) {
   3246     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3247     return false;
   3248   }
   3249 
   3250   current_key_ = object_store_data_key.user_key();
   3251 
   3252   int64 version;
   3253   slice = StringPiece(iterator_->Value());
   3254   if (!DecodeVarInt(&slice, &version)) {
   3255     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3256     return false;
   3257   }
   3258 
   3259   // TODO(jsbell): This re-encodes what was just decoded; try and optimize.
   3260   std::string encoded_key;
   3261   EncodeIDBKey(*current_key_, &encoded_key);
   3262   record_identifier_.Reset(encoded_key, version);
   3263 
   3264   return true;
   3265 }
   3266 
   3267 class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor {
   3268  public:
   3269   ObjectStoreCursorImpl(
   3270       scoped_refptr<IndexedDBBackingStore> backing_store,
   3271       IndexedDBBackingStore::Transaction* transaction,
   3272       int64 database_id,
   3273       const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
   3274       : IndexedDBBackingStore::Cursor(backing_store,
   3275                                       transaction,
   3276                                       database_id,
   3277                                       cursor_options) {}
   3278 
   3279   virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); }
   3280 
   3281   // IndexedDBBackingStore::Cursor
   3282   virtual IndexedDBValue* value() OVERRIDE { return &current_value_; }
   3283   virtual bool LoadCurrentRow() OVERRIDE;
   3284 
   3285  protected:
   3286   virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
   3287     return ObjectStoreDataKey::Encode(
   3288         cursor_options_.database_id, cursor_options_.object_store_id, key);
   3289   }
   3290   virtual std::string EncodeKey(const IndexedDBKey& key,
   3291                                 const IndexedDBKey& primary_key) OVERRIDE {
   3292     NOTREACHED();
   3293     return std::string();
   3294   }
   3295 
   3296  private:
   3297   explicit ObjectStoreCursorImpl(const ObjectStoreCursorImpl* other)
   3298       : IndexedDBBackingStore::Cursor(other),
   3299         current_value_(other->current_value_) {}
   3300 
   3301   IndexedDBValue current_value_;
   3302 
   3303   DISALLOW_COPY_AND_ASSIGN(ObjectStoreCursorImpl);
   3304 };
   3305 
   3306 bool ObjectStoreCursorImpl::LoadCurrentRow() {
   3307   StringPiece key_slice(iterator_->Key());
   3308   ObjectStoreDataKey object_store_data_key;
   3309   if (!ObjectStoreDataKey::Decode(&key_slice, &object_store_data_key)) {
   3310     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3311     return false;
   3312   }
   3313 
   3314   current_key_ = object_store_data_key.user_key();
   3315 
   3316   int64 version;
   3317   StringPiece value_slice = StringPiece(iterator_->Value());
   3318   if (!DecodeVarInt(&value_slice, &version)) {
   3319     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3320     return false;
   3321   }
   3322 
   3323   // TODO(jsbell): This re-encodes what was just decoded; try and optimize.
   3324   std::string encoded_key;
   3325   EncodeIDBKey(*current_key_, &encoded_key);
   3326   record_identifier_.Reset(encoded_key, version);
   3327 
   3328   if (!transaction_->GetBlobInfoForRecord(database_id_,
   3329                                           iterator_->Key().as_string(),
   3330                                           &current_value_).ok()) {
   3331     return false;
   3332   }
   3333   current_value_.bits = value_slice.as_string();
   3334   return true;
   3335 }
   3336 
   3337 class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor {
   3338  public:
   3339   IndexKeyCursorImpl(
   3340       scoped_refptr<IndexedDBBackingStore> backing_store,
   3341       IndexedDBBackingStore::Transaction* transaction,
   3342       int64 database_id,
   3343       const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
   3344       : IndexedDBBackingStore::Cursor(backing_store,
   3345                                       transaction,
   3346                                       database_id,
   3347                                       cursor_options) {}
   3348 
   3349   virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); }
   3350 
   3351   // IndexedDBBackingStore::Cursor
   3352   virtual IndexedDBValue* value() OVERRIDE {
   3353     NOTREACHED();
   3354     return NULL;
   3355   }
   3356   virtual const IndexedDBKey& primary_key() const OVERRIDE {
   3357     return *primary_key_;
   3358   }
   3359   virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier()
   3360       const OVERRIDE {
   3361     NOTREACHED();
   3362     return record_identifier_;
   3363   }
   3364   virtual bool LoadCurrentRow() OVERRIDE;
   3365 
   3366  protected:
   3367   virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
   3368     return IndexDataKey::Encode(cursor_options_.database_id,
   3369                                 cursor_options_.object_store_id,
   3370                                 cursor_options_.index_id,
   3371                                 key);
   3372   }
   3373   virtual std::string EncodeKey(const IndexedDBKey& key,
   3374                                 const IndexedDBKey& primary_key) OVERRIDE {
   3375     return IndexDataKey::Encode(cursor_options_.database_id,
   3376                                 cursor_options_.object_store_id,
   3377                                 cursor_options_.index_id,
   3378                                 key,
   3379                                 primary_key);
   3380   }
   3381 
   3382  private:
   3383   explicit IndexKeyCursorImpl(const IndexKeyCursorImpl* other)
   3384       : IndexedDBBackingStore::Cursor(other),
   3385         primary_key_(new IndexedDBKey(*other->primary_key_)) {}
   3386 
   3387   scoped_ptr<IndexedDBKey> primary_key_;
   3388 
   3389   DISALLOW_COPY_AND_ASSIGN(IndexKeyCursorImpl);
   3390 };
   3391 
   3392 bool IndexKeyCursorImpl::LoadCurrentRow() {
   3393   StringPiece slice(iterator_->Key());
   3394   IndexDataKey index_data_key;
   3395   if (!IndexDataKey::Decode(&slice, &index_data_key)) {
   3396     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3397     return false;
   3398   }
   3399 
   3400   current_key_ = index_data_key.user_key();
   3401   DCHECK(current_key_);
   3402 
   3403   slice = StringPiece(iterator_->Value());
   3404   int64 index_data_version;
   3405   if (!DecodeVarInt(&slice, &index_data_version)) {
   3406     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3407     return false;
   3408   }
   3409 
   3410   if (!DecodeIDBKey(&slice, &primary_key_) || !slice.empty()) {
   3411     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3412     return false;
   3413   }
   3414 
   3415   std::string primary_leveldb_key =
   3416       ObjectStoreDataKey::Encode(index_data_key.DatabaseId(),
   3417                                  index_data_key.ObjectStoreId(),
   3418                                  *primary_key_);
   3419 
   3420   std::string result;
   3421   bool found = false;
   3422   leveldb::Status s =
   3423       transaction_->transaction()->Get(primary_leveldb_key, &result, &found);
   3424   if (!s.ok()) {
   3425     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3426     return false;
   3427   }
   3428   if (!found) {
   3429     transaction_->transaction()->Remove(iterator_->Key());
   3430     return false;
   3431   }
   3432   if (!result.size()) {
   3433     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3434     return false;
   3435   }
   3436 
   3437   int64 object_store_data_version;
   3438   slice = StringPiece(result);
   3439   if (!DecodeVarInt(&slice, &object_store_data_version)) {
   3440     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3441     return false;
   3442   }
   3443 
   3444   if (object_store_data_version != index_data_version) {
   3445     transaction_->transaction()->Remove(iterator_->Key());
   3446     return false;
   3447   }
   3448 
   3449   return true;
   3450 }
   3451 
   3452 class IndexCursorImpl : public IndexedDBBackingStore::Cursor {
   3453  public:
   3454   IndexCursorImpl(
   3455       scoped_refptr<IndexedDBBackingStore> backing_store,
   3456       IndexedDBBackingStore::Transaction* transaction,
   3457       int64 database_id,
   3458       const IndexedDBBackingStore::Cursor::CursorOptions& cursor_options)
   3459       : IndexedDBBackingStore::Cursor(backing_store,
   3460                                       transaction,
   3461                                       database_id,
   3462                                       cursor_options) {}
   3463 
   3464   virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); }
   3465 
   3466   // IndexedDBBackingStore::Cursor
   3467   virtual IndexedDBValue* value() OVERRIDE { return &current_value_; }
   3468   virtual const IndexedDBKey& primary_key() const OVERRIDE {
   3469     return *primary_key_;
   3470   }
   3471   virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier()
   3472       const OVERRIDE {
   3473     NOTREACHED();
   3474     return record_identifier_;
   3475   }
   3476   virtual bool LoadCurrentRow() OVERRIDE;
   3477 
   3478  protected:
   3479   virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
   3480     return IndexDataKey::Encode(cursor_options_.database_id,
   3481                                 cursor_options_.object_store_id,
   3482                                 cursor_options_.index_id,
   3483                                 key);
   3484   }
   3485   virtual std::string EncodeKey(const IndexedDBKey& key,
   3486                                 const IndexedDBKey& primary_key) OVERRIDE {
   3487     return IndexDataKey::Encode(cursor_options_.database_id,
   3488                                 cursor_options_.object_store_id,
   3489                                 cursor_options_.index_id,
   3490                                 key,
   3491                                 primary_key);
   3492   }
   3493 
   3494  private:
   3495   explicit IndexCursorImpl(const IndexCursorImpl* other)
   3496       : IndexedDBBackingStore::Cursor(other),
   3497         primary_key_(new IndexedDBKey(*other->primary_key_)),
   3498         current_value_(other->current_value_),
   3499         primary_leveldb_key_(other->primary_leveldb_key_) {}
   3500 
   3501   scoped_ptr<IndexedDBKey> primary_key_;
   3502   IndexedDBValue current_value_;
   3503   std::string primary_leveldb_key_;
   3504 
   3505   DISALLOW_COPY_AND_ASSIGN(IndexCursorImpl);
   3506 };
   3507 
   3508 bool IndexCursorImpl::LoadCurrentRow() {
   3509   StringPiece slice(iterator_->Key());
   3510   IndexDataKey index_data_key;
   3511   if (!IndexDataKey::Decode(&slice, &index_data_key)) {
   3512     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3513     return false;
   3514   }
   3515 
   3516   current_key_ = index_data_key.user_key();
   3517   DCHECK(current_key_);
   3518 
   3519   slice = StringPiece(iterator_->Value());
   3520   int64 index_data_version;
   3521   if (!DecodeVarInt(&slice, &index_data_version)) {
   3522     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3523     return false;
   3524   }
   3525   if (!DecodeIDBKey(&slice, &primary_key_)) {
   3526     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3527     return false;
   3528   }
   3529 
   3530   DCHECK_EQ(index_data_key.DatabaseId(), database_id_);
   3531   primary_leveldb_key_ =
   3532       ObjectStoreDataKey::Encode(index_data_key.DatabaseId(),
   3533                                  index_data_key.ObjectStoreId(),
   3534                                  *primary_key_);
   3535 
   3536   std::string result;
   3537   bool found = false;
   3538   leveldb::Status s =
   3539       transaction_->transaction()->Get(primary_leveldb_key_, &result, &found);
   3540   if (!s.ok()) {
   3541     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3542     return false;
   3543   }
   3544   if (!found) {
   3545     transaction_->transaction()->Remove(iterator_->Key());
   3546     return false;
   3547   }
   3548   if (!result.size()) {
   3549     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3550     return false;
   3551   }
   3552 
   3553   int64 object_store_data_version;
   3554   slice = StringPiece(result);
   3555   if (!DecodeVarInt(&slice, &object_store_data_version)) {
   3556     INTERNAL_READ_ERROR_UNTESTED(LOAD_CURRENT_ROW);
   3557     return false;
   3558   }
   3559 
   3560   if (object_store_data_version != index_data_version) {
   3561     transaction_->transaction()->Remove(iterator_->Key());
   3562     return false;
   3563   }
   3564 
   3565   current_value_.bits = slice.as_string();
   3566   return transaction_->GetBlobInfoForRecord(database_id_,
   3567                                             primary_leveldb_key_,
   3568                                             &current_value_).ok();
   3569 }
   3570 
   3571 bool ObjectStoreCursorOptions(
   3572     LevelDBTransaction* transaction,
   3573     int64 database_id,
   3574     int64 object_store_id,
   3575     const IndexedDBKeyRange& range,
   3576     indexed_db::CursorDirection direction,
   3577     IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) {
   3578   cursor_options->database_id = database_id;
   3579   cursor_options->object_store_id = object_store_id;
   3580 
   3581   bool lower_bound = range.lower().IsValid();
   3582   bool upper_bound = range.upper().IsValid();
   3583   cursor_options->forward =
   3584       (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE ||
   3585        direction == indexed_db::CURSOR_NEXT);
   3586   cursor_options->unique = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE ||
   3587                             direction == indexed_db::CURSOR_PREV_NO_DUPLICATE);
   3588 
   3589   if (!lower_bound) {
   3590     cursor_options->low_key =
   3591         ObjectStoreDataKey::Encode(database_id, object_store_id, MinIDBKey());
   3592     cursor_options->low_open = true;  // Not included.
   3593   } else {
   3594     cursor_options->low_key =
   3595         ObjectStoreDataKey::Encode(database_id, object_store_id, range.lower());
   3596     cursor_options->low_open = range.lowerOpen();
   3597   }
   3598 
   3599   leveldb::Status s;
   3600 
   3601   if (!upper_bound) {
   3602     cursor_options->high_key =
   3603         ObjectStoreDataKey::Encode(database_id, object_store_id, MaxIDBKey());
   3604 
   3605     if (cursor_options->forward) {
   3606       cursor_options->high_open = true;  // Not included.
   3607     } else {
   3608       // We need a key that exists.
   3609       // TODO(cmumford): Handle this error (crbug.com/363397)
   3610       if (!FindGreatestKeyLessThanOrEqual(transaction,
   3611                                           cursor_options->high_key,
   3612                                           &cursor_options->high_key,
   3613                                           s))
   3614         return false;
   3615       cursor_options->high_open = false;
   3616     }
   3617   } else {
   3618     cursor_options->high_key =
   3619         ObjectStoreDataKey::Encode(database_id, object_store_id, range.upper());
   3620     cursor_options->high_open = range.upperOpen();
   3621 
   3622     if (!cursor_options->forward) {
   3623       // For reverse cursors, we need a key that exists.
   3624       std::string found_high_key;
   3625       // TODO(cmumford): Handle this error (crbug.com/363397)
   3626       if (!FindGreatestKeyLessThanOrEqual(
   3627               transaction, cursor_options->high_key, &found_high_key, s))
   3628         return false;
   3629 
   3630       // If the target key should not be included, but we end up with a smaller
   3631       // key, we should include that.
   3632       if (cursor_options->high_open &&
   3633           CompareIndexKeys(found_high_key, cursor_options->high_key) < 0)
   3634         cursor_options->high_open = false;
   3635 
   3636       cursor_options->high_key = found_high_key;
   3637     }
   3638   }
   3639 
   3640   return true;
   3641 }
   3642 
   3643 bool IndexCursorOptions(
   3644     LevelDBTransaction* transaction,
   3645     int64 database_id,
   3646     int64 object_store_id,
   3647     int64 index_id,
   3648     const IndexedDBKeyRange& range,
   3649     indexed_db::CursorDirection direction,
   3650     IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) {
   3651   DCHECK(transaction);
   3652   if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
   3653     return false;
   3654 
   3655   cursor_options->database_id = database_id;
   3656   cursor_options->object_store_id = object_store_id;
   3657   cursor_options->index_id = index_id;
   3658 
   3659   bool lower_bound = range.lower().IsValid();
   3660   bool upper_bound = range.upper().IsValid();
   3661   cursor_options->forward =
   3662       (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE ||
   3663        direction == indexed_db::CURSOR_NEXT);
   3664   cursor_options->unique = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE ||
   3665                             direction == indexed_db::CURSOR_PREV_NO_DUPLICATE);
   3666 
   3667   if (!lower_bound) {
   3668     cursor_options->low_key =
   3669         IndexDataKey::EncodeMinKey(database_id, object_store_id, index_id);
   3670     cursor_options->low_open = false;  // Included.
   3671   } else {
   3672     cursor_options->low_key = IndexDataKey::Encode(
   3673         database_id, object_store_id, index_id, range.lower());
   3674     cursor_options->low_open = range.lowerOpen();
   3675   }
   3676 
   3677   leveldb::Status s;
   3678 
   3679   if (!upper_bound) {
   3680     cursor_options->high_key =
   3681         IndexDataKey::EncodeMaxKey(database_id, object_store_id, index_id);
   3682     cursor_options->high_open = false;  // Included.
   3683 
   3684     if (!cursor_options->forward) {  // We need a key that exists.
   3685       if (!FindGreatestKeyLessThanOrEqual(transaction,
   3686                                           cursor_options->high_key,
   3687                                           &cursor_options->high_key,
   3688                                           s))
   3689         return false;
   3690       cursor_options->high_open = false;
   3691     }
   3692   } else {
   3693     cursor_options->high_key = IndexDataKey::Encode(
   3694         database_id, object_store_id, index_id, range.upper());
   3695     cursor_options->high_open = range.upperOpen();
   3696 
   3697     std::string found_high_key;
   3698     // Seek to the *last* key in the set of non-unique keys
   3699     // TODO(cmumford): Handle this error (crbug.com/363397)
   3700     if (!FindGreatestKeyLessThanOrEqual(
   3701             transaction, cursor_options->high_key, &found_high_key, s))
   3702       return false;
   3703 
   3704     // If the target key should not be included, but we end up with a smaller
   3705     // key, we should include that.
   3706     if (cursor_options->high_open &&
   3707         CompareIndexKeys(found_high_key, cursor_options->high_key) < 0)
   3708       cursor_options->high_open = false;
   3709 
   3710     cursor_options->high_key = found_high_key;
   3711   }
   3712 
   3713   return true;
   3714 }
   3715 
   3716 scoped_ptr<IndexedDBBackingStore::Cursor>
   3717 IndexedDBBackingStore::OpenObjectStoreCursor(
   3718     IndexedDBBackingStore::Transaction* transaction,
   3719     int64 database_id,
   3720     int64 object_store_id,
   3721     const IndexedDBKeyRange& range,
   3722     indexed_db::CursorDirection direction,
   3723     leveldb::Status* s) {
   3724   IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreCursor");
   3725   *s = leveldb::Status::OK();
   3726   LevelDBTransaction* leveldb_transaction = transaction->transaction();
   3727   IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
   3728   if (!ObjectStoreCursorOptions(leveldb_transaction,
   3729                                 database_id,
   3730                                 object_store_id,
   3731                                 range,
   3732                                 direction,
   3733                                 &cursor_options))
   3734     return scoped_ptr<IndexedDBBackingStore::Cursor>();
   3735   scoped_ptr<ObjectStoreCursorImpl> cursor(new ObjectStoreCursorImpl(
   3736       this, transaction, database_id, cursor_options));
   3737   if (!cursor->FirstSeek(s))
   3738     return scoped_ptr<IndexedDBBackingStore::Cursor>();
   3739 
   3740   return cursor.PassAs<IndexedDBBackingStore::Cursor>();
   3741 }
   3742 
   3743 scoped_ptr<IndexedDBBackingStore::Cursor>
   3744 IndexedDBBackingStore::OpenObjectStoreKeyCursor(
   3745     IndexedDBBackingStore::Transaction* transaction,
   3746     int64 database_id,
   3747     int64 object_store_id,
   3748     const IndexedDBKeyRange& range,
   3749     indexed_db::CursorDirection direction,
   3750     leveldb::Status* s) {
   3751   IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor");
   3752   *s = leveldb::Status::OK();
   3753   LevelDBTransaction* leveldb_transaction = transaction->transaction();
   3754   IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
   3755   if (!ObjectStoreCursorOptions(leveldb_transaction,
   3756                                 database_id,
   3757                                 object_store_id,
   3758                                 range,
   3759                                 direction,
   3760                                 &cursor_options))
   3761     return scoped_ptr<IndexedDBBackingStore::Cursor>();
   3762   scoped_ptr<ObjectStoreKeyCursorImpl> cursor(new ObjectStoreKeyCursorImpl(
   3763       this, transaction, database_id, cursor_options));
   3764   if (!cursor->FirstSeek(s))
   3765     return scoped_ptr<IndexedDBBackingStore::Cursor>();
   3766 
   3767   return cursor.PassAs<IndexedDBBackingStore::Cursor>();
   3768 }
   3769 
   3770 scoped_ptr<IndexedDBBackingStore::Cursor>
   3771 IndexedDBBackingStore::OpenIndexKeyCursor(
   3772     IndexedDBBackingStore::Transaction* transaction,
   3773     int64 database_id,
   3774     int64 object_store_id,
   3775     int64 index_id,
   3776     const IndexedDBKeyRange& range,
   3777     indexed_db::CursorDirection direction,
   3778     leveldb::Status* s) {
   3779   IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor");
   3780   *s = leveldb::Status::OK();
   3781   LevelDBTransaction* leveldb_transaction = transaction->transaction();
   3782   IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
   3783   if (!IndexCursorOptions(leveldb_transaction,
   3784                           database_id,
   3785                           object_store_id,
   3786                           index_id,
   3787                           range,
   3788                           direction,
   3789                           &cursor_options))
   3790     return scoped_ptr<IndexedDBBackingStore::Cursor>();
   3791   scoped_ptr<IndexKeyCursorImpl> cursor(
   3792       new IndexKeyCursorImpl(this, transaction, database_id, cursor_options));
   3793   if (!cursor->FirstSeek(s))
   3794     return scoped_ptr<IndexedDBBackingStore::Cursor>();
   3795 
   3796   return cursor.PassAs<IndexedDBBackingStore::Cursor>();
   3797 }
   3798 
   3799 scoped_ptr<IndexedDBBackingStore::Cursor>
   3800 IndexedDBBackingStore::OpenIndexCursor(
   3801     IndexedDBBackingStore::Transaction* transaction,
   3802     int64 database_id,
   3803     int64 object_store_id,
   3804     int64 index_id,
   3805     const IndexedDBKeyRange& range,
   3806     indexed_db::CursorDirection direction,
   3807     leveldb::Status* s) {
   3808   IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor");
   3809   LevelDBTransaction* leveldb_transaction = transaction->transaction();
   3810   IndexedDBBackingStore::Cursor::CursorOptions cursor_options;
   3811   if (!IndexCursorOptions(leveldb_transaction,
   3812                           database_id,
   3813                           object_store_id,
   3814                           index_id,
   3815                           range,
   3816                           direction,
   3817                           &cursor_options))
   3818     return scoped_ptr<IndexedDBBackingStore::Cursor>();
   3819   scoped_ptr<IndexCursorImpl> cursor(
   3820       new IndexCursorImpl(this, transaction, database_id, cursor_options));
   3821   if (!cursor->FirstSeek(s))
   3822     return scoped_ptr<IndexedDBBackingStore::Cursor>();
   3823 
   3824   return cursor.PassAs<IndexedDBBackingStore::Cursor>();
   3825 }
   3826 
   3827 IndexedDBBackingStore::Transaction::Transaction(
   3828     IndexedDBBackingStore* backing_store)
   3829     : backing_store_(backing_store), database_id_(-1) {
   3830 }
   3831 
   3832 IndexedDBBackingStore::Transaction::~Transaction() {
   3833   STLDeleteContainerPairSecondPointers(
   3834       blob_change_map_.begin(), blob_change_map_.end());
   3835   STLDeleteContainerPairSecondPointers(incognito_blob_map_.begin(),
   3836                                        incognito_blob_map_.end());
   3837 }
   3838 
   3839 void IndexedDBBackingStore::Transaction::Begin() {
   3840   IDB_TRACE("IndexedDBBackingStore::Transaction::Begin");
   3841   DCHECK(!transaction_.get());
   3842   transaction_ = IndexedDBClassFactory::Get()->CreateLevelDBTransaction(
   3843       backing_store_->db_.get());
   3844 
   3845   // If incognito, this snapshots blobs just as the above transaction_
   3846   // constructor snapshots the leveldb.
   3847   BlobChangeMap::const_iterator iter;
   3848   for (iter = backing_store_->incognito_blob_map_.begin();
   3849        iter != backing_store_->incognito_blob_map_.end();
   3850        ++iter)
   3851     incognito_blob_map_[iter->first] = iter->second->Clone().release();
   3852 }
   3853 
   3854 static GURL getURLFromUUID(const string& uuid) {
   3855   return GURL("blob:uuid/" + uuid);
   3856 }
   3857 
   3858 leveldb::Status IndexedDBBackingStore::Transaction::HandleBlobPreTransaction(
   3859     BlobEntryKeyValuePairVec* new_blob_entries,
   3860     WriteDescriptorVec* new_files_to_write) {
   3861   if (backing_store_->is_incognito())
   3862     return leveldb::Status::OK();
   3863 
   3864   BlobChangeMap::iterator iter = blob_change_map_.begin();
   3865   new_blob_entries->clear();
   3866   new_files_to_write->clear();
   3867   if (iter != blob_change_map_.end()) {
   3868     // Create LevelDBTransaction for the name generator seed and add-journal.
   3869     scoped_refptr<LevelDBTransaction> pre_transaction =
   3870         IndexedDBClassFactory::Get()->CreateLevelDBTransaction(
   3871             backing_store_->db_.get());
   3872     BlobJournalType journal;
   3873     for (; iter != blob_change_map_.end(); ++iter) {
   3874       std::vector<IndexedDBBlobInfo>::iterator info_iter;
   3875       std::vector<IndexedDBBlobInfo*> new_blob_keys;
   3876       for (info_iter = iter->second->mutable_blob_info().begin();
   3877            info_iter != iter->second->mutable_blob_info().end();
   3878            ++info_iter) {
   3879         int64 next_blob_key = -1;
   3880         bool result = GetBlobKeyGeneratorCurrentNumber(
   3881             pre_transaction.get(), database_id_, &next_blob_key);
   3882         if (!result || next_blob_key < 0)
   3883           return InternalInconsistencyStatus();
   3884         BlobJournalEntryType journal_entry =
   3885             std::make_pair(database_id_, next_blob_key);
   3886         journal.push_back(journal_entry);
   3887         if (info_iter->is_file()) {
   3888           new_files_to_write->push_back(
   3889               WriteDescriptor(info_iter->file_path(),
   3890                               next_blob_key,
   3891                               info_iter->size(),
   3892                               info_iter->last_modified()));
   3893         } else {
   3894           new_files_to_write->push_back(
   3895               WriteDescriptor(getURLFromUUID(info_iter->uuid()),
   3896                               next_blob_key,
   3897                               info_iter->size()));
   3898         }
   3899         info_iter->set_key(next_blob_key);
   3900         new_blob_keys.push_back(&*info_iter);
   3901         result = UpdateBlobKeyGeneratorCurrentNumber(
   3902             pre_transaction.get(), database_id_, next_blob_key + 1);
   3903         if (!result)
   3904           return InternalInconsistencyStatus();
   3905       }
   3906       BlobEntryKey blob_entry_key;
   3907       StringPiece key_piece(iter->second->key());
   3908       if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) {
   3909         NOTREACHED();
   3910         return InternalInconsistencyStatus();
   3911       }
   3912       new_blob_entries->push_back(
   3913           std::make_pair(blob_entry_key, EncodeBlobData(new_blob_keys)));
   3914     }
   3915     UpdatePrimaryJournalWithBlobList(pre_transaction.get(), journal);
   3916     leveldb::Status s = pre_transaction->Commit();
   3917     if (!s.ok())
   3918       return InternalInconsistencyStatus();
   3919   }
   3920   return leveldb::Status::OK();
   3921 }
   3922 
   3923 bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() {
   3924   if (backing_store_->is_incognito())
   3925     return true;
   3926 
   3927   BlobChangeMap::const_iterator iter = blob_change_map_.begin();
   3928   // Look up all old files to remove as part of the transaction, store their
   3929   // names in blobs_to_remove_, and remove their old blob data entries.
   3930   if (iter != blob_change_map_.end()) {
   3931     scoped_ptr<LevelDBIterator> db_iter = transaction_->CreateIterator();
   3932     for (; iter != blob_change_map_.end(); ++iter) {
   3933       BlobEntryKey blob_entry_key;
   3934       StringPiece key_piece(iter->second->key());
   3935       if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) {
   3936         NOTREACHED();
   3937         INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
   3938         transaction_ = NULL;
   3939         return false;
   3940       }
   3941       if (database_id_ < 0)
   3942         database_id_ = blob_entry_key.database_id();
   3943       else
   3944         DCHECK_EQ(database_id_, blob_entry_key.database_id());
   3945       std::string blob_entry_key_bytes = blob_entry_key.Encode();
   3946       db_iter->Seek(blob_entry_key_bytes);
   3947       if (db_iter->IsValid() &&
   3948           !CompareKeys(db_iter->Key(), blob_entry_key_bytes)) {
   3949         std::vector<IndexedDBBlobInfo> blob_info;
   3950         if (!DecodeBlobData(db_iter->Value().as_string(), &blob_info)) {
   3951           INTERNAL_READ_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
   3952           transaction_ = NULL;
   3953           return false;
   3954         }
   3955         std::vector<IndexedDBBlobInfo>::iterator blob_info_iter;
   3956         for (blob_info_iter = blob_info.begin();
   3957              blob_info_iter != blob_info.end();
   3958              ++blob_info_iter)
   3959           blobs_to_remove_.push_back(
   3960               std::make_pair(database_id_, blob_info_iter->key()));
   3961         transaction_->Remove(blob_entry_key_bytes);
   3962       }
   3963     }
   3964   }
   3965   return true;
   3966 }
   3967 
   3968 leveldb::Status IndexedDBBackingStore::Transaction::SortBlobsToRemove() {
   3969   IndexedDBActiveBlobRegistry* registry =
   3970       backing_store_->active_blob_registry();
   3971   BlobJournalType::iterator iter;
   3972   BlobJournalType primary_journal, live_blob_journal;
   3973   for (iter = blobs_to_remove_.begin(); iter != blobs_to_remove_.end();
   3974        ++iter) {
   3975     if (registry->MarkDeletedCheckIfUsed(iter->first, iter->second))
   3976       live_blob_journal.push_back(*iter);
   3977     else
   3978       primary_journal.push_back(*iter);
   3979   }
   3980   UpdatePrimaryJournalWithBlobList(transaction_.get(), primary_journal);
   3981   leveldb::Status s =
   3982       MergeBlobsIntoLiveBlobJournal(transaction_.get(), live_blob_journal);
   3983   if (!s.ok())
   3984     return s;
   3985   // To signal how many blobs need attention right now.
   3986   blobs_to_remove_.swap(primary_journal);
   3987   return leveldb::Status::OK();
   3988 }
   3989 
   3990 leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseOne(
   3991     scoped_refptr<BlobWriteCallback> callback) {
   3992   IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseOne");
   3993   DCHECK(transaction_);
   3994   DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread());
   3995 
   3996   leveldb::Status s;
   3997 
   3998   s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode());
   3999   if (!s.ok()) {
   4000     INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
   4001     transaction_ = NULL;
   4002     return s;
   4003   }
   4004 
   4005   BlobEntryKeyValuePairVec new_blob_entries;
   4006   WriteDescriptorVec new_files_to_write;
   4007   s = HandleBlobPreTransaction(&new_blob_entries, &new_files_to_write);
   4008   if (!s.ok()) {
   4009     INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
   4010     transaction_ = NULL;
   4011     return s;
   4012   }
   4013 
   4014   DCHECK(!new_files_to_write.size() ||
   4015          KeyPrefix::IsValidDatabaseId(database_id_));
   4016   if (!CollectBlobFilesToRemove()) {
   4017     INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
   4018     transaction_ = NULL;
   4019     return InternalInconsistencyStatus();
   4020   }
   4021 
   4022   if (new_files_to_write.size()) {
   4023     // This kicks off the writes of the new blobs, if any.
   4024     // This call will zero out new_blob_entries and new_files_to_write.
   4025     WriteNewBlobs(new_blob_entries, new_files_to_write, callback);
   4026     // Remove the add journal, if any; once the blobs are written, and we
   4027     // commit, this will do the cleanup.
   4028     ClearBlobJournal(transaction_.get(), BlobJournalKey::Encode());
   4029   } else {
   4030     callback->Run(true);
   4031   }
   4032 
   4033   return leveldb::Status::OK();
   4034 }
   4035 
   4036 leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseTwo() {
   4037   IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseTwo");
   4038   leveldb::Status s;
   4039   if (blobs_to_remove_.size()) {
   4040     s = SortBlobsToRemove();
   4041     if (!s.ok()) {
   4042       INTERNAL_READ_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
   4043       transaction_ = NULL;
   4044       return s;
   4045     }
   4046   }
   4047 
   4048   s = transaction_->Commit();
   4049   transaction_ = NULL;
   4050 
   4051   if (s.ok() && backing_store_->is_incognito() && !blob_change_map_.empty()) {
   4052     BlobChangeMap& target_map = backing_store_->incognito_blob_map_;
   4053     BlobChangeMap::iterator iter;
   4054     for (iter = blob_change_map_.begin(); iter != blob_change_map_.end();
   4055          ++iter) {
   4056       BlobChangeMap::iterator target_record = target_map.find(iter->first);
   4057       if (target_record != target_map.end()) {
   4058         delete target_record->second;
   4059         target_map.erase(target_record);
   4060       }
   4061       if (iter->second) {
   4062         target_map[iter->first] = iter->second;
   4063         iter->second = NULL;
   4064       }
   4065     }
   4066   }
   4067   if (!s.ok())
   4068     INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
   4069   else if (blobs_to_remove_.size())
   4070     s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode());
   4071 
   4072   return s;
   4073 }
   4074 
   4075 
   4076 class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper
   4077     : public IndexedDBBackingStore::BlobWriteCallback {
   4078  public:
   4079   BlobWriteCallbackWrapper(IndexedDBBackingStore::Transaction* transaction,
   4080                            scoped_refptr<BlobWriteCallback> callback)
   4081       : transaction_(transaction), callback_(callback) {}
   4082   virtual void Run(bool succeeded) OVERRIDE {
   4083     callback_->Run(succeeded);
   4084     if (succeeded)  // Else it's already been deleted during rollback.
   4085       transaction_->chained_blob_writer_ = NULL;
   4086   }
   4087 
   4088  private:
   4089   virtual ~BlobWriteCallbackWrapper() {}
   4090   friend class base::RefCounted<IndexedDBBackingStore::BlobWriteCallback>;
   4091 
   4092   IndexedDBBackingStore::Transaction* transaction_;
   4093   scoped_refptr<BlobWriteCallback> callback_;
   4094 
   4095   DISALLOW_COPY_AND_ASSIGN(BlobWriteCallbackWrapper);
   4096 };
   4097 
   4098 void IndexedDBBackingStore::Transaction::WriteNewBlobs(
   4099     BlobEntryKeyValuePairVec& new_blob_entries,
   4100     WriteDescriptorVec& new_files_to_write,
   4101     scoped_refptr<BlobWriteCallback> callback) {
   4102   DCHECK_GT(new_files_to_write.size(), 0UL);
   4103   DCHECK_GT(database_id_, 0);
   4104   BlobEntryKeyValuePairVec::iterator blob_entry_iter;
   4105   for (blob_entry_iter = new_blob_entries.begin();
   4106        blob_entry_iter != new_blob_entries.end();
   4107        ++blob_entry_iter) {
   4108     // Add the new blob-table entry for each blob to the main transaction, or
   4109     // remove any entry that may exist if there's no new one.
   4110     if (!blob_entry_iter->second.size())
   4111       transaction_->Remove(blob_entry_iter->first.Encode());
   4112     else
   4113       transaction_->Put(blob_entry_iter->first.Encode(),
   4114                         &blob_entry_iter->second);
   4115   }
   4116   // Creating the writer will start it going asynchronously.
   4117   chained_blob_writer_ =
   4118       new ChainedBlobWriterImpl(database_id_,
   4119                                 backing_store_,
   4120                                 new_files_to_write,
   4121                                 new BlobWriteCallbackWrapper(this, callback));
   4122 }
   4123 
   4124 void IndexedDBBackingStore::Transaction::Rollback() {
   4125   IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback");
   4126   DCHECK(transaction_.get());
   4127   if (chained_blob_writer_) {
   4128     chained_blob_writer_->Abort();
   4129     chained_blob_writer_ = NULL;
   4130   }
   4131   transaction_->Rollback();
   4132   transaction_ = NULL;
   4133 }
   4134 
   4135 IndexedDBBackingStore::BlobChangeRecord::BlobChangeRecord(
   4136     const std::string& key,
   4137     int64 object_store_id)
   4138     : key_(key), object_store_id_(object_store_id) {
   4139 }
   4140 
   4141 IndexedDBBackingStore::BlobChangeRecord::~BlobChangeRecord() {
   4142 }
   4143 
   4144 void IndexedDBBackingStore::BlobChangeRecord::SetBlobInfo(
   4145     std::vector<IndexedDBBlobInfo>* blob_info) {
   4146   blob_info_.clear();
   4147   if (blob_info)
   4148     blob_info_.swap(*blob_info);
   4149 }
   4150 
   4151 void IndexedDBBackingStore::BlobChangeRecord::SetHandles(
   4152     ScopedVector<webkit_blob::BlobDataHandle>* handles) {
   4153   handles_.clear();
   4154   if (handles)
   4155     handles_.swap(*handles);
   4156 }
   4157 
   4158 scoped_ptr<IndexedDBBackingStore::BlobChangeRecord>
   4159 IndexedDBBackingStore::BlobChangeRecord::Clone() const {
   4160   scoped_ptr<IndexedDBBackingStore::BlobChangeRecord> record(
   4161       new BlobChangeRecord(key_, object_store_id_));
   4162   record->blob_info_ = blob_info_;
   4163 
   4164   ScopedVector<webkit_blob::BlobDataHandle>::const_iterator iter;
   4165   for (iter = handles_.begin(); iter != handles_.end(); ++iter)
   4166     record->handles_.push_back(new webkit_blob::BlobDataHandle(**iter));
   4167   return record.Pass();
   4168 }
   4169 
   4170 leveldb::Status IndexedDBBackingStore::Transaction::PutBlobInfoIfNeeded(
   4171     int64 database_id,
   4172     int64 object_store_id,
   4173     const std::string& object_store_data_key,
   4174     std::vector<IndexedDBBlobInfo>* blob_info,
   4175     ScopedVector<webkit_blob::BlobDataHandle>* handles) {
   4176   if (!blob_info || blob_info->empty()) {
   4177     blob_change_map_.erase(object_store_data_key);
   4178     incognito_blob_map_.erase(object_store_data_key);
   4179 
   4180     BlobEntryKey blob_entry_key;
   4181     StringPiece leveldb_key_piece(object_store_data_key);
   4182     if (!BlobEntryKey::FromObjectStoreDataKey(&leveldb_key_piece,
   4183                                               &blob_entry_key)) {
   4184       NOTREACHED();
   4185       return InternalInconsistencyStatus();
   4186     }
   4187     std::string value;
   4188     bool found = false;
   4189     leveldb::Status s =
   4190         transaction()->Get(blob_entry_key.Encode(), &value, &found);
   4191     if (!s.ok())
   4192       return s;
   4193     if (!found)
   4194       return leveldb::Status::OK();
   4195   }
   4196   PutBlobInfo(
   4197       database_id, object_store_id, object_store_data_key, blob_info, handles);
   4198   return leveldb::Status::OK();
   4199 }
   4200 
   4201 // This is storing an info, even if empty, even if the previous key had no blob
   4202 // info that we know of.  It duplicates a bunch of information stored in the
   4203 // leveldb transaction, but only w.r.t. the user keys altered--we don't keep the
   4204 // changes to exists or index keys here.
   4205 void IndexedDBBackingStore::Transaction::PutBlobInfo(
   4206     int64 database_id,
   4207     int64 object_store_id,
   4208     const std::string& object_store_data_key,
   4209     std::vector<IndexedDBBlobInfo>* blob_info,
   4210     ScopedVector<webkit_blob::BlobDataHandle>* handles) {
   4211   DCHECK_GT(object_store_data_key.size(), 0UL);
   4212   if (database_id_ < 0)
   4213     database_id_ = database_id;
   4214   DCHECK_EQ(database_id_, database_id);
   4215 
   4216   BlobChangeMap::iterator it = blob_change_map_.find(object_store_data_key);
   4217   BlobChangeRecord* record = NULL;
   4218   if (it == blob_change_map_.end()) {
   4219     record = new BlobChangeRecord(object_store_data_key, object_store_id);
   4220     blob_change_map_[object_store_data_key] = record;
   4221   } else {
   4222     record = it->second;
   4223   }
   4224   DCHECK_EQ(record->object_store_id(), object_store_id);
   4225   record->SetBlobInfo(blob_info);
   4226   record->SetHandles(handles);
   4227   DCHECK(!handles || !handles->size());
   4228 }
   4229 
   4230 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
   4231     const GURL& url,
   4232     int64_t key,
   4233     int64_t size)
   4234     : is_file_(false), url_(url), key_(key), size_(size) {
   4235 }
   4236 
   4237 IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
   4238     const FilePath& file_path,
   4239     int64_t key,
   4240     int64_t size,
   4241     base::Time last_modified)
   4242     : is_file_(true),
   4243       file_path_(file_path),
   4244       key_(key),
   4245       size_(size),
   4246       last_modified_(last_modified) {
   4247 }
   4248 
   4249 }  // namespace content
   4250