Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / content / browser / indexed_db / indexed_db_transaction_coordinator.cc
bloba1eaad41ecd6dcef41137f33d497d33520d01f5d
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
3 // found in the LICENSE file.
5 #include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "content/browser/indexed_db/indexed_db_transaction.h"
11 namespace content {
13 IndexedDBTransactionCoordinator::IndexedDBTransactionCoordinator() {}
15 IndexedDBTransactionCoordinator::~IndexedDBTransactionCoordinator() {
16 DCHECK(!queued_transactions_.size());
17 DCHECK(!started_transactions_.size());
20 void IndexedDBTransactionCoordinator::DidCreateTransaction(
21 scoped_refptr<IndexedDBTransaction> transaction) {
22 DCHECK(!queued_transactions_.count(transaction));
23 DCHECK(!started_transactions_.count(transaction));
24 DCHECK_EQ(IndexedDBTransaction::CREATED, transaction->state());
26 queued_transactions_.insert(transaction);
27 ProcessQueuedTransactions();
30 void IndexedDBTransactionCoordinator::DidFinishTransaction(
31 IndexedDBTransaction* transaction) {
32 if (queued_transactions_.count(transaction)) {
33 DCHECK(!started_transactions_.count(transaction));
34 queued_transactions_.erase(transaction);
35 } else {
36 DCHECK(started_transactions_.count(transaction));
37 started_transactions_.erase(transaction);
40 ProcessQueuedTransactions();
43 bool IndexedDBTransactionCoordinator::IsRunningVersionChangeTransaction()
44 const {
45 return !started_transactions_.empty() &&
46 (*started_transactions_.begin())->mode() ==
47 indexed_db::TRANSACTION_VERSION_CHANGE;
50 #ifndef NDEBUG
51 // Verifies internal consistency while returning whether anything is found.
52 bool IndexedDBTransactionCoordinator::IsActive(
53 IndexedDBTransaction* transaction) {
54 bool found = false;
55 if (queued_transactions_.count(transaction))
56 found = true;
57 if (started_transactions_.count(transaction)) {
58 DCHECK(!found);
59 found = true;
61 return found;
63 #endif
65 std::vector<const IndexedDBTransaction*>
66 IndexedDBTransactionCoordinator::GetTransactions() const {
67 std::vector<const IndexedDBTransaction*> result;
69 for (TransactionSet::const_iterator it = started_transactions_.begin();
70 it != started_transactions_.end();
71 ++it) {
72 result.push_back(*it);
74 for (TransactionSet::const_iterator it = queued_transactions_.begin();
75 it != queued_transactions_.end();
76 ++it) {
77 result.push_back(*it);
80 return result;
83 void IndexedDBTransactionCoordinator::ProcessQueuedTransactions() {
84 if (queued_transactions_.empty())
85 return;
87 DCHECK(!IsRunningVersionChangeTransaction());
89 // The locked_scope set accumulates the ids of object stores in the scope of
90 // running read/write transactions. Other read-write transactions with
91 // stores in this set may not be started. Read-only transactions may start,
92 // taking a snapshot of the database, which does not include uncommitted
93 // data. ("Version change" transactions are exclusive, but handled by the
94 // connection sequencing in IndexedDBDatabase.)
95 std::set<int64> locked_scope;
96 for (TransactionSet::const_iterator it = started_transactions_.begin();
97 it != started_transactions_.end();
98 ++it) {
99 IndexedDBTransaction* transaction = *it;
100 if (transaction->mode() == indexed_db::TRANSACTION_READ_WRITE) {
101 // Started read/write transactions have exclusive access to the object
102 // stores within their scopes.
103 locked_scope.insert(transaction->scope().begin(),
104 transaction->scope().end());
108 TransactionSet::const_iterator it = queued_transactions_.begin();
109 while (it != queued_transactions_.end()) {
110 scoped_refptr<IndexedDBTransaction> transaction = *it;
111 ++it;
112 if (CanStartTransaction(transaction, locked_scope)) {
113 DCHECK_EQ(IndexedDBTransaction::CREATED, transaction->state());
114 queued_transactions_.erase(transaction);
115 started_transactions_.insert(transaction);
116 transaction->Start();
117 DCHECK_EQ(IndexedDBTransaction::STARTED, transaction->state());
119 if (transaction->mode() == indexed_db::TRANSACTION_READ_WRITE) {
120 // Either the transaction started, so it has exclusive access to the
121 // stores in its scope, or per the spec the transaction which was
122 // created first must get access first, so the stores are also locked.
123 locked_scope.insert(transaction->scope().begin(),
124 transaction->scope().end());
129 template<typename T>
130 static bool DoSetsIntersect(const std::set<T>& set1,
131 const std::set<T>& set2) {
132 typename std::set<T>::const_iterator it1 = set1.begin();
133 typename std::set<T>::const_iterator it2 = set2.begin();
134 while (it1 != set1.end() && it2 != set2.end()) {
135 if (*it1 < *it2)
136 ++it1;
137 else if (*it2 < *it1)
138 ++it2;
139 else
140 return true;
142 return false;
145 bool IndexedDBTransactionCoordinator::CanStartTransaction(
146 IndexedDBTransaction* const transaction,
147 const std::set<int64>& locked_scope) const {
148 DCHECK(queued_transactions_.count(transaction));
149 switch (transaction->mode()) {
150 case indexed_db::TRANSACTION_VERSION_CHANGE:
151 DCHECK_EQ(1u, queued_transactions_.size());
152 DCHECK(started_transactions_.empty());
153 DCHECK(locked_scope.empty());
154 return true;
156 case indexed_db::TRANSACTION_READ_ONLY:
157 return true;
159 case indexed_db::TRANSACTION_READ_WRITE:
160 return !DoSetsIntersect(transaction->scope(), locked_scope);
162 NOTREACHED();
163 return false;
166 } // namespace content