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"
10 #include "third_party/WebKit/public/platform/WebIDBTypes.h"
14 IndexedDBTransactionCoordinator::IndexedDBTransactionCoordinator() {}
16 IndexedDBTransactionCoordinator::~IndexedDBTransactionCoordinator() {
17 DCHECK(!queued_transactions_
.size());
18 DCHECK(!started_transactions_
.size());
21 void IndexedDBTransactionCoordinator::DidCreateTransaction(
22 scoped_refptr
<IndexedDBTransaction
> transaction
) {
23 DCHECK(!queued_transactions_
.count(transaction
));
24 DCHECK(!started_transactions_
.count(transaction
));
25 DCHECK_EQ(IndexedDBTransaction::CREATED
, transaction
->state());
27 queued_transactions_
.insert(transaction
);
28 ProcessQueuedTransactions();
31 void IndexedDBTransactionCoordinator::DidFinishTransaction(
32 IndexedDBTransaction
* transaction
) {
33 if (queued_transactions_
.count(transaction
)) {
34 DCHECK(!started_transactions_
.count(transaction
));
35 queued_transactions_
.erase(transaction
);
37 DCHECK(started_transactions_
.count(transaction
));
38 started_transactions_
.erase(transaction
);
41 ProcessQueuedTransactions();
44 bool IndexedDBTransactionCoordinator::IsRunningVersionChangeTransaction()
46 return !started_transactions_
.empty() &&
47 (*started_transactions_
.begin())->mode() ==
48 blink::WebIDBTransactionModeVersionChange
;
52 // Verifies internal consistency while returning whether anything is found.
53 bool IndexedDBTransactionCoordinator::IsActive(
54 IndexedDBTransaction
* transaction
) {
56 if (queued_transactions_
.count(transaction
))
58 if (started_transactions_
.count(transaction
)) {
66 std::vector
<const IndexedDBTransaction
*>
67 IndexedDBTransactionCoordinator::GetTransactions() const {
68 std::vector
<const IndexedDBTransaction
*> result
;
70 for (TransactionSet::const_iterator it
= started_transactions_
.begin();
71 it
!= started_transactions_
.end();
73 result
.push_back(*it
);
75 for (TransactionSet::const_iterator it
= queued_transactions_
.begin();
76 it
!= queued_transactions_
.end();
78 result
.push_back(*it
);
84 void IndexedDBTransactionCoordinator::ProcessQueuedTransactions() {
85 if (queued_transactions_
.empty())
88 DCHECK(!IsRunningVersionChangeTransaction());
90 // The locked_scope set accumulates the ids of object stores in the scope of
91 // running read/write transactions. Other read-write transactions with
92 // stores in this set may not be started. Read-only transactions may start,
93 // taking a snapshot of the database, which does not include uncommitted
94 // data. ("Version change" transactions are exclusive, but handled by the
95 // connection sequencing in IndexedDBDatabase.)
96 std::set
<int64
> locked_scope
;
97 for (TransactionSet::const_iterator it
= started_transactions_
.begin();
98 it
!= started_transactions_
.end();
100 IndexedDBTransaction
* transaction
= *it
;
101 if (transaction
->mode() == blink::WebIDBTransactionModeReadWrite
) {
102 // Started read/write transactions have exclusive access to the object
103 // stores within their scopes.
104 locked_scope
.insert(transaction
->scope().begin(),
105 transaction
->scope().end());
109 TransactionSet::const_iterator it
= queued_transactions_
.begin();
110 while (it
!= queued_transactions_
.end()) {
111 scoped_refptr
<IndexedDBTransaction
> transaction
= *it
;
113 if (CanStartTransaction(transaction
, locked_scope
)) {
114 DCHECK_EQ(IndexedDBTransaction::CREATED
, transaction
->state());
115 queued_transactions_
.erase(transaction
);
116 started_transactions_
.insert(transaction
);
117 transaction
->Start();
118 DCHECK_EQ(IndexedDBTransaction::STARTED
, transaction
->state());
120 if (transaction
->mode() == blink::WebIDBTransactionModeReadWrite
) {
121 // Either the transaction started, so it has exclusive access to the
122 // stores in its scope, or per the spec the transaction which was
123 // created first must get access first, so the stores are also locked.
124 locked_scope
.insert(transaction
->scope().begin(),
125 transaction
->scope().end());
131 static bool DoSetsIntersect(const std::set
<T
>& set1
,
132 const std::set
<T
>& set2
) {
133 typename
std::set
<T
>::const_iterator it1
= set1
.begin();
134 typename
std::set
<T
>::const_iterator it2
= set2
.begin();
135 while (it1
!= set1
.end() && it2
!= set2
.end()) {
138 else if (*it2
< *it1
)
146 bool IndexedDBTransactionCoordinator::CanStartTransaction(
147 IndexedDBTransaction
* const transaction
,
148 const std::set
<int64
>& locked_scope
) const {
149 DCHECK(queued_transactions_
.count(transaction
));
150 switch (transaction
->mode()) {
151 case blink::WebIDBTransactionModeVersionChange
:
152 DCHECK_EQ(1u, queued_transactions_
.size());
153 DCHECK(started_transactions_
.empty());
154 DCHECK(locked_scope
.empty());
157 case blink::WebIDBTransactionModeReadOnly
:
160 case blink::WebIDBTransactionModeReadWrite
:
161 return !DoSetsIntersect(transaction
->scope(), locked_scope
);
167 } // namespace content