indexed_db_database.cc revision f2477e01787aa58f445919b809d89e252beef54f
1600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang// Use of this source code is governed by a BSD-style license that can be 3600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang// found in the LICENSE file. 4600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 5600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "content/browser/indexed_db/indexed_db_database.h" 6600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 7600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include <math.h> 8600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include <set> 9600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 10600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "base/auto_reset.h" 11600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "base/logging.h" 12600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "base/memory/scoped_ptr.h" 13600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "base/strings/string_number_conversions.h" 14600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "base/strings/utf_string_conversions.h" 15600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "content/browser/indexed_db/indexed_db_connection.h" 16600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "content/browser/indexed_db/indexed_db_cursor.h" 17600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "content/browser/indexed_db/indexed_db_factory.h" 18600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "content/browser/indexed_db/indexed_db_index_writer.h" 19600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "content/browser/indexed_db/indexed_db_tracing.h" 20600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "content/browser/indexed_db/indexed_db_transaction.h" 21600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "content/common/indexed_db/indexed_db_key_path.h" 22600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "content/common/indexed_db/indexed_db_key_range.h" 23600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "content/public/browser/browser_thread.h" 24600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang#include "third_party/WebKit/public/platform/WebIDBDatabaseException.h" 25600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 26600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangusing base::Int64ToString16; 27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangusing blink::WebIDBKeyTypeNumber; 28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangnamespace content { 30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang// PendingOpenCall has a scoped_refptr<IndexedDBDatabaseCallbacks> because it 32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang// isn't a connection yet. 33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangclass IndexedDBDatabase::PendingOpenCall { 34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public: 35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang PendingOpenCall(scoped_refptr<IndexedDBCallbacks> callbacks, 36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, 37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 transaction_id, 38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 version) 39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang : callbacks_(callbacks), 40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang database_callbacks_(database_callbacks), 41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang version_(version), 42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang transaction_id_(transaction_id) {} 43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_refptr<IndexedDBCallbacks> Callbacks() { return callbacks_; } 44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_refptr<IndexedDBDatabaseCallbacks> DatabaseCallbacks() { 45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return database_callbacks_; 46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 Version() { return version_; } 48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 TransactionId() const { return transaction_id_; } 49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private: 51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_refptr<IndexedDBCallbacks> callbacks_; 52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks_; 53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 version_; 54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang const int64 transaction_id_; 55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}; 56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang// PendingUpgradeCall has a scoped_ptr<IndexedDBConnection> because it owns the 58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang// in-progress connection. 59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangclass IndexedDBDatabase::PendingUpgradeCall { 60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public: 61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang PendingUpgradeCall(scoped_refptr<IndexedDBCallbacks> callbacks, 62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_ptr<IndexedDBConnection> connection, 63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 transaction_id, 64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 version) 65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang : callbacks_(callbacks), 66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang connection_(connection.Pass()), 67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang version_(version), 68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang transaction_id_(transaction_id) {} 69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_refptr<IndexedDBCallbacks> Callbacks() { return callbacks_; } 70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_ptr<IndexedDBConnection> Connection() { return connection_.Pass(); } 71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 Version() { return version_; } 72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 TransactionId() const { return transaction_id_; } 73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private: 75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_refptr<IndexedDBCallbacks> callbacks_; 76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_ptr<IndexedDBConnection> connection_; 77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 version_; 78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang const int64 transaction_id_; 79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}; 80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang// PendingSuccessCall has a IndexedDBConnection* because the connection is now 82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang// owned elsewhere, but we need to cancel the success call if that connection 83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang// closes before it is sent. 84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangclass IndexedDBDatabase::PendingSuccessCall { 85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public: 86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang PendingSuccessCall(scoped_refptr<IndexedDBCallbacks> callbacks, 87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang IndexedDBConnection* connection, 88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 version) 89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang : callbacks_(callbacks), connection_(connection), version_(version) {} 90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_refptr<IndexedDBCallbacks> Callbacks() { return callbacks_; } 91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang IndexedDBConnection* Connection() { return connection_; } 92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 Version() { return version_; } 93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private: 95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_refptr<IndexedDBCallbacks> callbacks_; 96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang IndexedDBConnection* connection_; 97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 version_; 98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}; 99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangclass IndexedDBDatabase::PendingDeleteCall { 101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public: 102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang explicit PendingDeleteCall(scoped_refptr<IndexedDBCallbacks> callbacks) 103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang : callbacks_(callbacks) {} 104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_refptr<IndexedDBCallbacks> Callbacks() { return callbacks_; } 105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private: 107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_refptr<IndexedDBCallbacks> callbacks_; 108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}; 109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangscoped_refptr<IndexedDBDatabase> IndexedDBDatabase::Create( 111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang const string16& name, 112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang IndexedDBBackingStore* backing_store, 113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang IndexedDBFactory* factory, 114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang const Identifier& unique_identifier) { 115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scoped_refptr<IndexedDBDatabase> database = 116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang new IndexedDBDatabase(name, backing_store, factory, unique_identifier); 117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!database->OpenInternal()) 118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return 0; 119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return database; 120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangnamespace { 123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangconst base::string16::value_type kNoStringVersion[] = {0}; 124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangtemplate <typename T, typename U> 126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangbool Contains(const T& container, const U& item) { 127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return container.find(item) != container.end(); 128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih WangIndexedDBDatabase::IndexedDBDatabase(const string16& name, 132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang IndexedDBBackingStore* backing_store, 133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang IndexedDBFactory* factory, 134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang const Identifier& unique_identifier) 135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang : backing_store_(backing_store), 136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_(name, 137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang kInvalidId, 138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang kNoStringVersion, 139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang IndexedDBDatabaseMetadata::NO_INT_VERSION, 140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang kInvalidId), 141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang identifier_(unique_identifier), 142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang factory_(factory), 143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang running_version_change_transaction_(NULL) { 144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DCHECK(!metadata_.name.empty()); 145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangvoid IndexedDBDatabase::AddObjectStore( 148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang const IndexedDBObjectStoreMetadata& object_store, 149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 new_max_object_store_id) { 150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DCHECK(metadata_.object_stores.find(object_store.id) == 151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.object_stores.end()); 152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (new_max_object_store_id != IndexedDBObjectStoreMetadata::kInvalidId) { 153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DCHECK_LT(metadata_.max_object_store_id, new_max_object_store_id); 154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.max_object_store_id = new_max_object_store_id; 155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.object_stores[object_store.id] = object_store; 157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangvoid IndexedDBDatabase::RemoveObjectStore(int64 object_store_id) { 160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DCHECK(metadata_.object_stores.find(object_store_id) != 161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.object_stores.end()); 162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.object_stores.erase(object_store_id); 163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangvoid IndexedDBDatabase::AddIndex(int64 object_store_id, 166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang const IndexedDBIndexMetadata& index, 167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 new_max_index_id) { 168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DCHECK(metadata_.object_stores.find(object_store_id) != 169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.object_stores.end()); 170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang IndexedDBObjectStoreMetadata object_store = 171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.object_stores[object_store_id]; 172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DCHECK(object_store.indexes.find(index.id) == object_store.indexes.end()); 174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang object_store.indexes[index.id] = index; 175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (new_max_index_id != IndexedDBIndexMetadata::kInvalidId) { 176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DCHECK_LT(object_store.max_index_id, new_max_index_id); 177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang object_store.max_index_id = new_max_index_id; 178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.object_stores[object_store_id] = object_store; 180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangvoid IndexedDBDatabase::RemoveIndex(int64 object_store_id, int64 index_id) { 183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DCHECK(metadata_.object_stores.find(object_store_id) != 184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.object_stores.end()); 185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang IndexedDBObjectStoreMetadata object_store = 186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.object_stores[object_store_id]; 187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DCHECK(object_store.indexes.find(index_id) != object_store.indexes.end()); 189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang object_store.indexes.erase(index_id); 190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.object_stores[object_store_id] = object_store; 191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangbool IndexedDBDatabase::OpenInternal() { 194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang bool success = false; 195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang bool ok = backing_store_->GetIDBDatabaseMetaData( 196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.name, &metadata_, &success); 197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DCHECK(success == (metadata_.id != kInvalidId)) << "success = " << success 198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang << " id = " << metadata_.id; 199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!ok) 200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (success) 202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return backing_store_->GetObjectStores(metadata_.id, 203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang &metadata_.object_stores); 204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return backing_store_->CreateIDBDatabaseMetaData( 206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.name, metadata_.version, metadata_.int_version, &metadata_.id); 207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih WangIndexedDBDatabase::~IndexedDBDatabase() { 210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DCHECK(transactions_.empty()); 211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DCHECK(pending_open_calls_.empty()); 212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DCHECK(pending_delete_calls_.empty()); 213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih WangIndexedDBTransaction* IndexedDBDatabase::GetTransaction( 216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 transaction_id) const { 217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang TransactionMap::const_iterator trans_iterator = 218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang transactions_.find(transaction_id); 219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (trans_iterator == transactions_.end()) 220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return NULL; 221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return trans_iterator->second; 222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangbool IndexedDBDatabase::ValidateObjectStoreId(int64 object_store_id) const { 225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!Contains(metadata_.object_stores, object_store_id)) { 226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DLOG(ERROR) << "Invalid object_store_id"; 227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return true; 230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangbool IndexedDBDatabase::ValidateObjectStoreIdAndIndexId(int64 object_store_id, 233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 index_id) const { 234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!ValidateObjectStoreId(object_store_id)) 235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang const IndexedDBObjectStoreMetadata& object_store_metadata = 237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang metadata_.object_stores.find(object_store_id)->second; 238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!Contains(object_store_metadata.indexes, index_id)) { 239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang DLOG(ERROR) << "Invalid index_id"; 240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return true; 243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangbool IndexedDBDatabase::ValidateObjectStoreIdAndOptionalIndexId( 246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 object_store_id, 247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int64 index_id) const { 248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (!ValidateObjectStoreId(object_store_id)) 249 return false; 250 const IndexedDBObjectStoreMetadata& object_store_metadata = 251 metadata_.object_stores.find(object_store_id)->second; 252 if (index_id != IndexedDBIndexMetadata::kInvalidId && 253 !Contains(object_store_metadata.indexes, index_id)) { 254 DLOG(ERROR) << "Invalid index_id"; 255 return false; 256 } 257 return true; 258} 259 260bool IndexedDBDatabase::ValidateObjectStoreIdAndNewIndexId( 261 int64 object_store_id, 262 int64 index_id) const { 263 if (!ValidateObjectStoreId(object_store_id)) 264 return false; 265 const IndexedDBObjectStoreMetadata& object_store_metadata = 266 metadata_.object_stores.find(object_store_id)->second; 267 if (Contains(object_store_metadata.indexes, index_id)) { 268 DLOG(ERROR) << "Invalid index_id"; 269 return false; 270 } 271 return true; 272} 273 274void IndexedDBDatabase::CreateObjectStore(int64 transaction_id, 275 int64 object_store_id, 276 const string16& name, 277 const IndexedDBKeyPath& key_path, 278 bool auto_increment) { 279 IDB_TRACE("IndexedDBDatabase::CreateObjectStore"); 280 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 281 if (!transaction) 282 return; 283 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); 284 285 if (Contains(metadata_.object_stores, object_store_id)) { 286 DLOG(ERROR) << "Invalid object_store_id"; 287 return; 288 } 289 290 IndexedDBObjectStoreMetadata object_store_metadata( 291 name, 292 object_store_id, 293 key_path, 294 auto_increment, 295 IndexedDBDatabase::kMinimumIndexId); 296 297 transaction->ScheduleTask( 298 base::Bind(&IndexedDBDatabase::CreateObjectStoreOperation, 299 this, 300 object_store_metadata), 301 base::Bind(&IndexedDBDatabase::CreateObjectStoreAbortOperation, 302 this, 303 object_store_id)); 304 305 AddObjectStore(object_store_metadata, object_store_id); 306} 307 308void IndexedDBDatabase::CreateObjectStoreOperation( 309 const IndexedDBObjectStoreMetadata& object_store_metadata, 310 IndexedDBTransaction* transaction) { 311 IDB_TRACE("IndexedDBDatabase::CreateObjectStoreOperation"); 312 if (!backing_store_->CreateObjectStore( 313 transaction->BackingStoreTransaction(), 314 transaction->database()->id(), 315 object_store_metadata.id, 316 object_store_metadata.name, 317 object_store_metadata.key_path, 318 object_store_metadata.auto_increment)) { 319 transaction->Abort(IndexedDBDatabaseError( 320 blink::WebIDBDatabaseExceptionUnknownError, 321 ASCIIToUTF16("Internal error creating object store '") + 322 object_store_metadata.name + ASCIIToUTF16("'."))); 323 return; 324 } 325} 326 327void IndexedDBDatabase::DeleteObjectStore(int64 transaction_id, 328 int64 object_store_id) { 329 IDB_TRACE("IndexedDBDatabase::DeleteObjectStore"); 330 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 331 if (!transaction) 332 return; 333 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); 334 335 if (!ValidateObjectStoreId(object_store_id)) 336 return; 337 338 const IndexedDBObjectStoreMetadata& object_store_metadata = 339 metadata_.object_stores[object_store_id]; 340 341 transaction->ScheduleTask( 342 base::Bind(&IndexedDBDatabase::DeleteObjectStoreOperation, 343 this, 344 object_store_metadata), 345 base::Bind(&IndexedDBDatabase::DeleteObjectStoreAbortOperation, 346 this, 347 object_store_metadata)); 348 RemoveObjectStore(object_store_id); 349} 350 351void IndexedDBDatabase::CreateIndex(int64 transaction_id, 352 int64 object_store_id, 353 int64 index_id, 354 const string16& name, 355 const IndexedDBKeyPath& key_path, 356 bool unique, 357 bool multi_entry) { 358 IDB_TRACE("IndexedDBDatabase::CreateIndex"); 359 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 360 if (!transaction) 361 return; 362 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); 363 364 if (!ValidateObjectStoreIdAndNewIndexId(object_store_id, index_id)) 365 return; 366 const IndexedDBIndexMetadata index_metadata( 367 name, index_id, key_path, unique, multi_entry); 368 369 transaction->ScheduleTask( 370 base::Bind(&IndexedDBDatabase::CreateIndexOperation, 371 this, 372 object_store_id, 373 index_metadata), 374 base::Bind(&IndexedDBDatabase::CreateIndexAbortOperation, 375 this, 376 object_store_id, 377 index_id)); 378 379 AddIndex(object_store_id, index_metadata, index_id); 380} 381 382void IndexedDBDatabase::CreateIndexOperation( 383 int64 object_store_id, 384 const IndexedDBIndexMetadata& index_metadata, 385 IndexedDBTransaction* transaction) { 386 IDB_TRACE("IndexedDBDatabase::CreateIndexOperation"); 387 if (!backing_store_->CreateIndex(transaction->BackingStoreTransaction(), 388 transaction->database()->id(), 389 object_store_id, 390 index_metadata.id, 391 index_metadata.name, 392 index_metadata.key_path, 393 index_metadata.unique, 394 index_metadata.multi_entry)) { 395 string16 error_string = ASCIIToUTF16("Internal error creating index '") + 396 index_metadata.name + ASCIIToUTF16("'."); 397 transaction->Abort(IndexedDBDatabaseError( 398 blink::WebIDBDatabaseExceptionUnknownError, error_string)); 399 return; 400 } 401} 402 403void IndexedDBDatabase::CreateIndexAbortOperation( 404 int64 object_store_id, 405 int64 index_id, 406 IndexedDBTransaction* transaction) { 407 IDB_TRACE("IndexedDBDatabase::CreateIndexAbortOperation"); 408 DCHECK(!transaction); 409 RemoveIndex(object_store_id, index_id); 410} 411 412void IndexedDBDatabase::DeleteIndex(int64 transaction_id, 413 int64 object_store_id, 414 int64 index_id) { 415 IDB_TRACE("IndexedDBDatabase::DeleteIndex"); 416 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 417 if (!transaction) 418 return; 419 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); 420 421 if (!ValidateObjectStoreIdAndIndexId(object_store_id, index_id)) 422 return; 423 const IndexedDBIndexMetadata& index_metadata = 424 metadata_.object_stores[object_store_id].indexes[index_id]; 425 426 transaction->ScheduleTask( 427 base::Bind(&IndexedDBDatabase::DeleteIndexOperation, 428 this, 429 object_store_id, 430 index_metadata), 431 base::Bind(&IndexedDBDatabase::DeleteIndexAbortOperation, 432 this, 433 object_store_id, 434 index_metadata)); 435 436 RemoveIndex(object_store_id, index_id); 437} 438 439void IndexedDBDatabase::DeleteIndexOperation( 440 int64 object_store_id, 441 const IndexedDBIndexMetadata& index_metadata, 442 IndexedDBTransaction* transaction) { 443 IDB_TRACE("IndexedDBDatabase::DeleteIndexOperation"); 444 bool ok = backing_store_->DeleteIndex(transaction->BackingStoreTransaction(), 445 transaction->database()->id(), 446 object_store_id, 447 index_metadata.id); 448 if (!ok) { 449 string16 error_string = ASCIIToUTF16("Internal error deleting index '") + 450 index_metadata.name + ASCIIToUTF16("'."); 451 transaction->Abort(IndexedDBDatabaseError( 452 blink::WebIDBDatabaseExceptionUnknownError, error_string)); 453 } 454} 455 456void IndexedDBDatabase::DeleteIndexAbortOperation( 457 int64 object_store_id, 458 const IndexedDBIndexMetadata& index_metadata, 459 IndexedDBTransaction* transaction) { 460 IDB_TRACE("IndexedDBDatabase::DeleteIndexAbortOperation"); 461 DCHECK(!transaction); 462 AddIndex(object_store_id, index_metadata, IndexedDBIndexMetadata::kInvalidId); 463} 464 465void IndexedDBDatabase::Commit(int64 transaction_id) { 466 // The frontend suggests that we commit, but we may have previously initiated 467 // an abort, and so have disposed of the transaction. on_abort has already 468 // been dispatched to the frontend, so it will find out about that 469 // asynchronously. 470 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 471 if (transaction) 472 transaction->Commit(); 473} 474 475void IndexedDBDatabase::Abort(int64 transaction_id) { 476 // If the transaction is unknown, then it has already been aborted by the 477 // backend before this call so it is safe to ignore it. 478 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 479 if (transaction) 480 transaction->Abort(); 481} 482 483void IndexedDBDatabase::Abort(int64 transaction_id, 484 const IndexedDBDatabaseError& error) { 485 // If the transaction is unknown, then it has already been aborted by the 486 // backend before this call so it is safe to ignore it. 487 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 488 if (transaction) 489 transaction->Abort(error); 490} 491 492void IndexedDBDatabase::Get(int64 transaction_id, 493 int64 object_store_id, 494 int64 index_id, 495 scoped_ptr<IndexedDBKeyRange> key_range, 496 bool key_only, 497 scoped_refptr<IndexedDBCallbacks> callbacks) { 498 IDB_TRACE("IndexedDBDatabase::Get"); 499 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 500 if (!transaction) 501 return; 502 503 if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id)) 504 return; 505 506 transaction->ScheduleTask(base::Bind( 507 &IndexedDBDatabase::GetOperation, 508 this, 509 object_store_id, 510 index_id, 511 Passed(&key_range), 512 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE, 513 callbacks)); 514} 515 516void IndexedDBDatabase::GetOperation( 517 int64 object_store_id, 518 int64 index_id, 519 scoped_ptr<IndexedDBKeyRange> key_range, 520 indexed_db::CursorType cursor_type, 521 scoped_refptr<IndexedDBCallbacks> callbacks, 522 IndexedDBTransaction* transaction) { 523 IDB_TRACE("IndexedDBDatabase::GetOperation"); 524 525 DCHECK(metadata_.object_stores.find(object_store_id) != 526 metadata_.object_stores.end()); 527 const IndexedDBObjectStoreMetadata& object_store_metadata = 528 metadata_.object_stores[object_store_id]; 529 530 const IndexedDBKey* key; 531 532 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; 533 if (key_range->IsOnlyKey()) { 534 key = &key_range->lower(); 535 } else { 536 if (index_id == IndexedDBIndexMetadata::kInvalidId) { 537 DCHECK_NE(cursor_type, indexed_db::CURSOR_KEY_ONLY); 538 // ObjectStore Retrieval Operation 539 backing_store_cursor = backing_store_->OpenObjectStoreCursor( 540 transaction->BackingStoreTransaction(), 541 id(), 542 object_store_id, 543 *key_range, 544 indexed_db::CURSOR_NEXT); 545 } else if (cursor_type == indexed_db::CURSOR_KEY_ONLY) { 546 // Index Value Retrieval Operation 547 backing_store_cursor = backing_store_->OpenIndexKeyCursor( 548 transaction->BackingStoreTransaction(), 549 id(), 550 object_store_id, 551 index_id, 552 *key_range, 553 indexed_db::CURSOR_NEXT); 554 } else { 555 // Index Referenced Value Retrieval Operation 556 backing_store_cursor = backing_store_->OpenIndexCursor( 557 transaction->BackingStoreTransaction(), 558 id(), 559 object_store_id, 560 index_id, 561 *key_range, 562 indexed_db::CURSOR_NEXT); 563 } 564 565 if (!backing_store_cursor) { 566 callbacks->OnSuccess(); 567 return; 568 } 569 570 key = &backing_store_cursor->key(); 571 } 572 573 scoped_ptr<IndexedDBKey> primary_key; 574 bool ok; 575 if (index_id == IndexedDBIndexMetadata::kInvalidId) { 576 // Object Store Retrieval Operation 577 std::string value; 578 ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(), 579 id(), 580 object_store_id, 581 *key, 582 &value); 583 if (!ok) { 584 callbacks->OnError( 585 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, 586 "Internal error in GetRecord.")); 587 return; 588 } 589 590 if (value.empty()) { 591 callbacks->OnSuccess(); 592 return; 593 } 594 595 if (object_store_metadata.auto_increment && 596 !object_store_metadata.key_path.IsNull()) { 597 callbacks->OnSuccess(&value, *key, object_store_metadata.key_path); 598 return; 599 } 600 601 callbacks->OnSuccess(&value); 602 return; 603 } 604 605 // From here we are dealing only with indexes. 606 ok = backing_store_->GetPrimaryKeyViaIndex( 607 transaction->BackingStoreTransaction(), 608 id(), 609 object_store_id, 610 index_id, 611 *key, 612 &primary_key); 613 if (!ok) { 614 callbacks->OnError( 615 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, 616 "Internal error in GetPrimaryKeyViaIndex.")); 617 return; 618 } 619 if (!primary_key) { 620 callbacks->OnSuccess(); 621 return; 622 } 623 if (cursor_type == indexed_db::CURSOR_KEY_ONLY) { 624 // Index Value Retrieval Operation 625 callbacks->OnSuccess(*primary_key); 626 return; 627 } 628 629 // Index Referenced Value Retrieval Operation 630 std::string value; 631 ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(), 632 id(), 633 object_store_id, 634 *primary_key, 635 &value); 636 if (!ok) { 637 callbacks->OnError( 638 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, 639 "Internal error in GetRecord.")); 640 return; 641 } 642 643 if (value.empty()) { 644 callbacks->OnSuccess(); 645 return; 646 } 647 if (object_store_metadata.auto_increment && 648 !object_store_metadata.key_path.IsNull()) { 649 callbacks->OnSuccess(&value, *primary_key, object_store_metadata.key_path); 650 return; 651 } 652 callbacks->OnSuccess(&value); 653} 654 655static scoped_ptr<IndexedDBKey> GenerateKey( 656 scoped_refptr<IndexedDBBackingStore> backing_store, 657 scoped_refptr<IndexedDBTransaction> transaction, 658 int64 database_id, 659 int64 object_store_id) { 660 const int64 max_generator_value = 661 9007199254740992LL; // Maximum integer storable as ECMAScript number. 662 int64 current_number; 663 bool ok = backing_store->GetKeyGeneratorCurrentNumber( 664 transaction->BackingStoreTransaction(), 665 database_id, 666 object_store_id, 667 ¤t_number); 668 if (!ok) { 669 LOG(ERROR) << "Failed to GetKeyGeneratorCurrentNumber"; 670 return make_scoped_ptr(new IndexedDBKey()); 671 } 672 if (current_number < 0 || current_number > max_generator_value) 673 return make_scoped_ptr(new IndexedDBKey()); 674 675 return make_scoped_ptr(new IndexedDBKey(current_number, WebIDBKeyTypeNumber)); 676} 677 678static bool UpdateKeyGenerator( 679 scoped_refptr<IndexedDBBackingStore> backing_store, 680 scoped_refptr<IndexedDBTransaction> transaction, 681 int64 database_id, 682 int64 object_store_id, 683 const IndexedDBKey& key, 684 bool check_current) { 685 DCHECK_EQ(WebIDBKeyTypeNumber, key.type()); 686 return backing_store->MaybeUpdateKeyGeneratorCurrentNumber( 687 transaction->BackingStoreTransaction(), 688 database_id, 689 object_store_id, 690 static_cast<int64>(floor(key.number())) + 1, 691 check_current); 692} 693 694struct IndexedDBDatabase::PutOperationParams { 695 PutOperationParams() {} 696 int64 object_store_id; 697 std::string value; 698 scoped_ptr<IndexedDBKey> key; 699 IndexedDBDatabase::PutMode put_mode; 700 scoped_refptr<IndexedDBCallbacks> callbacks; 701 std::vector<int64> index_ids; 702 std::vector<IndexKeys> index_keys; 703 704 DISALLOW_COPY_AND_ASSIGN(PutOperationParams); 705}; 706 707void IndexedDBDatabase::Put(int64 transaction_id, 708 int64 object_store_id, 709 std::string* value, 710 scoped_ptr<IndexedDBKey> key, 711 PutMode put_mode, 712 scoped_refptr<IndexedDBCallbacks> callbacks, 713 const std::vector<int64>& index_ids, 714 const std::vector<IndexKeys>& index_keys) { 715 IDB_TRACE("IndexedDBDatabase::Put"); 716 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 717 if (!transaction) 718 return; 719 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY); 720 721 if (!ValidateObjectStoreId(object_store_id)) 722 return; 723 724 DCHECK(key); 725 scoped_ptr<PutOperationParams> params(new PutOperationParams()); 726 params->object_store_id = object_store_id; 727 params->value.swap(*value); 728 params->key = key.Pass(); 729 params->put_mode = put_mode; 730 params->callbacks = callbacks; 731 params->index_ids = index_ids; 732 params->index_keys = index_keys; 733 transaction->ScheduleTask(base::Bind( 734 &IndexedDBDatabase::PutOperation, this, base::Passed(¶ms))); 735} 736 737void IndexedDBDatabase::PutOperation(scoped_ptr<PutOperationParams> params, 738 IndexedDBTransaction* transaction) { 739 IDB_TRACE("IndexedDBDatabase::PutOperation"); 740 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY); 741 DCHECK_EQ(params->index_ids.size(), params->index_keys.size()); 742 bool key_was_generated = false; 743 744 DCHECK(metadata_.object_stores.find(params->object_store_id) != 745 metadata_.object_stores.end()); 746 const IndexedDBObjectStoreMetadata& object_store = 747 metadata_.object_stores[params->object_store_id]; 748 DCHECK(object_store.auto_increment || params->key->IsValid()); 749 750 scoped_ptr<IndexedDBKey> key; 751 if (params->put_mode != IndexedDBDatabase::CURSOR_UPDATE && 752 object_store.auto_increment && !params->key->IsValid()) { 753 scoped_ptr<IndexedDBKey> auto_inc_key = 754 GenerateKey(backing_store_, transaction, id(), params->object_store_id); 755 key_was_generated = true; 756 if (!auto_inc_key->IsValid()) { 757 params->callbacks->OnError( 758 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionConstraintError, 759 "Maximum key generator value reached.")); 760 return; 761 } 762 key = auto_inc_key.Pass(); 763 } else { 764 key = params->key.Pass(); 765 } 766 767 DCHECK(key->IsValid()); 768 769 IndexedDBBackingStore::RecordIdentifier record_identifier; 770 if (params->put_mode == IndexedDBDatabase::ADD_ONLY) { 771 bool found = false; 772 bool ok = backing_store_->KeyExistsInObjectStore( 773 transaction->BackingStoreTransaction(), 774 id(), 775 params->object_store_id, 776 *key, 777 &record_identifier, 778 &found); 779 if (!ok) { 780 params->callbacks->OnError( 781 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, 782 "Internal error checking key existence.")); 783 return; 784 } 785 if (found) { 786 params->callbacks->OnError( 787 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionConstraintError, 788 "Key already exists in the object store.")); 789 return; 790 } 791 } 792 793 ScopedVector<IndexWriter> index_writers; 794 string16 error_message; 795 bool obeys_constraints = false; 796 bool backing_store_success = MakeIndexWriters(transaction, 797 backing_store_.get(), 798 id(), 799 object_store, 800 *key, 801 key_was_generated, 802 params->index_ids, 803 params->index_keys, 804 &index_writers, 805 &error_message, 806 &obeys_constraints); 807 if (!backing_store_success) { 808 params->callbacks->OnError(IndexedDBDatabaseError( 809 blink::WebIDBDatabaseExceptionUnknownError, 810 "Internal error: backing store error updating index keys.")); 811 return; 812 } 813 if (!obeys_constraints) { 814 params->callbacks->OnError(IndexedDBDatabaseError( 815 blink::WebIDBDatabaseExceptionConstraintError, error_message)); 816 return; 817 } 818 819 // Before this point, don't do any mutation. After this point, rollback the 820 // transaction in case of error. 821 backing_store_success = 822 backing_store_->PutRecord(transaction->BackingStoreTransaction(), 823 id(), 824 params->object_store_id, 825 *key, 826 params->value, 827 &record_identifier); 828 if (!backing_store_success) { 829 params->callbacks->OnError(IndexedDBDatabaseError( 830 blink::WebIDBDatabaseExceptionUnknownError, 831 "Internal error: backing store error performing put/add.")); 832 return; 833 } 834 835 for (size_t i = 0; i < index_writers.size(); ++i) { 836 IndexWriter* index_writer = index_writers[i]; 837 index_writer->WriteIndexKeys(record_identifier, 838 backing_store_.get(), 839 transaction->BackingStoreTransaction(), 840 id(), 841 params->object_store_id); 842 } 843 844 if (object_store.auto_increment && 845 params->put_mode != IndexedDBDatabase::CURSOR_UPDATE && 846 key->type() == WebIDBKeyTypeNumber) { 847 bool ok = UpdateKeyGenerator(backing_store_, 848 transaction, 849 id(), 850 params->object_store_id, 851 *key, 852 !key_was_generated); 853 if (!ok) { 854 params->callbacks->OnError( 855 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, 856 "Internal error updating key generator.")); 857 return; 858 } 859 } 860 861 params->callbacks->OnSuccess(*key); 862} 863 864void IndexedDBDatabase::SetIndexKeys(int64 transaction_id, 865 int64 object_store_id, 866 scoped_ptr<IndexedDBKey> primary_key, 867 const std::vector<int64>& index_ids, 868 const std::vector<IndexKeys>& index_keys) { 869 IDB_TRACE("IndexedDBDatabase::SetIndexKeys"); 870 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 871 if (!transaction) 872 return; 873 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); 874 875 // TODO(alecflett): This method could be asynchronous, but we need to 876 // evaluate if it's worth the extra complexity. 877 IndexedDBBackingStore::RecordIdentifier record_identifier; 878 bool found = false; 879 bool ok = backing_store_->KeyExistsInObjectStore( 880 transaction->BackingStoreTransaction(), 881 metadata_.id, 882 object_store_id, 883 *primary_key, 884 &record_identifier, 885 &found); 886 if (!ok) { 887 transaction->Abort( 888 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, 889 "Internal error setting index keys.")); 890 return; 891 } 892 if (!found) { 893 transaction->Abort(IndexedDBDatabaseError( 894 blink::WebIDBDatabaseExceptionUnknownError, 895 "Internal error setting index keys for object store.")); 896 return; 897 } 898 899 ScopedVector<IndexWriter> index_writers; 900 string16 error_message; 901 bool obeys_constraints = false; 902 DCHECK(metadata_.object_stores.find(object_store_id) != 903 metadata_.object_stores.end()); 904 const IndexedDBObjectStoreMetadata& object_store_metadata = 905 metadata_.object_stores[object_store_id]; 906 bool backing_store_success = MakeIndexWriters(transaction, 907 backing_store_, 908 id(), 909 object_store_metadata, 910 *primary_key, 911 false, 912 index_ids, 913 index_keys, 914 &index_writers, 915 &error_message, 916 &obeys_constraints); 917 if (!backing_store_success) { 918 transaction->Abort(IndexedDBDatabaseError( 919 blink::WebIDBDatabaseExceptionUnknownError, 920 "Internal error: backing store error updating index keys.")); 921 return; 922 } 923 if (!obeys_constraints) { 924 transaction->Abort(IndexedDBDatabaseError( 925 blink::WebIDBDatabaseExceptionConstraintError, error_message)); 926 return; 927 } 928 929 for (size_t i = 0; i < index_writers.size(); ++i) { 930 IndexWriter* index_writer = index_writers[i]; 931 index_writer->WriteIndexKeys(record_identifier, 932 backing_store_, 933 transaction->BackingStoreTransaction(), 934 id(), 935 object_store_id); 936 } 937} 938 939void IndexedDBDatabase::SetIndexesReady(int64 transaction_id, 940 int64, 941 const std::vector<int64>& index_ids) { 942 IDB_TRACE("IndexedDBDatabase::SetIndexesReady"); 943 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 944 if (!transaction) 945 return; 946 DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE); 947 948 transaction->ScheduleTask( 949 IndexedDBDatabase::PREEMPTIVE_TASK, 950 base::Bind(&IndexedDBDatabase::SetIndexesReadyOperation, 951 this, 952 index_ids.size())); 953} 954 955void IndexedDBDatabase::SetIndexesReadyOperation( 956 size_t index_count, 957 IndexedDBTransaction* transaction) { 958 IDB_TRACE("IndexedDBDatabase::SetIndexesReadyOperation"); 959 for (size_t i = 0; i < index_count; ++i) 960 transaction->DidCompletePreemptiveEvent(); 961} 962 963struct IndexedDBDatabase::OpenCursorOperationParams { 964 OpenCursorOperationParams() {} 965 int64 object_store_id; 966 int64 index_id; 967 scoped_ptr<IndexedDBKeyRange> key_range; 968 indexed_db::CursorDirection direction; 969 indexed_db::CursorType cursor_type; 970 IndexedDBDatabase::TaskType task_type; 971 scoped_refptr<IndexedDBCallbacks> callbacks; 972 973 DISALLOW_COPY_AND_ASSIGN(OpenCursorOperationParams); 974}; 975 976void IndexedDBDatabase::OpenCursor( 977 int64 transaction_id, 978 int64 object_store_id, 979 int64 index_id, 980 scoped_ptr<IndexedDBKeyRange> key_range, 981 indexed_db::CursorDirection direction, 982 bool key_only, 983 TaskType task_type, 984 scoped_refptr<IndexedDBCallbacks> callbacks) { 985 IDB_TRACE("IndexedDBDatabase::OpenCursor"); 986 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 987 if (!transaction) 988 return; 989 990 if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id)) 991 return; 992 993 scoped_ptr<OpenCursorOperationParams> params(new OpenCursorOperationParams()); 994 params->object_store_id = object_store_id; 995 params->index_id = index_id; 996 params->key_range = key_range.Pass(); 997 params->direction = direction; 998 params->cursor_type = 999 key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE; 1000 params->task_type = task_type; 1001 params->callbacks = callbacks; 1002 transaction->ScheduleTask(base::Bind( 1003 &IndexedDBDatabase::OpenCursorOperation, this, base::Passed(¶ms))); 1004} 1005 1006void IndexedDBDatabase::OpenCursorOperation( 1007 scoped_ptr<OpenCursorOperationParams> params, 1008 IndexedDBTransaction* transaction) { 1009 IDB_TRACE("IndexedDBDatabase::OpenCursorOperation"); 1010 1011 // The frontend has begun indexing, so this pauses the transaction 1012 // until the indexing is complete. This can't happen any earlier 1013 // because we don't want to switch to early mode in case multiple 1014 // indexes are being created in a row, with Put()'s in between. 1015 if (params->task_type == IndexedDBDatabase::PREEMPTIVE_TASK) 1016 transaction->AddPreemptiveEvent(); 1017 1018 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; 1019 if (params->index_id == IndexedDBIndexMetadata::kInvalidId) { 1020 if (params->cursor_type == indexed_db::CURSOR_KEY_ONLY) { 1021 DCHECK_EQ(params->task_type, IndexedDBDatabase::NORMAL_TASK); 1022 backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor( 1023 transaction->BackingStoreTransaction(), 1024 id(), 1025 params->object_store_id, 1026 *params->key_range, 1027 params->direction); 1028 } else { 1029 backing_store_cursor = backing_store_->OpenObjectStoreCursor( 1030 transaction->BackingStoreTransaction(), 1031 id(), 1032 params->object_store_id, 1033 *params->key_range, 1034 params->direction); 1035 } 1036 } else { 1037 DCHECK_EQ(params->task_type, IndexedDBDatabase::NORMAL_TASK); 1038 if (params->cursor_type == indexed_db::CURSOR_KEY_ONLY) { 1039 backing_store_cursor = backing_store_->OpenIndexKeyCursor( 1040 transaction->BackingStoreTransaction(), 1041 id(), 1042 params->object_store_id, 1043 params->index_id, 1044 *params->key_range, 1045 params->direction); 1046 } else { 1047 backing_store_cursor = backing_store_->OpenIndexCursor( 1048 transaction->BackingStoreTransaction(), 1049 id(), 1050 params->object_store_id, 1051 params->index_id, 1052 *params->key_range, 1053 params->direction); 1054 } 1055 } 1056 1057 if (!backing_store_cursor) { 1058 params->callbacks->OnSuccess(static_cast<std::string*>(NULL)); 1059 return; 1060 } 1061 1062 scoped_refptr<IndexedDBCursor> cursor = 1063 new IndexedDBCursor(backing_store_cursor.Pass(), 1064 params->cursor_type, 1065 params->task_type, 1066 transaction); 1067 params->callbacks->OnSuccess( 1068 cursor, cursor->key(), cursor->primary_key(), cursor->Value()); 1069} 1070 1071void IndexedDBDatabase::Count(int64 transaction_id, 1072 int64 object_store_id, 1073 int64 index_id, 1074 scoped_ptr<IndexedDBKeyRange> key_range, 1075 scoped_refptr<IndexedDBCallbacks> callbacks) { 1076 IDB_TRACE("IndexedDBDatabase::Count"); 1077 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 1078 if (!transaction) 1079 return; 1080 1081 if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id)) 1082 return; 1083 1084 transaction->ScheduleTask(base::Bind(&IndexedDBDatabase::CountOperation, 1085 this, 1086 object_store_id, 1087 index_id, 1088 base::Passed(&key_range), 1089 callbacks)); 1090} 1091 1092void IndexedDBDatabase::CountOperation( 1093 int64 object_store_id, 1094 int64 index_id, 1095 scoped_ptr<IndexedDBKeyRange> key_range, 1096 scoped_refptr<IndexedDBCallbacks> callbacks, 1097 IndexedDBTransaction* transaction) { 1098 IDB_TRACE("IndexedDBDatabase::CountOperation"); 1099 uint32 count = 0; 1100 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor; 1101 1102 if (index_id == IndexedDBIndexMetadata::kInvalidId) { 1103 backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor( 1104 transaction->BackingStoreTransaction(), 1105 id(), 1106 object_store_id, 1107 *key_range, 1108 indexed_db::CURSOR_NEXT); 1109 } else { 1110 backing_store_cursor = backing_store_->OpenIndexKeyCursor( 1111 transaction->BackingStoreTransaction(), 1112 id(), 1113 object_store_id, 1114 index_id, 1115 *key_range, 1116 indexed_db::CURSOR_NEXT); 1117 } 1118 if (!backing_store_cursor) { 1119 callbacks->OnSuccess(count); 1120 return; 1121 } 1122 1123 do { 1124 ++count; 1125 } while (backing_store_cursor->Continue()); 1126 1127 callbacks->OnSuccess(count); 1128} 1129 1130void IndexedDBDatabase::DeleteRange( 1131 int64 transaction_id, 1132 int64 object_store_id, 1133 scoped_ptr<IndexedDBKeyRange> key_range, 1134 scoped_refptr<IndexedDBCallbacks> callbacks) { 1135 IDB_TRACE("IndexedDBDatabase::DeleteRange"); 1136 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 1137 if (!transaction) 1138 return; 1139 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY); 1140 1141 if (!ValidateObjectStoreId(object_store_id)) 1142 return; 1143 1144 transaction->ScheduleTask(base::Bind(&IndexedDBDatabase::DeleteRangeOperation, 1145 this, 1146 object_store_id, 1147 base::Passed(&key_range), 1148 callbacks)); 1149} 1150 1151void IndexedDBDatabase::DeleteRangeOperation( 1152 int64 object_store_id, 1153 scoped_ptr<IndexedDBKeyRange> key_range, 1154 scoped_refptr<IndexedDBCallbacks> callbacks, 1155 IndexedDBTransaction* transaction) { 1156 IDB_TRACE("IndexedDBDatabase::DeleteRangeOperation"); 1157 scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor = 1158 backing_store_->OpenObjectStoreCursor( 1159 transaction->BackingStoreTransaction(), 1160 id(), 1161 object_store_id, 1162 *key_range, 1163 indexed_db::CURSOR_NEXT); 1164 if (backing_store_cursor) { 1165 do { 1166 if (!backing_store_->DeleteRecord( 1167 transaction->BackingStoreTransaction(), 1168 id(), 1169 object_store_id, 1170 backing_store_cursor->record_identifier())) { 1171 callbacks->OnError( 1172 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, 1173 "Internal error deleting data in range")); 1174 return; 1175 } 1176 } while (backing_store_cursor->Continue()); 1177 } 1178 1179 callbacks->OnSuccess(); 1180} 1181 1182void IndexedDBDatabase::Clear(int64 transaction_id, 1183 int64 object_store_id, 1184 scoped_refptr<IndexedDBCallbacks> callbacks) { 1185 IDB_TRACE("IndexedDBDatabase::Clear"); 1186 IndexedDBTransaction* transaction = GetTransaction(transaction_id); 1187 if (!transaction) 1188 return; 1189 DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY); 1190 1191 if (!ValidateObjectStoreId(object_store_id)) 1192 return; 1193 1194 transaction->ScheduleTask(base::Bind( 1195 &IndexedDBDatabase::ClearOperation, this, object_store_id, callbacks)); 1196} 1197 1198void IndexedDBDatabase::ClearOperation( 1199 int64 object_store_id, 1200 scoped_refptr<IndexedDBCallbacks> callbacks, 1201 IndexedDBTransaction* transaction) { 1202 IDB_TRACE("IndexedDBDatabase::ObjectStoreClearOperation"); 1203 if (!backing_store_->ClearObjectStore( 1204 transaction->BackingStoreTransaction(), id(), object_store_id)) { 1205 callbacks->OnError( 1206 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, 1207 "Internal error clearing object store")); 1208 return; 1209 } 1210 callbacks->OnSuccess(); 1211} 1212 1213void IndexedDBDatabase::DeleteObjectStoreOperation( 1214 const IndexedDBObjectStoreMetadata& object_store_metadata, 1215 IndexedDBTransaction* transaction) { 1216 IDB_TRACE("IndexedDBDatabase::DeleteObjectStoreOperation"); 1217 bool ok = 1218 backing_store_->DeleteObjectStore(transaction->BackingStoreTransaction(), 1219 transaction->database()->id(), 1220 object_store_metadata.id); 1221 if (!ok) { 1222 string16 error_string = 1223 ASCIIToUTF16("Internal error deleting object store '") + 1224 object_store_metadata.name + ASCIIToUTF16("'."); 1225 transaction->Abort(IndexedDBDatabaseError( 1226 blink::WebIDBDatabaseExceptionUnknownError, error_string)); 1227 } 1228} 1229 1230void IndexedDBDatabase::VersionChangeOperation( 1231 int64 version, 1232 scoped_refptr<IndexedDBCallbacks> callbacks, 1233 scoped_ptr<IndexedDBConnection> connection, 1234 blink::WebIDBDataLoss data_loss, 1235 std::string data_loss_message, 1236 IndexedDBTransaction* transaction) { 1237 IDB_TRACE("IndexedDBDatabase::VersionChangeOperation"); 1238 int64 old_version = metadata_.int_version; 1239 DCHECK_GT(version, old_version); 1240 metadata_.int_version = version; 1241 if (!backing_store_->UpdateIDBDatabaseIntVersion( 1242 transaction->BackingStoreTransaction(), 1243 id(), 1244 metadata_.int_version)) { 1245 IndexedDBDatabaseError error( 1246 blink::WebIDBDatabaseExceptionUnknownError, 1247 ASCIIToUTF16( 1248 "Internal error writing data to stable storage when " 1249 "updating version.")); 1250 callbacks->OnError(error); 1251 transaction->Abort(error); 1252 return; 1253 } 1254 DCHECK(!pending_second_half_open_); 1255 pending_second_half_open_.reset( 1256 new PendingSuccessCall(callbacks, connection.get(), version)); 1257 callbacks->OnUpgradeNeeded( 1258 old_version, connection.Pass(), metadata(), data_loss, data_loss_message); 1259} 1260 1261void IndexedDBDatabase::TransactionStarted(IndexedDBTransaction* transaction) { 1262 1263 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { 1264 DCHECK(!running_version_change_transaction_); 1265 running_version_change_transaction_ = transaction; 1266 } 1267} 1268 1269void IndexedDBDatabase::TransactionFinished(IndexedDBTransaction* transaction) { 1270 1271 DCHECK(transactions_.find(transaction->id()) != transactions_.end()); 1272 DCHECK_EQ(transactions_[transaction->id()], transaction); 1273 transactions_.erase(transaction->id()); 1274 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { 1275 DCHECK_EQ(transaction, running_version_change_transaction_); 1276 running_version_change_transaction_ = NULL; 1277 } 1278} 1279 1280void IndexedDBDatabase::TransactionFinishedAndAbortFired( 1281 IndexedDBTransaction* transaction) { 1282 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { 1283 if (pending_second_half_open_) { 1284 pending_second_half_open_->Callbacks()->OnError( 1285 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError, 1286 "Version change transaction was aborted in " 1287 "upgradeneeded event handler.")); 1288 pending_second_half_open_.reset(); 1289 } 1290 ProcessPendingCalls(); 1291 } 1292} 1293 1294void IndexedDBDatabase::TransactionFinishedAndCompleteFired( 1295 IndexedDBTransaction* transaction) { 1296 if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) { 1297 DCHECK(pending_second_half_open_); 1298 if (pending_second_half_open_) { 1299 DCHECK_EQ(pending_second_half_open_->Version(), metadata_.int_version); 1300 DCHECK(metadata_.id != kInvalidId); 1301 1302 // Connection was already minted for OnUpgradeNeeded callback. 1303 scoped_ptr<IndexedDBConnection> connection; 1304 1305 pending_second_half_open_->Callbacks()->OnSuccess(connection.Pass(), 1306 this->metadata()); 1307 pending_second_half_open_.reset(); 1308 } 1309 ProcessPendingCalls(); 1310 } 1311} 1312 1313void IndexedDBDatabase::TransactionCommitFailed() { 1314 factory_->HandleBackingStoreFailure(backing_store_->origin_url()); 1315} 1316 1317size_t IndexedDBDatabase::ConnectionCount() const { 1318 // This does not include pending open calls, as those should not block version 1319 // changes and deletes. 1320 return connections_.size(); 1321} 1322 1323size_t IndexedDBDatabase::PendingOpenCount() const { 1324 return pending_open_calls_.size(); 1325} 1326 1327size_t IndexedDBDatabase::PendingUpgradeCount() const { 1328 return pending_run_version_change_transaction_call_ ? 1 : 0; 1329} 1330 1331size_t IndexedDBDatabase::RunningUpgradeCount() const { 1332 return pending_second_half_open_ ? 1 : 0; 1333} 1334 1335size_t IndexedDBDatabase::PendingDeleteCount() const { 1336 return pending_delete_calls_.size(); 1337} 1338 1339void IndexedDBDatabase::ProcessPendingCalls() { 1340 if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) { 1341 DCHECK(pending_run_version_change_transaction_call_->Version() > 1342 metadata_.int_version); 1343 scoped_ptr<PendingUpgradeCall> pending_call = 1344 pending_run_version_change_transaction_call_.Pass(); 1345 RunVersionChangeTransactionFinal(pending_call->Callbacks(), 1346 pending_call->Connection(), 1347 pending_call->TransactionId(), 1348 pending_call->Version()); 1349 DCHECK_EQ(static_cast<size_t>(1), ConnectionCount()); 1350 // Fall through would be a no-op, since transaction must complete 1351 // asynchronously. 1352 DCHECK(IsDeleteDatabaseBlocked()); 1353 DCHECK(IsOpenConnectionBlocked()); 1354 return; 1355 } 1356 1357 if (!IsDeleteDatabaseBlocked()) { 1358 PendingDeleteCallList pending_delete_calls; 1359 pending_delete_calls_.swap(pending_delete_calls); 1360 while (!pending_delete_calls.empty()) { 1361 // Only the first delete call will delete the database, but each must fire 1362 // callbacks. 1363 scoped_ptr<PendingDeleteCall> pending_delete_call( 1364 pending_delete_calls.front()); 1365 pending_delete_calls.pop_front(); 1366 DeleteDatabaseFinal(pending_delete_call->Callbacks()); 1367 } 1368 // delete_database_final should never re-queue calls. 1369 DCHECK(pending_delete_calls_.empty()); 1370 // Fall through when complete, as pending opens may be unblocked. 1371 } 1372 1373 if (!IsOpenConnectionBlocked()) { 1374 PendingOpenCallList pending_open_calls; 1375 pending_open_calls_.swap(pending_open_calls); 1376 while (!pending_open_calls.empty()) { 1377 scoped_ptr<PendingOpenCall> pending_open_call(pending_open_calls.front()); 1378 pending_open_calls.pop_front(); 1379 OpenConnection(pending_open_call->Callbacks(), 1380 pending_open_call->DatabaseCallbacks(), 1381 pending_open_call->TransactionId(), 1382 pending_open_call->Version()); 1383 } 1384 } 1385} 1386 1387void IndexedDBDatabase::CreateTransaction( 1388 int64 transaction_id, 1389 IndexedDBConnection* connection, 1390 const std::vector<int64>& object_store_ids, 1391 uint16 mode) { 1392 1393 DCHECK(connections_.count(connection)); 1394 DCHECK(transactions_.find(transaction_id) == transactions_.end()); 1395 if (transactions_.find(transaction_id) != transactions_.end()) 1396 return; 1397 1398 scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction( 1399 transaction_id, 1400 connection->callbacks(), 1401 std::set<int64>(object_store_ids.begin(), object_store_ids.end()), 1402 static_cast<indexed_db::TransactionMode>(mode), 1403 this); 1404 transactions_[transaction_id] = transaction; 1405} 1406 1407bool IndexedDBDatabase::IsOpenConnectionBlocked() const { 1408 return !pending_delete_calls_.empty() || 1409 running_version_change_transaction_ || 1410 pending_run_version_change_transaction_call_; 1411} 1412 1413void IndexedDBDatabase::OpenConnection( 1414 scoped_refptr<IndexedDBCallbacks> callbacks, 1415 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, 1416 int64 transaction_id, 1417 int64 version) { 1418 const blink::WebIDBDataLoss kDataLoss = 1419 blink::WebIDBDataLossNone; 1420 OpenConnection( 1421 callbacks, database_callbacks, transaction_id, version, kDataLoss, ""); 1422} 1423 1424void IndexedDBDatabase::OpenConnection( 1425 scoped_refptr<IndexedDBCallbacks> callbacks, 1426 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, 1427 int64 transaction_id, 1428 int64 version, 1429 blink::WebIDBDataLoss data_loss, 1430 std::string data_loss_message) { 1431 DCHECK(backing_store_); 1432 1433 // TODO(jsbell): Should have a priority queue so that higher version 1434 // requests are processed first. http://crbug.com/225850 1435 if (IsOpenConnectionBlocked()) { 1436 // The backing store only detects data loss when it is first opened. The 1437 // presence of existing connections means we didn't even check for data loss 1438 // so there'd better not be any. 1439 DCHECK_NE(blink::WebIDBDataLossTotal, data_loss); 1440 pending_open_calls_.push_back(new PendingOpenCall( 1441 callbacks, database_callbacks, transaction_id, version)); 1442 return; 1443 } 1444 1445 if (metadata_.id == kInvalidId) { 1446 // The database was deleted then immediately re-opened; OpenInternal() 1447 // recreates it in the backing store. 1448 if (OpenInternal()) { 1449 DCHECK_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION, 1450 metadata_.int_version); 1451 } else { 1452 string16 message; 1453 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION) 1454 message = ASCIIToUTF16( 1455 "Internal error opening database with no version specified."); 1456 else 1457 message = 1458 ASCIIToUTF16("Internal error opening database with version ") + 1459 Int64ToString16(version); 1460 callbacks->OnError(IndexedDBDatabaseError( 1461 blink::WebIDBDatabaseExceptionUnknownError, message)); 1462 return; 1463 } 1464 } 1465 1466 // We infer that the database didn't exist from its lack of either type of 1467 // version. 1468 bool is_new_database = 1469 metadata_.version == kNoStringVersion && 1470 metadata_.int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION; 1471 1472 scoped_ptr<IndexedDBConnection> connection( 1473 new IndexedDBConnection(this, database_callbacks)); 1474 1475 if (version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) { 1476 // For unit tests only - skip upgrade steps. Calling from script with 1477 // DEFAULT_INT_VERSION throws exception. 1478 // TODO(jsbell): DCHECK that not in unit tests. 1479 DCHECK(is_new_database); 1480 connections_.insert(connection.get()); 1481 callbacks->OnSuccess(connection.Pass(), this->metadata()); 1482 return; 1483 } 1484 1485 if (version == IndexedDBDatabaseMetadata::NO_INT_VERSION) { 1486 if (!is_new_database) { 1487 connections_.insert(connection.get()); 1488 callbacks->OnSuccess(connection.Pass(), this->metadata()); 1489 return; 1490 } 1491 // Spec says: If no version is specified and no database exists, set 1492 // database version to 1. 1493 version = 1; 1494 } 1495 1496 if (version > metadata_.int_version) { 1497 connections_.insert(connection.get()); 1498 RunVersionChangeTransaction(callbacks, 1499 connection.Pass(), 1500 transaction_id, 1501 version, 1502 data_loss, 1503 data_loss_message); 1504 return; 1505 } 1506 if (version < metadata_.int_version) { 1507 callbacks->OnError(IndexedDBDatabaseError( 1508 blink::WebIDBDatabaseExceptionVersionError, 1509 ASCIIToUTF16("The requested version (") + Int64ToString16(version) + 1510 ASCIIToUTF16(") is less than the existing version (") + 1511 Int64ToString16(metadata_.int_version) + ASCIIToUTF16(")."))); 1512 return; 1513 } 1514 DCHECK_EQ(version, metadata_.int_version); 1515 connections_.insert(connection.get()); 1516 callbacks->OnSuccess(connection.Pass(), this->metadata()); 1517} 1518 1519void IndexedDBDatabase::RunVersionChangeTransaction( 1520 scoped_refptr<IndexedDBCallbacks> callbacks, 1521 scoped_ptr<IndexedDBConnection> connection, 1522 int64 transaction_id, 1523 int64 requested_version, 1524 blink::WebIDBDataLoss data_loss, 1525 std::string data_loss_message) { 1526 1527 DCHECK(callbacks); 1528 DCHECK(connections_.count(connection.get())); 1529 if (ConnectionCount() > 1) { 1530 DCHECK_NE(blink::WebIDBDataLossTotal, data_loss); 1531 // Front end ensures the event is not fired at connections that have 1532 // close_pending set. 1533 for (ConnectionSet::const_iterator it = connections_.begin(); 1534 it != connections_.end(); 1535 ++it) { 1536 if (*it != connection.get()) { 1537 (*it)->callbacks()->OnVersionChange(metadata_.int_version, 1538 requested_version); 1539 } 1540 } 1541 // TODO(jsbell): Remove the call to OnBlocked and instead wait 1542 // until the frontend tells us that all the "versionchange" events 1543 // have been delivered. http://crbug.com/100123 1544 callbacks->OnBlocked(metadata_.int_version); 1545 1546 DCHECK(!pending_run_version_change_transaction_call_); 1547 pending_run_version_change_transaction_call_.reset(new PendingUpgradeCall( 1548 callbacks, connection.Pass(), transaction_id, requested_version)); 1549 return; 1550 } 1551 RunVersionChangeTransactionFinal(callbacks, 1552 connection.Pass(), 1553 transaction_id, 1554 requested_version, 1555 data_loss, 1556 data_loss_message); 1557} 1558 1559void IndexedDBDatabase::RunVersionChangeTransactionFinal( 1560 scoped_refptr<IndexedDBCallbacks> callbacks, 1561 scoped_ptr<IndexedDBConnection> connection, 1562 int64 transaction_id, 1563 int64 requested_version) { 1564 const blink::WebIDBDataLoss kDataLoss = 1565 blink::WebIDBDataLossNone; 1566 RunVersionChangeTransactionFinal(callbacks, 1567 connection.Pass(), 1568 transaction_id, 1569 requested_version, 1570 kDataLoss, 1571 ""); 1572} 1573 1574void IndexedDBDatabase::RunVersionChangeTransactionFinal( 1575 scoped_refptr<IndexedDBCallbacks> callbacks, 1576 scoped_ptr<IndexedDBConnection> connection, 1577 int64 transaction_id, 1578 int64 requested_version, 1579 blink::WebIDBDataLoss data_loss, 1580 std::string data_loss_message) { 1581 1582 std::vector<int64> object_store_ids; 1583 CreateTransaction(transaction_id, 1584 connection.get(), 1585 object_store_ids, 1586 indexed_db::TRANSACTION_VERSION_CHANGE); 1587 scoped_refptr<IndexedDBTransaction> transaction = 1588 transactions_[transaction_id]; 1589 1590 transaction->ScheduleTask( 1591 base::Bind(&IndexedDBDatabase::VersionChangeOperation, 1592 this, 1593 requested_version, 1594 callbacks, 1595 base::Passed(&connection), 1596 data_loss, 1597 data_loss_message), 1598 base::Bind(&IndexedDBDatabase::VersionChangeAbortOperation, 1599 this, 1600 metadata_.version, 1601 metadata_.int_version)); 1602 1603 DCHECK(!pending_second_half_open_); 1604} 1605 1606void IndexedDBDatabase::DeleteDatabase( 1607 scoped_refptr<IndexedDBCallbacks> callbacks) { 1608 1609 if (IsDeleteDatabaseBlocked()) { 1610 for (ConnectionSet::const_iterator it = connections_.begin(); 1611 it != connections_.end(); 1612 ++it) { 1613 // Front end ensures the event is not fired at connections that have 1614 // close_pending set. 1615 (*it)->callbacks()->OnVersionChange( 1616 metadata_.int_version, IndexedDBDatabaseMetadata::NO_INT_VERSION); 1617 } 1618 // TODO(jsbell): Only fire OnBlocked if there are open 1619 // connections after the VersionChangeEvents are received, not 1620 // just set up to fire. http://crbug.com/100123 1621 callbacks->OnBlocked(metadata_.int_version); 1622 pending_delete_calls_.push_back(new PendingDeleteCall(callbacks)); 1623 return; 1624 } 1625 DeleteDatabaseFinal(callbacks); 1626} 1627 1628bool IndexedDBDatabase::IsDeleteDatabaseBlocked() const { 1629 return !!ConnectionCount(); 1630} 1631 1632void IndexedDBDatabase::DeleteDatabaseFinal( 1633 scoped_refptr<IndexedDBCallbacks> callbacks) { 1634 DCHECK(!IsDeleteDatabaseBlocked()); 1635 DCHECK(backing_store_); 1636 if (!backing_store_->DeleteDatabase(metadata_.name)) { 1637 callbacks->OnError( 1638 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, 1639 "Internal error deleting database.")); 1640 return; 1641 } 1642 metadata_.version = kNoStringVersion; 1643 metadata_.id = kInvalidId; 1644 metadata_.int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION; 1645 metadata_.object_stores.clear(); 1646 callbacks->OnSuccess(); 1647} 1648 1649void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) { 1650 DCHECK(connections_.count(connection)); 1651 DCHECK(connection->IsConnected()); 1652 DCHECK(connection->database() == this); 1653 1654 // Abort outstanding transactions from the closing connection. This 1655 // can not happen if the close is requested by the connection itself 1656 // as the front-end defers the close until all transactions are 1657 // complete, but can occur on process termination or forced close. 1658 { 1659 TransactionMap transactions(transactions_); 1660 for (TransactionMap::const_iterator it = transactions.begin(), 1661 end = transactions.end(); 1662 it != end; 1663 ++it) { 1664 if (it->second->connection() == connection->callbacks()) 1665 it->second->Abort( 1666 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, 1667 "Connection is closing.")); 1668 } 1669 } 1670 1671 connections_.erase(connection); 1672 if (pending_second_half_open_ && 1673 pending_second_half_open_->Connection() == connection) { 1674 pending_second_half_open_->Callbacks()->OnError( 1675 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError, 1676 "The connection was closed.")); 1677 pending_second_half_open_.reset(); 1678 } 1679 1680 ProcessPendingCalls(); 1681 1682 // TODO(jsbell): Add a test for the pending_open_calls_ cases below. 1683 if (!ConnectionCount() && !pending_open_calls_.size() && 1684 !pending_delete_calls_.size()) { 1685 DCHECK(transactions_.empty()); 1686 1687 const GURL origin_url = backing_store_->origin_url(); 1688 backing_store_ = NULL; 1689 1690 // factory_ should only be null in unit tests. 1691 // TODO(jsbell): DCHECK(factory_ || !in_unit_tests) - somehow. 1692 if (factory_) { 1693 factory_->ReleaseDatabase(identifier_, origin_url, forced); 1694 factory_ = NULL; 1695 } 1696 } 1697} 1698 1699void IndexedDBDatabase::CreateObjectStoreAbortOperation( 1700 int64 object_store_id, 1701 IndexedDBTransaction* transaction) { 1702 IDB_TRACE("IndexedDBDatabase::CreateObjectStoreAbortOperation"); 1703 DCHECK(!transaction); 1704 RemoveObjectStore(object_store_id); 1705} 1706 1707void IndexedDBDatabase::DeleteObjectStoreAbortOperation( 1708 const IndexedDBObjectStoreMetadata& object_store_metadata, 1709 IndexedDBTransaction* transaction) { 1710 IDB_TRACE("IndexedDBDatabase::DeleteObjectStoreAbortOperation"); 1711 DCHECK(!transaction); 1712 AddObjectStore(object_store_metadata, 1713 IndexedDBObjectStoreMetadata::kInvalidId); 1714} 1715 1716void IndexedDBDatabase::VersionChangeAbortOperation( 1717 const string16& previous_version, 1718 int64 previous_int_version, 1719 IndexedDBTransaction* transaction) { 1720 IDB_TRACE("IndexedDBDatabase::VersionChangeAbortOperation"); 1721 DCHECK(!transaction); 1722 metadata_.version = previous_version; 1723 metadata_.int_version = previous_int_version; 1724} 1725 1726} // namespace content 1727