Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/indexed_db/indexed_db_database.h" | 5 #include "content/browser/indexed_db/indexed_db_database.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include <limits> | 9 #include <limits> |
| 10 #include <memory> | 10 #include <memory> |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 70 return KEY_PATH_TYPE_STRING; | 70 return KEY_PATH_TYPE_STRING; |
| 71 case blink::WebIDBKeyPathTypeArray: | 71 case blink::WebIDBKeyPathTypeArray: |
| 72 return KEY_PATH_TYPE_ARRAY; | 72 return KEY_PATH_TYPE_ARRAY; |
| 73 } | 73 } |
| 74 NOTREACHED(); | 74 NOTREACHED(); |
| 75 return KEY_PATH_TYPE_NONE; | 75 return KEY_PATH_TYPE_NONE; |
| 76 } | 76 } |
| 77 | 77 |
| 78 } // namespace | 78 } // namespace |
| 79 | 79 |
| 80 // PendingUpgradeCall has a std::unique_ptr<IndexedDBConnection> because it owns | 80 // This represents what script calls an 'IDBOpenDBRequest' - either a database |
| 81 // the | 81 // open or delete call. These may be blocked on other connections. After every |
| 82 // in-progress connection. | 82 // callback, the request must call IndexedDBDatabase::RequestComplete() or be |
| 83 class IndexedDBDatabase::PendingUpgradeCall { | 83 // expecting a further callback. |
| 84 class IndexedDBDatabase::OpenOrDeleteRequest { | |
| 84 public: | 85 public: |
| 85 PendingUpgradeCall(scoped_refptr<IndexedDBCallbacks> callbacks, | 86 explicit OpenOrDeleteRequest(scoped_refptr<IndexedDBDatabase> db) : db_(db) {} |
| 86 std::unique_ptr<IndexedDBConnection> connection, | 87 |
| 87 int64_t transaction_id, | 88 virtual ~OpenOrDeleteRequest() {} |
| 88 int64_t version) | 89 |
| 89 : callbacks_(callbacks), | 90 // Called when the request makes it to the front of the queue. |
| 90 connection_(std::move(connection)), | 91 virtual void Perform() = 0; |
| 91 version_(version), | 92 |
| 92 transaction_id_(transaction_id) {} | 93 // Called if a front-end signals that it is ignoring a "versionchange" |
| 93 scoped_refptr<IndexedDBCallbacks> callbacks() const { return callbacks_; } | 94 // event. This should result in firing a "blocked" event at the request. |
| 94 // Takes ownership of the connection object. | 95 virtual void OnVersionChangeIgnored() const = 0; |
| 95 std::unique_ptr<IndexedDBConnection> ReleaseConnection() WARN_UNUSED_RESULT { | 96 |
| 96 return std::move(connection_); | 97 // Called when a connection is closed; if it corresponds to this connection, |
| 97 } | 98 // need to do cleanup. Otherwise, it may unblock further steps. |
| 98 int64_t version() const { return version_; } | 99 virtual void OnConnectionClosed(IndexedDBConnection* connection) = 0; |
| 99 int64_t transaction_id() const { return transaction_id_; } | 100 |
| 101 // Called when the upgrade transaction has started executing. | |
| 102 virtual void UpgradeTransactionStarted(int64_t old_version) = 0; | |
| 103 | |
| 104 // Called when the upgrade transaction has finished. | |
| 105 virtual void UpgradeTransactionFinished(bool committed) = 0; | |
| 106 | |
| 107 protected: | |
| 108 scoped_refptr<IndexedDBDatabase> db_; | |
| 109 | |
| 110 private: | |
| 111 DISALLOW_COPY_AND_ASSIGN(OpenOrDeleteRequest); | |
| 112 }; | |
| 113 | |
| 114 class IndexedDBDatabase::OpenRequest | |
| 115 : public IndexedDBDatabase::OpenOrDeleteRequest { | |
| 116 public: | |
| 117 OpenRequest(scoped_refptr<IndexedDBDatabase> db, | |
| 118 const IndexedDBPendingConnection& pending_connection) | |
| 119 : OpenOrDeleteRequest(db), | |
| 120 child_process_id_(pending_connection.child_process_id), | |
| 121 transaction_id_(pending_connection.transaction_id), | |
| 122 version_(pending_connection.version), | |
| 123 callbacks_(pending_connection.callbacks), | |
| 124 database_callbacks_(pending_connection.database_callbacks) {} | |
| 125 | |
| 126 void Perform() override { | |
| 127 if (db_->metadata_.id == kInvalidId) { | |
| 128 // The database was deleted then immediately re-opened; OpenInternal() | |
| 129 // recreates it in the backing store. | |
| 130 if (!db_->OpenInternal().ok()) { | |
|
cmumford
2016/07/15 14:55:36
We're throwing away the message in leveldb::Status
jsbell
2016/07/15 17:22:22
Behavior change, making that a TODO.
| |
| 131 base::string16 message; | |
| 132 if (version_ == IndexedDBDatabaseMetadata::NO_VERSION) { | |
| 133 message = ASCIIToUTF16( | |
| 134 "Internal error opening database with no version specified."); | |
| 135 } else { | |
| 136 message = | |
| 137 ASCIIToUTF16("Internal error opening database with version ") + | |
| 138 Int64ToString16(version_); | |
| 139 } | |
| 140 callbacks_->OnError(IndexedDBDatabaseError( | |
| 141 blink::WebIDBDatabaseExceptionUnknownError, message)); | |
| 142 db_->RequestComplete(this); | |
| 143 return; | |
| 144 } | |
| 145 | |
| 146 DCHECK_EQ(IndexedDBDatabaseMetadata::NO_VERSION, db_->metadata_.version); | |
| 147 } | |
| 148 | |
| 149 const int64_t old_version = db_->metadata_.version; | |
| 150 int64_t& new_version = version_; | |
| 151 | |
| 152 bool is_new_database = old_version == IndexedDBDatabaseMetadata::NO_VERSION; | |
| 153 | |
| 154 if (new_version == IndexedDBDatabaseMetadata::DEFAULT_VERSION) { | |
| 155 // For unit tests only - skip upgrade steps. (Calling from script with | |
| 156 // DEFAULT_VERSION throws exception.) | |
| 157 DCHECK(is_new_database); | |
| 158 callbacks_->OnSuccess( | |
| 159 db_->CreateConnection(database_callbacks_, child_process_id_), | |
| 160 db_->metadata_); | |
| 161 db_->RequestComplete(this); | |
| 162 return; | |
| 163 } | |
| 164 | |
| 165 // Database already exists and either requested version is equal to | |
|
cmumford
2016/07/15 14:55:36
The comment is a restatement of the if (...) condi
jsbell
2016/07/15 17:22:22
Removed.
| |
| 166 // current version or no version was specified: no upgrade needed. | |
| 167 if (!is_new_database && | |
| 168 (new_version == old_version || | |
| 169 new_version == IndexedDBDatabaseMetadata::NO_VERSION)) { | |
| 170 callbacks_->OnSuccess( | |
| 171 db_->CreateConnection(database_callbacks_, child_process_id_), | |
| 172 db_->metadata_); | |
| 173 db_->RequestComplete(this); | |
| 174 return; | |
| 175 } | |
| 176 | |
| 177 if (new_version == IndexedDBDatabaseMetadata::NO_VERSION) { | |
| 178 // If no version is specified and no database exists, upgrade the | |
| 179 // database version to 1. | |
| 180 DCHECK(is_new_database); | |
| 181 new_version = 1; | |
| 182 } else if (new_version < old_version) { | |
| 183 // Requested version is lower than current version - fail the request. | |
| 184 DCHECK(!is_new_database); | |
| 185 callbacks_->OnError(IndexedDBDatabaseError( | |
| 186 blink::WebIDBDatabaseExceptionVersionError, | |
| 187 ASCIIToUTF16("The requested version (") + Int64ToString16(version_) + | |
| 188 ASCIIToUTF16(") is less than the existing version (") + | |
| 189 Int64ToString16(db_->metadata_.version) + ASCIIToUTF16(")."))); | |
| 190 db_->RequestComplete(this); | |
| 191 return; | |
| 192 } | |
| 193 | |
| 194 // Requested version is higher than current version - upgrade needed. | |
| 195 DCHECK_GT(new_version, old_version); | |
| 196 | |
| 197 if (db_->connections_.empty()) { | |
| 198 StartUpgrade(); | |
| 199 return; | |
| 200 } | |
| 201 | |
| 202 // There are outstanding connections - fire "versionchange" events and | |
| 203 // wait for the connections to close. Front end ensures the event is not | |
| 204 // fired at connections that have close_pending set. A "blocked" event | |
| 205 // will be fired at the request when one of the connections acks that the | |
| 206 // "versionchange" event was ignored. | |
| 207 DCHECK_NE(callbacks_->data_loss_info().status, blink::WebIDBDataLossTotal); | |
| 208 for (const auto* connection : db_->connections_) | |
| 209 connection->callbacks()->OnVersionChange(old_version, new_version); | |
| 210 | |
| 211 // When all connections have closed the upgrade can proceed. | |
| 212 } | |
| 213 | |
| 214 void OnVersionChangeIgnored() const override { | |
| 215 callbacks_->OnBlocked(db_->metadata_.version); | |
| 216 } | |
| 217 | |
| 218 void OnConnectionClosed(IndexedDBConnection* connection) override { | |
| 219 // This connection closed prematurely; signal an error and complete. | |
| 220 if (connection && connection->callbacks() == database_callbacks_) { | |
| 221 callbacks_->OnError( | |
| 222 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError, | |
| 223 "The connection was closed.")); | |
| 224 db_->RequestComplete(this); | |
| 225 return; | |
| 226 } | |
| 227 | |
| 228 if (!db_->connections_.empty()) | |
| 229 return; | |
| 230 | |
| 231 StartUpgrade(); | |
| 232 } | |
| 233 | |
| 234 // Initiate the upgrade. The bulk of the work actually happens in | |
| 235 // IndexedDBDatabase::VersionChangeOperation in order to kick the | |
| 236 // transaction into the correct state. | |
| 237 void StartUpgrade() { | |
| 238 connection_ = db_->CreateConnection(database_callbacks_, child_process_id_); | |
| 239 DCHECK_EQ(db_->connections_.count(connection_.get()), 1UL); | |
| 240 | |
| 241 std::vector<int64_t> object_store_ids; | |
| 242 IndexedDBTransaction* transaction = db_->CreateTransaction( | |
| 243 transaction_id_, connection_.get(), object_store_ids, | |
| 244 blink::WebIDBTransactionModeVersionChange); | |
| 245 | |
| 246 DCHECK(db_->transaction_coordinator_.IsRunningVersionChangeTransaction()); | |
| 247 transaction->ScheduleTask(base::Bind( | |
| 248 &IndexedDBDatabase::VersionChangeOperation, db_, version_, callbacks_)); | |
| 249 } | |
| 250 | |
| 251 // Called when the upgrade transaction has started executing. | |
| 252 void UpgradeTransactionStarted(int64_t old_version) override { | |
| 253 DCHECK(connection_); | |
| 254 callbacks_->OnUpgradeNeeded(old_version, std::move(connection_), | |
| 255 db_->metadata_); | |
| 256 } | |
| 257 | |
| 258 void UpgradeTransactionFinished(bool committed) override { | |
| 259 // Ownership of connection was already pased along in OnUpgradeNeeded. | |
|
cmumford
2016/07/15 14:55:36
s/pased/passed/
jsbell
2016/07/15 17:22:22
Done.
| |
| 260 DCHECK(!connection_); | |
| 261 | |
| 262 if (committed) { | |
| 263 DCHECK_EQ(version_, db_->metadata_.version); | |
| 264 callbacks_->OnSuccess(std::unique_ptr<IndexedDBConnection>(), | |
| 265 db_->metadata()); | |
| 266 } else { | |
| 267 DCHECK_NE(version_, db_->metadata_.version); | |
| 268 callbacks_->OnError( | |
| 269 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError, | |
| 270 "Version change transaction was aborted in " | |
| 271 "upgradeneeded event handler.")); | |
| 272 } | |
| 273 db_->RequestComplete(this); | |
| 274 } | |
| 275 | |
| 276 private: | |
| 277 const int child_process_id_; | |
|
cmumford
2016/07/15 14:55:36
This class is passed (in the constructor) a Indexe
jsbell
2016/07/15 17:22:22
Done.
| |
| 278 const int64_t transaction_id_; | |
| 279 int64_t version_; | |
| 280 scoped_refptr<IndexedDBCallbacks> callbacks_; | |
| 281 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks_; | |
| 282 | |
| 283 // If an upgrade is needed, holds the pending connection until ownership is | |
| 284 // transferred to the IndexedDBDispatcherHost via OnUpgradeNeeded. | |
| 285 std::unique_ptr<IndexedDBConnection> connection_; | |
| 286 | |
| 287 DISALLOW_COPY_AND_ASSIGN(OpenRequest); | |
| 288 }; | |
| 289 | |
| 290 class IndexedDBDatabase::DeleteRequest | |
| 291 : public IndexedDBDatabase::OpenOrDeleteRequest { | |
| 292 public: | |
| 293 DeleteRequest(scoped_refptr<IndexedDBDatabase> db, | |
| 294 scoped_refptr<IndexedDBCallbacks> callbacks) | |
| 295 : OpenOrDeleteRequest(db), callbacks_(callbacks) {} | |
| 296 | |
| 297 void Perform() override { | |
| 298 if (db_->connections_.empty()) { | |
| 299 // No connections, so delete immediately. | |
| 300 DoDelete(); | |
| 301 return; | |
| 302 } | |
| 303 | |
| 304 // Front end ensures the event is not fired at connections that have | |
| 305 // close_pending set. | |
| 306 const int64_t old_version = db_->metadata_.version; | |
| 307 const int64_t new_version = IndexedDBDatabaseMetadata::NO_VERSION; | |
| 308 DCHECK_NE(callbacks_->data_loss_info().status, blink::WebIDBDataLossTotal); | |
| 309 for (const auto* connection : db_->connections_) | |
| 310 connection->callbacks()->OnVersionChange(old_version, new_version); | |
| 311 } | |
| 312 | |
| 313 void OnVersionChangeIgnored() const override { | |
| 314 callbacks_->OnBlocked(db_->metadata_.version); | |
| 315 } | |
| 316 | |
| 317 void OnConnectionClosed(IndexedDBConnection* connection) override { | |
| 318 if (!db_->connections_.empty()) | |
| 319 return; | |
| 320 DoDelete(); | |
| 321 } | |
| 322 | |
| 323 void DoDelete() { | |
| 324 leveldb::Status s = | |
| 325 db_->backing_store_->DeleteDatabase(db_->metadata_.name); | |
| 326 if (!s.ok()) { | |
| 327 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, | |
| 328 "Internal error deleting database."); | |
|
cmumford
2016/07/15 14:55:36
Can we sanitize and use message from |s|?
jsbell
2016/07/15 17:22:22
Added a TODO.
| |
| 329 callbacks_->OnError(error); | |
| 330 if (s.IsCorruption()) { | |
| 331 url::Origin origin = db_->backing_store_->origin(); | |
| 332 db_->backing_store_ = NULL; | |
|
cmumford
2016/07/15 14:55:36
nullptr
jsbell
2016/07/15 17:22:22
Done.
| |
| 333 db_->factory_->HandleBackingStoreCorruption(origin, error); | |
| 334 } | |
| 335 db_->RequestComplete(this); | |
| 336 return; | |
| 337 } | |
| 338 | |
| 339 int64_t old_version = db_->metadata_.version; | |
| 340 db_->metadata_.id = kInvalidId; | |
| 341 db_->metadata_.version = IndexedDBDatabaseMetadata::NO_VERSION; | |
| 342 db_->metadata_.object_stores.clear(); | |
|
cmumford
2016/07/15 14:55:36
Reset max_object_store_id?
jsbell
2016/07/15 17:22:22
Interesting that this wasn't done before. Done!
| |
| 343 callbacks_->OnSuccess(old_version); | |
| 344 db_->factory_->DatabaseDeleted(db_->identifier_); | |
| 345 | |
| 346 db_->RequestComplete(this); | |
| 347 } | |
| 348 | |
| 349 void UpgradeTransactionStarted(int64_t old_version) override { NOTREACHED(); } | |
| 350 | |
| 351 void UpgradeTransactionFinished(bool committed) override { NOTREACHED(); } | |
| 100 | 352 |
| 101 private: | 353 private: |
| 102 scoped_refptr<IndexedDBCallbacks> callbacks_; | 354 scoped_refptr<IndexedDBCallbacks> callbacks_; |
| 103 std::unique_ptr<IndexedDBConnection> connection_; | 355 |
| 104 int64_t version_; | 356 DISALLOW_COPY_AND_ASSIGN(DeleteRequest); |
| 105 const int64_t transaction_id_; | |
| 106 }; | 357 }; |
| 107 | 358 |
| 108 // PendingSuccessCall has a IndexedDBConnection* because the connection is now | |
| 109 // owned elsewhere, but we need to cancel the success call if that connection | |
| 110 // closes before it is sent. | |
| 111 class IndexedDBDatabase::PendingSuccessCall { | |
| 112 public: | |
| 113 PendingSuccessCall(scoped_refptr<IndexedDBCallbacks> callbacks, | |
| 114 IndexedDBConnection* connection, | |
| 115 int64_t version) | |
| 116 : callbacks_(callbacks), connection_(connection), version_(version) {} | |
| 117 scoped_refptr<IndexedDBCallbacks> callbacks() const { return callbacks_; } | |
| 118 IndexedDBConnection* connection() const { return connection_; } | |
| 119 int64_t version() const { return version_; } | |
| 120 | |
| 121 private: | |
| 122 scoped_refptr<IndexedDBCallbacks> callbacks_; | |
| 123 IndexedDBConnection* connection_; | |
| 124 int64_t version_; | |
| 125 }; | |
| 126 | |
| 127 class IndexedDBDatabase::PendingDeleteCall { | |
| 128 public: | |
| 129 explicit PendingDeleteCall(scoped_refptr<IndexedDBCallbacks> callbacks) | |
| 130 : callbacks_(callbacks) {} | |
| 131 scoped_refptr<IndexedDBCallbacks> callbacks() const { return callbacks_; } | |
| 132 | |
| 133 private: | |
| 134 scoped_refptr<IndexedDBCallbacks> callbacks_; | |
| 135 }; | |
| 136 | |
| 137 scoped_refptr<IndexedDBDatabase> IndexedDBDatabase::Create( | 359 scoped_refptr<IndexedDBDatabase> IndexedDBDatabase::Create( |
| 138 const base::string16& name, | 360 const base::string16& name, |
| 139 IndexedDBBackingStore* backing_store, | 361 IndexedDBBackingStore* backing_store, |
| 140 IndexedDBFactory* factory, | 362 IndexedDBFactory* factory, |
| 141 const Identifier& unique_identifier, | 363 const Identifier& unique_identifier, |
| 142 leveldb::Status* s) { | 364 leveldb::Status* s) { |
| 143 scoped_refptr<IndexedDBDatabase> database = | 365 scoped_refptr<IndexedDBDatabase> database = |
| 144 IndexedDBClassFactory::Get()->CreateIndexedDBDatabase( | 366 IndexedDBClassFactory::Get()->CreateIndexedDBDatabase( |
| 145 name, backing_store, factory, unique_identifier); | 367 name, backing_store, factory, unique_identifier); |
| 146 *s = database->OpenInternal(); | 368 *s = database->OpenInternal(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 224 if (success) | 446 if (success) |
| 225 return backing_store_->GetObjectStores(metadata_.id, | 447 return backing_store_->GetObjectStores(metadata_.id, |
| 226 &metadata_.object_stores); | 448 &metadata_.object_stores); |
| 227 | 449 |
| 228 return backing_store_->CreateIDBDatabaseMetaData( | 450 return backing_store_->CreateIDBDatabaseMetaData( |
| 229 metadata_.name, metadata_.version, &metadata_.id); | 451 metadata_.name, metadata_.version, &metadata_.id); |
| 230 } | 452 } |
| 231 | 453 |
| 232 IndexedDBDatabase::~IndexedDBDatabase() { | 454 IndexedDBDatabase::~IndexedDBDatabase() { |
| 233 DCHECK(transactions_.empty()); | 455 DCHECK(transactions_.empty()); |
| 234 DCHECK(pending_open_calls_.empty()); | 456 DCHECK(!active_request_); |
| 235 DCHECK(pending_delete_calls_.empty()); | 457 DCHECK(pending_requests_.empty()); |
| 236 DCHECK(blocked_delete_calls_.empty()); | |
| 237 } | 458 } |
| 238 | 459 |
| 239 size_t IndexedDBDatabase::GetMaxMessageSizeInBytes() const { | 460 size_t IndexedDBDatabase::GetMaxMessageSizeInBytes() const { |
| 240 return kMaxIDBMessageSizeInBytes; | 461 return kMaxIDBMessageSizeInBytes; |
| 241 } | 462 } |
| 242 | 463 |
| 243 std::unique_ptr<IndexedDBConnection> IndexedDBDatabase::CreateConnection( | 464 std::unique_ptr<IndexedDBConnection> IndexedDBDatabase::CreateConnection( |
| 244 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, | 465 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, |
| 245 int child_process_id) { | 466 int child_process_id) { |
| 246 std::unique_ptr<IndexedDBConnection> connection( | 467 std::unique_ptr<IndexedDBConnection> connection( |
| (...skipping 1275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1522 RemoveObjectStore(object_store_id); | 1743 RemoveObjectStore(object_store_id); |
| 1523 transaction->ScheduleAbortTask( | 1744 transaction->ScheduleAbortTask( |
| 1524 base::Bind(&IndexedDBDatabase::DeleteObjectStoreAbortOperation, | 1745 base::Bind(&IndexedDBDatabase::DeleteObjectStoreAbortOperation, |
| 1525 this, | 1746 this, |
| 1526 object_store_metadata)); | 1747 object_store_metadata)); |
| 1527 } | 1748 } |
| 1528 | 1749 |
| 1529 void IndexedDBDatabase::VersionChangeOperation( | 1750 void IndexedDBDatabase::VersionChangeOperation( |
| 1530 int64_t version, | 1751 int64_t version, |
| 1531 scoped_refptr<IndexedDBCallbacks> callbacks, | 1752 scoped_refptr<IndexedDBCallbacks> callbacks, |
| 1532 std::unique_ptr<IndexedDBConnection> connection, | |
| 1533 IndexedDBTransaction* transaction) { | 1753 IndexedDBTransaction* transaction) { |
| 1534 IDB_TRACE1( | 1754 IDB_TRACE1( |
| 1535 "IndexedDBDatabase::VersionChangeOperation", "txn.id", transaction->id()); | 1755 "IndexedDBDatabase::VersionChangeOperation", "txn.id", transaction->id()); |
| 1536 int64_t old_version = metadata_.version; | 1756 int64_t old_version = metadata_.version; |
| 1537 DCHECK_GT(version, old_version); | 1757 DCHECK_GT(version, old_version); |
| 1538 | 1758 |
| 1539 if (!backing_store_->UpdateIDBDatabaseIntVersion( | 1759 if (!backing_store_->UpdateIDBDatabaseIntVersion( |
| 1540 transaction->BackingStoreTransaction(), id(), version)) { | 1760 transaction->BackingStoreTransaction(), id(), version)) { |
| 1541 IndexedDBDatabaseError error( | 1761 IndexedDBDatabaseError error( |
| 1542 blink::WebIDBDatabaseExceptionUnknownError, | 1762 blink::WebIDBDatabaseExceptionUnknownError, |
| 1543 ASCIIToUTF16( | 1763 ASCIIToUTF16( |
| 1544 "Internal error writing data to stable storage when " | 1764 "Internal error writing data to stable storage when " |
| 1545 "updating version.")); | 1765 "updating version.")); |
| 1546 callbacks->OnError(error); | 1766 callbacks->OnError(error); |
| 1547 transaction->Abort(error); | 1767 transaction->Abort(error); |
| 1548 return; | 1768 return; |
| 1549 } | 1769 } |
| 1550 | 1770 |
| 1551 transaction->ScheduleAbortTask( | 1771 transaction->ScheduleAbortTask( |
| 1552 base::Bind(&IndexedDBDatabase::VersionChangeAbortOperation, this, | 1772 base::Bind(&IndexedDBDatabase::VersionChangeAbortOperation, this, |
| 1553 metadata_.version)); | 1773 metadata_.version)); |
| 1554 metadata_.version = version; | 1774 metadata_.version = version; |
| 1555 | 1775 |
| 1556 DCHECK(!pending_second_half_open_); | 1776 active_request_->UpgradeTransactionStarted(old_version); |
| 1557 pending_second_half_open_.reset( | |
| 1558 new PendingSuccessCall(callbacks, connection.get(), version)); | |
| 1559 callbacks->OnUpgradeNeeded(old_version, std::move(connection), metadata()); | |
| 1560 } | 1777 } |
| 1561 | 1778 |
| 1562 void IndexedDBDatabase::TransactionFinished(IndexedDBTransaction* transaction, | 1779 void IndexedDBDatabase::TransactionFinished(IndexedDBTransaction* transaction, |
| 1563 bool committed) { | 1780 bool committed) { |
| 1564 IDB_TRACE1("IndexedDBTransaction::TransactionFinished", "txn.id", id()); | 1781 IDB_TRACE1("IndexedDBTransaction::TransactionFinished", "txn.id", id()); |
| 1565 DCHECK(transactions_.find(transaction->id()) != transactions_.end()); | 1782 DCHECK(transactions_.find(transaction->id()) != transactions_.end()); |
| 1566 DCHECK_EQ(transactions_[transaction->id()], transaction); | 1783 DCHECK_EQ(transactions_[transaction->id()], transaction); |
| 1567 transactions_.erase(transaction->id()); | 1784 transactions_.erase(transaction->id()); |
| 1568 | 1785 |
| 1569 if (transaction->mode() == blink::WebIDBTransactionModeVersionChange) { | 1786 // This may be an unrelated transaction finishing while waiting for |
| 1570 if (pending_second_half_open_) { | 1787 // connections to close, or the actual upgrade transaction from an active |
| 1571 if (committed) { | 1788 // request. Notify the active request if it's the latter. |
| 1572 DCHECK_EQ(pending_second_half_open_->version(), metadata_.version); | 1789 if (active_request_ && |
| 1573 DCHECK(metadata_.id != kInvalidId); | 1790 transaction->mode() == blink::WebIDBTransactionModeVersionChange) { |
| 1574 | 1791 active_request_->UpgradeTransactionFinished(committed); |
| 1575 // Connection was already minted for OnUpgradeNeeded callback. | |
| 1576 std::unique_ptr<IndexedDBConnection> connection; | |
| 1577 pending_second_half_open_->callbacks()->OnSuccess(std::move(connection), | |
| 1578 this->metadata()); | |
| 1579 } else { | |
| 1580 pending_second_half_open_->callbacks()->OnError( | |
| 1581 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError, | |
| 1582 "Version change transaction was aborted in " | |
| 1583 "upgradeneeded event handler.")); | |
| 1584 } | |
| 1585 pending_second_half_open_.reset(); | |
| 1586 } | |
| 1587 | |
| 1588 // Connection queue is now unblocked. | |
| 1589 ProcessPendingCalls(); | |
| 1590 } | 1792 } |
| 1591 } | 1793 } |
| 1592 | 1794 |
| 1593 void IndexedDBDatabase::TransactionCommitFailed(const leveldb::Status& status) { | 1795 void IndexedDBDatabase::TransactionCommitFailed(const leveldb::Status& status) { |
| 1594 if (status.IsCorruption()) { | 1796 if (status.IsCorruption()) { |
| 1595 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, | 1797 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, |
| 1596 "Error committing transaction"); | 1798 "Error committing transaction"); |
| 1597 factory_->HandleBackingStoreCorruption(backing_store_->origin(), error); | 1799 factory_->HandleBackingStoreCorruption(backing_store_->origin(), error); |
| 1598 } else { | 1800 } else { |
| 1599 factory_->HandleBackingStoreFailure(backing_store_->origin()); | 1801 factory_->HandleBackingStoreFailure(backing_store_->origin()); |
| 1600 } | 1802 } |
| 1601 } | 1803 } |
| 1602 | 1804 |
| 1603 size_t IndexedDBDatabase::ConnectionCount() const { | 1805 void IndexedDBDatabase::AppendRequest( |
| 1604 // This does not include pending open calls, as those should not block version | 1806 std::unique_ptr<OpenOrDeleteRequest> request) { |
| 1605 // changes and deletes. | 1807 pending_requests_.push(std::move(request)); |
| 1606 return connections_.size(); | 1808 |
| 1809 if (!active_request_) | |
| 1810 ProcessRequestQueue(); | |
| 1607 } | 1811 } |
| 1608 | 1812 |
| 1609 size_t IndexedDBDatabase::PendingOpenCount() const { | 1813 void IndexedDBDatabase::RequestComplete(OpenOrDeleteRequest* request) { |
| 1610 return pending_open_calls_.size(); | 1814 DCHECK_EQ(request, active_request_.get()); |
| 1815 active_request_.reset(); | |
| 1816 | |
| 1817 if (!pending_requests_.empty()) | |
| 1818 ProcessRequestQueue(); | |
| 1611 } | 1819 } |
| 1612 | 1820 |
| 1613 size_t IndexedDBDatabase::PendingUpgradeCount() const { | 1821 void IndexedDBDatabase::ProcessRequestQueue() { |
| 1614 return pending_run_version_change_transaction_call_ ? 1 : 0; | 1822 // Don't run re-entrantly to avoid exploding call stacks for requests that |
| 1823 // complete synchronously. The loop below will process requests until one is | |
| 1824 // blocked. | |
| 1825 if (processing_pending_requests_) | |
| 1826 return; | |
| 1827 | |
| 1828 DCHECK(!active_request_); | |
| 1829 DCHECK(!pending_requests_.empty()); | |
| 1830 | |
| 1831 base::AutoReset<bool> processing(&processing_pending_requests_, true); | |
| 1832 do { | |
| 1833 active_request_ = std::move(pending_requests_.front()); | |
| 1834 pending_requests_.pop(); | |
| 1835 active_request_->Perform(); | |
| 1836 // If the active request completed synchronously, keep going. | |
| 1837 } while (!active_request_ && !pending_requests_.empty()); | |
| 1615 } | 1838 } |
| 1616 | 1839 |
| 1617 size_t IndexedDBDatabase::RunningUpgradeCount() const { | 1840 IndexedDBTransaction* IndexedDBDatabase::CreateTransaction( |
| 1618 return pending_second_half_open_ ? 1 : 0; | |
| 1619 } | |
| 1620 | |
| 1621 size_t IndexedDBDatabase::PendingDeleteCount() const { | |
| 1622 return pending_delete_calls_.size(); | |
| 1623 } | |
| 1624 | |
| 1625 void IndexedDBDatabase::ProcessPendingCalls() { | |
| 1626 if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) { | |
| 1627 DCHECK(pending_run_version_change_transaction_call_->version() > | |
| 1628 metadata_.version); | |
| 1629 std::unique_ptr<PendingUpgradeCall> pending_call = | |
| 1630 std::move(pending_run_version_change_transaction_call_); | |
| 1631 RunVersionChangeTransactionFinal(pending_call->callbacks(), | |
| 1632 pending_call->ReleaseConnection(), | |
| 1633 pending_call->transaction_id(), | |
| 1634 pending_call->version()); | |
| 1635 DCHECK_EQ(1u, ConnectionCount()); | |
| 1636 // Fall through would be a no-op, since transaction must complete | |
| 1637 // asynchronously. | |
| 1638 DCHECK(IsUpgradeRunning()); | |
| 1639 DCHECK(IsDeleteDatabaseBlocked()); | |
| 1640 DCHECK(IsOpenConnectionBlocked()); | |
| 1641 return; | |
| 1642 } | |
| 1643 | |
| 1644 if (IsUpgradeRunning()) { | |
| 1645 DCHECK_EQ(ConnectionCount(), 1UL); | |
| 1646 return; | |
| 1647 } | |
| 1648 | |
| 1649 // These delete calls were blocked by a running upgrade, and did not even | |
| 1650 // get as far as broadcasting OnVersionChange (if needed). | |
| 1651 { | |
| 1652 std::list<std::unique_ptr<PendingDeleteCall>> pending_delete_calls; | |
| 1653 pending_delete_calls_.swap(pending_delete_calls); | |
| 1654 while (!pending_delete_calls.empty()) { | |
| 1655 std::unique_ptr<PendingDeleteCall> pending_delete_call( | |
| 1656 std::move(pending_delete_calls.front())); | |
| 1657 pending_delete_calls.pop_front(); | |
| 1658 DeleteDatabase(pending_delete_call->callbacks()); | |
| 1659 } | |
| 1660 // DeleteDatabase should never re-queue these calls. | |
| 1661 DCHECK(pending_delete_calls_.empty()); | |
| 1662 // Fall through when complete, as pending deletes/opens may be unblocked. | |
| 1663 } | |
| 1664 | |
| 1665 // These delete calls broadcast OnVersionChange (if needed) but were blocked | |
| 1666 // by open connections. | |
| 1667 if (!IsDeleteDatabaseBlocked()) { | |
| 1668 std::list<std::unique_ptr<PendingDeleteCall>> blocked_delete_calls; | |
| 1669 blocked_delete_calls_.swap(blocked_delete_calls); | |
| 1670 while (!blocked_delete_calls.empty()) { | |
| 1671 // Only the first delete call will delete the database, but each must fire | |
| 1672 // callbacks. | |
| 1673 std::unique_ptr<PendingDeleteCall> pending_delete_call( | |
| 1674 std::move(blocked_delete_calls.front())); | |
| 1675 blocked_delete_calls.pop_front(); | |
| 1676 DeleteDatabaseFinal(pending_delete_call->callbacks()); | |
| 1677 } | |
| 1678 // DeleteDatabaseFinal should never re-queue these calls. | |
| 1679 DCHECK(blocked_delete_calls_.empty()); | |
| 1680 // Fall through when complete, as pending opens may be unblocked. | |
| 1681 } | |
| 1682 | |
| 1683 // These open calls were blocked by a pending/running upgrade or a pending | |
| 1684 // delete. | |
| 1685 if (!IsOpenConnectionBlocked()) { | |
| 1686 std::queue<IndexedDBPendingConnection> pending_open_calls; | |
| 1687 pending_open_calls_.swap(pending_open_calls); | |
| 1688 while (!pending_open_calls.empty()) { | |
| 1689 // This may re-queue open calls if an upgrade is necessary. | |
| 1690 OpenConnection(pending_open_calls.front()); | |
| 1691 pending_open_calls.pop(); | |
| 1692 } | |
| 1693 } | |
| 1694 } | |
| 1695 | |
| 1696 void IndexedDBDatabase::CreateTransaction( | |
| 1697 int64_t transaction_id, | 1841 int64_t transaction_id, |
| 1698 IndexedDBConnection* connection, | 1842 IndexedDBConnection* connection, |
| 1699 const std::vector<int64_t>& object_store_ids, | 1843 const std::vector<int64_t>& object_store_ids, |
| 1700 blink::WebIDBTransactionMode mode) { | 1844 blink::WebIDBTransactionMode mode) { |
| 1701 IDB_TRACE1("IndexedDBDatabase::CreateTransaction", "txn.id", transaction_id); | 1845 IDB_TRACE1("IndexedDBDatabase::CreateTransaction", "txn.id", transaction_id); |
| 1702 DCHECK(connections_.count(connection)); | 1846 DCHECK(connections_.count(connection)); |
| 1703 DCHECK(transactions_.find(transaction_id) == transactions_.end()); | 1847 DCHECK(transactions_.find(transaction_id) == transactions_.end()); |
| 1704 if (transactions_.find(transaction_id) != transactions_.end()) | 1848 if (transactions_.find(transaction_id) != transactions_.end()) |
| 1705 return; | 1849 return nullptr; |
| 1706 | 1850 |
| 1707 UMA_HISTOGRAM_COUNTS_1000( | 1851 UMA_HISTOGRAM_COUNTS_1000( |
| 1708 "WebCore.IndexedDB.Database.OutstandingTransactionCount", | 1852 "WebCore.IndexedDB.Database.OutstandingTransactionCount", |
| 1709 transactions_.size()); | 1853 transactions_.size()); |
| 1710 | 1854 |
| 1711 // The transaction will add itself to this database's coordinator, which | 1855 // The transaction will add itself to this database's coordinator, which |
| 1712 // manages the lifetime of the object. | 1856 // manages the lifetime of the object. |
| 1713 TransactionCreated(IndexedDBClassFactory::Get()->CreateIndexedDBTransaction( | 1857 IndexedDBTransaction* transaction = |
| 1714 transaction_id, connection->GetWeakPtr(), | 1858 IndexedDBClassFactory::Get()->CreateIndexedDBTransaction( |
| 1715 std::set<int64_t>(object_store_ids.begin(), object_store_ids.end()), mode, | 1859 transaction_id, connection->GetWeakPtr(), |
| 1716 new IndexedDBBackingStore::Transaction(backing_store_.get()))); | 1860 std::set<int64_t>(object_store_ids.begin(), object_store_ids.end()), |
| 1861 mode, new IndexedDBBackingStore::Transaction(backing_store_.get())); | |
| 1862 TransactionCreated(transaction); | |
| 1863 return transaction; | |
| 1717 } | 1864 } |
| 1718 | 1865 |
| 1719 void IndexedDBDatabase::TransactionCreated(IndexedDBTransaction* transaction) { | 1866 void IndexedDBDatabase::TransactionCreated(IndexedDBTransaction* transaction) { |
| 1720 transactions_[transaction->id()] = transaction; | 1867 transactions_[transaction->id()] = transaction; |
| 1721 } | 1868 } |
| 1722 | 1869 |
| 1723 bool IndexedDBDatabase::IsUpgradeRunning() const { | |
| 1724 return transaction_coordinator_.IsRunningVersionChangeTransaction(); | |
| 1725 } | |
| 1726 | |
| 1727 bool IndexedDBDatabase::IsUpgradePendingOrRunning() const { | |
| 1728 return pending_run_version_change_transaction_call_ || IsUpgradeRunning(); | |
| 1729 } | |
| 1730 | |
| 1731 bool IndexedDBDatabase::IsOpenConnectionBlocked() const { | |
| 1732 return IsUpgradePendingOrRunning() || !blocked_delete_calls_.empty(); | |
| 1733 } | |
| 1734 | |
| 1735 void IndexedDBDatabase::OpenConnection( | 1870 void IndexedDBDatabase::OpenConnection( |
| 1736 const IndexedDBPendingConnection& connection) { | 1871 const IndexedDBPendingConnection& connection) { |
| 1737 DCHECK(backing_store_.get()); | 1872 AppendRequest(base::MakeUnique<OpenRequest>(this, connection)); |
| 1738 | |
| 1739 if (IsOpenConnectionBlocked()) { | |
| 1740 // The backing store only detects data loss when it is first opened. The | |
| 1741 // presence of existing connections means we didn't even check for data loss | |
| 1742 // so there'd better not be any. | |
| 1743 DCHECK_NE(blink::WebIDBDataLossTotal, | |
| 1744 connection.callbacks->data_loss_info().status); | |
| 1745 pending_open_calls_.push(connection); | |
| 1746 return; | |
| 1747 } | |
| 1748 | |
| 1749 if (metadata_.id == kInvalidId) { | |
| 1750 // The database was deleted then immediately re-opened; OpenInternal() | |
| 1751 // recreates it in the backing store. | |
| 1752 if (OpenInternal().ok()) { | |
| 1753 DCHECK_EQ(IndexedDBDatabaseMetadata::NO_VERSION, metadata_.version); | |
| 1754 } else { | |
| 1755 base::string16 message; | |
| 1756 if (connection.version == IndexedDBDatabaseMetadata::NO_VERSION) { | |
| 1757 message = ASCIIToUTF16( | |
| 1758 "Internal error opening database with no version specified."); | |
| 1759 } else { | |
| 1760 message = | |
| 1761 ASCIIToUTF16("Internal error opening database with version ") + | |
| 1762 Int64ToString16(connection.version); | |
| 1763 } | |
| 1764 connection.callbacks->OnError(IndexedDBDatabaseError( | |
| 1765 blink::WebIDBDatabaseExceptionUnknownError, message)); | |
| 1766 return; | |
| 1767 } | |
| 1768 } | |
| 1769 | |
| 1770 // We infer that the database didn't exist from its lack of either type of | |
| 1771 // version. | |
| 1772 bool is_new_database = | |
| 1773 metadata_.version == IndexedDBDatabaseMetadata::NO_VERSION; | |
| 1774 | |
| 1775 if (connection.version == IndexedDBDatabaseMetadata::DEFAULT_VERSION) { | |
| 1776 // For unit tests only - skip upgrade steps. Calling from script with | |
| 1777 // DEFAULT_VERSION throws exception. | |
| 1778 // TODO(jsbell): DCHECK that not in unit tests. | |
| 1779 DCHECK(is_new_database); | |
| 1780 connection.callbacks->OnSuccess( | |
| 1781 CreateConnection(connection.database_callbacks, | |
| 1782 connection.child_process_id), | |
| 1783 this->metadata()); | |
| 1784 return; | |
| 1785 } | |
| 1786 | |
| 1787 // We may need to change the version. | |
| 1788 int64_t local_version = connection.version; | |
| 1789 if (local_version == IndexedDBDatabaseMetadata::NO_VERSION) { | |
| 1790 if (!is_new_database) { | |
| 1791 connection.callbacks->OnSuccess( | |
| 1792 CreateConnection(connection.database_callbacks, | |
| 1793 connection.child_process_id), | |
| 1794 this->metadata()); | |
| 1795 return; | |
| 1796 } | |
| 1797 // Spec says: If no version is specified and no database exists, set | |
| 1798 // database version to 1. | |
| 1799 local_version = 1; | |
| 1800 } | |
| 1801 | |
| 1802 if (local_version > metadata_.version) { | |
| 1803 RunVersionChangeTransaction(connection.callbacks, | |
| 1804 CreateConnection(connection.database_callbacks, | |
| 1805 connection.child_process_id), | |
| 1806 connection.transaction_id, | |
| 1807 local_version); | |
| 1808 return; | |
| 1809 } | |
| 1810 if (local_version < metadata_.version) { | |
| 1811 connection.callbacks->OnError(IndexedDBDatabaseError( | |
| 1812 blink::WebIDBDatabaseExceptionVersionError, | |
| 1813 ASCIIToUTF16("The requested version (") + | |
| 1814 Int64ToString16(local_version) + | |
| 1815 ASCIIToUTF16(") is less than the existing version (") + | |
| 1816 Int64ToString16(metadata_.version) + ASCIIToUTF16(")."))); | |
| 1817 return; | |
| 1818 } | |
| 1819 DCHECK_EQ(local_version, metadata_.version); | |
| 1820 connection.callbacks->OnSuccess( | |
| 1821 CreateConnection(connection.database_callbacks, | |
| 1822 connection.child_process_id), | |
| 1823 this->metadata()); | |
| 1824 } | |
| 1825 | |
| 1826 void IndexedDBDatabase::RunVersionChangeTransaction( | |
| 1827 scoped_refptr<IndexedDBCallbacks> callbacks, | |
| 1828 std::unique_ptr<IndexedDBConnection> connection, | |
| 1829 int64_t transaction_id, | |
| 1830 int64_t requested_version) { | |
| 1831 DCHECK(callbacks.get()); | |
| 1832 DCHECK(connections_.count(connection.get())); | |
| 1833 if (ConnectionCount() > 1) { | |
| 1834 DCHECK_NE(blink::WebIDBDataLossTotal, callbacks->data_loss_info().status); | |
| 1835 // Front end ensures the event is not fired at connections that have | |
| 1836 // close_pending set. | |
| 1837 for (const auto* iter : connections_) { | |
| 1838 if (iter != connection.get()) { | |
| 1839 iter->callbacks()->OnVersionChange(metadata_.version, | |
| 1840 requested_version); | |
| 1841 } | |
| 1842 } | |
| 1843 // OnBlocked will be fired at the request when one of the other | |
| 1844 // connections acks that the OnVersionChange was ignored. | |
| 1845 | |
| 1846 DCHECK(!pending_run_version_change_transaction_call_); | |
| 1847 pending_run_version_change_transaction_call_.reset(new PendingUpgradeCall( | |
| 1848 callbacks, std::move(connection), transaction_id, requested_version)); | |
| 1849 return; | |
| 1850 } | |
| 1851 RunVersionChangeTransactionFinal(callbacks, std::move(connection), | |
| 1852 transaction_id, requested_version); | |
| 1853 } | |
| 1854 | |
| 1855 void IndexedDBDatabase::RunVersionChangeTransactionFinal( | |
| 1856 scoped_refptr<IndexedDBCallbacks> callbacks, | |
| 1857 std::unique_ptr<IndexedDBConnection> connection, | |
| 1858 int64_t transaction_id, | |
| 1859 int64_t requested_version) { | |
| 1860 std::vector<int64_t> object_store_ids; | |
| 1861 CreateTransaction(transaction_id, | |
| 1862 connection.get(), | |
| 1863 object_store_ids, | |
| 1864 blink::WebIDBTransactionModeVersionChange); | |
| 1865 | |
| 1866 DCHECK(transaction_coordinator_.IsRunningVersionChangeTransaction()); | |
| 1867 transactions_[transaction_id]->ScheduleTask( | |
| 1868 base::Bind(&IndexedDBDatabase::VersionChangeOperation, | |
| 1869 this, | |
| 1870 requested_version, | |
| 1871 callbacks, | |
| 1872 base::Passed(&connection))); | |
| 1873 DCHECK(!pending_second_half_open_); | |
| 1874 } | 1873 } |
| 1875 | 1874 |
| 1876 void IndexedDBDatabase::DeleteDatabase( | 1875 void IndexedDBDatabase::DeleteDatabase( |
| 1877 scoped_refptr<IndexedDBCallbacks> callbacks) { | 1876 scoped_refptr<IndexedDBCallbacks> callbacks) { |
| 1878 // If there's a running upgrade, the delete calls should be deferred so that | 1877 AppendRequest(base::MakeUnique<DeleteRequest>(this, callbacks)); |
| 1879 // "versionchange" is seen after "success" fires. | |
| 1880 if (IsUpgradeRunning()) { | |
| 1881 pending_delete_calls_.push_back( | |
| 1882 std::unique_ptr<PendingDeleteCall>(new PendingDeleteCall(callbacks))); | |
| 1883 return; | |
| 1884 } | |
| 1885 | |
| 1886 if (IsDeleteDatabaseBlocked()) { | |
| 1887 for (const auto* connection : connections_) { | |
| 1888 // Front end ensures the event is not fired at connections that have | |
| 1889 // close_pending set. | |
| 1890 connection->callbacks()->OnVersionChange( | |
| 1891 metadata_.version, IndexedDBDatabaseMetadata::NO_VERSION); | |
| 1892 } | |
| 1893 // OnBlocked will be fired at the request when one of the other | |
| 1894 // connections acks that the OnVersionChange was ignored. | |
| 1895 | |
| 1896 blocked_delete_calls_.push_back( | |
| 1897 std::unique_ptr<PendingDeleteCall>(new PendingDeleteCall(callbacks))); | |
| 1898 return; | |
| 1899 } | |
| 1900 DeleteDatabaseFinal(callbacks); | |
| 1901 } | |
| 1902 | |
| 1903 bool IndexedDBDatabase::IsDeleteDatabaseBlocked() const { | |
| 1904 return IsUpgradePendingOrRunning() || !!ConnectionCount(); | |
| 1905 } | |
| 1906 | |
| 1907 void IndexedDBDatabase::DeleteDatabaseFinal( | |
| 1908 scoped_refptr<IndexedDBCallbacks> callbacks) { | |
| 1909 DCHECK(!IsDeleteDatabaseBlocked()); | |
| 1910 DCHECK(backing_store_.get()); | |
| 1911 leveldb::Status s = backing_store_->DeleteDatabase(metadata_.name); | |
| 1912 if (!s.ok()) { | |
| 1913 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, | |
| 1914 "Internal error deleting database."); | |
| 1915 callbacks->OnError(error); | |
| 1916 if (s.IsCorruption()) { | |
| 1917 url::Origin origin = backing_store_->origin(); | |
| 1918 backing_store_ = NULL; | |
| 1919 factory_->HandleBackingStoreCorruption(origin, error); | |
| 1920 } | |
| 1921 return; | |
| 1922 } | |
| 1923 int64_t old_version = metadata_.version; | |
| 1924 metadata_.id = kInvalidId; | |
| 1925 metadata_.version = IndexedDBDatabaseMetadata::NO_VERSION; | |
| 1926 metadata_.object_stores.clear(); | |
| 1927 callbacks->OnSuccess(old_version); | |
| 1928 factory_->DatabaseDeleted(identifier_); | |
| 1929 } | 1878 } |
| 1930 | 1879 |
| 1931 void IndexedDBDatabase::ForceClose() { | 1880 void IndexedDBDatabase::ForceClose() { |
| 1932 // IndexedDBConnection::ForceClose() may delete this database, so hold ref. | 1881 // IndexedDBConnection::ForceClose() may delete this database, so hold ref. |
| 1933 scoped_refptr<IndexedDBDatabase> protect(this); | 1882 scoped_refptr<IndexedDBDatabase> protect(this); |
| 1934 auto it = connections_.begin(); | 1883 auto it = connections_.begin(); |
| 1935 while (it != connections_.end()) { | 1884 while (it != connections_.end()) { |
| 1936 IndexedDBConnection* connection = *it++; | 1885 IndexedDBConnection* connection = *it++; |
| 1937 connection->ForceClose(); | 1886 connection->ForceClose(); |
| 1938 } | 1887 } |
| 1939 DCHECK(connections_.empty()); | 1888 DCHECK(connections_.empty()); |
| 1940 } | 1889 } |
| 1941 | 1890 |
| 1942 void IndexedDBDatabase::VersionChangeIgnored() { | 1891 void IndexedDBDatabase::VersionChangeIgnored() { |
| 1943 if (pending_run_version_change_transaction_call_) { | 1892 if (active_request_) |
| 1944 pending_run_version_change_transaction_call_->callbacks()->OnBlocked( | 1893 active_request_->OnVersionChangeIgnored(); |
| 1945 metadata_.version); | |
| 1946 } | |
| 1947 | |
| 1948 for (const auto& pending_delete_call : blocked_delete_calls_) | |
| 1949 pending_delete_call->callbacks()->OnBlocked(metadata_.version); | |
| 1950 } | 1894 } |
| 1951 | 1895 |
| 1952 void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) { | 1896 void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) { |
| 1953 DCHECK(connections_.count(connection)); | 1897 DCHECK(connections_.count(connection)); |
| 1954 DCHECK(connection->IsConnected()); | 1898 DCHECK(connection->IsConnected()); |
| 1955 DCHECK(connection->database() == this); | 1899 DCHECK(connection->database() == this); |
| 1956 | 1900 |
| 1957 IDB_TRACE("IndexedDBDatabase::Close"); | 1901 IDB_TRACE("IndexedDBDatabase::Close"); |
| 1958 | 1902 |
| 1959 connections_.erase(connection); | 1903 // Abort outstanding transactions from the closing connection. This can not |
| 1960 | 1904 // happen if the close is requested by the connection itself as the |
| 1961 // Abort outstanding transactions from the closing connection. This | 1905 // front-end defers the close until all transactions are complete, but can |
| 1962 // can not happen if the close is requested by the connection itself | 1906 // occur on process termination or forced close. |
| 1963 // as the front-end defers the close until all transactions are | |
| 1964 // complete, but can occur on process termination or forced close. | |
| 1965 { | 1907 { |
| 1966 auto transactions(transactions_); | 1908 auto transactions(transactions_); |
| 1967 for (const auto& it : transactions) { | 1909 for (const auto& it : transactions) { |
| 1968 if (it.second->callbacks() == connection->callbacks()) | 1910 if (it.second->callbacks() == connection->callbacks()) |
| 1969 it.second->Abort( | 1911 it.second->Abort( |
| 1970 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, | 1912 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, |
| 1971 "Connection is closing.")); | 1913 "Connection is closing.")); |
| 1972 } | 1914 } |
| 1973 } | 1915 } |
| 1974 | 1916 |
| 1975 if (pending_second_half_open_ && | 1917 // Abort transactions before removing the connection; aborting may complete |
| 1976 pending_second_half_open_->connection() == connection) { | 1918 // an upgrade, and thus allow the next open/delete requests to proceed. The |
| 1977 pending_second_half_open_->callbacks()->OnError( | 1919 // new active_request_ should see the old connection count until explicitly |
| 1978 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError, | 1920 // notified below. |
| 1979 "The connection was closed.")); | 1921 connections_.erase(connection); |
| 1980 pending_second_half_open_.reset(); | |
| 1981 } | |
| 1982 | 1922 |
| 1983 ProcessPendingCalls(); | 1923 // Notify the active request, which may need to do cleanup or proceed with |
| 1924 // the operation. This may trigger other work, such as more connections or | |
| 1925 // deletions, so |active_request_| itself may change. | |
| 1926 if (active_request_) | |
| 1927 active_request_->OnConnectionClosed(connection); | |
| 1984 | 1928 |
| 1985 // TODO(jsbell): Add a test for the pending_open_calls_ cases below. | 1929 // If there are no more connections (current, active, or pending), tell the |
| 1986 if (!ConnectionCount() && pending_open_calls_.empty() && | 1930 // factory to clean us up. |
| 1987 blocked_delete_calls_.empty()) { | 1931 if (connections_.empty() && !active_request_ && pending_requests_.empty()) { |
| 1988 DCHECK(transactions_.empty()); | 1932 DCHECK(transactions_.empty()); |
| 1989 backing_store_ = NULL; | 1933 backing_store_ = nullptr; |
| 1990 factory_->ReleaseDatabase(identifier_, forced); | 1934 factory_->ReleaseDatabase(identifier_, forced); |
| 1991 } | 1935 } |
| 1992 } | 1936 } |
| 1993 | 1937 |
| 1994 void IndexedDBDatabase::CreateObjectStoreAbortOperation( | 1938 void IndexedDBDatabase::CreateObjectStoreAbortOperation( |
| 1995 int64_t object_store_id, | 1939 int64_t object_store_id, |
| 1996 IndexedDBTransaction* transaction) { | 1940 IndexedDBTransaction* transaction) { |
| 1997 DCHECK(!transaction); | 1941 DCHECK(!transaction); |
| 1998 IDB_TRACE("IndexedDBDatabase::CreateObjectStoreAbortOperation"); | 1942 IDB_TRACE("IndexedDBDatabase::CreateObjectStoreAbortOperation"); |
| 1999 RemoveObjectStore(object_store_id); | 1943 RemoveObjectStore(object_store_id); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 2010 | 1954 |
| 2011 void IndexedDBDatabase::VersionChangeAbortOperation( | 1955 void IndexedDBDatabase::VersionChangeAbortOperation( |
| 2012 int64_t previous_version, | 1956 int64_t previous_version, |
| 2013 IndexedDBTransaction* transaction) { | 1957 IndexedDBTransaction* transaction) { |
| 2014 DCHECK(!transaction); | 1958 DCHECK(!transaction); |
| 2015 IDB_TRACE("IndexedDBDatabase::VersionChangeAbortOperation"); | 1959 IDB_TRACE("IndexedDBDatabase::VersionChangeAbortOperation"); |
| 2016 metadata_.version = previous_version; | 1960 metadata_.version = previous_version; |
| 2017 } | 1961 } |
| 2018 | 1962 |
| 2019 } // namespace content | 1963 } // namespace content |
| OLD | NEW |