• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
6 
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"
11 
12 namespace content {
13 
IndexedDBTransactionCoordinator()14 IndexedDBTransactionCoordinator::IndexedDBTransactionCoordinator() {}
15 
~IndexedDBTransactionCoordinator()16 IndexedDBTransactionCoordinator::~IndexedDBTransactionCoordinator() {
17   DCHECK(!queued_transactions_.size());
18   DCHECK(!started_transactions_.size());
19 }
20 
DidCreateTransaction(scoped_refptr<IndexedDBTransaction> transaction)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());
26 
27   queued_transactions_.insert(transaction);
28   ProcessQueuedTransactions();
29 }
30 
DidFinishTransaction(IndexedDBTransaction * transaction)31 void IndexedDBTransactionCoordinator::DidFinishTransaction(
32     IndexedDBTransaction* transaction) {
33   if (queued_transactions_.count(transaction)) {
34     DCHECK(!started_transactions_.count(transaction));
35     queued_transactions_.erase(transaction);
36   } else {
37     DCHECK(started_transactions_.count(transaction));
38     started_transactions_.erase(transaction);
39   }
40 
41   ProcessQueuedTransactions();
42 }
43 
IsRunningVersionChangeTransaction() const44 bool IndexedDBTransactionCoordinator::IsRunningVersionChangeTransaction()
45     const {
46   return !started_transactions_.empty() &&
47          (*started_transactions_.begin())->mode() ==
48              blink::WebIDBTransactionModeVersionChange;
49 }
50 
51 #ifndef NDEBUG
52 // Verifies internal consistency while returning whether anything is found.
IsActive(IndexedDBTransaction * transaction)53 bool IndexedDBTransactionCoordinator::IsActive(
54     IndexedDBTransaction* transaction) {
55   bool found = false;
56   if (queued_transactions_.count(transaction))
57     found = true;
58   if (started_transactions_.count(transaction)) {
59     DCHECK(!found);
60     found = true;
61   }
62   return found;
63 }
64 #endif
65 
66 std::vector<const IndexedDBTransaction*>
GetTransactions() const67 IndexedDBTransactionCoordinator::GetTransactions() const {
68   std::vector<const IndexedDBTransaction*> result;
69 
70   for (TransactionSet::const_iterator it = started_transactions_.begin();
71        it != started_transactions_.end();
72        ++it) {
73     result.push_back(it->get());
74   }
75   for (TransactionSet::const_iterator it = queued_transactions_.begin();
76        it != queued_transactions_.end();
77        ++it) {
78     result.push_back(it->get());
79   }
80 
81   return result;
82 }
83 
ProcessQueuedTransactions()84 void IndexedDBTransactionCoordinator::ProcessQueuedTransactions() {
85   if (queued_transactions_.empty())
86     return;
87 
88   DCHECK(!IsRunningVersionChangeTransaction());
89 
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();
99        ++it) {
100     IndexedDBTransaction* transaction = it->get();
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());
106     }
107   }
108 
109   TransactionSet::const_iterator it = queued_transactions_.begin();
110   while (it != queued_transactions_.end()) {
111     scoped_refptr<IndexedDBTransaction> transaction = *it;
112     ++it;
113     if (CanStartTransaction(transaction.get(), 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());
119     }
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());
126     }
127   }
128 }
129 
130 template<typename T>
DoSetsIntersect(const std::set<T> & set1,const std::set<T> & set2)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()) {
136     if (*it1 < *it2)
137       ++it1;
138     else if (*it2 < *it1)
139       ++it2;
140     else
141       return true;
142   }
143   return false;
144 }
145 
CanStartTransaction(IndexedDBTransaction * const transaction,const std::set<int64> & locked_scope) const146 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());
155       return true;
156 
157     case blink::WebIDBTransactionModeReadOnly:
158       return true;
159 
160     case blink::WebIDBTransactionModeReadWrite:
161       return !DoSetsIntersect(transaction->scope(), locked_scope);
162   }
163   NOTREACHED();
164   return false;
165 }
166 
167 }  // namespace content
168