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