1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_database.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <math.h>
87dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include <set>
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/auto_reset.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/logging.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/memory/scoped_vector.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/stl_util.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "content/browser/indexed_db/indexed_db_blob_info.h"
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/browser/indexed_db/indexed_db_connection.h"
19e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "content/browser/indexed_db/indexed_db_context_impl.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_cursor.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_factory.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_index_writer.h"
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_pending_connection.h"
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_tracing.h"
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_transaction.h"
2623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "content/browser/indexed_db/indexed_db_value.h"
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/common/indexed_db/indexed_db_key_path.h"
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/common/indexed_db/indexed_db_key_range.h"
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/browser/blob/blob_data_handle.h"
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
3146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "third_party/leveldatabase/env_chromium.h"
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::ASCIIToUTF16;
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using base::Int64ToString16;
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebIDBKeyTypeNumber;
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace content {
38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// PendingUpgradeCall has a scoped_ptr<IndexedDBConnection> because it owns the
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// in-progress connection.
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass IndexedDBDatabase::PendingUpgradeCall {
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public:
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PendingUpgradeCall(scoped_refptr<IndexedDBCallbacks> callbacks,
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     scoped_ptr<IndexedDBConnection> connection,
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     int64 transaction_id,
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     int64 version)
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      : callbacks_(callbacks),
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        connection_(connection.Pass()),
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        version_(version),
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        transaction_id_(transaction_id) {}
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<IndexedDBCallbacks> callbacks() const { return callbacks_; }
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Takes ownership of the connection object.
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<IndexedDBConnection> ReleaseConnection() WARN_UNUSED_RESULT {
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return connection_.Pass();
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int64 version() const { return version_; }
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int64 transaction_id() const { return transaction_id_; }
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private:
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_refptr<IndexedDBCallbacks> callbacks_;
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<IndexedDBConnection> connection_;
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int64 version_;
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const int64 transaction_id_;
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// PendingSuccessCall has a IndexedDBConnection* because the connection is now
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// owned elsewhere, but we need to cancel the success call if that connection
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// closes before it is sent.
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass IndexedDBDatabase::PendingSuccessCall {
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public:
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PendingSuccessCall(scoped_refptr<IndexedDBCallbacks> callbacks,
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     IndexedDBConnection* connection,
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                     int64 version)
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      : callbacks_(callbacks), connection_(connection), version_(version) {}
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<IndexedDBCallbacks> callbacks() const { return callbacks_; }
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IndexedDBConnection* connection() const { return connection_; }
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int64 version() const { return version_; }
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private:
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_refptr<IndexedDBCallbacks> callbacks_;
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  IndexedDBConnection* connection_;
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int64 version_;
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)class IndexedDBDatabase::PendingDeleteCall {
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) public:
87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  explicit PendingDeleteCall(scoped_refptr<IndexedDBCallbacks> callbacks)
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      : callbacks_(callbacks) {}
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<IndexedDBCallbacks> callbacks() const { return callbacks_; }
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private:
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_refptr<IndexedDBCallbacks> callbacks_;
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)scoped_refptr<IndexedDBDatabase> IndexedDBDatabase::Create(
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& name,
97424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    IndexedDBBackingStore* backing_store,
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    IndexedDBFactory* factory,
990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const Identifier& unique_identifier,
1000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    leveldb::Status* s) {
101424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  scoped_refptr<IndexedDBDatabase> database =
102424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      new IndexedDBDatabase(name, backing_store, factory, unique_identifier);
1030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  *s = database->OpenInternal();
1040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (s->ok())
1050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return database;
1060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  else
1070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return NULL;
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace {
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const base::string16::value_type kNoStringVersion[] = {0};
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)IndexedDBDatabase::IndexedDBDatabase(const base::string16& name,
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                     IndexedDBBackingStore* backing_store,
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                     IndexedDBFactory* factory,
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                     const Identifier& unique_identifier)
118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : backing_store_(backing_store),
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      metadata_(name,
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                kInvalidId,
121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                kNoStringVersion,
122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                IndexedDBDatabaseMetadata::NO_INT_VERSION,
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                kInvalidId),
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      identifier_(unique_identifier),
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      factory_(factory) {
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(factory != NULL);
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBDatabase::AddObjectStore(
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const IndexedDBObjectStoreMetadata& object_store,
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int64 new_max_object_store_id) {
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(metadata_.object_stores.find(object_store.id) ==
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)         metadata_.object_stores.end());
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (new_max_object_store_id != IndexedDBObjectStoreMetadata::kInvalidId) {
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_LT(metadata_.max_object_store_id, new_max_object_store_id);
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    metadata_.max_object_store_id = new_max_object_store_id;
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  metadata_.object_stores[object_store.id] = object_store;
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBDatabase::RemoveObjectStore(int64 object_store_id) {
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(metadata_.object_stores.find(object_store_id) !=
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)         metadata_.object_stores.end());
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  metadata_.object_stores.erase(object_store_id);
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBDatabase::AddIndex(int64 object_store_id,
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                 const IndexedDBIndexMetadata& index,
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                 int64 new_max_index_id) {
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(metadata_.object_stores.find(object_store_id) !=
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)         metadata_.object_stores.end());
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IndexedDBObjectStoreMetadata object_store =
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      metadata_.object_stores[object_store_id];
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(object_store.indexes.find(index.id) == object_store.indexes.end());
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  object_store.indexes[index.id] = index;
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (new_max_index_id != IndexedDBIndexMetadata::kInvalidId) {
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_LT(object_store.max_index_id, new_max_index_id);
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    object_store.max_index_id = new_max_index_id;
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  metadata_.object_stores[object_store_id] = object_store;
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBDatabase::RemoveIndex(int64 object_store_id, int64 index_id) {
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(metadata_.object_stores.find(object_store_id) !=
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)         metadata_.object_stores.end());
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IndexedDBObjectStoreMetadata object_store =
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      metadata_.object_stores[object_store_id];
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end());
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  object_store.indexes.erase(index_id);
172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  metadata_.object_stores[object_store_id] = object_store;
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)leveldb::Status IndexedDBDatabase::OpenInternal() {
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool success = false;
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  leveldb::Status s = backing_store_->GetIDBDatabaseMetaData(
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      metadata_.name, &metadata_, &success);
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(success == (metadata_.id != kInvalidId)) << "success = " << success
180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                  << " id = " << metadata_.id;
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!s.ok())
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return s;
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (success)
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return backing_store_->GetObjectStores(metadata_.id,
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                           &metadata_.object_stores);
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return backing_store_->CreateIDBDatabaseMetaData(
188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      metadata_.name, metadata_.version, metadata_.int_version, &metadata_.id);
189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBDatabase::~IndexedDBDatabase() {
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(transactions_.empty());
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(pending_open_calls_.empty());
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(pending_delete_calls_.empty());
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)scoped_ptr<IndexedDBConnection> IndexedDBDatabase::CreateConnection(
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks,
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int child_process_id) {
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<IndexedDBConnection> connection(
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      new IndexedDBConnection(this, database_callbacks));
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  connections_.insert(connection.get());
2030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  backing_store_->GrantChildProcessPermissions(child_process_id);
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return connection.Pass();
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2077dbb3d5cf0c15f500944d211057644d6a2f37371Ben MurdochIndexedDBTransaction* IndexedDBDatabase::GetTransaction(
2087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    int64 transaction_id) const {
2097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  TransactionMap::const_iterator trans_iterator =
2107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      transactions_.find(transaction_id);
2117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (trans_iterator == transactions_.end())
2127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return NULL;
2137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return trans_iterator->second;
2147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool IndexedDBDatabase::ValidateObjectStoreId(int64 object_store_id) const {
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ContainsKey(metadata_.object_stores, object_store_id)) {
2187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DLOG(ERROR) << "Invalid object_store_id";
2197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
2207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return true;
2227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool IndexedDBDatabase::ValidateObjectStoreIdAndIndexId(int64 object_store_id,
2257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                                        int64 index_id) const {
2267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!ValidateObjectStoreId(object_store_id))
2277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
2287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const IndexedDBObjectStoreMetadata& object_store_metadata =
2297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      metadata_.object_stores.find(object_store_id)->second;
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ContainsKey(object_store_metadata.indexes, index_id)) {
2317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DLOG(ERROR) << "Invalid index_id";
2327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
2337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return true;
2357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool IndexedDBDatabase::ValidateObjectStoreIdAndOptionalIndexId(
2387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    int64 object_store_id,
2397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    int64 index_id) const {
2407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!ValidateObjectStoreId(object_store_id))
2417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
2427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const IndexedDBObjectStoreMetadata& object_store_metadata =
2437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      metadata_.object_stores.find(object_store_id)->second;
2447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (index_id != IndexedDBIndexMetadata::kInvalidId &&
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !ContainsKey(object_store_metadata.indexes, index_id)) {
2467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DLOG(ERROR) << "Invalid index_id";
2477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
2487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return true;
2507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool IndexedDBDatabase::ValidateObjectStoreIdAndNewIndexId(
2537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    int64 object_store_id,
2547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    int64 index_id) const {
2557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!ValidateObjectStoreId(object_store_id))
2567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
2577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const IndexedDBObjectStoreMetadata& object_store_metadata =
2587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      metadata_.object_stores.find(object_store_id)->second;
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (ContainsKey(object_store_metadata.indexes, index_id)) {
2607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DLOG(ERROR) << "Invalid index_id";
2617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
2627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return true;
2647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
266868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBDatabase::CreateObjectStore(int64 transaction_id,
267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                          int64 object_store_id,
268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                          const base::string16& name,
269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                          const IndexedDBKeyPath& key_path,
270868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                          bool auto_increment) {
271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBDatabase::CreateObjectStore", "txn.id", transaction_id);
2727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  IndexedDBTransaction* transaction = GetTransaction(transaction_id);
2737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!transaction)
274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (ContainsKey(metadata_.object_stores, object_store_id)) {
2787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DLOG(ERROR) << "Invalid object_store_id";
2797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
2807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Store creation is done synchronously, as it may be followed by
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // index creation (also sync) since preemptive OpenCursor/SetIndexKeys
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // may follow.
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IndexedDBObjectStoreMetadata object_store_metadata(
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      name,
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      object_store_id,
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      key_path,
289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      auto_increment,
290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      IndexedDBDatabase::kMinimumIndexId);
291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
292e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  leveldb::Status s =
293e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      backing_store_->CreateObjectStore(transaction->BackingStoreTransaction(),
294e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                        transaction->database()->id(),
295e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                        object_store_metadata.id,
296e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                        object_store_metadata.name,
297e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                        object_store_metadata.key_path,
298e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                        object_store_metadata.auto_increment);
299e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (!s.ok()) {
300e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    IndexedDBDatabaseError error(
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        blink::WebIDBDatabaseExceptionUnknownError,
302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        ASCIIToUTF16("Internal error creating object store '") +
303e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch            object_store_metadata.name + ASCIIToUTF16("'."));
304e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    transaction->Abort(error);
30546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (leveldb_env::IsCorruption(s))
306e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
307e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                             error);
308868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AddObjectStore(object_store_metadata, object_store_id);
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  transaction->ScheduleAbortTask(
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&IndexedDBDatabase::CreateObjectStoreAbortOperation,
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 this,
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 object_store_id));
316868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBDatabase::DeleteObjectStore(int64 transaction_id,
319868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                          int64 object_store_id) {
320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBDatabase::DeleteObjectStore", "txn.id", transaction_id);
3217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  IndexedDBTransaction* transaction = GetTransaction(transaction_id);
3227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!transaction)
323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
324116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!ValidateObjectStoreId(object_store_id))
3277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
3287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  transaction->ScheduleTask(
3303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(&IndexedDBDatabase::DeleteObjectStoreOperation,
3313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 this,
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 object_store_id));
333868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
335868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBDatabase::CreateIndex(int64 transaction_id,
336868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                    int64 object_store_id,
337868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                    int64 index_id,
338a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                    const base::string16& name,
339868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                    const IndexedDBKeyPath& key_path,
340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                    bool unique,
341868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                    bool multi_entry) {
342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBDatabase::CreateIndex", "txn.id", transaction_id);
3437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  IndexedDBTransaction* transaction = GetTransaction(transaction_id);
3447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!transaction)
345868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
346116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!ValidateObjectStoreIdAndNewIndexId(object_store_id, index_id))
3497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
350cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
351cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Index creation is done synchronously since preemptive
352cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // OpenCursor/SetIndexKeys may follow.
353868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const IndexedDBIndexMetadata index_metadata(
354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      name, index_id, key_path, unique, multi_entry);
355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!backing_store_->CreateIndex(transaction->BackingStoreTransaction(),
357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                   transaction->database()->id(),
3583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                   object_store_id,
3593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                   index_metadata.id,
3603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                   index_metadata.name,
3613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                   index_metadata.key_path,
3623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                   index_metadata.unique,
363a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                   index_metadata.multi_entry).ok()) {
364a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16 error_string =
365a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        ASCIIToUTF16("Internal error creating index '") +
366a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        index_metadata.name + ASCIIToUTF16("'.");
367868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    transaction->Abort(IndexedDBDatabaseError(
368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        blink::WebIDBDatabaseExceptionUnknownError, error_string));
369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
370868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
371cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
372cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AddIndex(object_store_id, index_metadata, index_id);
373cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  transaction->ScheduleAbortTask(
374cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&IndexedDBDatabase::CreateIndexAbortOperation,
375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 this,
376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 object_store_id,
377cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 index_id));
378868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
379868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void IndexedDBDatabase::CreateIndexAbortOperation(
3813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int64 object_store_id,
3823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int64 index_id,
3833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    IndexedDBTransaction* transaction) {
384f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBDatabase::CreateIndexAbortOperation",
385f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             "txn.id",
386f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             transaction->id());
387868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!transaction);
3883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  RemoveIndex(object_store_id, index_id);
389868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
390868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
391868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBDatabase::DeleteIndex(int64 transaction_id,
392868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                    int64 object_store_id,
393868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                    int64 index_id) {
394f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBDatabase::DeleteIndex", "txn.id", transaction_id);
3957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  IndexedDBTransaction* transaction = GetTransaction(transaction_id);
3967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!transaction)
397868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
398116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
399868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
4007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!ValidateObjectStoreIdAndIndexId(object_store_id, index_id))
4017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
402868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
403868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  transaction->ScheduleTask(
4043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(&IndexedDBDatabase::DeleteIndexOperation,
4053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 this,
4063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 object_store_id,
407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 index_id));
408868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
409868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
4103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void IndexedDBDatabase::DeleteIndexOperation(
4113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int64 object_store_id,
412cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    int64 index_id,
4133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    IndexedDBTransaction* transaction) {
414f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1(
415f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "IndexedDBDatabase::DeleteIndexOperation", "txn.id", transaction->id());
416cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
417cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const IndexedDBIndexMetadata index_metadata =
418cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      metadata_.object_stores[object_store_id].indexes[index_id];
419cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
420a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  leveldb::Status s =
421a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      backing_store_->DeleteIndex(transaction->BackingStoreTransaction(),
422a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  transaction->database()->id(),
423a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  object_store_id,
424cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                  index_id);
425a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!s.ok()) {
426a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16 error_string =
427a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        ASCIIToUTF16("Internal error deleting index '") +
428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        index_metadata.name + ASCIIToUTF16("'.");
429e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
430e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                 error_string);
431e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    transaction->Abort(error);
43246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (leveldb_env::IsCorruption(s))
433e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
434e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                             error);
435cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
436868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
437cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
438cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  RemoveIndex(object_store_id, index_id);
439cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  transaction->ScheduleAbortTask(
440cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&IndexedDBDatabase::DeleteIndexAbortOperation,
441cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 this,
442cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 object_store_id,
443cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 index_metadata));
444868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
445868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
4463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void IndexedDBDatabase::DeleteIndexAbortOperation(
4473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int64 object_store_id,
4483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const IndexedDBIndexMetadata& index_metadata,
4493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    IndexedDBTransaction* transaction) {
450868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!transaction);
451f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBDatabase::DeleteIndexAbortOperation",
452f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             "txn.id",
453f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)             transaction->id());
4543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  AddIndex(object_store_id, index_metadata, IndexedDBIndexMetadata::kInvalidId);
455868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
456868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
457868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBDatabase::Commit(int64 transaction_id) {
458868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The frontend suggests that we commit, but we may have previously initiated
459868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // an abort, and so have disposed of the transaction. on_abort has already
460868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // been dispatched to the frontend, so it will find out about that
461868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // asynchronously.
4627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  IndexedDBTransaction* transaction = GetTransaction(transaction_id);
463116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (transaction) {
464116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_refptr<IndexedDBFactory> factory = factory_;
465116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    leveldb::Status s = transaction->Commit();
466116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (s.IsCorruption()) {
467116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
468116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                   "Internal error committing transaction.");
469116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      factory->HandleBackingStoreCorruption(identifier_.first, error);
470116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
471116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
472868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
473868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
474868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBDatabase::Abort(int64 transaction_id) {
475868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // If the transaction is unknown, then it has already been aborted by the
476868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // backend before this call so it is safe to ignore it.
477f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBDatabase::Abort", "txn.id", transaction_id);
4787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  IndexedDBTransaction* transaction = GetTransaction(transaction_id);
4797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (transaction)
4807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    transaction->Abort();
481868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
482868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
483868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBDatabase::Abort(int64 transaction_id,
484868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              const IndexedDBDatabaseError& error) {
485f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBDatabase::Abort(error)", "txn.id", transaction_id);
486868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // If the transaction is unknown, then it has already been aborted by the
487868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // backend before this call so it is safe to ignore it.
4887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  IndexedDBTransaction* transaction = GetTransaction(transaction_id);
4897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (transaction)
4907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    transaction->Abort(error);
491868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
492868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
493eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid IndexedDBDatabase::Get(int64 transaction_id,
494eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            int64 object_store_id,
495eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            int64 index_id,
496eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            scoped_ptr<IndexedDBKeyRange> key_range,
497eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            bool key_only,
498eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            scoped_refptr<IndexedDBCallbacks> callbacks) {
499f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBDatabase::Get", "txn.id", transaction_id);
5007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  IndexedDBTransaction* transaction = GetTransaction(transaction_id);
5017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!transaction)
502868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
5037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id))
5057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return;
506868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  transaction->ScheduleTask(base::Bind(
5083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      &IndexedDBDatabase::GetOperation,
5093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      this,
510868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      object_store_id,
511868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      index_id,
5123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      Passed(&key_range),
513868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE,
514868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      callbacks));
515868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
516868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void IndexedDBDatabase::GetOperation(
5183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int64 object_store_id,
5193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int64 index_id,
5203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    scoped_ptr<IndexedDBKeyRange> key_range,
5213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    indexed_db::CursorType cursor_type,
5223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    scoped_refptr<IndexedDBCallbacks> callbacks,
5233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    IndexedDBTransaction* transaction) {
524f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBDatabase::GetOperation", "txn.id", transaction->id());
5253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(metadata_.object_stores.find(object_store_id) !=
5273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         metadata_.object_stores.end());
5283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const IndexedDBObjectStoreMetadata& object_store_metadata =
5293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      metadata_.object_stores[object_store_id];
530868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
531868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const IndexedDBKey* key;
532868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  leveldb::Status s;
534868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
5353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (key_range->IsOnlyKey()) {
5363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    key = &key_range->lower();
537868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
5383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (index_id == IndexedDBIndexMetadata::kInvalidId) {
5393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      DCHECK_NE(cursor_type, indexed_db::CURSOR_KEY_ONLY);
540868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // ObjectStore Retrieval Operation
541868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      backing_store_cursor = backing_store_->OpenObjectStoreCursor(
542868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          transaction->BackingStoreTransaction(),
5433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          id(),
5443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          object_store_id,
5453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          *key_range,
546116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          blink::WebIDBCursorDirectionNext,
5470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          &s);
5483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    } else if (cursor_type == indexed_db::CURSOR_KEY_ONLY) {
549868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // Index Value Retrieval Operation
550868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      backing_store_cursor = backing_store_->OpenIndexKeyCursor(
551868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          transaction->BackingStoreTransaction(),
5523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          id(),
5533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          object_store_id,
5543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          index_id,
5553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          *key_range,
556116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          blink::WebIDBCursorDirectionNext,
5570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          &s);
558868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    } else {
559868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // Index Referenced Value Retrieval Operation
560868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      backing_store_cursor = backing_store_->OpenIndexCursor(
561868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          transaction->BackingStoreTransaction(),
5623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          id(),
5633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          object_store_id,
5643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          index_id,
5653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          *key_range,
566116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          blink::WebIDBCursorDirectionNext,
5670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          &s);
5680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
5690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
5700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (!s.ok()) {
5710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString();
5720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
5730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                   "Internal error deleting data in range");
57446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (leveldb_env::IsCorruption(s)) {
5750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
5760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                               error);
5770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      }
578868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
579868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
580868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!backing_store_cursor) {
5813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      callbacks->OnSuccess();
582868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return;
583868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
584868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
585868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    key = &backing_store_cursor->key();
586868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
587868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
588868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<IndexedDBKey> primary_key;
5893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (index_id == IndexedDBIndexMetadata::kInvalidId) {
590868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Object Store Retrieval Operation
59123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    IndexedDBValue value;
592a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    s = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
593a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  id(),
594a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  object_store_id,
595a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  *key,
596a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  &value);
597a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!s.ok()) {
598e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
599e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                   "Internal error in GetRecord.");
600e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      callbacks->OnError(error);
601e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
60246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (leveldb_env::IsCorruption(s))
603e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
604e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                               error);
605868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return;
606868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
607868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
608868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (value.empty()) {
6093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      callbacks->OnSuccess();
610868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return;
611868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
612868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
6133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (object_store_metadata.auto_increment &&
6143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        !object_store_metadata.key_path.IsNull()) {
6153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      callbacks->OnSuccess(&value, *key, object_store_metadata.key_path);
616868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return;
617868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
618868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
6193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    callbacks->OnSuccess(&value);
620868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
621868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
622868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
623868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // From here we are dealing only with indexes.
624a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  s = backing_store_->GetPrimaryKeyViaIndex(
625868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      transaction->BackingStoreTransaction(),
6263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      id(),
6273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      object_store_id,
6283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      index_id,
629868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      *key,
630868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      &primary_key);
631a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!s.ok()) {
632e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
633e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                 "Internal error in GetPrimaryKeyViaIndex.");
634e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    callbacks->OnError(error);
63546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (leveldb_env::IsCorruption(s))
636e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
637e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                             error);
638868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
639868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
640868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!primary_key) {
6413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    callbacks->OnSuccess();
642868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
643868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
6443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (cursor_type == indexed_db::CURSOR_KEY_ONLY) {
645868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Index Value Retrieval Operation
6463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    callbacks->OnSuccess(*primary_key);
647868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
648868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
649868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
650868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Index Referenced Value Retrieval Operation
65123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  IndexedDBValue value;
652a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  s = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
653a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                id(),
654a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                object_store_id,
655a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                *primary_key,
656a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                &value);
657a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!s.ok()) {
658e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
659e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                 "Internal error in GetRecord.");
660e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    callbacks->OnError(error);
66146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (leveldb_env::IsCorruption(s))
662e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
663e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                             error);
664868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
665868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
666868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
667868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (value.empty()) {
6683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    callbacks->OnSuccess();
669868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
670868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
6713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (object_store_metadata.auto_increment &&
6723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      !object_store_metadata.key_path.IsNull()) {
6733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    callbacks->OnSuccess(&value, *primary_key, object_store_metadata.key_path);
674868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
675868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
6763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  callbacks->OnSuccess(&value);
677868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
678868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
679868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)static scoped_ptr<IndexedDBKey> GenerateKey(
6805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IndexedDBBackingStore* backing_store,
6815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IndexedDBTransaction* transaction,
682868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int64 database_id,
683868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int64 object_store_id) {
684868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const int64 max_generator_value =
685868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      9007199254740992LL;  // Maximum integer storable as ECMAScript number.
686868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int64 current_number;
687a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  leveldb::Status s = backing_store->GetKeyGeneratorCurrentNumber(
688868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      transaction->BackingStoreTransaction(),
689868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      database_id,
690868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      object_store_id,
691868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      &current_number);
692a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!s.ok()) {
693eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(ERROR) << "Failed to GetKeyGeneratorCurrentNumber";
694868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return make_scoped_ptr(new IndexedDBKey());
695868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
696868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (current_number < 0 || current_number > max_generator_value)
697868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return make_scoped_ptr(new IndexedDBKey());
698868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
6993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return make_scoped_ptr(new IndexedDBKey(current_number, WebIDBKeyTypeNumber));
700868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
701868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
702a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static leveldb::Status UpdateKeyGenerator(IndexedDBBackingStore* backing_store,
703a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                          IndexedDBTransaction* transaction,
704a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                          int64 database_id,
705a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                          int64 object_store_id,
706a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                          const IndexedDBKey& key,
707a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                          bool check_current) {
7083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK_EQ(WebIDBKeyTypeNumber, key.type());
709868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return backing_store->MaybeUpdateKeyGeneratorCurrentNumber(
710868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      transaction->BackingStoreTransaction(),
711868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      database_id,
712868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      object_store_id,
7133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      static_cast<int64>(floor(key.number())) + 1,
714868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      check_current);
715868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
716868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)struct IndexedDBDatabase::PutOperationParams {
7183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  PutOperationParams() {}
7193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int64 object_store_id;
72023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  IndexedDBValue value;
72103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ScopedVector<storage::BlobDataHandle> handles;
7223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  scoped_ptr<IndexedDBKey> key;
723116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  blink::WebIDBPutMode put_mode;
7243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  scoped_refptr<IndexedDBCallbacks> callbacks;
7253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<IndexKeys> index_keys;
7263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
7283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(PutOperationParams);
7293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
7303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
731868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBDatabase::Put(int64 transaction_id,
732868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                            int64 object_store_id,
73323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            IndexedDBValue* value,
73403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            ScopedVector<storage::BlobDataHandle>* handles,
735868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                            scoped_ptr<IndexedDBKey> key,
736116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                            blink::WebIDBPutMode put_mode,
737eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            scoped_refptr<IndexedDBCallbacks> callbacks,
738868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                            const std::vector<IndexKeys>& index_keys) {
739f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBDatabase::Put", "txn.id", transaction_id);
7407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  IndexedDBTransaction* transaction = GetTransaction(transaction_id);
7417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!transaction)
742868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
743116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
744868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!ValidateObjectStoreId(object_store_id))
7467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
747868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
748868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(key);
7490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(value);
7503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  scoped_ptr<PutOperationParams> params(new PutOperationParams());
7513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  params->object_store_id = object_store_id;
7523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  params->value.swap(*value);
7530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  params->handles.swap(*handles);
7543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  params->key = key.Pass();
7553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  params->put_mode = put_mode;
7563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  params->callbacks = callbacks;
7573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  params->index_keys = index_keys;
7583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  transaction->ScheduleTask(base::Bind(
7593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      &IndexedDBDatabase::PutOperation, this, base::Passed(&params)));
7603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
7613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void IndexedDBDatabase::PutOperation(scoped_ptr<PutOperationParams> params,
7633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                     IndexedDBTransaction* transaction) {
764f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBDatabase::PutOperation", "txn.id", transaction->id());
765116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
766868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool key_was_generated = false;
767868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(metadata_.object_stores.find(params->object_store_id) !=
7693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         metadata_.object_stores.end());
7703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const IndexedDBObjectStoreMetadata& object_store =
7713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      metadata_.object_stores[params->object_store_id];
7723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(object_store.auto_increment || params->key->IsValid());
7733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
774868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<IndexedDBKey> key;
775116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (params->put_mode != blink::WebIDBPutModeCursorUpdate &&
7763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      object_store.auto_increment && !params->key->IsValid()) {
7775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<IndexedDBKey> auto_inc_key = GenerateKey(
7785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        backing_store_.get(), transaction, id(), params->object_store_id);
779868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    key_was_generated = true;
780868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!auto_inc_key->IsValid()) {
7813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      params->callbacks->OnError(
782f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionConstraintError,
783868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                 "Maximum key generator value reached."));
784868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return;
785868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
786868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    key = auto_inc_key.Pass();
787868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
7883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    key = params->key.Pass();
789868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
790868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
791868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(key->IsValid());
792868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
793868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IndexedDBBackingStore::RecordIdentifier record_identifier;
794116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (params->put_mode == blink::WebIDBPutModeAddOnly) {
795868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    bool found = false;
796a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    leveldb::Status s = backing_store_->KeyExistsInObjectStore(
797868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        transaction->BackingStoreTransaction(),
7983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        id(),
7993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        params->object_store_id,
8003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        *key,
801868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        &record_identifier,
802868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        &found);
803a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!s.ok()) {
804e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
805e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                   "Internal error checking key existence.");
806e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      params->callbacks->OnError(error);
80746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (leveldb_env::IsCorruption(s))
808e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
809e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                               error);
810868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return;
811868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
812868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (found) {
8133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      params->callbacks->OnError(
814f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionConstraintError,
815868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                 "Key already exists in the object store."));
816868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return;
817868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
818868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
819868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
820eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ScopedVector<IndexWriter> index_writers;
821a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 error_message;
822868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool obeys_constraints = false;
823eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool backing_store_success = MakeIndexWriters(transaction,
8243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                backing_store_.get(),
8253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                id(),
8263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                object_store,
827eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                *key,
828eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                key_was_generated,
8293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                params->index_keys,
830eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                &index_writers,
831eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                &error_message,
832eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                &obeys_constraints);
833868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!backing_store_success) {
8343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    params->callbacks->OnError(IndexedDBDatabaseError(
835f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        blink::WebIDBDatabaseExceptionUnknownError,
836868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        "Internal error: backing store error updating index keys."));
837868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
838868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
839868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!obeys_constraints) {
8403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    params->callbacks->OnError(IndexedDBDatabaseError(
841f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        blink::WebIDBDatabaseExceptionConstraintError, error_message));
842868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
843868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
844868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
845868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Before this point, don't do any mutation. After this point, rollback the
846868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // transaction in case of error.
847a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  leveldb::Status s =
848868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      backing_store_->PutRecord(transaction->BackingStoreTransaction(),
8493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                id(),
8503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                params->object_store_id,
8513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                *key,
8525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                &params->value,
8530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                &params->handles,
854868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                &record_identifier);
855a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!s.ok()) {
856e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    IndexedDBDatabaseError error(
857f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        blink::WebIDBDatabaseExceptionUnknownError,
858e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        "Internal error: backing store error performing put/add.");
859e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    params->callbacks->OnError(error);
86046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (leveldb_env::IsCorruption(s))
861e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
862e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                             error);
863868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
864868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
865868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
866868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (size_t i = 0; i < index_writers.size(); ++i) {
867eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    IndexWriter* index_writer = index_writers[i];
868868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    index_writer->WriteIndexKeys(record_identifier,
8693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 backing_store_.get(),
870868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                 transaction->BackingStoreTransaction(),
8713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 id(),
8723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 params->object_store_id);
873868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
874868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
8753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (object_store.auto_increment &&
876116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      params->put_mode != blink::WebIDBPutModeCursorUpdate &&
877ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      key->type() == WebIDBKeyTypeNumber) {
878a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    leveldb::Status s = UpdateKeyGenerator(backing_store_.get(),
879a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                           transaction,
880a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                           id(),
881a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                           params->object_store_id,
882a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                           *key,
883a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                           !key_was_generated);
884a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!s.ok()) {
885e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
886e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                   "Internal error updating key generator.");
887e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      params->callbacks->OnError(error);
88846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      if (leveldb_env::IsCorruption(s))
889e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
890e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                               error);
891868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return;
892868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
893868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
894868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
8953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  params->callbacks->OnSuccess(*key);
896868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
897868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
898868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBDatabase::SetIndexKeys(int64 transaction_id,
899868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                     int64 object_store_id,
900868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                     scoped_ptr<IndexedDBKey> primary_key,
901868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                     const std::vector<IndexKeys>& index_keys) {
902f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  IDB_TRACE1("IndexedDBDatabase::SetIndexKeys", "txn.id", transaction_id);
9037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  IndexedDBTransaction* transaction = GetTransaction(transaction_id);
9047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!transaction)
905868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
906116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
907868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
908eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // TODO(alecflett): This method could be asynchronous, but we need to
909868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // evaluate if it's worth the extra complexity.
910868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IndexedDBBackingStore::RecordIdentifier record_identifier;
911868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool found = false;
912a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  leveldb::Status s = backing_store_->KeyExistsInObjectStore(
9131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      transaction->BackingStoreTransaction(),
9141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      metadata_.id,
9151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      object_store_id,
9161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      *primary_key,
9171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      &record_identifier,
9181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      &found);
919a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!s.ok()) {
920e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
921e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                 "Internal error setting index keys.");
922e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    transaction->Abort(error);
92346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (leveldb_env::IsCorruption(s))
924e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
925e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                                             error);
926868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
927868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
928868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!found) {
929868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    transaction->Abort(IndexedDBDatabaseError(
930f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        blink::WebIDBDatabaseExceptionUnknownError,
931868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        "Internal error setting index keys for object store."));
932868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
933868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
934868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
935eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ScopedVector<IndexWriter> index_writers;
936a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 error_message;
937868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool obeys_constraints = false;
938868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(metadata_.object_stores.find(object_store_id) !=
939868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)         metadata_.object_stores.end());
940868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const IndexedDBObjectStoreMetadata& object_store_metadata =
941868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      metadata_.object_stores[object_store_id];
942eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool backing_store_success = MakeIndexWriters(transaction,
9431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                backing_store_.get(),
944eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                id(),
945eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                object_store_metadata,
946eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                *primary_key,
947eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                false,
948eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                index_keys,
949eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                &index_writers,
950eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                &error_message,
951eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                &obeys_constraints);
952868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!backing_store_success) {
953868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    transaction->Abort(IndexedDBDatabaseError(
954f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        blink::WebIDBDatabaseExceptionUnknownError,
955868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        "Internal error: backing store error updating index keys."));
956868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
957868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
958868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!obeys_constraints) {
959868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    transaction->Abort(IndexedDBDatabaseError(
960f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        blink::WebIDBDatabaseExceptionConstraintError, error_message));
961868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
962868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
963868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
964868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (size_t i = 0; i < index_writers.size(); ++i) {
965eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    IndexWriter* index_writer = index_writers[i];
966868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    index_writer->WriteIndexKeys(record_identifier,
9671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 backing_store_.get(),
968