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"
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
);
36 DCHECK(started_transactions_
.count(transaction
));
37 started_transactions_
.erase(transaction
);
40 ProcessQueuedTransactions();
43 bool IndexedDBTransactionCoordinator::IsRunningVersionChangeTransaction()
45 return !started_transactions_
.empty() &&
46 (*started_transactions_
.begin())->mode() ==
47 indexed_db::TRANSACTION_VERSION_CHANGE
;
51 // Verifies internal consistency while returning whether anything is found.
52 bool IndexedDBTransactionCoordinator::IsActive(
53 IndexedDBTransaction
* transaction
) {
55 if (queued_transactions_
.count(transaction
))
57 if (started_transactions_
.count(transaction
)) {
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();
72 result
.push_back(*it
);
74 for (TransactionSet::const_iterator it
= queued_transactions_
.begin();
75 it
!= queued_transactions_
.end();
77 result
.push_back(*it
);
83 void IndexedDBTransactionCoordinator::ProcessQueuedTransactions() {
84 if (queued_transactions_
.empty())
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();
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
;
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());
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()) {
137 else if (*it2
< *it1
)
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());
156 case indexed_db::TRANSACTION_READ_ONLY
:
159 case indexed_db::TRANSACTION_READ_WRITE
:
160 return !DoSetsIntersect(transaction
->scope(), locked_scope
);
166 } // namespace content