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