Home | History | Annotate | Download | only in indexed_db
      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 
     11 namespace content {
     12 
     13 IndexedDBTransactionCoordinator::IndexedDBTransactionCoordinator() {}
     14 
     15 IndexedDBTransactionCoordinator::~IndexedDBTransactionCoordinator() {
     16   DCHECK(!transactions_.size());
     17   DCHECK(!queued_transactions_.size());
     18   DCHECK(!started_transactions_.size());
     19 }
     20 
     21 void IndexedDBTransactionCoordinator::DidCreateTransaction(
     22     IndexedDBTransaction* transaction) {
     23   DCHECK(transactions_.find(transaction) == transactions_.end());
     24   transactions_[transaction] = transaction;
     25 }
     26 
     27 void IndexedDBTransactionCoordinator::DidStartTransaction(
     28     IndexedDBTransaction* transaction) {
     29   DCHECK(transactions_.find(transaction) != transactions_.end());
     30 
     31   queued_transactions_.insert(transaction);
     32   ProcessStartedTransactions();
     33 }
     34 
     35 void IndexedDBTransactionCoordinator::DidFinishTransaction(
     36     IndexedDBTransaction* transaction) {
     37   DCHECK(transactions_.find(transaction) != transactions_.end());
     38 
     39   if (queued_transactions_.has(transaction)) {
     40     DCHECK(!started_transactions_.has(transaction));
     41     queued_transactions_.erase(transaction);
     42   } else {
     43     if (started_transactions_.has(transaction))
     44       started_transactions_.erase(transaction);
     45   }
     46   transactions_.erase(transaction);
     47 
     48   ProcessStartedTransactions();
     49 }
     50 
     51 #ifndef NDEBUG
     52 // Verifies internal consistency while returning whether anything is found.
     53 bool IndexedDBTransactionCoordinator::IsActive(
     54     IndexedDBTransaction* transaction) {
     55   bool found = false;
     56   if (queued_transactions_.has(transaction))
     57     found = true;
     58   if (started_transactions_.has(transaction)) {
     59     DCHECK(!found);
     60     found = true;
     61   }
     62   DCHECK_EQ(found, (transactions_.find(transaction) != transactions_.end()));
     63   return found;
     64 }
     65 #endif
     66 
     67 std::vector<const IndexedDBTransaction*>
     68 IndexedDBTransactionCoordinator::GetTransactions() const {
     69   std::vector<const IndexedDBTransaction*> result;
     70 
     71   for (list_set<IndexedDBTransaction*>::const_iterator it =
     72            started_transactions_.begin();
     73        it != started_transactions_.end();
     74        ++it) {
     75     result.push_back(*it);
     76   }
     77   for (list_set<IndexedDBTransaction*>::const_iterator it =
     78            queued_transactions_.begin();
     79        it != queued_transactions_.end();
     80        ++it) {
     81     result.push_back(*it);
     82   }
     83 
     84   return result;
     85 }
     86 
     87 void IndexedDBTransactionCoordinator::ProcessStartedTransactions() {
     88   if (queued_transactions_.empty())
     89     return;
     90 
     91   DCHECK(started_transactions_.empty() ||
     92          (*started_transactions_.begin())->mode() !=
     93              indexed_db::TRANSACTION_VERSION_CHANGE);
     94 
     95   list_set<IndexedDBTransaction*>::const_iterator it =
     96       queued_transactions_.begin();
     97   while (it != queued_transactions_.end()) {
     98     IndexedDBTransaction* transaction = *it;
     99     ++it;
    100     if (CanRunTransaction(transaction)) {
    101       queued_transactions_.erase(transaction);
    102       started_transactions_.insert(transaction);
    103       transaction->Run();
    104     }
    105   }
    106 }
    107 
    108 static bool DoScopesOverlap(const std::set<int64>& scope1,
    109                             const std::set<int64>& scope2) {
    110   for (std::set<int64>::const_iterator it = scope1.begin(); it != scope1.end();
    111        ++it) {
    112     if (scope2.find(*it) != scope2.end())
    113       return true;
    114   }
    115   return false;
    116 }
    117 
    118 bool IndexedDBTransactionCoordinator::CanRunTransaction(
    119     IndexedDBTransaction* transaction) {
    120   DCHECK(queued_transactions_.has(transaction));
    121   switch (transaction->mode()) {
    122     case indexed_db::TRANSACTION_VERSION_CHANGE:
    123       DCHECK_EQ(static_cast<size_t>(1), queued_transactions_.size());
    124       DCHECK(started_transactions_.empty());
    125       return true;
    126 
    127     case indexed_db::TRANSACTION_READ_ONLY:
    128       return true;
    129 
    130     case indexed_db::TRANSACTION_READ_WRITE:
    131       for (list_set<IndexedDBTransaction*>::const_iterator it =
    132                started_transactions_.begin();
    133            it != started_transactions_.end();
    134            ++it) {
    135         IndexedDBTransaction* other = *it;
    136         if (other->mode() == indexed_db::TRANSACTION_READ_WRITE &&
    137             DoScopesOverlap(transaction->scope(), other->scope()))
    138           return false;
    139       }
    140       for (list_set<IndexedDBTransaction*>::const_iterator it =
    141                queued_transactions_.begin();
    142            *it != transaction;
    143            ++it) {
    144         DCHECK(it != queued_transactions_.end());
    145         IndexedDBTransaction* other = *it;
    146         if (other->mode() == indexed_db::TRANSACTION_READ_WRITE &&
    147             DoScopesOverlap(transaction->scope(), other->scope()))
    148           return false;
    149       }
    150       return true;
    151   }
    152   NOTREACHED();
    153   return false;
    154 }
    155 
    156 }  // namespace content
    157