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