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_database.h"
      6 
      7 #include <math.h>
      8 #include <set>
      9 
     10 #include "base/auto_reset.h"
     11 #include "base/logging.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/memory/scoped_vector.h"
     14 #include "base/stl_util.h"
     15 #include "base/strings/string_number_conversions.h"
     16 #include "base/strings/utf_string_conversions.h"
     17 #include "content/browser/indexed_db/indexed_db_blob_info.h"
     18 #include "content/browser/indexed_db/indexed_db_connection.h"
     19 #include "content/browser/indexed_db/indexed_db_context_impl.h"
     20 #include "content/browser/indexed_db/indexed_db_cursor.h"
     21 #include "content/browser/indexed_db/indexed_db_factory.h"
     22 #include "content/browser/indexed_db/indexed_db_index_writer.h"
     23 #include "content/browser/indexed_db/indexed_db_pending_connection.h"
     24 #include "content/browser/indexed_db/indexed_db_tracing.h"
     25 #include "content/browser/indexed_db/indexed_db_transaction.h"
     26 #include "content/browser/indexed_db/indexed_db_value.h"
     27 #include "content/common/indexed_db/indexed_db_key_path.h"
     28 #include "content/common/indexed_db/indexed_db_key_range.h"
     29 #include "storage/browser/blob/blob_data_handle.h"
     30 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
     31 #include "third_party/leveldatabase/env_chromium.h"
     32 
     33 using base::ASCIIToUTF16;
     34 using base::Int64ToString16;
     35 using blink::WebIDBKeyTypeNumber;
     36 
     37 namespace content {
     38 
     39 // PendingUpgradeCall has a scoped_ptr<IndexedDBConnection> because it owns the
     40 // in-progress connection.
     41 class IndexedDBDatabase::PendingUpgradeCall {
     42  public:
     43   PendingUpgradeCall(scoped_refptr<IndexedDBCallbacks> callbacks,
     44                      scoped_ptr<IndexedDBConnection> connection,
     45                      int64 transaction_id,
     46                      int64 version)
     47       : callbacks_(callbacks),
     48         connection_(connection.Pass()),
     49         version_(version),
     50         transaction_id_(transaction_id) {}
     51   scoped_refptr<IndexedDBCallbacks> callbacks() const { return callbacks_; }
     52   // Takes ownership of the connection object.
     53   scoped_ptr<IndexedDBConnection> ReleaseConnection() WARN_UNUSED_RESULT {
     54     return connection_.Pass();
     55   }
     56   int64 version() const { return version_; }
     57   int64 transaction_id() const { return transaction_id_; }
     58 
     59  private:
     60   scoped_refptr<IndexedDBCallbacks> callbacks_;
     61   scoped_ptr<IndexedDBConnection> connection_;
     62   int64 version_;
     63   const int64 transaction_id_;
     64 };
     65 
     66 // PendingSuccessCall has a IndexedDBConnection* because the connection is now
     67 // owned elsewhere, but we need to cancel the success call if that connection
     68 // closes before it is sent.
     69 class IndexedDBDatabase::PendingSuccessCall {
     70  public:
     71   PendingSuccessCall(scoped_refptr<IndexedDBCallbacks> callbacks,
     72                      IndexedDBConnection* connection,
     73                      int64 version)
     74       : callbacks_(callbacks), connection_(connection), version_(version) {}
     75   scoped_refptr<IndexedDBCallbacks> callbacks() const { return callbacks_; }
     76   IndexedDBConnection* connection() const { return connection_; }
     77   int64 version() const { return version_; }
     78 
     79  private:
     80   scoped_refptr<IndexedDBCallbacks> callbacks_;
     81   IndexedDBConnection* connection_;
     82   int64 version_;
     83 };
     84 
     85 class IndexedDBDatabase::PendingDeleteCall {
     86  public:
     87   explicit PendingDeleteCall(scoped_refptr<IndexedDBCallbacks> callbacks)
     88       : callbacks_(callbacks) {}
     89   scoped_refptr<IndexedDBCallbacks> callbacks() const { return callbacks_; }
     90 
     91  private:
     92   scoped_refptr<IndexedDBCallbacks> callbacks_;
     93 };
     94 
     95 scoped_refptr<IndexedDBDatabase> IndexedDBDatabase::Create(
     96     const base::string16& name,
     97     IndexedDBBackingStore* backing_store,
     98     IndexedDBFactory* factory,
     99     const Identifier& unique_identifier,
    100     leveldb::Status* s) {
    101   scoped_refptr<IndexedDBDatabase> database =
    102       new IndexedDBDatabase(name, backing_store, factory, unique_identifier);
    103   *s = database->OpenInternal();
    104   if (s->ok())
    105     return database;
    106   else
    107     return NULL;
    108 }
    109 
    110 namespace {
    111 const base::string16::value_type kNoStringVersion[] = {0};
    112 }
    113 
    114 IndexedDBDatabase::IndexedDBDatabase(const base::string16& name,
    115                                      IndexedDBBackingStore* backing_store,
    116                                      IndexedDBFactory* factory,
    117                                      const Identifier& unique_identifier)
    118     : backing_store_(backing_store),
    119       metadata_(name,
    120                 kInvalidId,
    121                 kNoStringVersion,
    122                 IndexedDBDatabaseMetadata::NO_INT_VERSION,
    123                 kInvalidId),
    124       identifier_(unique_identifier),
    125       factory_(factory) {
    126   DCHECK(factory != NULL);
    127 }
    128 
    129 void IndexedDBDatabase::AddObjectStore(
    130     const IndexedDBObjectStoreMetadata& object_store,
    131     int64 new_max_object_store_id) {
    132   DCHECK(metadata_.object_stores.find(object_store.id) ==
    133          metadata_.object_stores.end());
    134   if (new_max_object_store_id != IndexedDBObjectStoreMetadata::kInvalidId) {
    135     DCHECK_LT(metadata_.max_object_store_id, new_max_object_store_id);
    136     metadata_.max_object_store_id = new_max_object_store_id;
    137   }
    138   metadata_.object_stores[object_store.id] = object_store;
    139 }
    140 
    141 void IndexedDBDatabase::RemoveObjectStore(int64 object_store_id) {
    142   DCHECK(metadata_.object_stores.find(object_store_id) !=
    143          metadata_.object_stores.end());
    144   metadata_.object_stores.erase(object_store_id);
    145 }
    146 
    147 void IndexedDBDatabase::AddIndex(int64 object_store_id,
    148                                  const IndexedDBIndexMetadata& index,
    149                                  int64 new_max_index_id) {
    150   DCHECK(metadata_.object_stores.find(object_store_id) !=
    151          metadata_.object_stores.end());
    152   IndexedDBObjectStoreMetadata object_store =
    153       metadata_.object_stores[object_store_id];
    154 
    155   DCHECK(object_store.indexes.find(index.id) == object_store.indexes.end());
    156   object_store.indexes[index.id] = index;
    157   if (new_max_index_id != IndexedDBIndexMetadata::kInvalidId) {
    158     DCHECK_LT(object_store.max_index_id, new_max_index_id);
    159     object_store.max_index_id = new_max_index_id;
    160   }
    161   metadata_.object_stores[object_store_id] = object_store;
    162 }
    163 
    164 void IndexedDBDatabase::RemoveIndex(int64 object_store_id, int64 index_id) {
    165   DCHECK(metadata_.object_stores.find(object_store_id) !=
    166          metadata_.object_stores.end());
    167   IndexedDBObjectStoreMetadata object_store =
    168       metadata_.object_stores[object_store_id];
    169 
    170   DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end());
    171   object_store.indexes.erase(index_id);
    172   metadata_.object_stores[object_store_id] = object_store;
    173 }
    174 
    175 leveldb::Status IndexedDBDatabase::OpenInternal() {
    176   bool success = false;
    177   leveldb::Status s = backing_store_->GetIDBDatabaseMetaData(
    178       metadata_.name, &metadata_, &success);
    179   DCHECK(success == (metadata_.id != kInvalidId)) << "success = " << success
    180                                                   << " id = " << metadata_.id;
    181   if (!s.ok())
    182     return s;
    183   if (success)
    184     return backing_store_->GetObjectStores(metadata_.id,
    185                                            &metadata_.object_stores);
    186 
    187   return backing_store_->CreateIDBDatabaseMetaData(
    188       metadata_.name, metadata_.version, metadata_.int_version, &metadata_.id);
    189 }
    190 
    191 IndexedDBDatabase::~IndexedDBDatabase() {
    192   DCHECK(transactions_.empty());
    193   DCHECK(pending_open_calls_.empty());
    194   DCHECK(pending_delete_calls_.empty());
    195 }
    196 
    197 scoped_ptr<IndexedDBConnection> IndexedDBDatabase::CreateConnection(
    198     scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks,
    199     int child_process_id) {
    200   scoped_ptr<IndexedDBConnection> connection(
    201       new IndexedDBConnection(this, database_callbacks));
    202   connections_.insert(connection.get());
    203   backing_store_->GrantChildProcessPermissions(child_process_id);
    204   return connection.Pass();
    205 }
    206 
    207 IndexedDBTransaction* IndexedDBDatabase::GetTransaction(
    208     int64 transaction_id) const {
    209   TransactionMap::const_iterator trans_iterator =
    210       transactions_.find(transaction_id);
    211   if (trans_iterator == transactions_.end())
    212     return NULL;
    213   return trans_iterator->second;
    214 }
    215 
    216 bool IndexedDBDatabase::ValidateObjectStoreId(int64 object_store_id) const {
    217   if (!ContainsKey(metadata_.object_stores, object_store_id)) {
    218     DLOG(ERROR) << "Invalid object_store_id";
    219     return false;
    220   }
    221   return true;
    222 }
    223 
    224 bool IndexedDBDatabase::ValidateObjectStoreIdAndIndexId(int64 object_store_id,
    225                                                         int64 index_id) const {
    226   if (!ValidateObjectStoreId(object_store_id))
    227     return false;
    228   const IndexedDBObjectStoreMetadata& object_store_metadata =
    229       metadata_.object_stores.find(object_store_id)->second;
    230   if (!ContainsKey(object_store_metadata.indexes, index_id)) {
    231     DLOG(ERROR) << "Invalid index_id";
    232     return false;
    233   }
    234   return true;
    235 }
    236 
    237 bool IndexedDBDatabase::ValidateObjectStoreIdAndOptionalIndexId(
    238     int64 object_store_id,
    239     int64 index_id) const {
    240   if (!ValidateObjectStoreId(object_store_id))
    241     return false;
    242   const IndexedDBObjectStoreMetadata& object_store_metadata =
    243       metadata_.object_stores.find(object_store_id)->second;
    244   if (index_id != IndexedDBIndexMetadata::kInvalidId &&
    245       !ContainsKey(object_store_metadata.indexes, index_id)) {
    246     DLOG(ERROR) << "Invalid index_id";
    247     return false;
    248   }
    249   return true;
    250 }
    251 
    252 bool IndexedDBDatabase::ValidateObjectStoreIdAndNewIndexId(
    253     int64 object_store_id,
    254     int64 index_id) const {
    255   if (!ValidateObjectStoreId(object_store_id))
    256     return false;
    257   const IndexedDBObjectStoreMetadata& object_store_metadata =
    258       metadata_.object_stores.find(object_store_id)->second;
    259   if (ContainsKey(object_store_metadata.indexes, index_id)) {
    260     DLOG(ERROR) << "Invalid index_id";
    261     return false;
    262   }
    263   return true;
    264 }
    265 
    266 void IndexedDBDatabase::CreateObjectStore(int64 transaction_id,
    267                                           int64 object_store_id,
    268                                           const base::string16& name,
    269                                           const IndexedDBKeyPath& key_path,
    270                                           bool auto_increment) {
    271   IDB_TRACE1("IndexedDBDatabase::CreateObjectStore", "txn.id", transaction_id);
    272   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
    273   if (!transaction)
    274     return;
    275   DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
    276 
    277   if (ContainsKey(metadata_.object_stores, object_store_id)) {
    278     DLOG(ERROR) << "Invalid object_store_id";
    279     return;
    280   }
    281 
    282   // Store creation is done synchronously, as it may be followed by
    283   // index creation (also sync) since preemptive OpenCursor/SetIndexKeys
    284   // may follow.
    285   IndexedDBObjectStoreMetadata object_store_metadata(
    286       name,
    287       object_store_id,
    288       key_path,
    289       auto_increment,
    290       IndexedDBDatabase::kMinimumIndexId);
    291 
    292   leveldb::Status s =
    293       backing_store_->CreateObjectStore(transaction->BackingStoreTransaction(),
    294                                         transaction->database()->id(),
    295                                         object_store_metadata.id,
    296                                         object_store_metadata.name,
    297                                         object_store_metadata.key_path,
    298                                         object_store_metadata.auto_increment);
    299   if (!s.ok()) {
    300     IndexedDBDatabaseError error(
    301         blink::WebIDBDatabaseExceptionUnknownError,
    302         ASCIIToUTF16("Internal error creating object store '") +
    303             object_store_metadata.name + ASCIIToUTF16("'."));
    304     transaction->Abort(error);
    305     if (leveldb_env::IsCorruption(s))
    306       factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
    307                                              error);
    308     return;
    309   }
    310 
    311   AddObjectStore(object_store_metadata, object_store_id);
    312   transaction->ScheduleAbortTask(
    313       base::Bind(&IndexedDBDatabase::CreateObjectStoreAbortOperation,
    314                  this,
    315                  object_store_id));
    316 }
    317 
    318 void IndexedDBDatabase::DeleteObjectStore(int64 transaction_id,
    319                                           int64 object_store_id) {
    320   IDB_TRACE1("IndexedDBDatabase::DeleteObjectStore", "txn.id", transaction_id);
    321   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
    322   if (!transaction)
    323     return;
    324   DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
    325 
    326   if (!ValidateObjectStoreId(object_store_id))
    327     return;
    328 
    329   transaction->ScheduleTask(
    330       base::Bind(&IndexedDBDatabase::DeleteObjectStoreOperation,
    331                  this,
    332                  object_store_id));
    333 }
    334 
    335 void IndexedDBDatabase::CreateIndex(int64 transaction_id,
    336                                     int64 object_store_id,
    337                                     int64 index_id,
    338                                     const base::string16& name,
    339                                     const IndexedDBKeyPath& key_path,
    340                                     bool unique,
    341                                     bool multi_entry) {
    342   IDB_TRACE1("IndexedDBDatabase::CreateIndex", "txn.id", transaction_id);
    343   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
    344   if (!transaction)
    345     return;
    346   DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
    347 
    348   if (!ValidateObjectStoreIdAndNewIndexId(object_store_id, index_id))
    349     return;
    350 
    351   // Index creation is done synchronously since preemptive
    352   // OpenCursor/SetIndexKeys may follow.
    353   const IndexedDBIndexMetadata index_metadata(
    354       name, index_id, key_path, unique, multi_entry);
    355 
    356   if (!backing_store_->CreateIndex(transaction->BackingStoreTransaction(),
    357                                    transaction->database()->id(),
    358                                    object_store_id,
    359                                    index_metadata.id,
    360                                    index_metadata.name,
    361                                    index_metadata.key_path,
    362                                    index_metadata.unique,
    363                                    index_metadata.multi_entry).ok()) {
    364     base::string16 error_string =
    365         ASCIIToUTF16("Internal error creating index '") +
    366         index_metadata.name + ASCIIToUTF16("'.");
    367     transaction->Abort(IndexedDBDatabaseError(
    368         blink::WebIDBDatabaseExceptionUnknownError, error_string));
    369     return;
    370   }
    371 
    372   AddIndex(object_store_id, index_metadata, index_id);
    373   transaction->ScheduleAbortTask(
    374       base::Bind(&IndexedDBDatabase::CreateIndexAbortOperation,
    375                  this,
    376                  object_store_id,
    377                  index_id));
    378 }
    379 
    380 void IndexedDBDatabase::CreateIndexAbortOperation(
    381     int64 object_store_id,
    382     int64 index_id,
    383     IndexedDBTransaction* transaction) {
    384   IDB_TRACE1("IndexedDBDatabase::CreateIndexAbortOperation",
    385              "txn.id",
    386              transaction->id());
    387   DCHECK(!transaction);
    388   RemoveIndex(object_store_id, index_id);
    389 }
    390 
    391 void IndexedDBDatabase::DeleteIndex(int64 transaction_id,
    392                                     int64 object_store_id,
    393                                     int64 index_id) {
    394   IDB_TRACE1("IndexedDBDatabase::DeleteIndex", "txn.id", transaction_id);
    395   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
    396   if (!transaction)
    397     return;
    398   DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
    399 
    400   if (!ValidateObjectStoreIdAndIndexId(object_store_id, index_id))
    401     return;
    402 
    403   transaction->ScheduleTask(
    404       base::Bind(&IndexedDBDatabase::DeleteIndexOperation,
    405                  this,
    406                  object_store_id,
    407                  index_id));
    408 }
    409 
    410 void IndexedDBDatabase::DeleteIndexOperation(
    411     int64 object_store_id,
    412     int64 index_id,
    413     IndexedDBTransaction* transaction) {
    414   IDB_TRACE1(
    415       "IndexedDBDatabase::DeleteIndexOperation", "txn.id", transaction->id());
    416 
    417   const IndexedDBIndexMetadata index_metadata =
    418       metadata_.object_stores[object_store_id].indexes[index_id];
    419 
    420   leveldb::Status s =
    421       backing_store_->DeleteIndex(transaction->BackingStoreTransaction(),
    422                                   transaction->database()->id(),
    423                                   object_store_id,
    424                                   index_id);
    425   if (!s.ok()) {
    426     base::string16 error_string =
    427         ASCIIToUTF16("Internal error deleting index '") +
    428         index_metadata.name + ASCIIToUTF16("'.");
    429     IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
    430                                  error_string);
    431     transaction->Abort(error);
    432     if (leveldb_env::IsCorruption(s))
    433       factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
    434                                              error);
    435     return;
    436   }
    437 
    438   RemoveIndex(object_store_id, index_id);
    439   transaction->ScheduleAbortTask(
    440       base::Bind(&IndexedDBDatabase::DeleteIndexAbortOperation,
    441                  this,
    442                  object_store_id,
    443                  index_metadata));
    444 }
    445 
    446 void IndexedDBDatabase::DeleteIndexAbortOperation(
    447     int64 object_store_id,
    448     const IndexedDBIndexMetadata& index_metadata,
    449     IndexedDBTransaction* transaction) {
    450   DCHECK(!transaction);
    451   IDB_TRACE1("IndexedDBDatabase::DeleteIndexAbortOperation",
    452              "txn.id",
    453              transaction->id());
    454   AddIndex(object_store_id, index_metadata, IndexedDBIndexMetadata::kInvalidId);
    455 }
    456 
    457 void IndexedDBDatabase::Commit(int64 transaction_id) {
    458   // The frontend suggests that we commit, but we may have previously initiated
    459   // an abort, and so have disposed of the transaction. on_abort has already
    460   // been dispatched to the frontend, so it will find out about that
    461   // asynchronously.
    462   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
    463   if (transaction) {
    464     scoped_refptr<IndexedDBFactory> factory = factory_;
    465     leveldb::Status s = transaction->Commit();
    466     if (s.IsCorruption()) {
    467       IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
    468                                    "Internal error committing transaction.");
    469       factory->HandleBackingStoreCorruption(identifier_.first, error);
    470     }
    471   }
    472 }
    473 
    474 void IndexedDBDatabase::Abort(int64 transaction_id) {
    475   // If the transaction is unknown, then it has already been aborted by the
    476   // backend before this call so it is safe to ignore it.
    477   IDB_TRACE1("IndexedDBDatabase::Abort", "txn.id", transaction_id);
    478   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
    479   if (transaction)
    480     transaction->Abort();
    481 }
    482 
    483 void IndexedDBDatabase::Abort(int64 transaction_id,
    484                               const IndexedDBDatabaseError& error) {
    485   IDB_TRACE1("IndexedDBDatabase::Abort(error)", "txn.id", transaction_id);
    486   // If the transaction is unknown, then it has already been aborted by the
    487   // backend before this call so it is safe to ignore it.
    488   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
    489   if (transaction)
    490     transaction->Abort(error);
    491 }
    492 
    493 void IndexedDBDatabase::Get(int64 transaction_id,
    494                             int64 object_store_id,
    495                             int64 index_id,
    496                             scoped_ptr<IndexedDBKeyRange> key_range,
    497                             bool key_only,
    498                             scoped_refptr<IndexedDBCallbacks> callbacks) {
    499   IDB_TRACE1("IndexedDBDatabase::Get", "txn.id", transaction_id);
    500   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
    501   if (!transaction)
    502     return;
    503 
    504   if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id))
    505     return;
    506 
    507   transaction->ScheduleTask(base::Bind(
    508       &IndexedDBDatabase::GetOperation,
    509       this,
    510       object_store_id,
    511       index_id,
    512       Passed(&key_range),
    513       key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE,
    514       callbacks));
    515 }
    516 
    517 void IndexedDBDatabase::GetOperation(
    518     int64 object_store_id,
    519     int64 index_id,
    520     scoped_ptr<IndexedDBKeyRange> key_range,
    521     indexed_db::CursorType cursor_type,
    522     scoped_refptr<IndexedDBCallbacks> callbacks,
    523     IndexedDBTransaction* transaction) {
    524   IDB_TRACE1("IndexedDBDatabase::GetOperation", "txn.id", transaction->id());
    525 
    526   DCHECK(metadata_.object_stores.find(object_store_id) !=
    527          metadata_.object_stores.end());
    528   const IndexedDBObjectStoreMetadata& object_store_metadata =
    529       metadata_.object_stores[object_store_id];
    530 
    531   const IndexedDBKey* key;
    532 
    533   leveldb::Status s;
    534   scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
    535   if (key_range->IsOnlyKey()) {
    536     key = &key_range->lower();
    537   } else {
    538     if (index_id == IndexedDBIndexMetadata::kInvalidId) {
    539       DCHECK_NE(cursor_type, indexed_db::CURSOR_KEY_ONLY);
    540       // ObjectStore Retrieval Operation
    541       backing_store_cursor = backing_store_->OpenObjectStoreCursor(
    542           transaction->BackingStoreTransaction(),
    543           id(),
    544           object_store_id,
    545           *key_range,
    546           blink::WebIDBCursorDirectionNext,
    547           &s);
    548     } else if (cursor_type == indexed_db::CURSOR_KEY_ONLY) {
    549       // Index Value Retrieval Operation
    550       backing_store_cursor = backing_store_->OpenIndexKeyCursor(
    551           transaction->BackingStoreTransaction(),
    552           id(),
    553           object_store_id,
    554           index_id,
    555           *key_range,
    556           blink::WebIDBCursorDirectionNext,
    557           &s);
    558     } else {
    559       // Index Referenced Value Retrieval Operation
    560       backing_store_cursor = backing_store_->OpenIndexCursor(
    561           transaction->BackingStoreTransaction(),
    562           id(),
    563           object_store_id,
    564           index_id,
    565           *key_range,
    566           blink::WebIDBCursorDirectionNext,
    567           &s);
    568     }
    569 
    570     if (!s.ok()) {
    571       DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString();
    572       IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
    573                                    "Internal error deleting data in range");
    574       if (leveldb_env::IsCorruption(s)) {
    575         factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
    576                                                error);
    577       }
    578     }
    579 
    580     if (!backing_store_cursor) {
    581       callbacks->OnSuccess();
    582       return;
    583     }
    584 
    585     key = &backing_store_cursor->key();
    586   }
    587 
    588   scoped_ptr<IndexedDBKey> primary_key;
    589   if (index_id == IndexedDBIndexMetadata::kInvalidId) {
    590     // Object Store Retrieval Operation
    591     IndexedDBValue value;
    592     s = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
    593                                   id(),
    594                                   object_store_id,
    595                                   *key,
    596                                   &value);
    597     if (!s.ok()) {
    598       IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
    599                                    "Internal error in GetRecord.");
    600       callbacks->OnError(error);
    601 
    602       if (leveldb_env::IsCorruption(s))
    603         factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
    604                                                error);
    605       return;
    606     }
    607 
    608     if (value.empty()) {
    609       callbacks->OnSuccess();
    610       return;
    611     }
    612 
    613     if (object_store_metadata.auto_increment &&
    614         !object_store_metadata.key_path.IsNull()) {
    615       callbacks->OnSuccess(&value, *key, object_store_metadata.key_path);
    616       return;
    617     }
    618 
    619     callbacks->OnSuccess(&value);
    620     return;
    621   }
    622 
    623   // From here we are dealing only with indexes.
    624   s = backing_store_->GetPrimaryKeyViaIndex(
    625       transaction->BackingStoreTransaction(),
    626       id(),
    627       object_store_id,
    628       index_id,
    629       *key,
    630       &primary_key);
    631   if (!s.ok()) {
    632     IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
    633                                  "Internal error in GetPrimaryKeyViaIndex.");
    634     callbacks->OnError(error);
    635     if (leveldb_env::IsCorruption(s))
    636       factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
    637                                              error);
    638     return;
    639   }
    640   if (!primary_key) {
    641     callbacks->OnSuccess();
    642     return;
    643   }
    644   if (cursor_type == indexed_db::CURSOR_KEY_ONLY) {
    645     // Index Value Retrieval Operation
    646     callbacks->OnSuccess(*primary_key);
    647     return;
    648   }
    649 
    650   // Index Referenced Value Retrieval Operation
    651   IndexedDBValue value;
    652   s = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
    653                                 id(),
    654                                 object_store_id,
    655                                 *primary_key,
    656                                 &value);
    657   if (!s.ok()) {
    658     IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
    659                                  "Internal error in GetRecord.");
    660     callbacks->OnError(error);
    661     if (leveldb_env::IsCorruption(s))
    662       factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
    663                                              error);
    664     return;
    665   }
    666 
    667   if (value.empty()) {
    668     callbacks->OnSuccess();
    669     return;
    670   }
    671   if (object_store_metadata.auto_increment &&
    672       !object_store_metadata.key_path.IsNull()) {
    673     callbacks->OnSuccess(&value, *primary_key, object_store_metadata.key_path);
    674     return;
    675   }
    676   callbacks->OnSuccess(&value);
    677 }
    678 
    679 static scoped_ptr<IndexedDBKey> GenerateKey(
    680     IndexedDBBackingStore* backing_store,
    681     IndexedDBTransaction* transaction,
    682     int64 database_id,
    683     int64 object_store_id) {
    684   const int64 max_generator_value =
    685       9007199254740992LL;  // Maximum integer storable as ECMAScript number.
    686   int64 current_number;
    687   leveldb::Status s = backing_store->GetKeyGeneratorCurrentNumber(
    688       transaction->BackingStoreTransaction(),
    689       database_id,
    690       object_store_id,
    691       &current_number);
    692   if (!s.ok()) {
    693     LOG(ERROR) << "Failed to GetKeyGeneratorCurrentNumber";
    694     return make_scoped_ptr(new IndexedDBKey());
    695   }
    696   if (current_number < 0 || current_number > max_generator_value)
    697     return make_scoped_ptr(new IndexedDBKey());
    698 
    699   return make_scoped_ptr(new IndexedDBKey(current_number, WebIDBKeyTypeNumber));
    700 }
    701 
    702 static leveldb::Status UpdateKeyGenerator(IndexedDBBackingStore* backing_store,
    703                                           IndexedDBTransaction* transaction,
    704                                           int64 database_id,
    705                                           int64 object_store_id,
    706                                           const IndexedDBKey& key,
    707                                           bool check_current) {
    708   DCHECK_EQ(WebIDBKeyTypeNumber, key.type());
    709   return backing_store->MaybeUpdateKeyGeneratorCurrentNumber(
    710       transaction->BackingStoreTransaction(),
    711       database_id,
    712       object_store_id,
    713       static_cast<int64>(floor(key.number())) + 1,
    714       check_current);
    715 }
    716 
    717 struct IndexedDBDatabase::PutOperationParams {
    718   PutOperationParams() {}
    719   int64 object_store_id;
    720   IndexedDBValue value;
    721   ScopedVector<storage::BlobDataHandle> handles;
    722   scoped_ptr<IndexedDBKey> key;
    723   blink::WebIDBPutMode put_mode;
    724   scoped_refptr<IndexedDBCallbacks> callbacks;
    725   std::vector<IndexKeys> index_keys;
    726 
    727  private:
    728   DISALLOW_COPY_AND_ASSIGN(PutOperationParams);
    729 };
    730 
    731 void IndexedDBDatabase::Put(int64 transaction_id,
    732                             int64 object_store_id,
    733                             IndexedDBValue* value,
    734                             ScopedVector<storage::BlobDataHandle>* handles,
    735                             scoped_ptr<IndexedDBKey> key,
    736                             blink::WebIDBPutMode put_mode,
    737                             scoped_refptr<IndexedDBCallbacks> callbacks,
    738                             const std::vector<IndexKeys>& index_keys) {
    739   IDB_TRACE1("IndexedDBDatabase::Put", "txn.id", transaction_id);
    740   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
    741   if (!transaction)
    742     return;
    743   DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
    744 
    745   if (!ValidateObjectStoreId(object_store_id))
    746     return;
    747 
    748   DCHECK(key);
    749   DCHECK(value);
    750   scoped_ptr<PutOperationParams> params(new PutOperationParams());
    751   params->object_store_id = object_store_id;
    752   params->value.swap(*value);
    753   params->handles.swap(*handles);
    754   params->key = key.Pass();
    755   params->put_mode = put_mode;
    756   params->callbacks = callbacks;
    757   params->index_keys = index_keys;
    758   transaction->ScheduleTask(base::Bind(
    759       &IndexedDBDatabase::PutOperation, this, base::Passed(&params)));
    760 }
    761 
    762 void IndexedDBDatabase::PutOperation(scoped_ptr<PutOperationParams> params,
    763                                      IndexedDBTransaction* transaction) {
    764   IDB_TRACE1("IndexedDBDatabase::PutOperation", "txn.id", transaction->id());
    765   DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
    766   bool key_was_generated = false;
    767 
    768   DCHECK(metadata_.object_stores.find(params->object_store_id) !=
    769          metadata_.object_stores.end());
    770   const IndexedDBObjectStoreMetadata& object_store =
    771       metadata_.object_stores[params->object_store_id];
    772   DCHECK(object_store.auto_increment || params->key->IsValid());
    773 
    774   scoped_ptr<IndexedDBKey> key;
    775   if (params->put_mode != blink::WebIDBPutModeCursorUpdate &&
    776       object_store.auto_increment && !params->key->IsValid()) {
    777     scoped_ptr<IndexedDBKey> auto_inc_key = GenerateKey(
    778         backing_store_.get(), transaction, id(), params->object_store_id);
    779     key_was_generated = true;
    780     if (!auto_inc_key->IsValid()) {
    781       params->callbacks->OnError(
    782           IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionConstraintError,
    783                                  "Maximum key generator value reached."));
    784       return;
    785     }
    786     key = auto_inc_key.Pass();
    787   } else {
    788     key = params->key.Pass();
    789   }
    790 
    791   DCHECK(key->IsValid());
    792 
    793   IndexedDBBackingStore::RecordIdentifier record_identifier;
    794   if (params->put_mode == blink::WebIDBPutModeAddOnly) {
    795     bool found = false;
    796     leveldb::Status s = backing_store_->KeyExistsInObjectStore(
    797         transaction->BackingStoreTransaction(),
    798         id(),
    799         params->object_store_id,
    800         *key,
    801         &record_identifier,
    802         &found);
    803     if (!s.ok()) {
    804       IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
    805                                    "Internal error checking key existence.");
    806       params->callbacks->OnError(error);
    807       if (leveldb_env::IsCorruption(s))
    808         factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
    809                                                error);
    810       return;
    811     }
    812     if (found) {
    813       params->callbacks->OnError(
    814           IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionConstraintError,
    815                                  "Key already exists in the object store."));
    816       return;
    817     }
    818   }
    819 
    820   ScopedVector<IndexWriter> index_writers;
    821   base::string16 error_message;
    822   bool obeys_constraints = false;
    823   bool backing_store_success = MakeIndexWriters(transaction,
    824                                                 backing_store_.get(),
    825                                                 id(),
    826                                                 object_store,
    827                                                 *key,
    828                                                 key_was_generated,
    829                                                 params->index_keys,
    830                                                 &index_writers,
    831                                                 &error_message,
    832                                                 &obeys_constraints);
    833   if (!backing_store_success) {
    834     params->callbacks->OnError(IndexedDBDatabaseError(
    835         blink::WebIDBDatabaseExceptionUnknownError,
    836         "Internal error: backing store error updating index keys."));
    837     return;
    838   }
    839   if (!obeys_constraints) {
    840     params->callbacks->OnError(IndexedDBDatabaseError(
    841         blink::WebIDBDatabaseExceptionConstraintError, error_message));
    842     return;
    843   }
    844 
    845   // Before this point, don't do any mutation. After this point, rollback the
    846   // transaction in case of error.
    847   leveldb::Status s =
    848       backing_store_->PutRecord(transaction->BackingStoreTransaction(),
    849                                 id(),
    850                                 params->object_store_id,
    851                                 *key,
    852                                 &params->value,
    853                                 &params->handles,
    854                                 &record_identifier);
    855   if (!s.ok()) {
    856     IndexedDBDatabaseError error(
    857         blink::WebIDBDatabaseExceptionUnknownError,
    858         "Internal error: backing store error performing put/add.");
    859     params->callbacks->OnError(error);
    860     if (leveldb_env::IsCorruption(s))
    861       factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
    862                                              error);
    863     return;
    864   }
    865 
    866   for (size_t i = 0; i < index_writers.size(); ++i) {
    867     IndexWriter* index_writer = index_writers[i];
    868     index_writer->WriteIndexKeys(record_identifier,
    869                                  backing_store_.get(),
    870                                  transaction->BackingStoreTransaction(),
    871                                  id(),
    872                                  params->object_store_id);
    873   }
    874 
    875   if (object_store.auto_increment &&
    876       params->put_mode != blink::WebIDBPutModeCursorUpdate &&
    877       key->type() == WebIDBKeyTypeNumber) {
    878     leveldb::Status s = UpdateKeyGenerator(backing_store_.get(),
    879                                            transaction,
    880                                            id(),
    881                                            params->object_store_id,
    882                                            *key,
    883                                            !key_was_generated);
    884     if (!s.ok()) {
    885       IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
    886                                    "Internal error updating key generator.");
    887       params->callbacks->OnError(error);
    888       if (leveldb_env::IsCorruption(s))
    889         factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
    890                                                error);
    891       return;
    892     }
    893   }
    894 
    895   params->callbacks->OnSuccess(*key);
    896 }
    897 
    898 void IndexedDBDatabase::SetIndexKeys(int64 transaction_id,
    899                                      int64 object_store_id,
    900                                      scoped_ptr<IndexedDBKey> primary_key,
    901                                      const std::vector<IndexKeys>& index_keys) {
    902   IDB_TRACE1("IndexedDBDatabase::SetIndexKeys", "txn.id", transaction_id);
    903   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
    904   if (!transaction)
    905     return;
    906   DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
    907 
    908   // TODO(alecflett): This method could be asynchronous, but we need to
    909   // evaluate if it's worth the extra complexity.
    910   IndexedDBBackingStore::RecordIdentifier record_identifier;
    911   bool found = false;
    912   leveldb::Status s = backing_store_->KeyExistsInObjectStore(
    913       transaction->BackingStoreTransaction(),
    914       metadata_.id,
    915       object_store_id,
    916       *primary_key,
    917       &record_identifier,
    918       &found);
    919   if (!s.ok()) {
    920     IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
    921                                  "Internal error setting index keys.");
    922     transaction->Abort(error);
    923     if (leveldb_env::IsCorruption(s))
    924       factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
    925                                              error);
    926     return;
    927   }
    928   if (!found) {
    929     transaction->Abort(IndexedDBDatabaseError(
    930         blink::WebIDBDatabaseExceptionUnknownError,
    931         "Internal error setting index keys for object store."));
    932     return;
    933   }
    934 
    935   ScopedVector<IndexWriter> index_writers;
    936   base::string16 error_message;
    937   bool obeys_constraints = false;
    938   DCHECK(metadata_.object_stores.find(object_store_id) !=
    939          metadata_.object_stores.end());
    940   const IndexedDBObjectStoreMetadata& object_store_metadata =
    941       metadata_.object_stores[object_store_id];
    942   bool backing_store_success = MakeIndexWriters(transaction,
    943                                                 backing_store_.get(),
    944                                                 id(),
    945                                                 object_store_metadata,
    946                                                 *primary_key,
    947                                                 false,
    948                                                 index_keys,
    949                                                 &index_writers,
    950                                                 &error_message,
    951                                                 &obeys_constraints);
    952   if (!backing_store_success) {
    953     transaction->Abort(IndexedDBDatabaseError(
    954         blink::WebIDBDatabaseExceptionUnknownError,
    955         "Internal error: backing store error updating index keys."));
    956     return;
    957   }
    958   if (!obeys_constraints) {
    959     transaction->Abort(IndexedDBDatabaseError(
    960         blink::WebIDBDatabaseExceptionConstraintError, error_message));
    961     return;
    962   }
    963 
    964   for (size_t i = 0; i < index_writers.size(); ++i) {
    965     IndexWriter* index_writer = index_writers[i];
    966     index_writer->WriteIndexKeys(record_identifier,
    967                                  backing_store_.get(),
    968                                  transaction->BackingStoreTransaction(),
    969                                  id(),
    970                                  object_store_id);
    971   }
    972 }
    973 
    974 void IndexedDBDatabase::SetIndexesReady(int64 transaction_id,
    975                                         int64,
    976                                         const std::vector<int64>& index_ids) {
    977   IDB_TRACE1("IndexedDBDatabase::SetIndexesReady", "txn.id", transaction_id);
    978   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
    979   if (!transaction)
    980     return;
    981   DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
    982 
    983   transaction->ScheduleTask(
    984       blink::WebIDBTaskTypePreemptive,
    985       base::Bind(&IndexedDBDatabase::SetIndexesReadyOperation,
    986                  this,
    987                  index_ids.size()));
    988 }
    989 
    990 void IndexedDBDatabase::SetIndexesReadyOperation(
    991     size_t index_count,
    992     IndexedDBTransaction* transaction) {
    993   IDB_TRACE1("IndexedDBDatabase::SetIndexesReadyOperation",
    994              "txn.id",
    995              transaction->id());
    996   for (size_t i = 0; i < index_count; ++i)
    997     transaction->DidCompletePreemptiveEvent();
    998 }
    999 
   1000 struct IndexedDBDatabase::OpenCursorOperationParams {
   1001   OpenCursorOperationParams() {}
   1002   int64 object_store_id;
   1003   int64 index_id;
   1004   scoped_ptr<IndexedDBKeyRange> key_range;
   1005   blink::WebIDBCursorDirection direction;
   1006   indexed_db::CursorType cursor_type;
   1007   blink::WebIDBTaskType task_type;
   1008   scoped_refptr<IndexedDBCallbacks> callbacks;
   1009 
   1010  private:
   1011   DISALLOW_COPY_AND_ASSIGN(OpenCursorOperationParams);
   1012 };
   1013 
   1014 void IndexedDBDatabase::OpenCursor(
   1015     int64 transaction_id,
   1016     int64 object_store_id,
   1017     int64 index_id,
   1018     scoped_ptr<IndexedDBKeyRange> key_range,
   1019     blink::WebIDBCursorDirection direction,
   1020     bool key_only,
   1021     blink::WebIDBTaskType task_type,
   1022     scoped_refptr<IndexedDBCallbacks> callbacks) {
   1023   IDB_TRACE1("IndexedDBDatabase::OpenCursor", "txn.id", transaction_id);
   1024   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
   1025   if (!transaction)
   1026     return;
   1027 
   1028   if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id))
   1029     return;
   1030 
   1031   scoped_ptr<OpenCursorOperationParams> params(new OpenCursorOperationParams());
   1032   params->object_store_id = object_store_id;
   1033   params->index_id = index_id;
   1034   params->key_range = key_range.Pass();
   1035   params->direction = direction;
   1036   params->cursor_type =
   1037       key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE;
   1038   params->task_type = task_type;
   1039   params->callbacks = callbacks;
   1040   transaction->ScheduleTask(base::Bind(
   1041       &IndexedDBDatabase::OpenCursorOperation, this, base::Passed(&params)));
   1042 }
   1043 
   1044 void IndexedDBDatabase::OpenCursorOperation(
   1045     scoped_ptr<OpenCursorOperationParams> params,
   1046     IndexedDBTransaction* transaction) {
   1047   IDB_TRACE1(
   1048       "IndexedDBDatabase::OpenCursorOperation", "txn.id", transaction->id());
   1049 
   1050   // The frontend has begun indexing, so this pauses the transaction
   1051   // until the indexing is complete. This can't happen any earlier
   1052   // because we don't want to switch to early mode in case multiple
   1053   // indexes are being created in a row, with Put()'s in between.
   1054   if (params->task_type == blink::WebIDBTaskTypePreemptive)
   1055     transaction->AddPreemptiveEvent();
   1056 
   1057   leveldb::Status s;
   1058   scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
   1059   if (params->index_id == IndexedDBIndexMetadata::kInvalidId) {
   1060     if (params->cursor_type == indexed_db::CURSOR_KEY_ONLY) {
   1061       DCHECK_EQ(params->task_type, blink::WebIDBTaskTypeNormal);
   1062       backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor(
   1063           transaction->BackingStoreTransaction(),
   1064           id(),
   1065           params->object_store_id,
   1066           *params->key_range,
   1067           params->direction,
   1068           &s);
   1069     } else {
   1070       backing_store_cursor = backing_store_->OpenObjectStoreCursor(
   1071           transaction->BackingStoreTransaction(),
   1072           id(),
   1073           params->object_store_id,
   1074           *params->key_range,
   1075           params->direction,
   1076           &s);
   1077     }
   1078   } else {
   1079     DCHECK_EQ(params->task_type, blink::WebIDBTaskTypeNormal);
   1080     if (params->cursor_type == indexed_db::CURSOR_KEY_ONLY) {
   1081       backing_store_cursor = backing_store_->OpenIndexKeyCursor(
   1082           transaction->BackingStoreTransaction(),
   1083           id(),
   1084           params->object_store_id,
   1085           params->index_id,
   1086           *params->key_range,
   1087           params->direction,
   1088           &s);
   1089     } else {
   1090       backing_store_cursor = backing_store_->OpenIndexCursor(
   1091           transaction->BackingStoreTransaction(),
   1092           id(),
   1093           params->object_store_id,
   1094           params->index_id,
   1095           *params->key_range,
   1096           params->direction,
   1097           &s);
   1098     }
   1099   }
   1100 
   1101   if (!s.ok()) {
   1102     DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString();
   1103     IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
   1104                                  "Internal error opening cursor operation");
   1105     if (leveldb_env::IsCorruption(s)) {
   1106       factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
   1107                                              error);
   1108     }
   1109   }
   1110 
   1111   if (!backing_store_cursor) {
   1112     // Why is Success being called?
   1113     params->callbacks->OnSuccess(static_cast<IndexedDBValue*>(NULL));
   1114     return;
   1115   }
   1116 
   1117   scoped_refptr<IndexedDBCursor> cursor =
   1118       new IndexedDBCursor(backing_store_cursor.Pass(),
   1119                           params->cursor_type,
   1120                           params->task_type,
   1121                           transaction);
   1122   params->callbacks->OnSuccess(
   1123       cursor, cursor->key(), cursor->primary_key(), cursor->Value());
   1124 }
   1125 
   1126 void IndexedDBDatabase::Count(int64 transaction_id,
   1127                               int64 object_store_id,
   1128                               int64 index_id,
   1129                               scoped_ptr<IndexedDBKeyRange> key_range,
   1130                               scoped_refptr<IndexedDBCallbacks> callbacks) {
   1131   IDB_TRACE1("IndexedDBDatabase::Count", "txn.id", transaction_id);
   1132   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
   1133   if (!transaction)
   1134     return;
   1135 
   1136   if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id))
   1137     return;
   1138 
   1139   transaction->ScheduleTask(base::Bind(&IndexedDBDatabase::CountOperation,
   1140                                        this,
   1141                                        object_store_id,
   1142                                        index_id,
   1143                                        base::Passed(&key_range),
   1144                                        callbacks));
   1145 }
   1146 
   1147 void IndexedDBDatabase::CountOperation(
   1148     int64 object_store_id,
   1149     int64 index_id,
   1150     scoped_ptr<IndexedDBKeyRange> key_range,
   1151     scoped_refptr<IndexedDBCallbacks> callbacks,
   1152     IndexedDBTransaction* transaction) {
   1153   IDB_TRACE1("IndexedDBDatabase::CountOperation", "txn.id", transaction->id());
   1154   uint32 count = 0;
   1155   scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
   1156 
   1157   leveldb::Status s;
   1158   if (index_id == IndexedDBIndexMetadata::kInvalidId) {
   1159     backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor(
   1160         transaction->BackingStoreTransaction(),
   1161         id(),
   1162         object_store_id,
   1163         *key_range,
   1164         blink::WebIDBCursorDirectionNext,
   1165         &s);
   1166   } else {
   1167     backing_store_cursor = backing_store_->OpenIndexKeyCursor(
   1168         transaction->BackingStoreTransaction(),
   1169         id(),
   1170         object_store_id,
   1171         index_id,
   1172         *key_range,
   1173         blink::WebIDBCursorDirectionNext,
   1174         &s);
   1175   }
   1176   if (!s.ok()) {
   1177     DLOG(ERROR) << "Unable perform count operation: " << s.ToString();
   1178     IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
   1179                                  "Internal error performing count operation");
   1180     if (leveldb_env::IsCorruption(s)) {
   1181       factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
   1182                                              error);
   1183     }
   1184   }
   1185   if (!backing_store_cursor) {
   1186     callbacks->OnSuccess(count);
   1187     return;
   1188   }
   1189 
   1190   do {
   1191     ++count;
   1192   } while (backing_store_cursor->Continue(&s));
   1193 
   1194   // TODO(cmumford): Check for database corruption.
   1195 
   1196   callbacks->OnSuccess(count);
   1197 }
   1198 
   1199 void IndexedDBDatabase::DeleteRange(
   1200     int64 transaction_id,
   1201     int64 object_store_id,
   1202     scoped_ptr<IndexedDBKeyRange> key_range,
   1203     scoped_refptr<IndexedDBCallbacks> callbacks) {
   1204   IDB_TRACE1("IndexedDBDatabase::DeleteRange", "txn.id", transaction_id);
   1205   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
   1206   if (!transaction)
   1207     return;
   1208   DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
   1209 
   1210   if (!ValidateObjectStoreId(object_store_id))
   1211     return;
   1212 
   1213   transaction->ScheduleTask(base::Bind(&IndexedDBDatabase::DeleteRangeOperation,
   1214                                        this,
   1215                                        object_store_id,
   1216                                        base::Passed(&key_range),
   1217                                        callbacks));
   1218 }
   1219 
   1220 void IndexedDBDatabase::DeleteRangeOperation(
   1221     int64 object_store_id,
   1222     scoped_ptr<IndexedDBKeyRange> key_range,
   1223     scoped_refptr<IndexedDBCallbacks> callbacks,
   1224     IndexedDBTransaction* transaction) {
   1225   IDB_TRACE1(
   1226       "IndexedDBDatabase::DeleteRangeOperation", "txn.id", transaction->id());
   1227   leveldb::Status s =
   1228       backing_store_->DeleteRange(transaction->BackingStoreTransaction(),
   1229                                   id(),
   1230                                   object_store_id,
   1231                                   *key_range);
   1232   if (!s.ok()) {
   1233     base::string16 error_string =
   1234         ASCIIToUTF16("Internal error deleting data in range");
   1235     IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
   1236                                  error_string);
   1237     transaction->Abort(error);
   1238     if (leveldb_env::IsCorruption(s)) {
   1239       factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
   1240                                              error);
   1241     }
   1242     return;
   1243   }
   1244   callbacks->OnSuccess();
   1245 }
   1246 
   1247 void IndexedDBDatabase::Clear(int64 transaction_id,
   1248                               int64 object_store_id,
   1249                               scoped_refptr<IndexedDBCallbacks> callbacks) {
   1250   IDB_TRACE1("IndexedDBDatabase::Clear", "txn.id", transaction_id);
   1251   IndexedDBTransaction* transaction = GetTransaction(transaction_id);
   1252   if (!transaction)
   1253     return;
   1254   DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
   1255 
   1256   if (!ValidateObjectStoreId(object_store_id))
   1257     return;
   1258 
   1259   transaction->ScheduleTask(base::Bind(
   1260       &IndexedDBDatabase::ClearOperation, this, object_store_id, callbacks));
   1261 }
   1262 
   1263 void IndexedDBDatabase::ClearOperation(
   1264     int64 object_store_id,
   1265     scoped_refptr<IndexedDBCallbacks> callbacks,
   1266     IndexedDBTransaction* transaction) {
   1267   IDB_TRACE1("IndexedDBDatabase::ClearOperation", "txn.id", transaction->id());
   1268   leveldb::Status s = backing_store_->ClearObjectStore(
   1269       transaction->BackingStoreTransaction(), id(), object_store_id);
   1270   if (!s.ok()) {
   1271     IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
   1272                                  "Internal error clearing object store");
   1273     callbacks->OnError(error);
   1274     if (leveldb_env::IsCorruption(s)) {
   1275       factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
   1276                                              error);
   1277     }
   1278     return;
   1279   }
   1280   callbacks->OnSuccess();
   1281 }
   1282 
   1283 void IndexedDBDatabase::DeleteObjectStoreOperation(
   1284     int64 object_store_id,
   1285     IndexedDBTransaction* transaction) {
   1286   IDB_TRACE1("IndexedDBDatabase::DeleteObjectStoreOperation",
   1287              "txn.id",
   1288              transaction->id());
   1289 
   1290   const IndexedDBObjectStoreMetadata object_store_metadata =
   1291       metadata_.object_stores[object_store_id];
   1292   leveldb::Status s =
   1293       backing_store_->DeleteObjectStore(transaction->BackingStoreTransaction(),
   1294                                         transaction->database()->id(),
   1295                                         object_store_id);
   1296   if (!s.ok()) {
   1297     base::string16 error_string =
   1298         ASCIIToUTF16("Internal error deleting object store '") +
   1299         object_store_metadata.name + ASCIIToUTF16("'.");
   1300     IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
   1301                                  error_string);
   1302     transaction->Abort(error);
   1303     if (leveldb_env::IsCorruption(s))
   1304       factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
   1305                                              error);
   1306     return;
   1307   }
   1308 
   1309   RemoveObjectStore(object_store_id);
   1310   transaction->ScheduleAbortTask(
   1311       base::Bind(&IndexedDBDatabase::DeleteObjectStoreAbortOperation,
   1312                  this,
   1313                  object_store_metadata));
   1314 }
   1315 
   1316 void IndexedDBDatabase::VersionChangeOperation(
   1317     int64 version,
   1318     scoped_refptr<IndexedDBCallbacks> callbacks,
   1319     scoped_ptr<IndexedDBConnection> connection,
   1320     IndexedDBTransaction* transaction) {
   1321   IDB_TRACE1(
   1322       "IndexedDBDatabase::VersionChangeOperation", "txn.id", transaction->id());
   1323   int64 old_version = metadata_.int_version;
   1324   DCHECK_GT(version, old_version);
   1325 
   1326   if (!backing_store_->UpdateIDBDatabaseIntVersion(
   1327           transaction->BackingStoreTransaction(), id(), version)) {
   1328     IndexedDBDatabaseError error(
   1329         blink::WebIDBDatabaseExceptionUnknownError,
   1330         ASCIIToUTF16(
   1331             "Internal error writing data to stable storage when "
   1332             "updating version."));
   1333     callbacks->OnError(error);
   1334     transaction->Abort(error);
   1335     return;
   1336   }
   1337 
   1338   transaction->ScheduleAbortTask(
   1339       base::Bind(&IndexedDBDatabase::VersionChangeAbortOperation,
   1340                  this,
   1341                  metadata_.version,
   1342                  metadata_.int_version));
   1343   metadata_.int_version = version;
   1344   metadata_.version = kNoStringVersion;
   1345 
   1346   DCHECK(!pending_second_half_open_);
   1347   pending_second_half_open_.reset(
   1348       new PendingSuccessCall(callbacks, connection.get(), version));
   1349   callbacks->OnUpgradeNeeded(old_version, connection.Pass(), metadata());
   1350 }
   1351 
   1352 void IndexedDBDatabase::TransactionFinished(IndexedDBTransaction* transaction,
   1353                                             bool committed) {
   1354   DCHECK(transactions_.find(transaction->id()) != transactions_.end());
   1355   DCHECK_EQ(transactions_[transaction->id()], transaction);
   1356   transactions_.erase(transaction->id());
   1357 
   1358   if (transaction->mode() == blink::WebIDBTransactionModeVersionChange) {
   1359     if (pending_second_half_open_) {
   1360       if (committed) {
   1361         DCHECK_EQ(pending_second_half_open_->version(), metadata_.int_version);
   1362         DCHECK(metadata_.id != kInvalidId);
   1363 
   1364         // Connection was already minted for OnUpgradeNeeded callback.
   1365         scoped_ptr<IndexedDBConnection> connection;
   1366         pending_second_half_open_->callbacks()->OnSuccess(connection.Pass(),
   1367                                                           this->metadata());
   1368       } else {
   1369         pending_second_half_open_->callbacks()->OnError(
   1370             IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError,
   1371                                    "Version change transaction was aborted in "
   1372                                    "upgradeneeded event handler."));
   1373       }
   1374       pending_second_half_open_.reset();
   1375     }
   1376 
   1377     // Connection queue is now unblocked.
   1378     ProcessPendingCalls();
   1379   }
   1380 }
   1381 
   1382 void IndexedDBDatabase::TransactionCommitFailed(const leveldb::Status& status) {
   1383   if (status.IsCorruption()) {
   1384     IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
   1385                                  "Error committing transaction");
   1386     factory_->HandleBackingStoreCorruption(backing_store_->origin_url(), error);
   1387   } else {
   1388     factory_->HandleBackingStoreFailure(backing_store_->origin_url());
   1389   }
   1390 }
   1391 
   1392 size_t IndexedDBDatabase::ConnectionCount() const {
   1393   // This does not include pending open calls, as those should not block version
   1394   // changes and deletes.
   1395   return connections_.size();
   1396 }
   1397 
   1398 size_t IndexedDBDatabase::PendingOpenCount() const {
   1399   return pending_open_calls_.size();
   1400 }
   1401 
   1402 size_t IndexedDBDatabase::PendingUpgradeCount() const {
   1403   return pending_run_version_change_transaction_call_ ? 1 : 0;
   1404 }
   1405 
   1406 size_t IndexedDBDatabase::RunningUpgradeCount() const {
   1407   return pending_second_half_open_ ? 1 : 0;
   1408 }
   1409 
   1410 size_t IndexedDBDatabase::PendingDeleteCount() const {
   1411   return pending_delete_calls_.size();
   1412 }
   1413 
   1414 void IndexedDBDatabase::ProcessPendingCalls() {
   1415   if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) {
   1416     DCHECK(pending_run_version_change_transaction_call_->version() >
   1417            metadata_.int_version);
   1418     scoped_ptr<PendingUpgradeCall> pending_call =
   1419         pending_run_version_change_transaction_call_.Pass();
   1420     RunVersionChangeTransactionFinal(pending_call->callbacks(),
   1421                                      pending_call->ReleaseConnection(),
   1422                                      pending_call->transaction_id(),
   1423                                      pending_call->version());
   1424     DCHECK_EQ(1u, ConnectionCount());
   1425     // Fall through would be a no-op, since transaction must complete
   1426     // asynchronously.
   1427     DCHECK(IsDeleteDatabaseBlocked());
   1428     DCHECK(IsOpenConnectionBlocked());
   1429     return;
   1430   }
   1431 
   1432   if (!IsDeleteDatabaseBlocked()) {
   1433     PendingDeleteCallList pending_delete_calls;
   1434     pending_delete_calls_.swap(pending_delete_calls);
   1435     while (!pending_delete_calls.empty()) {
   1436       // Only the first delete call will delete the database, but each must fire
   1437       // callbacks.
   1438       scoped_ptr<PendingDeleteCall> pending_delete_call(
   1439           pending_delete_calls.front());
   1440       pending_delete_calls.pop_front();
   1441       DeleteDatabaseFinal(pending_delete_call->callbacks());
   1442     }
   1443     // delete_database_final should never re-queue calls.
   1444     DCHECK(pending_delete_calls_.empty());
   1445     // Fall through when complete, as pending opens may be unblocked.
   1446   }
   1447 
   1448   if (!IsOpenConnectionBlocked()) {
   1449     PendingOpenCallList pending_open_calls;
   1450     pending_open_calls_.swap(pending_open_calls);
   1451     while (!pending_open_calls.empty()) {
   1452       OpenConnection(pending_open_calls.front());
   1453       pending_open_calls.pop_front();
   1454     }
   1455   }
   1456 }
   1457 
   1458 void IndexedDBDatabase::CreateTransaction(
   1459     int64 transaction_id,
   1460     IndexedDBConnection* connection,
   1461     const std::vector<int64>& object_store_ids,
   1462     blink::WebIDBTransactionMode mode) {
   1463   IDB_TRACE1("IndexedDBDatabase::CreateTransaction", "txn.id", transaction_id);
   1464   DCHECK(connections_.count(connection));
   1465   DCHECK(transactions_.find(transaction_id) == transactions_.end());
   1466   if (transactions_.find(transaction_id) != transactions_.end())
   1467     return;
   1468 
   1469   // The transaction will add itself to this database's coordinator, which
   1470   // manages the lifetime of the object.
   1471   TransactionCreated(new IndexedDBTransaction(
   1472       transaction_id,
   1473       connection->callbacks(),
   1474       std::set<int64>(object_store_ids.begin(), object_store_ids.end()),
   1475       mode,
   1476       this,
   1477       new IndexedDBBackingStore::Transaction(backing_store_.get())));
   1478 }
   1479 
   1480 void IndexedDBDatabase::TransactionCreated(IndexedDBTransaction* transaction) {
   1481   transactions_[transaction->id()] = transaction;
   1482 }
   1483 
   1484 bool IndexedDBDatabase::IsOpenConnectionBlocked() const {
   1485   return !pending_delete_calls_.empty() ||
   1486          transaction_coordinator_.IsRunningVersionChangeTransaction() ||
   1487          pending_run_version_change_transaction_call_;
   1488 }
   1489 
   1490 void IndexedDBDatabase::OpenConnection(
   1491     const IndexedDBPendingConnection& connection) {
   1492   DCHECK(backing_store_.get());
   1493 
   1494   // TODO(jsbell): Should have a priority queue so that higher version
   1495   // requests are processed first. http://crbug.com/225850
   1496   if (IsOpenConnectionBlocked()) {
   1497     // The backing store only detects data loss when it is first opened. The
   1498     // presence of existing connections means we didn't even check for data loss
   1499     // so there'd better not be any.
   1500     DCHECK_NE(blink::WebIDBDataLossTotal, connection.callbacks->data_loss());
   1501     pending_open_calls_.push_back(connection);
   1502     return;
   1503   }
   1504 
   1505   if (metadata_.id == kInvalidId) {
   1506     // The database was deleted then immediately re-opened; OpenInternal()
   1507     // recreates it in the backing store.
   1508     if (OpenInternal().ok()) {
   1509       DCHECK_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION,
   1510                 metadata_.int_version);
   1511     } else {
   1512       base::string16 message;
   1513       if (connection.version == IndexedDBDatabaseMetadata::NO_INT_VERSION) {
   1514         message = ASCIIToUTF16(
   1515             "Internal error opening database with no version specified.");
   1516       } else {
   1517         message =
   1518             ASCIIToUTF16("Internal error opening database with version ") +
   1519             Int64ToString16(connection.version);
   1520       }
   1521       connection.callbacks->OnError(IndexedDBDatabaseError(
   1522           blink::WebIDBDatabaseExceptionUnknownError, message));
   1523       return;
   1524     }
   1525   }
   1526 
   1527   // We infer that the database didn't exist from its lack of either type of
   1528   // version.
   1529   bool is_new_database =
   1530       metadata_.version == kNoStringVersion &&
   1531       metadata_.int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION;
   1532 
   1533   if (connection.version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) {
   1534     // For unit tests only - skip upgrade steps. Calling from script with
   1535     // DEFAULT_INT_VERSION throws exception.
   1536     // TODO(jsbell): DCHECK that not in unit tests.
   1537     DCHECK(is_new_database);
   1538     connection.callbacks->OnSuccess(
   1539         CreateConnection(connection.database_callbacks,
   1540                          connection.child_process_id),
   1541         this->metadata());
   1542     return;
   1543   }
   1544 
   1545   // We may need to change the version.
   1546   int64 local_version = connection.version;
   1547   if (local_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) {
   1548     if (!is_new_database) {
   1549       connection.callbacks->OnSuccess(
   1550           CreateConnection(connection.database_callbacks,
   1551                            connection.child_process_id),
   1552           this->metadata());
   1553       return;
   1554     }
   1555     // Spec says: If no version is specified and no database exists, set
   1556     // database version to 1.
   1557     local_version = 1;
   1558   }
   1559 
   1560   if (local_version > metadata_.int_version) {
   1561     RunVersionChangeTransaction(connection.callbacks,
   1562                                 CreateConnection(connection.database_callbacks,
   1563                                                  connection.child_process_id),
   1564                                 connection.transaction_id,
   1565                                 local_version);
   1566     return;
   1567   }
   1568   if (local_version < metadata_.int_version) {
   1569     connection.callbacks->OnError(IndexedDBDatabaseError(
   1570         blink::WebIDBDatabaseExceptionVersionError,
   1571         ASCIIToUTF16("The requested version (") +
   1572             Int64ToString16(local_version) +
   1573             ASCIIToUTF16(") is less than the existing version (") +
   1574             Int64ToString16(metadata_.int_version) + ASCIIToUTF16(").")));
   1575     return;
   1576   }
   1577   DCHECK_EQ(local_version, metadata_.int_version);
   1578   connection.callbacks->OnSuccess(
   1579       CreateConnection(connection.database_callbacks,
   1580                        connection.child_process_id),
   1581       this->metadata());
   1582 }
   1583 
   1584 void IndexedDBDatabase::RunVersionChangeTransaction(
   1585     scoped_refptr<IndexedDBCallbacks> callbacks,
   1586     scoped_ptr<IndexedDBConnection> connection,
   1587     int64 transaction_id,
   1588     int64 requested_version) {
   1589   DCHECK(callbacks.get());
   1590   DCHECK(connections_.count(connection.get()));
   1591   if (ConnectionCount() > 1) {
   1592     DCHECK_NE(blink::WebIDBDataLossTotal, callbacks->data_loss());
   1593     // Front end ensures the event is not fired at connections that have
   1594     // close_pending set.
   1595     for (ConnectionSet::const_iterator it = connections_.begin();
   1596          it != connections_.end();
   1597          ++it) {
   1598       if (*it != connection.get()) {
   1599         (*it)->callbacks()->OnVersionChange(metadata_.int_version,
   1600                                             requested_version);
   1601       }
   1602     }
   1603     // OnBlocked will be fired at the request when one of the other
   1604     // connections acks that the OnVersionChange was ignored.
   1605 
   1606     DCHECK(!pending_run_version_change_transaction_call_);
   1607     pending_run_version_change_transaction_call_.reset(new PendingUpgradeCall(
   1608         callbacks, connection.Pass(), transaction_id, requested_version));
   1609     return;
   1610   }
   1611   RunVersionChangeTransactionFinal(
   1612       callbacks, connection.Pass(), transaction_id, requested_version);
   1613 }
   1614 
   1615 void IndexedDBDatabase::RunVersionChangeTransactionFinal(
   1616     scoped_refptr<IndexedDBCallbacks> callbacks,
   1617     scoped_ptr<IndexedDBConnection> connection,
   1618     int64 transaction_id,
   1619     int64 requested_version) {
   1620 
   1621   std::vector<int64> object_store_ids;
   1622   CreateTransaction(transaction_id,
   1623                     connection.get(),
   1624                     object_store_ids,
   1625                     blink::WebIDBTransactionModeVersionChange);
   1626 
   1627   transactions_[transaction_id]->ScheduleTask(
   1628       base::Bind(&IndexedDBDatabase::VersionChangeOperation,
   1629                  this,
   1630                  requested_version,
   1631                  callbacks,
   1632                  base::Passed(&connection)));
   1633   DCHECK(!pending_second_half_open_);
   1634 }
   1635 
   1636 void IndexedDBDatabase::DeleteDatabase(
   1637     scoped_refptr<IndexedDBCallbacks> callbacks) {
   1638 
   1639   if (IsDeleteDatabaseBlocked()) {
   1640     for (ConnectionSet::const_iterator it = connections_.begin();
   1641          it != connections_.end();
   1642          ++it) {
   1643       // Front end ensures the event is not fired at connections that have
   1644       // close_pending set.
   1645       (*it)->callbacks()->OnVersionChange(
   1646           metadata_.int_version, IndexedDBDatabaseMetadata::NO_INT_VERSION);
   1647     }
   1648     // OnBlocked will be fired at the request when one of the other
   1649     // connections acks that the OnVersionChange was ignored.
   1650 
   1651     pending_delete_calls_.push_back(new PendingDeleteCall(callbacks));
   1652     return;
   1653   }
   1654   DeleteDatabaseFinal(callbacks);
   1655 }
   1656 
   1657 bool IndexedDBDatabase::IsDeleteDatabaseBlocked() const {
   1658   return !!ConnectionCount();
   1659 }
   1660 
   1661 void IndexedDBDatabase::DeleteDatabaseFinal(
   1662     scoped_refptr<IndexedDBCallbacks> callbacks) {
   1663   DCHECK(!IsDeleteDatabaseBlocked());
   1664   DCHECK(backing_store_.get());
   1665   leveldb::Status s = backing_store_->DeleteDatabase(metadata_.name);
   1666   if (!s.ok()) {
   1667     IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
   1668                                  "Internal error deleting database.");
   1669     callbacks->OnError(error);
   1670     if (s.IsCorruption()) {
   1671       GURL origin_url = backing_store_->origin_url();
   1672       backing_store_ = NULL;
   1673       factory_->HandleBackingStoreCorruption(origin_url, error);
   1674     }
   1675     return;
   1676   }
   1677   int64 old_version = metadata_.int_version;
   1678   metadata_.version = kNoStringVersion;
   1679   metadata_.id = kInvalidId;
   1680   metadata_.int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION;
   1681   metadata_.object_stores.clear();
   1682   callbacks->OnSuccess(old_version);
   1683   factory_->DatabaseDeleted(identifier_);
   1684 }
   1685 
   1686 void IndexedDBDatabase::ForceClose() {
   1687   // IndexedDBConnection::ForceClose() may delete this database, so hold ref.
   1688   scoped_refptr<IndexedDBDatabase> protect(this);
   1689   ConnectionSet::const_iterator it = connections_.begin();
   1690   while (it != connections_.end()) {
   1691     IndexedDBConnection* connection = *it++;
   1692     connection->ForceClose();
   1693   }
   1694   DCHECK(connections_.empty());
   1695 }
   1696 
   1697 void IndexedDBDatabase::VersionChangeIgnored() {
   1698   if (pending_run_version_change_transaction_call_)
   1699     pending_run_version_change_transaction_call_->callbacks()->OnBlocked(
   1700         metadata_.int_version);
   1701 
   1702   for (PendingDeleteCallList::iterator it = pending_delete_calls_.begin();
   1703        it != pending_delete_calls_.end();
   1704        ++it) {
   1705     (*it)->callbacks()->OnBlocked(metadata_.int_version);
   1706   }
   1707 }
   1708 
   1709 
   1710 void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) {
   1711   DCHECK(connections_.count(connection));
   1712   DCHECK(connection->IsConnected());
   1713   DCHECK(connection->database() == this);
   1714 
   1715   IDB_TRACE("IndexedDBDatabase::Close");
   1716   // Abort outstanding transactions from the closing connection. This
   1717   // can not happen if the close is requested by the connection itself
   1718   // as the front-end defers the close until all transactions are
   1719   // complete, but can occur on process termination or forced close.
   1720   {
   1721     TransactionMap transactions(transactions_);
   1722     for (TransactionMap::const_iterator it = transactions.begin(),
   1723                                         end = transactions.end();
   1724          it != end;
   1725          ++it) {
   1726       if (it->second->connection() == connection->callbacks())
   1727         it->second->Abort(
   1728             IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
   1729                                    "Connection is closing."));
   1730     }
   1731   }
   1732 
   1733   connections_.erase(connection);
   1734   if (pending_second_half_open_ &&
   1735       pending_second_half_open_->connection() == connection) {
   1736     pending_second_half_open_->callbacks()->OnError(
   1737         IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError,
   1738                                "The connection was closed."));
   1739     pending_second_half_open_.reset();
   1740   }
   1741 
   1742   ProcessPendingCalls();
   1743 
   1744   // TODO(jsbell): Add a test for the pending_open_calls_ cases below.
   1745   if (!ConnectionCount() && !pending_open_calls_.size() &&
   1746       !pending_delete_calls_.size()) {
   1747     DCHECK(transactions_.empty());
   1748 
   1749     const GURL origin_url = backing_store_->origin_url();
   1750     backing_store_ = NULL;
   1751 
   1752     factory_->ReleaseDatabase(identifier_, forced);
   1753   }
   1754 }
   1755 
   1756 void IndexedDBDatabase::CreateObjectStoreAbortOperation(
   1757     int64 object_store_id,
   1758     IndexedDBTransaction* transaction) {
   1759   DCHECK(!transaction);
   1760   IDB_TRACE1("IndexedDBDatabase::CreateObjectStoreAbortOperation",
   1761              "txn.id",
   1762              transaction->id());
   1763   RemoveObjectStore(object_store_id);
   1764 }
   1765 
   1766 void IndexedDBDatabase::DeleteObjectStoreAbortOperation(
   1767     const IndexedDBObjectStoreMetadata& object_store_metadata,
   1768     IndexedDBTransaction* transaction) {
   1769   DCHECK(!transaction);
   1770   IDB_TRACE1("IndexedDBDatabase::DeleteObjectStoreAbortOperation",
   1771              "txn.id",
   1772              transaction->id());
   1773   AddObjectStore(object_store_metadata,
   1774                  IndexedDBObjectStoreMetadata::kInvalidId);
   1775 }
   1776 
   1777 void IndexedDBDatabase::VersionChangeAbortOperation(
   1778     const base::string16& previous_version,
   1779     int64 previous_int_version,
   1780     IndexedDBTransaction* transaction) {
   1781   DCHECK(!transaction);
   1782   IDB_TRACE1("IndexedDBDatabase::VersionChangeAbortOperation",
   1783              "txn.id",
   1784              transaction->id());
   1785   metadata_.version = previous_version;
   1786   metadata_.int_version = previous_int_version;
   1787 }
   1788 
   1789 }  // namespace content
   1790