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