| 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), pending_(pending_connection) {} |
| 120 |
| 121 void Perform() override { |
| 122 if (db_->metadata_.id == kInvalidId) { |
| 123 // The database was deleted then immediately re-opened; OpenInternal() |
| 124 // recreates it in the backing store. |
| 125 if (!db_->OpenInternal().ok()) { |
| 126 // TODO(jsbell): Consider including sanitized leveldb status message. |
| 127 base::string16 message; |
| 128 if (pending_.version == IndexedDBDatabaseMetadata::NO_VERSION) { |
| 129 message = ASCIIToUTF16( |
| 130 "Internal error opening database with no version specified."); |
| 131 } else { |
| 132 message = |
| 133 ASCIIToUTF16("Internal error opening database with version ") + |
| 134 Int64ToString16(pending_.version); |
| 135 } |
| 136 pending_.callbacks->OnError(IndexedDBDatabaseError( |
| 137 blink::WebIDBDatabaseExceptionUnknownError, message)); |
| 138 db_->RequestComplete(this); |
| 139 return; |
| 140 } |
| 141 |
| 142 DCHECK_EQ(IndexedDBDatabaseMetadata::NO_VERSION, db_->metadata_.version); |
| 143 } |
| 144 |
| 145 const int64_t old_version = db_->metadata_.version; |
| 146 int64_t& new_version = pending_.version; |
| 147 |
| 148 bool is_new_database = old_version == IndexedDBDatabaseMetadata::NO_VERSION; |
| 149 |
| 150 if (new_version == IndexedDBDatabaseMetadata::DEFAULT_VERSION) { |
| 151 // For unit tests only - skip upgrade steps. (Calling from script with |
| 152 // DEFAULT_VERSION throws exception.) |
| 153 DCHECK(is_new_database); |
| 154 pending_.callbacks->OnSuccess( |
| 155 db_->CreateConnection(pending_.database_callbacks, |
| 156 pending_.child_process_id), |
| 157 db_->metadata_); |
| 158 db_->RequestComplete(this); |
| 159 return; |
| 160 } |
| 161 |
| 162 if (!is_new_database && |
| 163 (new_version == old_version || |
| 164 new_version == IndexedDBDatabaseMetadata::NO_VERSION)) { |
| 165 pending_.callbacks->OnSuccess( |
| 166 db_->CreateConnection(pending_.database_callbacks, |
| 167 pending_.child_process_id), |
| 168 db_->metadata_); |
| 169 db_->RequestComplete(this); |
| 170 return; |
| 171 } |
| 172 |
| 173 if (new_version == IndexedDBDatabaseMetadata::NO_VERSION) { |
| 174 // If no version is specified and no database exists, upgrade the |
| 175 // database version to 1. |
| 176 DCHECK(is_new_database); |
| 177 new_version = 1; |
| 178 } else if (new_version < old_version) { |
| 179 // Requested version is lower than current version - fail the request. |
| 180 DCHECK(!is_new_database); |
| 181 pending_.callbacks->OnError(IndexedDBDatabaseError( |
| 182 blink::WebIDBDatabaseExceptionVersionError, |
| 183 ASCIIToUTF16("The requested version (") + |
| 184 Int64ToString16(pending_.version) + |
| 185 ASCIIToUTF16(") is less than the existing version (") + |
| 186 Int64ToString16(db_->metadata_.version) + ASCIIToUTF16(")."))); |
| 187 db_->RequestComplete(this); |
| 188 return; |
| 189 } |
| 190 |
| 191 // Requested version is higher than current version - upgrade needed. |
| 192 DCHECK_GT(new_version, old_version); |
| 193 |
| 194 if (db_->connections_.empty()) { |
| 195 StartUpgrade(); |
| 196 return; |
| 197 } |
| 198 |
| 199 // There are outstanding connections - fire "versionchange" events and |
| 200 // wait for the connections to close. Front end ensures the event is not |
| 201 // fired at connections that have close_pending set. A "blocked" event |
| 202 // will be fired at the request when one of the connections acks that the |
| 203 // "versionchange" event was ignored. |
| 204 DCHECK_NE(pending_.callbacks->data_loss_info().status, |
| 205 blink::WebIDBDataLossTotal); |
| 206 for (const auto* connection : db_->connections_) |
| 207 connection->callbacks()->OnVersionChange(old_version, new_version); |
| 208 |
| 209 // When all connections have closed the upgrade can proceed. |
| 210 } |
| 211 |
| 212 void OnVersionChangeIgnored() const override { |
| 213 pending_.callbacks->OnBlocked(db_->metadata_.version); |
| 214 } |
| 215 |
| 216 void OnConnectionClosed(IndexedDBConnection* connection) override { |
| 217 // This connection closed prematurely; signal an error and complete. |
| 218 if (connection && connection->callbacks() == pending_.database_callbacks) { |
| 219 pending_.callbacks->OnError( |
| 220 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError, |
| 221 "The connection was closed.")); |
| 222 db_->RequestComplete(this); |
| 223 return; |
| 224 } |
| 225 |
| 226 if (!db_->connections_.empty()) |
| 227 return; |
| 228 |
| 229 StartUpgrade(); |
| 230 } |
| 231 |
| 232 // Initiate the upgrade. The bulk of the work actually happens in |
| 233 // IndexedDBDatabase::VersionChangeOperation in order to kick the |
| 234 // transaction into the correct state. |
| 235 void StartUpgrade() { |
| 236 connection_ = db_->CreateConnection(pending_.database_callbacks, |
| 237 pending_.child_process_id); |
| 238 DCHECK_EQ(db_->connections_.count(connection_.get()), 1UL); |
| 239 |
| 240 std::vector<int64_t> object_store_ids; |
| 241 IndexedDBTransaction* transaction = db_->CreateTransaction( |
| 242 pending_.transaction_id, connection_.get(), object_store_ids, |
| 243 blink::WebIDBTransactionModeVersionChange); |
| 244 |
| 245 DCHECK(db_->transaction_coordinator_.IsRunningVersionChangeTransaction()); |
| 246 transaction->ScheduleTask( |
| 247 base::Bind(&IndexedDBDatabase::VersionChangeOperation, db_, |
| 248 pending_.version, pending_.callbacks)); |
| 249 } |
| 250 |
| 251 // Called when the upgrade transaction has started executing. |
| 252 void UpgradeTransactionStarted(int64_t old_version) override { |
| 253 DCHECK(connection_); |
| 254 pending_.callbacks->OnUpgradeNeeded(old_version, std::move(connection_), |
| 255 db_->metadata_); |
| 256 } |
| 257 |
| 258 void UpgradeTransactionFinished(bool committed) override { |
| 259 // Ownership of connection was already passed along in OnUpgradeNeeded. |
| 260 DCHECK(!connection_); |
| 261 |
| 262 if (committed) { |
| 263 DCHECK_EQ(pending_.version, db_->metadata_.version); |
| 264 pending_.callbacks->OnSuccess(std::unique_ptr<IndexedDBConnection>(), |
| 265 db_->metadata()); |
| 266 } else { |
| 267 DCHECK_NE(pending_.version, db_->metadata_.version); |
| 268 pending_.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 IndexedDBPendingConnection pending_; |
| 278 |
| 279 // If an upgrade is needed, holds the pending connection until ownership is |
| 280 // transferred to the IndexedDBDispatcherHost via OnUpgradeNeeded. |
| 281 std::unique_ptr<IndexedDBConnection> connection_; |
| 282 |
| 283 DISALLOW_COPY_AND_ASSIGN(OpenRequest); |
| 284 }; |
| 285 |
| 286 class IndexedDBDatabase::DeleteRequest |
| 287 : public IndexedDBDatabase::OpenOrDeleteRequest { |
| 288 public: |
| 289 DeleteRequest(scoped_refptr<IndexedDBDatabase> db, |
| 290 scoped_refptr<IndexedDBCallbacks> callbacks) |
| 291 : OpenOrDeleteRequest(db), callbacks_(callbacks) {} |
| 292 |
| 293 void Perform() override { |
| 294 if (db_->connections_.empty()) { |
| 295 // No connections, so delete immediately. |
| 296 DoDelete(); |
| 297 return; |
| 298 } |
| 299 |
| 300 // Front end ensures the event is not fired at connections that have |
| 301 // close_pending set. |
| 302 const int64_t old_version = db_->metadata_.version; |
| 303 const int64_t new_version = IndexedDBDatabaseMetadata::NO_VERSION; |
| 304 DCHECK_NE(callbacks_->data_loss_info().status, blink::WebIDBDataLossTotal); |
| 305 for (const auto* connection : db_->connections_) |
| 306 connection->callbacks()->OnVersionChange(old_version, new_version); |
| 307 } |
| 308 |
| 309 void OnVersionChangeIgnored() const override { |
| 310 callbacks_->OnBlocked(db_->metadata_.version); |
| 311 } |
| 312 |
| 313 void OnConnectionClosed(IndexedDBConnection* connection) override { |
| 314 if (!db_->connections_.empty()) |
| 315 return; |
| 316 DoDelete(); |
| 317 } |
| 318 |
| 319 void DoDelete() { |
| 320 leveldb::Status s = |
| 321 db_->backing_store_->DeleteDatabase(db_->metadata_.name); |
| 322 if (!s.ok()) { |
| 323 // TODO(jsbell): Consider including sanitized leveldb status message. |
| 324 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, |
| 325 "Internal error deleting database."); |
| 326 callbacks_->OnError(error); |
| 327 if (s.IsCorruption()) { |
| 328 url::Origin origin = db_->backing_store_->origin(); |
| 329 db_->backing_store_ = nullptr; |
| 330 db_->factory_->HandleBackingStoreCorruption(origin, error); |
| 331 } |
| 332 db_->RequestComplete(this); |
| 333 return; |
| 334 } |
| 335 |
| 336 int64_t old_version = db_->metadata_.version; |
| 337 db_->metadata_.id = kInvalidId; |
| 338 db_->metadata_.version = IndexedDBDatabaseMetadata::NO_VERSION; |
| 339 db_->metadata_.max_object_store_id = kInvalidId; |
| 340 db_->metadata_.object_stores.clear(); |
| 341 callbacks_->OnSuccess(old_version); |
| 342 db_->factory_->DatabaseDeleted(db_->identifier_); |
| 343 |
| 344 db_->RequestComplete(this); |
| 345 } |
| 346 |
| 347 void UpgradeTransactionStarted(int64_t old_version) override { NOTREACHED(); } |
| 348 |
| 349 void UpgradeTransactionFinished(bool committed) override { NOTREACHED(); } |
| 100 | 350 |
| 101 private: | 351 private: |
| 102 scoped_refptr<IndexedDBCallbacks> callbacks_; | 352 scoped_refptr<IndexedDBCallbacks> callbacks_; |
| 103 std::unique_ptr<IndexedDBConnection> connection_; | 353 |
| 104 int64_t version_; | 354 DISALLOW_COPY_AND_ASSIGN(DeleteRequest); |
| 105 const int64_t transaction_id_; | |
| 106 }; | 355 }; |
| 107 | 356 |
| 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( | 357 scoped_refptr<IndexedDBDatabase> IndexedDBDatabase::Create( |
| 138 const base::string16& name, | 358 const base::string16& name, |
| 139 IndexedDBBackingStore* backing_store, | 359 IndexedDBBackingStore* backing_store, |
| 140 IndexedDBFactory* factory, | 360 IndexedDBFactory* factory, |
| 141 const Identifier& unique_identifier, | 361 const Identifier& unique_identifier, |
| 142 leveldb::Status* s) { | 362 leveldb::Status* s) { |
| 143 scoped_refptr<IndexedDBDatabase> database = | 363 scoped_refptr<IndexedDBDatabase> database = |
| 144 IndexedDBClassFactory::Get()->CreateIndexedDBDatabase( | 364 IndexedDBClassFactory::Get()->CreateIndexedDBDatabase( |
| 145 name, backing_store, factory, unique_identifier); | 365 name, backing_store, factory, unique_identifier); |
| 146 *s = database->OpenInternal(); | 366 *s = database->OpenInternal(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 if (success) | 444 if (success) |
| 225 return backing_store_->GetObjectStores(metadata_.id, | 445 return backing_store_->GetObjectStores(metadata_.id, |
| 226 &metadata_.object_stores); | 446 &metadata_.object_stores); |
| 227 | 447 |
| 228 return backing_store_->CreateIDBDatabaseMetaData( | 448 return backing_store_->CreateIDBDatabaseMetaData( |
| 229 metadata_.name, metadata_.version, &metadata_.id); | 449 metadata_.name, metadata_.version, &metadata_.id); |
| 230 } | 450 } |
| 231 | 451 |
| 232 IndexedDBDatabase::~IndexedDBDatabase() { | 452 IndexedDBDatabase::~IndexedDBDatabase() { |
| 233 DCHECK(transactions_.empty()); | 453 DCHECK(transactions_.empty()); |
| 234 DCHECK(pending_open_calls_.empty()); | 454 DCHECK(!active_request_); |
| 235 DCHECK(pending_delete_calls_.empty()); | 455 DCHECK(pending_requests_.empty()); |
| 236 DCHECK(blocked_delete_calls_.empty()); | |
| 237 } | 456 } |
| 238 | 457 |
| 239 size_t IndexedDBDatabase::GetMaxMessageSizeInBytes() const { | 458 size_t IndexedDBDatabase::GetMaxMessageSizeInBytes() const { |
| 240 return kMaxIDBMessageSizeInBytes; | 459 return kMaxIDBMessageSizeInBytes; |
| 241 } | 460 } |
| 242 | 461 |
| 243 std::unique_ptr<IndexedDBConnection> IndexedDBDatabase::CreateConnection( | 462 std::unique_ptr<IndexedDBConnection> IndexedDBDatabase::CreateConnection( |
| 244 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, | 463 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, |
| 245 int child_process_id) { | 464 int child_process_id) { |
| 246 std::unique_ptr<IndexedDBConnection> connection( | 465 std::unique_ptr<IndexedDBConnection> connection( |
| (...skipping 1275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1522 RemoveObjectStore(object_store_id); | 1741 RemoveObjectStore(object_store_id); |
| 1523 transaction->ScheduleAbortTask( | 1742 transaction->ScheduleAbortTask( |
| 1524 base::Bind(&IndexedDBDatabase::DeleteObjectStoreAbortOperation, | 1743 base::Bind(&IndexedDBDatabase::DeleteObjectStoreAbortOperation, |
| 1525 this, | 1744 this, |
| 1526 object_store_metadata)); | 1745 object_store_metadata)); |
| 1527 } | 1746 } |
| 1528 | 1747 |
| 1529 void IndexedDBDatabase::VersionChangeOperation( | 1748 void IndexedDBDatabase::VersionChangeOperation( |
| 1530 int64_t version, | 1749 int64_t version, |
| 1531 scoped_refptr<IndexedDBCallbacks> callbacks, | 1750 scoped_refptr<IndexedDBCallbacks> callbacks, |
| 1532 std::unique_ptr<IndexedDBConnection> connection, | |
| 1533 IndexedDBTransaction* transaction) { | 1751 IndexedDBTransaction* transaction) { |
| 1534 IDB_TRACE1( | 1752 IDB_TRACE1( |
| 1535 "IndexedDBDatabase::VersionChangeOperation", "txn.id", transaction->id()); | 1753 "IndexedDBDatabase::VersionChangeOperation", "txn.id", transaction->id()); |
| 1536 int64_t old_version = metadata_.version; | 1754 int64_t old_version = metadata_.version; |
| 1537 DCHECK_GT(version, old_version); | 1755 DCHECK_GT(version, old_version); |
| 1538 | 1756 |
| 1539 if (!backing_store_->UpdateIDBDatabaseIntVersion( | 1757 if (!backing_store_->UpdateIDBDatabaseIntVersion( |
| 1540 transaction->BackingStoreTransaction(), id(), version)) { | 1758 transaction->BackingStoreTransaction(), id(), version)) { |
| 1541 IndexedDBDatabaseError error( | 1759 IndexedDBDatabaseError error( |
| 1542 blink::WebIDBDatabaseExceptionUnknownError, | 1760 blink::WebIDBDatabaseExceptionUnknownError, |
| 1543 ASCIIToUTF16( | 1761 ASCIIToUTF16( |
| 1544 "Internal error writing data to stable storage when " | 1762 "Internal error writing data to stable storage when " |
| 1545 "updating version.")); | 1763 "updating version.")); |
| 1546 callbacks->OnError(error); | 1764 callbacks->OnError(error); |
| 1547 transaction->Abort(error); | 1765 transaction->Abort(error); |
| 1548 return; | 1766 return; |
| 1549 } | 1767 } |
| 1550 | 1768 |
| 1551 transaction->ScheduleAbortTask( | 1769 transaction->ScheduleAbortTask( |
| 1552 base::Bind(&IndexedDBDatabase::VersionChangeAbortOperation, this, | 1770 base::Bind(&IndexedDBDatabase::VersionChangeAbortOperation, this, |
| 1553 metadata_.version)); | 1771 metadata_.version)); |
| 1554 metadata_.version = version; | 1772 metadata_.version = version; |
| 1555 | 1773 |
| 1556 DCHECK(!pending_second_half_open_); | 1774 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 } | 1775 } |
| 1561 | 1776 |
| 1562 void IndexedDBDatabase::TransactionFinished(IndexedDBTransaction* transaction, | 1777 void IndexedDBDatabase::TransactionFinished(IndexedDBTransaction* transaction, |
| 1563 bool committed) { | 1778 bool committed) { |
| 1564 IDB_TRACE1("IndexedDBTransaction::TransactionFinished", "txn.id", id()); | 1779 IDB_TRACE1("IndexedDBTransaction::TransactionFinished", "txn.id", id()); |
| 1565 DCHECK(transactions_.find(transaction->id()) != transactions_.end()); | 1780 DCHECK(transactions_.find(transaction->id()) != transactions_.end()); |
| 1566 DCHECK_EQ(transactions_[transaction->id()], transaction); | 1781 DCHECK_EQ(transactions_[transaction->id()], transaction); |
| 1567 transactions_.erase(transaction->id()); | 1782 transactions_.erase(transaction->id()); |
| 1568 | 1783 |
| 1569 if (transaction->mode() == blink::WebIDBTransactionModeVersionChange) { | 1784 // This may be an unrelated transaction finishing while waiting for |
| 1570 if (pending_second_half_open_) { | 1785 // connections to close, or the actual upgrade transaction from an active |
| 1571 if (committed) { | 1786 // request. Notify the active request if it's the latter. |
| 1572 DCHECK_EQ(pending_second_half_open_->version(), metadata_.version); | 1787 if (active_request_ && |
| 1573 DCHECK(metadata_.id != kInvalidId); | 1788 transaction->mode() == blink::WebIDBTransactionModeVersionChange) { |
| 1574 | 1789 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 } | 1790 } |
| 1591 } | 1791 } |
| 1592 | 1792 |
| 1593 void IndexedDBDatabase::TransactionCommitFailed(const leveldb::Status& status) { | 1793 void IndexedDBDatabase::TransactionCommitFailed(const leveldb::Status& status) { |
| 1594 if (status.IsCorruption()) { | 1794 if (status.IsCorruption()) { |
| 1595 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, | 1795 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, |
| 1596 "Error committing transaction"); | 1796 "Error committing transaction"); |
| 1597 factory_->HandleBackingStoreCorruption(backing_store_->origin(), error); | 1797 factory_->HandleBackingStoreCorruption(backing_store_->origin(), error); |
| 1598 } else { | 1798 } else { |
| 1599 factory_->HandleBackingStoreFailure(backing_store_->origin()); | 1799 factory_->HandleBackingStoreFailure(backing_store_->origin()); |
| 1600 } | 1800 } |
| 1601 } | 1801 } |
| 1602 | 1802 |
| 1603 size_t IndexedDBDatabase::ConnectionCount() const { | 1803 void IndexedDBDatabase::AppendRequest( |
| 1604 // This does not include pending open calls, as those should not block version | 1804 std::unique_ptr<OpenOrDeleteRequest> request) { |
| 1605 // changes and deletes. | 1805 pending_requests_.push(std::move(request)); |
| 1606 return connections_.size(); | 1806 |
| 1807 if (!active_request_) |
| 1808 ProcessRequestQueue(); |
| 1607 } | 1809 } |
| 1608 | 1810 |
| 1609 size_t IndexedDBDatabase::PendingOpenCount() const { | 1811 void IndexedDBDatabase::RequestComplete(OpenOrDeleteRequest* request) { |
| 1610 return pending_open_calls_.size(); | 1812 DCHECK_EQ(request, active_request_.get()); |
| 1813 active_request_.reset(); |
| 1814 |
| 1815 if (!pending_requests_.empty()) |
| 1816 ProcessRequestQueue(); |
| 1611 } | 1817 } |
| 1612 | 1818 |
| 1613 size_t IndexedDBDatabase::PendingUpgradeCount() const { | 1819 void IndexedDBDatabase::ProcessRequestQueue() { |
| 1614 return pending_run_version_change_transaction_call_ ? 1 : 0; | 1820 // Don't run re-entrantly to avoid exploding call stacks for requests that |
| 1821 // complete synchronously. The loop below will process requests until one is |
| 1822 // blocked. |
| 1823 if (processing_pending_requests_) |
| 1824 return; |
| 1825 |
| 1826 DCHECK(!active_request_); |
| 1827 DCHECK(!pending_requests_.empty()); |
| 1828 |
| 1829 base::AutoReset<bool> processing(&processing_pending_requests_, true); |
| 1830 do { |
| 1831 active_request_ = std::move(pending_requests_.front()); |
| 1832 pending_requests_.pop(); |
| 1833 active_request_->Perform(); |
| 1834 // If the active request completed synchronously, keep going. |
| 1835 } while (!active_request_ && !pending_requests_.empty()); |
| 1615 } | 1836 } |
| 1616 | 1837 |
| 1617 size_t IndexedDBDatabase::RunningUpgradeCount() const { | 1838 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, | 1839 int64_t transaction_id, |
| 1698 IndexedDBConnection* connection, | 1840 IndexedDBConnection* connection, |
| 1699 const std::vector<int64_t>& object_store_ids, | 1841 const std::vector<int64_t>& object_store_ids, |
| 1700 blink::WebIDBTransactionMode mode) { | 1842 blink::WebIDBTransactionMode mode) { |
| 1701 IDB_TRACE1("IndexedDBDatabase::CreateTransaction", "txn.id", transaction_id); | 1843 IDB_TRACE1("IndexedDBDatabase::CreateTransaction", "txn.id", transaction_id); |
| 1702 DCHECK(connections_.count(connection)); | 1844 DCHECK(connections_.count(connection)); |
| 1703 DCHECK(transactions_.find(transaction_id) == transactions_.end()); | 1845 DCHECK(transactions_.find(transaction_id) == transactions_.end()); |
| 1704 if (transactions_.find(transaction_id) != transactions_.end()) | 1846 if (transactions_.find(transaction_id) != transactions_.end()) |
| 1705 return; | 1847 return nullptr; |
| 1706 | 1848 |
| 1707 UMA_HISTOGRAM_COUNTS_1000( | 1849 UMA_HISTOGRAM_COUNTS_1000( |
| 1708 "WebCore.IndexedDB.Database.OutstandingTransactionCount", | 1850 "WebCore.IndexedDB.Database.OutstandingTransactionCount", |
| 1709 transactions_.size()); | 1851 transactions_.size()); |
| 1710 | 1852 |
| 1711 // The transaction will add itself to this database's coordinator, which | 1853 // The transaction will add itself to this database's coordinator, which |
| 1712 // manages the lifetime of the object. | 1854 // manages the lifetime of the object. |
| 1713 TransactionCreated(IndexedDBClassFactory::Get()->CreateIndexedDBTransaction( | 1855 IndexedDBTransaction* transaction = |
| 1714 transaction_id, connection->GetWeakPtr(), | 1856 IndexedDBClassFactory::Get()->CreateIndexedDBTransaction( |
| 1715 std::set<int64_t>(object_store_ids.begin(), object_store_ids.end()), mode, | 1857 transaction_id, connection->GetWeakPtr(), |
| 1716 new IndexedDBBackingStore::Transaction(backing_store_.get()))); | 1858 std::set<int64_t>(object_store_ids.begin(), object_store_ids.end()), |
| 1859 mode, new IndexedDBBackingStore::Transaction(backing_store_.get())); |
| 1860 TransactionCreated(transaction); |
| 1861 return transaction; |
| 1717 } | 1862 } |
| 1718 | 1863 |
| 1719 void IndexedDBDatabase::TransactionCreated(IndexedDBTransaction* transaction) { | 1864 void IndexedDBDatabase::TransactionCreated(IndexedDBTransaction* transaction) { |
| 1720 transactions_[transaction->id()] = transaction; | 1865 transactions_[transaction->id()] = transaction; |
| 1721 } | 1866 } |
| 1722 | 1867 |
| 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( | 1868 void IndexedDBDatabase::OpenConnection( |
| 1736 const IndexedDBPendingConnection& connection) { | 1869 const IndexedDBPendingConnection& connection) { |
| 1737 DCHECK(backing_store_.get()); | 1870 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 } | 1871 } |
| 1875 | 1872 |
| 1876 void IndexedDBDatabase::DeleteDatabase( | 1873 void IndexedDBDatabase::DeleteDatabase( |
| 1877 scoped_refptr<IndexedDBCallbacks> callbacks) { | 1874 scoped_refptr<IndexedDBCallbacks> callbacks) { |
| 1878 // If there's a running upgrade, the delete calls should be deferred so that | 1875 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 } | 1876 } |
| 1930 | 1877 |
| 1931 void IndexedDBDatabase::ForceClose() { | 1878 void IndexedDBDatabase::ForceClose() { |
| 1932 // IndexedDBConnection::ForceClose() may delete this database, so hold ref. | 1879 // IndexedDBConnection::ForceClose() may delete this database, so hold ref. |
| 1933 scoped_refptr<IndexedDBDatabase> protect(this); | 1880 scoped_refptr<IndexedDBDatabase> protect(this); |
| 1934 auto it = connections_.begin(); | 1881 auto it = connections_.begin(); |
| 1935 while (it != connections_.end()) { | 1882 while (it != connections_.end()) { |
| 1936 IndexedDBConnection* connection = *it++; | 1883 IndexedDBConnection* connection = *it++; |
| 1937 connection->ForceClose(); | 1884 connection->ForceClose(); |
| 1938 } | 1885 } |
| 1939 DCHECK(connections_.empty()); | 1886 DCHECK(connections_.empty()); |
| 1940 } | 1887 } |
| 1941 | 1888 |
| 1942 void IndexedDBDatabase::VersionChangeIgnored() { | 1889 void IndexedDBDatabase::VersionChangeIgnored() { |
| 1943 if (pending_run_version_change_transaction_call_) { | 1890 if (active_request_) |
| 1944 pending_run_version_change_transaction_call_->callbacks()->OnBlocked( | 1891 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 } | 1892 } |
| 1951 | 1893 |
| 1952 void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) { | 1894 void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) { |
| 1953 DCHECK(connections_.count(connection)); | 1895 DCHECK(connections_.count(connection)); |
| 1954 DCHECK(connection->IsConnected()); | 1896 DCHECK(connection->IsConnected()); |
| 1955 DCHECK(connection->database() == this); | 1897 DCHECK(connection->database() == this); |
| 1956 | 1898 |
| 1957 IDB_TRACE("IndexedDBDatabase::Close"); | 1899 IDB_TRACE("IndexedDBDatabase::Close"); |
| 1958 | 1900 |
| 1959 connections_.erase(connection); | 1901 // Abort outstanding transactions from the closing connection. This can not |
| 1960 | 1902 // happen if the close is requested by the connection itself as the |
| 1961 // Abort outstanding transactions from the closing connection. This | 1903 // 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 | 1904 // 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 { | 1905 { |
| 1966 auto transactions(transactions_); | 1906 auto transactions(transactions_); |
| 1967 for (const auto& it : transactions) { | 1907 for (const auto& it : transactions) { |
| 1968 if (it.second->callbacks() == connection->callbacks()) | 1908 if (it.second->callbacks() == connection->callbacks()) |
| 1969 it.second->Abort( | 1909 it.second->Abort( |
| 1970 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, | 1910 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError, |
| 1971 "Connection is closing.")); | 1911 "Connection is closing.")); |
| 1972 } | 1912 } |
| 1973 } | 1913 } |
| 1974 | 1914 |
| 1975 if (pending_second_half_open_ && | 1915 // Abort transactions before removing the connection; aborting may complete |
| 1976 pending_second_half_open_->connection() == connection) { | 1916 // an upgrade, and thus allow the next open/delete requests to proceed. The |
| 1977 pending_second_half_open_->callbacks()->OnError( | 1917 // new active_request_ should see the old connection count until explicitly |
| 1978 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError, | 1918 // notified below. |
| 1979 "The connection was closed.")); | 1919 connections_.erase(connection); |
| 1980 pending_second_half_open_.reset(); | |
| 1981 } | |
| 1982 | 1920 |
| 1983 ProcessPendingCalls(); | 1921 // Notify the active request, which may need to do cleanup or proceed with |
| 1922 // the operation. This may trigger other work, such as more connections or |
| 1923 // deletions, so |active_request_| itself may change. |
| 1924 if (active_request_) |
| 1925 active_request_->OnConnectionClosed(connection); |
| 1984 | 1926 |
| 1985 // TODO(jsbell): Add a test for the pending_open_calls_ cases below. | 1927 // If there are no more connections (current, active, or pending), tell the |
| 1986 if (!ConnectionCount() && pending_open_calls_.empty() && | 1928 // factory to clean us up. |
| 1987 blocked_delete_calls_.empty()) { | 1929 if (connections_.empty() && !active_request_ && pending_requests_.empty()) { |
| 1988 DCHECK(transactions_.empty()); | 1930 DCHECK(transactions_.empty()); |
| 1989 backing_store_ = NULL; | 1931 backing_store_ = nullptr; |
| 1990 factory_->ReleaseDatabase(identifier_, forced); | 1932 factory_->ReleaseDatabase(identifier_, forced); |
| 1991 } | 1933 } |
| 1992 } | 1934 } |
| 1993 | 1935 |
| 1994 void IndexedDBDatabase::CreateObjectStoreAbortOperation( | 1936 void IndexedDBDatabase::CreateObjectStoreAbortOperation( |
| 1995 int64_t object_store_id, | 1937 int64_t object_store_id, |
| 1996 IndexedDBTransaction* transaction) { | 1938 IndexedDBTransaction* transaction) { |
| 1997 DCHECK(!transaction); | 1939 DCHECK(!transaction); |
| 1998 IDB_TRACE("IndexedDBDatabase::CreateObjectStoreAbortOperation"); | 1940 IDB_TRACE("IndexedDBDatabase::CreateObjectStoreAbortOperation"); |
| 1999 RemoveObjectStore(object_store_id); | 1941 RemoveObjectStore(object_store_id); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2010 | 1952 |
| 2011 void IndexedDBDatabase::VersionChangeAbortOperation( | 1953 void IndexedDBDatabase::VersionChangeAbortOperation( |
| 2012 int64_t previous_version, | 1954 int64_t previous_version, |
| 2013 IndexedDBTransaction* transaction) { | 1955 IndexedDBTransaction* transaction) { |
| 2014 DCHECK(!transaction); | 1956 DCHECK(!transaction); |
| 2015 IDB_TRACE("IndexedDBDatabase::VersionChangeAbortOperation"); | 1957 IDB_TRACE("IndexedDBDatabase::VersionChangeAbortOperation"); |
| 2016 metadata_.version = previous_version; | 1958 metadata_.version = previous_version; |
| 2017 } | 1959 } |
| 2018 | 1960 |
| 2019 } // namespace content | 1961 } // namespace content |
| OLD | NEW |