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 |