1/* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "IDBTransactionCoordinator.h" 28 29#if ENABLE(INDEXED_DATABASE) 30 31#include "IDBDatabaseBackendImpl.h" 32#include "IDBTransactionBackendImpl.h" 33 34namespace WebCore { 35 36PassOwnPtr<IDBTransactionCoordinator> IDBTransactionCoordinator::create() 37{ 38 return adoptPtr(new IDBTransactionCoordinator()); 39} 40 41IDBTransactionCoordinator::IDBTransactionCoordinator() 42{ 43} 44 45IDBTransactionCoordinator::~IDBTransactionCoordinator() 46{ 47} 48 49void IDBTransactionCoordinator::didCreateTransaction(IDBTransactionBackendImpl* transaction) 50{ 51 ASSERT(!m_transactions.contains(transaction)); 52 m_transactions.add(transaction, transaction); 53} 54 55void IDBTransactionCoordinator::didStartTransaction(IDBTransactionBackendImpl* transaction) 56{ 57 ASSERT(m_transactions.contains(transaction)); 58 59 m_queuedTransactions.add(transaction); 60 processStartedTransactions(); 61} 62 63void IDBTransactionCoordinator::didFinishTransaction(IDBTransactionBackendImpl* transaction) 64{ 65 ASSERT(m_transactions.contains(transaction)); 66 67 if (m_queuedTransactions.contains(transaction)) { 68 ASSERT(!m_startedTransactions.contains(transaction)); 69 m_queuedTransactions.remove(transaction); 70 } else if (m_startedTransactions.contains(transaction)) 71 m_startedTransactions.remove(transaction); 72 73 m_transactions.remove(transaction); 74 75 processStartedTransactions(); 76} 77 78#ifndef NDEBUG 79// Verifies internal consistiency while returning whether anything is found. 80bool IDBTransactionCoordinator::isActive(IDBTransactionBackendImpl* transaction) 81{ 82 bool found = false; 83 if (m_queuedTransactions.contains(transaction)) 84 found = true; 85 if (m_startedTransactions.contains(transaction)) { 86 ASSERT(!found); 87 found = true; 88 } 89 ASSERT(found == m_transactions.contains(transaction)); 90 return found; 91} 92#endif 93 94void IDBTransactionCoordinator::processStartedTransactions() 95{ 96 if (m_queuedTransactions.isEmpty()) 97 return; 98 99 ASSERT(m_startedTransactions.isEmpty() || (*m_startedTransactions.begin())->mode() != IndexedDB::TransactionVersionChange); 100 101 ListHashSet<IDBTransactionBackendImpl*>::const_iterator it = m_queuedTransactions.begin(); 102 while (it != m_queuedTransactions.end()) { 103 IDBTransactionBackendImpl* transaction = *it; 104 ++it; 105 if (canRunTransaction(transaction)) { 106 m_queuedTransactions.remove(transaction); 107 m_startedTransactions.add(transaction); 108 transaction->run(); 109 } 110 } 111} 112 113static bool doScopesOverlap(const HashSet<int64_t>& scope1, const HashSet<int64_t>& scope2) 114{ 115 for (HashSet<int64_t>::const_iterator it = scope1.begin(); it != scope1.end(); ++it) { 116 if (scope2.contains(*it)) 117 return true; 118 } 119 return false; 120} 121 122bool IDBTransactionCoordinator::canRunTransaction(IDBTransactionBackendImpl* transaction) 123{ 124 ASSERT(m_queuedTransactions.contains(transaction)); 125 switch (transaction->mode()) { 126 case IndexedDB::TransactionVersionChange: 127 ASSERT(m_queuedTransactions.size() == 1); 128 ASSERT(m_startedTransactions.isEmpty()); 129 return true; 130 131 case IndexedDB::TransactionReadOnly: 132 return true; 133 134 case IndexedDB::TransactionReadWrite: 135 for (HashSet<IDBTransactionBackendImpl*>::const_iterator it = m_startedTransactions.begin(); it != m_startedTransactions.end(); ++it) { 136 if ((*it)->mode() == IndexedDB::TransactionReadWrite && doScopesOverlap(transaction->scope(), (*it)->scope())) 137 return false; 138 } 139 for (ListHashSet<IDBTransactionBackendImpl*>::const_iterator it = m_queuedTransactions.begin(); *it != transaction; ++it) { 140 ASSERT(it != m_queuedTransactions.end()); 141 if ((*it)->mode() == IndexedDB::TransactionReadWrite && doScopesOverlap(transaction->scope(), (*it)->scope())) 142 return false; 143 } 144 return true; 145 } 146 ASSERT_NOT_REACHED(); 147 return false; 148} 149 150}; 151 152#endif // ENABLE(INDEXED_DATABASE) 153