Index: content/browser/indexed_db/indexed_db_transaction_coordinator.cc |
diff --git a/content/browser/indexed_db/indexed_db_transaction_coordinator.cc b/content/browser/indexed_db/indexed_db_transaction_coordinator.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..06d6fa0a061f5853f55b594b0359837fcb771ccb |
--- /dev/null |
+++ b/content/browser/indexed_db/indexed_db_transaction_coordinator.cc |
@@ -0,0 +1,135 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/indexed_db/indexed_db_transaction_coordinator.h" |
+ |
+#include "base/basictypes.h" |
+#include "base/logging.h" |
+#include "content/browser/indexed_db/indexed_db_transaction.h" |
+ |
+namespace content { |
+ |
+IndexedDBTransactionCoordinator::IndexedDBTransactionCoordinator() {} |
+ |
+IndexedDBTransactionCoordinator::~IndexedDBTransactionCoordinator() { |
+ // TODO(jsbell): DCHECK that all queues are empty. http://crbug.com/241821 |
+} |
+ |
+void IndexedDBTransactionCoordinator::DidCreateTransaction( |
+ IndexedDBTransaction* transaction) { |
+ DCHECK(transactions_.find(transaction) == transactions_.end()); |
+ transactions_[transaction] = transaction; |
+} |
+ |
+void IndexedDBTransactionCoordinator::DidStartTransaction( |
+ IndexedDBTransaction* transaction) { |
+ DCHECK(transactions_.find(transaction) != transactions_.end()); |
+ |
+ queued_transactions_.insert(transaction); |
+ ProcessStartedTransactions(); |
+} |
+ |
+void IndexedDBTransactionCoordinator::DidFinishTransaction( |
+ IndexedDBTransaction* transaction) { |
+ DCHECK(transactions_.find(transaction) != transactions_.end()); |
+ |
+ if (queued_transactions_.has(transaction)) { |
+ DCHECK(started_transactions_.find(transaction) == |
+ started_transactions_.end()); |
+ queued_transactions_.erase(transaction); |
+ } else { |
+ if (started_transactions_.find(transaction) != started_transactions_.end()) |
+ started_transactions_.erase(transaction); |
+ } |
+ transactions_.erase(transaction); |
+ |
+ ProcessStartedTransactions(); |
+} |
+ |
+#ifndef NDEBUG |
+// Verifies internal consistency while returning whether anything is found. |
+bool IndexedDBTransactionCoordinator::IsActive( |
+ IndexedDBTransaction* transaction) { |
+ bool found = false; |
+ if (queued_transactions_.has(transaction)) |
+ found = true; |
+ if (started_transactions_.find(transaction) != started_transactions_.end()) { |
+ DCHECK(!found); |
+ found = true; |
+ } |
+ DCHECK_EQ(found, (transactions_.find(transaction) != transactions_.end())); |
+ return found; |
+} |
+#endif |
+ |
+void IndexedDBTransactionCoordinator::ProcessStartedTransactions() { |
+ if (queued_transactions_.empty()) |
+ return; |
+ |
+ DCHECK(started_transactions_.empty() || |
+ (*started_transactions_.begin())->mode() != |
+ indexed_db::TRANSACTION_VERSION_CHANGE); |
+ |
+ list_set<IndexedDBTransaction*>::const_iterator it = |
+ queued_transactions_.begin(); |
+ while (it != queued_transactions_.end()) { |
+ IndexedDBTransaction* transaction = *it; |
+ ++it; |
+ if (CanRunTransaction(transaction)) { |
+ queued_transactions_.erase(transaction); |
+ started_transactions_.insert(transaction); |
+ transaction->Run(); |
+ } |
+ } |
+} |
+ |
+static bool DoScopesOverlap(const std::set<int64>& scope1, |
+ const std::set<int64>& scope2) { |
+ for (std::set<int64>::const_iterator it = scope1.begin(); it != scope1.end(); |
+ ++it) { |
+ if (scope2.find(*it) != scope2.end()) |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool IndexedDBTransactionCoordinator::CanRunTransaction( |
+ IndexedDBTransaction* transaction) { |
+ DCHECK(queued_transactions_.has(transaction)); |
+ switch (transaction->mode()) { |
+ case indexed_db::TRANSACTION_VERSION_CHANGE: |
+ DCHECK(queued_transactions_.size() == 1); |
+ DCHECK(started_transactions_.empty()); |
+ return true; |
+ |
+ case indexed_db::TRANSACTION_READ_ONLY: |
+ return true; |
+ |
+ case indexed_db::TRANSACTION_READ_WRITE: |
+ for (std::set<IndexedDBTransaction*>::const_iterator it = |
+ started_transactions_.begin(); |
+ it != started_transactions_.end(); |
+ ++it) { |
+ IndexedDBTransaction* other = *it; |
+ if (other->mode() == indexed_db::TRANSACTION_READ_WRITE && |
+ DoScopesOverlap(transaction->scope(), other->scope())) |
+ return false; |
+ } |
+ for (list_set<IndexedDBTransaction*>::const_iterator it = |
+ queued_transactions_.begin(); |
+ *it != transaction; |
+ ++it) { |
+ DCHECK(it != queued_transactions_.end()); |
+ IndexedDBTransaction* other = *it; |
+ if (other->mode() == indexed_db::TRANSACTION_READ_WRITE && |
+ DoScopesOverlap(transaction->scope(), other->scope())) |
+ return false; |
+ } |
+ return true; |
+ } |
+ NOTREACHED(); |
+ return false; |
+} |
+ |
+} // namespace content |