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