Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(182)

Side by Side Diff: content/browser/indexed_db/indexed_db_database.cc

Issue 2084053004: IndexedDB: Defer delete calls when there is a running upgrade (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 &metadata_.object_stores); 226 &metadata_.object_stores);
227 227
228 return backing_store_->CreateIDBDatabaseMetaData( 228 return backing_store_->CreateIDBDatabaseMetaData(
229 metadata_.name, metadata_.version, &metadata_.id); 229 metadata_.name, metadata_.version, &metadata_.id);
230 } 230 }
231 231
232 IndexedDBDatabase::~IndexedDBDatabase() { 232 IndexedDBDatabase::~IndexedDBDatabase() {
233 DCHECK(transactions_.empty()); 233 DCHECK(transactions_.empty());
234 DCHECK(pending_open_calls_.empty()); 234 DCHECK(pending_open_calls_.empty());
235 DCHECK(pending_delete_calls_.empty()); 235 DCHECK(pending_delete_calls_.empty());
236 DCHECK(blocked_delete_calls_.empty());
236 } 237 }
237 238
238 size_t IndexedDBDatabase::GetMaxMessageSizeInBytes() const { 239 size_t IndexedDBDatabase::GetMaxMessageSizeInBytes() const {
239 return kMaxIDBMessageSizeInBytes; 240 return kMaxIDBMessageSizeInBytes;
240 } 241 }
241 242
242 std::unique_ptr<IndexedDBConnection> IndexedDBDatabase::CreateConnection( 243 std::unique_ptr<IndexedDBConnection> IndexedDBDatabase::CreateConnection(
243 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks, 244 scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks,
244 int child_process_id) { 245 int child_process_id) {
245 std::unique_ptr<IndexedDBConnection> connection( 246 std::unique_ptr<IndexedDBConnection> connection(
(...skipping 1347 matching lines...) Expand 10 before | Expand all | Expand 10 after
1593 1594
1594 size_t IndexedDBDatabase::PendingUpgradeCount() const { 1595 size_t IndexedDBDatabase::PendingUpgradeCount() const {
1595 return pending_run_version_change_transaction_call_ ? 1 : 0; 1596 return pending_run_version_change_transaction_call_ ? 1 : 0;
1596 } 1597 }
1597 1598
1598 size_t IndexedDBDatabase::RunningUpgradeCount() const { 1599 size_t IndexedDBDatabase::RunningUpgradeCount() const {
1599 return pending_second_half_open_ ? 1 : 0; 1600 return pending_second_half_open_ ? 1 : 0;
1600 } 1601 }
1601 1602
1602 size_t IndexedDBDatabase::PendingDeleteCount() const { 1603 size_t IndexedDBDatabase::PendingDeleteCount() const {
1603 return pending_delete_calls_.size(); 1604 return pending_delete_calls_.size() + blocked_delete_calls_.size();
1604 } 1605 }
1605 1606
1606 void IndexedDBDatabase::ProcessPendingCalls() { 1607 void IndexedDBDatabase::ProcessPendingCalls() {
1607 if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) { 1608 if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) {
1608 DCHECK(pending_run_version_change_transaction_call_->version() > 1609 DCHECK(pending_run_version_change_transaction_call_->version() >
1609 metadata_.version); 1610 metadata_.version);
1610 std::unique_ptr<PendingUpgradeCall> pending_call = 1611 std::unique_ptr<PendingUpgradeCall> pending_call =
1611 std::move(pending_run_version_change_transaction_call_); 1612 std::move(pending_run_version_change_transaction_call_);
1612 RunVersionChangeTransactionFinal(pending_call->callbacks(), 1613 RunVersionChangeTransactionFinal(pending_call->callbacks(),
1613 pending_call->ReleaseConnection(), 1614 pending_call->ReleaseConnection(),
1614 pending_call->transaction_id(), 1615 pending_call->transaction_id(),
1615 pending_call->version()); 1616 pending_call->version());
1616 DCHECK_EQ(1u, ConnectionCount()); 1617 DCHECK_EQ(1u, ConnectionCount());
1617 // Fall through would be a no-op, since transaction must complete 1618 // Fall through would be a no-op, since transaction must complete
1618 // asynchronously. 1619 // asynchronously.
1620 DCHECK(IsUpgradeRunning());
1619 DCHECK(IsDeleteDatabaseBlocked()); 1621 DCHECK(IsDeleteDatabaseBlocked());
1620 DCHECK(IsOpenConnectionBlocked()); 1622 DCHECK(IsOpenConnectionBlocked());
1621 return; 1623 return;
1622 } 1624 }
1623 1625
1624 if (!IsDeleteDatabaseBlocked()) { 1626 if (IsUpgradeRunning()) {
1627 DCHECK_EQ(ConnectionCount(), 1UL);
1628 return;
1629 }
1630
1631 // These delete calls were blocked by a running upgrade, and did not even
1632 // get as far as broadcasting OnVersionChange (if needed).
1633 {
1625 PendingDeleteCallList pending_delete_calls; 1634 PendingDeleteCallList pending_delete_calls;
1626 pending_delete_calls_.swap(pending_delete_calls); 1635 pending_delete_calls_.swap(pending_delete_calls);
1627 while (!pending_delete_calls.empty()) { 1636 while (!pending_delete_calls.empty()) {
1637 std::unique_ptr<PendingDeleteCall> pending_delete_call(
1638 pending_delete_calls.front());
1639 pending_delete_calls.pop_front();
1640 DeleteDatabase(pending_delete_call->callbacks());
1641 }
1642 // DeleteDatabase should never re-queue these calls.
1643 DCHECK(pending_delete_calls_.empty());
1644 // Fall through when complete, as pending deletes/opens may be unblocked.
1645 }
1646
1647 // These delete calls broadcast OnVersionChange (if needed) but were blocked
1648 // by open connections.
1649 if (!IsDeleteDatabaseBlocked()) {
1650 PendingDeleteCallList blocked_delete_calls;
1651 blocked_delete_calls_.swap(blocked_delete_calls);
1652 while (!blocked_delete_calls.empty()) {
1628 // Only the first delete call will delete the database, but each must fire 1653 // Only the first delete call will delete the database, but each must fire
1629 // callbacks. 1654 // callbacks.
1630 std::unique_ptr<PendingDeleteCall> pending_delete_call( 1655 std::unique_ptr<PendingDeleteCall> pending_delete_call(
1631 pending_delete_calls.front()); 1656 blocked_delete_calls.front());
1632 pending_delete_calls.pop_front(); 1657 blocked_delete_calls.pop_front();
1633 DeleteDatabaseFinal(pending_delete_call->callbacks()); 1658 DeleteDatabaseFinal(pending_delete_call->callbacks());
1634 } 1659 }
1635 // delete_database_final should never re-queue calls. 1660 // DeleteDatabaseFinal should never re-queue these calls.
1636 DCHECK(pending_delete_calls_.empty()); 1661 DCHECK(blocked_delete_calls_.empty());
1637 // Fall through when complete, as pending opens may be unblocked. 1662 // Fall through when complete, as pending opens may be unblocked.
1638 } 1663 }
1639 1664
1665 // These open calls were blocked by a pending/running upgrade or a pending
1666 // delete.
1640 if (!IsOpenConnectionBlocked()) { 1667 if (!IsOpenConnectionBlocked()) {
1641 PendingOpenCallList pending_open_calls; 1668 PendingOpenCallList pending_open_calls;
1642 pending_open_calls_.swap(pending_open_calls); 1669 pending_open_calls_.swap(pending_open_calls);
1643 while (!pending_open_calls.empty()) { 1670 while (!pending_open_calls.empty()) {
1671 // This may re-queue open calls if an upgrade is necessary.
1644 OpenConnection(pending_open_calls.front()); 1672 OpenConnection(pending_open_calls.front());
1645 pending_open_calls.pop_front(); 1673 pending_open_calls.pop_front();
1646 } 1674 }
1647 } 1675 }
1648 } 1676 }
1649 1677
1650 void IndexedDBDatabase::CreateTransaction( 1678 void IndexedDBDatabase::CreateTransaction(
1651 int64_t transaction_id, 1679 int64_t transaction_id,
1652 IndexedDBConnection* connection, 1680 IndexedDBConnection* connection,
1653 const std::vector<int64_t>& object_store_ids, 1681 const std::vector<int64_t>& object_store_ids,
(...skipping 13 matching lines...) Expand all
1667 TransactionCreated(IndexedDBClassFactory::Get()->CreateIndexedDBTransaction( 1695 TransactionCreated(IndexedDBClassFactory::Get()->CreateIndexedDBTransaction(
1668 transaction_id, connection->callbacks(), 1696 transaction_id, connection->callbacks(),
1669 std::set<int64_t>(object_store_ids.begin(), object_store_ids.end()), mode, 1697 std::set<int64_t>(object_store_ids.begin(), object_store_ids.end()), mode,
1670 this, new IndexedDBBackingStore::Transaction(backing_store_.get()))); 1698 this, new IndexedDBBackingStore::Transaction(backing_store_.get())));
1671 } 1699 }
1672 1700
1673 void IndexedDBDatabase::TransactionCreated(IndexedDBTransaction* transaction) { 1701 void IndexedDBDatabase::TransactionCreated(IndexedDBTransaction* transaction) {
1674 transactions_[transaction->id()] = transaction; 1702 transactions_[transaction->id()] = transaction;
1675 } 1703 }
1676 1704
1705 bool IndexedDBDatabase::IsUpgradeRunning() const {
1706 return transaction_coordinator_.IsRunningVersionChangeTransaction();
1707 }
1708
1709 bool IndexedDBDatabase::IsUpgradePendingOrRunning() const {
1710 return pending_run_version_change_transaction_call_ || IsUpgradeRunning();
1711 }
1712
1677 bool IndexedDBDatabase::IsOpenConnectionBlocked() const { 1713 bool IndexedDBDatabase::IsOpenConnectionBlocked() const {
1678 return !pending_delete_calls_.empty() || 1714 return IsUpgradePendingOrRunning() || !blocked_delete_calls_.empty();
cmumford 2016/06/23 21:44:19 nit: blocked_delete_calls_.empty() is constant tim
jsbell 2016/06/23 22:26:50 IsUpgradePendingOrRunning() should be constant tim
1679 transaction_coordinator_.IsRunningVersionChangeTransaction() ||
1680 pending_run_version_change_transaction_call_;
1681 } 1715 }
1682 1716
1683 void IndexedDBDatabase::OpenConnection( 1717 void IndexedDBDatabase::OpenConnection(
1684 const IndexedDBPendingConnection& connection) { 1718 const IndexedDBPendingConnection& connection) {
1685 DCHECK(backing_store_.get()); 1719 DCHECK(backing_store_.get());
1686 1720
1687 // TODO(jsbell): Should have a priority queue so that higher version
1688 // requests are processed first. http://crbug.com/225850
1689 if (IsOpenConnectionBlocked()) { 1721 if (IsOpenConnectionBlocked()) {
1690 // The backing store only detects data loss when it is first opened. The 1722 // The backing store only detects data loss when it is first opened. The
1691 // presence of existing connections means we didn't even check for data loss 1723 // presence of existing connections means we didn't even check for data loss
1692 // so there'd better not be any. 1724 // so there'd better not be any.
1693 DCHECK_NE(blink::WebIDBDataLossTotal, connection.callbacks->data_loss()); 1725 DCHECK_NE(blink::WebIDBDataLossTotal, connection.callbacks->data_loss());
1694 pending_open_calls_.push_back(connection); 1726 pending_open_calls_.push_back(connection);
1695 return; 1727 return;
1696 } 1728 }
1697 1729
1698 if (metadata_.id == kInvalidId) { 1730 if (metadata_.id == kInvalidId) {
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
1805 scoped_refptr<IndexedDBCallbacks> callbacks, 1837 scoped_refptr<IndexedDBCallbacks> callbacks,
1806 std::unique_ptr<IndexedDBConnection> connection, 1838 std::unique_ptr<IndexedDBConnection> connection,
1807 int64_t transaction_id, 1839 int64_t transaction_id,
1808 int64_t requested_version) { 1840 int64_t requested_version) {
1809 std::vector<int64_t> object_store_ids; 1841 std::vector<int64_t> object_store_ids;
1810 CreateTransaction(transaction_id, 1842 CreateTransaction(transaction_id,
1811 connection.get(), 1843 connection.get(),
1812 object_store_ids, 1844 object_store_ids,
1813 blink::WebIDBTransactionModeVersionChange); 1845 blink::WebIDBTransactionModeVersionChange);
1814 1846
1847 DCHECK(transaction_coordinator_.IsRunningVersionChangeTransaction());
1815 transactions_[transaction_id]->ScheduleTask( 1848 transactions_[transaction_id]->ScheduleTask(
1816 base::Bind(&IndexedDBDatabase::VersionChangeOperation, 1849 base::Bind(&IndexedDBDatabase::VersionChangeOperation,
1817 this, 1850 this,
1818 requested_version, 1851 requested_version,
1819 callbacks, 1852 callbacks,
1820 base::Passed(&connection))); 1853 base::Passed(&connection)));
1821 DCHECK(!pending_second_half_open_); 1854 DCHECK(!pending_second_half_open_);
1822 } 1855 }
1823 1856
1824 void IndexedDBDatabase::DeleteDatabase( 1857 void IndexedDBDatabase::DeleteDatabase(
1825 scoped_refptr<IndexedDBCallbacks> callbacks) { 1858 scoped_refptr<IndexedDBCallbacks> callbacks) {
1859 // If there's a running upgrade, the delete calls should be deferred so that
1860 // "versionchange" is seen after "success" fires.
1861 if (IsUpgradeRunning()) {
1862 pending_delete_calls_.push_back(new PendingDeleteCall(callbacks));
1863 return;
1864 }
1826 1865
1827 if (IsDeleteDatabaseBlocked()) { 1866 if (IsDeleteDatabaseBlocked()) {
1828 for (const auto* connection : connections_) { 1867 for (const auto* connection : connections_) {
1829 // Front end ensures the event is not fired at connections that have 1868 // Front end ensures the event is not fired at connections that have
1830 // close_pending set. 1869 // close_pending set.
1831 connection->callbacks()->OnVersionChange( 1870 connection->callbacks()->OnVersionChange(
1832 metadata_.version, IndexedDBDatabaseMetadata::NO_VERSION); 1871 metadata_.version, IndexedDBDatabaseMetadata::NO_VERSION);
1833 } 1872 }
1834 // OnBlocked will be fired at the request when one of the other 1873 // OnBlocked will be fired at the request when one of the other
1835 // connections acks that the OnVersionChange was ignored. 1874 // connections acks that the OnVersionChange was ignored.
1836 1875
1837 pending_delete_calls_.push_back(new PendingDeleteCall(callbacks)); 1876 blocked_delete_calls_.push_back(new PendingDeleteCall(callbacks));
1838 return; 1877 return;
1839 } 1878 }
1840 DeleteDatabaseFinal(callbacks); 1879 DeleteDatabaseFinal(callbacks);
1841 } 1880 }
1842 1881
1843 bool IndexedDBDatabase::IsDeleteDatabaseBlocked() const { 1882 bool IndexedDBDatabase::IsDeleteDatabaseBlocked() const {
1844 return !!ConnectionCount(); 1883 return IsUpgradePendingOrRunning() || !!ConnectionCount();
1845 } 1884 }
1846 1885
1847 void IndexedDBDatabase::DeleteDatabaseFinal( 1886 void IndexedDBDatabase::DeleteDatabaseFinal(
1848 scoped_refptr<IndexedDBCallbacks> callbacks) { 1887 scoped_refptr<IndexedDBCallbacks> callbacks) {
1849 DCHECK(!IsDeleteDatabaseBlocked()); 1888 DCHECK(!IsDeleteDatabaseBlocked());
1850 DCHECK(backing_store_.get()); 1889 DCHECK(backing_store_.get());
1851 leveldb::Status s = backing_store_->DeleteDatabase(metadata_.name); 1890 leveldb::Status s = backing_store_->DeleteDatabase(metadata_.name);
1852 if (!s.ok()) { 1891 if (!s.ok()) {
1853 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError, 1892 IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
1854 "Internal error deleting database."); 1893 "Internal error deleting database.");
(...skipping 18 matching lines...) Expand all
1873 scoped_refptr<IndexedDBDatabase> protect(this); 1912 scoped_refptr<IndexedDBDatabase> protect(this);
1874 ConnectionSet::const_iterator it = connections_.begin(); 1913 ConnectionSet::const_iterator it = connections_.begin();
1875 while (it != connections_.end()) { 1914 while (it != connections_.end()) {
1876 IndexedDBConnection* connection = *it++; 1915 IndexedDBConnection* connection = *it++;
1877 connection->ForceClose(); 1916 connection->ForceClose();
1878 } 1917 }
1879 DCHECK(connections_.empty()); 1918 DCHECK(connections_.empty());
1880 } 1919 }
1881 1920
1882 void IndexedDBDatabase::VersionChangeIgnored() { 1921 void IndexedDBDatabase::VersionChangeIgnored() {
1883 if (pending_run_version_change_transaction_call_) 1922 if (pending_run_version_change_transaction_call_) {
1884 pending_run_version_change_transaction_call_->callbacks()->OnBlocked( 1923 pending_run_version_change_transaction_call_->callbacks()->OnBlocked(
1885 metadata_.version); 1924 metadata_.version);
1925 }
1886 1926
1887 for (const auto& pending_delete_call : pending_delete_calls_) 1927 for (const auto& pending_delete_call : blocked_delete_calls_)
1888 pending_delete_call->callbacks()->OnBlocked(metadata_.version); 1928 pending_delete_call->callbacks()->OnBlocked(metadata_.version);
1889 } 1929 }
1890 1930
1891
1892 void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) { 1931 void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) {
1893 DCHECK(connections_.count(connection)); 1932 DCHECK(connections_.count(connection));
1894 DCHECK(connection->IsConnected()); 1933 DCHECK(connection->IsConnected());
1895 DCHECK(connection->database() == this); 1934 DCHECK(connection->database() == this);
1896 1935
1897 IDB_TRACE("IndexedDBDatabase::Close"); 1936 IDB_TRACE("IndexedDBDatabase::Close");
1898 1937
1899 connections_.erase(connection); 1938 connections_.erase(connection);
1900 1939
1901 // Abort outstanding transactions from the closing connection. This 1940 // Abort outstanding transactions from the closing connection. This
(...skipping 15 matching lines...) Expand all
1917 pending_second_half_open_->callbacks()->OnError( 1956 pending_second_half_open_->callbacks()->OnError(
1918 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError, 1957 IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionAbortError,
1919 "The connection was closed.")); 1958 "The connection was closed."));
1920 pending_second_half_open_.reset(); 1959 pending_second_half_open_.reset();
1921 } 1960 }
1922 1961
1923 ProcessPendingCalls(); 1962 ProcessPendingCalls();
1924 1963
1925 // TODO(jsbell): Add a test for the pending_open_calls_ cases below. 1964 // TODO(jsbell): Add a test for the pending_open_calls_ cases below.
1926 if (!ConnectionCount() && !pending_open_calls_.size() && 1965 if (!ConnectionCount() && !pending_open_calls_.size() &&
1927 !pending_delete_calls_.size()) { 1966 !blocked_delete_calls_.size()) {
cmumford 2016/06/23 21:44:19 Nit: I know you're sticking with existing pattern,
jsbell 2016/06/23 22:26:50 Whoops, yeah, I'll use empty(). That was ported fr
1928 DCHECK(transactions_.empty()); 1967 DCHECK(transactions_.empty());
1929 backing_store_ = NULL; 1968 backing_store_ = NULL;
1930 factory_->ReleaseDatabase(identifier_, forced); 1969 factory_->ReleaseDatabase(identifier_, forced);
1931 } 1970 }
1932 } 1971 }
1933 1972
1934 void IndexedDBDatabase::CreateObjectStoreAbortOperation( 1973 void IndexedDBDatabase::CreateObjectStoreAbortOperation(
1935 int64_t object_store_id, 1974 int64_t object_store_id,
1936 IndexedDBTransaction* transaction) { 1975 IndexedDBTransaction* transaction) {
1937 DCHECK(!transaction); 1976 DCHECK(!transaction);
(...skipping 12 matching lines...) Expand all
1950 1989
1951 void IndexedDBDatabase::VersionChangeAbortOperation( 1990 void IndexedDBDatabase::VersionChangeAbortOperation(
1952 int64_t previous_version, 1991 int64_t previous_version,
1953 IndexedDBTransaction* transaction) { 1992 IndexedDBTransaction* transaction) {
1954 DCHECK(!transaction); 1993 DCHECK(!transaction);
1955 IDB_TRACE("IndexedDBDatabase::VersionChangeAbortOperation"); 1994 IDB_TRACE("IndexedDBDatabase::VersionChangeAbortOperation");
1956 metadata_.version = previous_version; 1995 metadata_.version = previous_version;
1957 } 1996 }
1958 1997
1959 } // namespace content 1998 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698