1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/basictypes.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/logging.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/browser/indexed_db/indexed_db_transaction.h"
10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "third_party/WebKit/public/platform/WebIDBTypes.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace content {
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransactionCoordinator::IndexedDBTransactionCoordinator() {}
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)IndexedDBTransactionCoordinator::~IndexedDBTransactionCoordinator() {
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!queued_transactions_.size());
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!started_transactions_.size());
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransactionCoordinator::DidCreateTransaction(
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    scoped_refptr<IndexedDBTransaction> transaction) {
23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!queued_transactions_.count(transaction));
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!started_transactions_.count(transaction));
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK_EQ(IndexedDBTransaction::CREATED, transaction->state());
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  queued_transactions_.insert(transaction);
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ProcessQueuedTransactions();
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void IndexedDBTransactionCoordinator::DidFinishTransaction(
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IndexedDBTransaction* transaction) {
338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (queued_transactions_.count(transaction)) {
348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    DCHECK(!started_transactions_.count(transaction));
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    queued_transactions_.erase(transaction);
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DCHECK(started_transactions_.count(transaction));
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    started_transactions_.erase(transaction);
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ProcessQueuedTransactions();
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool IndexedDBTransactionCoordinator::IsRunningVersionChangeTransaction()
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const {
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return !started_transactions_.empty() &&
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         (*started_transactions_.begin())->mode() ==
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch             blink::WebIDBTransactionModeVersionChange;
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#ifndef NDEBUG
52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Verifies internal consistency while returning whether anything is found.
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool IndexedDBTransactionCoordinator::IsActive(
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    IndexedDBTransaction* transaction) {
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool found = false;
568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (queued_transactions_.count(transaction))
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    found = true;
588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (started_transactions_.count(transaction)) {
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK(!found);
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    found = true;
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return found;
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
66ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstd::vector<const IndexedDBTransaction*>
67ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochIndexedDBTransactionCoordinator::GetTransactions() const {
68ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  std::vector<const IndexedDBTransaction*> result;
69ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (TransactionSet::const_iterator it = started_transactions_.begin();
71ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch       it != started_transactions_.end();
72ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch       ++it) {
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    result.push_back(it->get());
74ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (TransactionSet::const_iterator it = queued_transactions_.begin();
76ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch       it != queued_transactions_.end();
77ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch       ++it) {
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    result.push_back(it->get());
79ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
80ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
81ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return result;
82ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
83ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void IndexedDBTransactionCoordinator::ProcessQueuedTransactions() {
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (queued_transactions_.empty())
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!IsRunningVersionChangeTransaction());
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // The locked_scope set accumulates the ids of object stores in the scope of
9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // running read/write transactions. Other read-write transactions with
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // stores in this set may not be started. Read-only transactions may start,
9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // taking a snapshot of the database, which does not include uncommitted
9458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // data. ("Version change" transactions are exclusive, but handled by the
9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // connection sequencing in IndexedDBDatabase.)
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::set<int64> locked_scope;
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (TransactionSet::const_iterator it = started_transactions_.begin();
9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       it != started_transactions_.end();
9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       ++it) {
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    IndexedDBTransaction* transaction = it->get();
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (transaction->mode() == blink::WebIDBTransactionModeReadWrite) {
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // Started read/write transactions have exclusive access to the object
10358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // stores within their scopes.
10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      locked_scope.insert(transaction->scope().begin(),
10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                          transaction->scope().end());
10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  TransactionSet::const_iterator it = queued_transactions_.begin();
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (it != queued_transactions_.end()) {
111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    scoped_refptr<IndexedDBTransaction> transaction = *it;
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ++it;
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (CanStartTransaction(transaction.get(), locked_scope)) {
114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DCHECK_EQ(IndexedDBTransaction::CREATED, transaction->state());
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      queued_transactions_.erase(transaction);
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      started_transactions_.insert(transaction);
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      transaction->Start();
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DCHECK_EQ(IndexedDBTransaction::STARTED, transaction->state());
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (transaction->mode() == blink::WebIDBTransactionModeReadWrite) {
12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // Either the transaction started, so it has exclusive access to the
12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // stores in its scope, or per the spec the transaction which was
12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // created first must get access first, so the stores are also locked.
12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      locked_scope.insert(transaction->scope().begin(),
12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                          transaction->scope().end());
12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
130424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)template<typename T>
131424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)static bool DoSetsIntersect(const std::set<T>& set1,
132424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                            const std::set<T>& set2) {
133424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  typename std::set<T>::const_iterator it1 = set1.begin();
134424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  typename std::set<T>::const_iterator it2 = set2.begin();
135424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  while (it1 != set1.end() && it2 != set2.end()) {
136424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (*it1 < *it2)
137424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      ++it1;
138424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    else if (*it2 < *it1)
139424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      ++it2;
140424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    else
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return true;
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return false;
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool IndexedDBTransactionCoordinator::CanStartTransaction(
147d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    IndexedDBTransaction* const transaction,
148d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::set<int64>& locked_scope) const {
1498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK(queued_transactions_.count(transaction));
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  switch (transaction->mode()) {
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case blink::WebIDBTransactionModeVersionChange:
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK_EQ(1u, queued_transactions_.size());
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      DCHECK(started_transactions_.empty());
15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      DCHECK(locked_scope.empty());
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return true;
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case blink::WebIDBTransactionModeReadOnly:
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return true;
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    case blink::WebIDBTransactionModeReadWrite:
16158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return !DoSetsIntersect(transaction->scope(), locked_scope);
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  NOTREACHED();
164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return false;
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace content
168