1e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block/* 2e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * Copyright (C) 2010 Google Inc. All rights reserved. 3e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * 4e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * Redistribution and use in source and binary forms, with or without 5e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * modification, are permitted provided that the following conditions 6e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * are met: 7e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * 8e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * 1. Redistributions of source code must retain the above copyright 9e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * notice, this list of conditions and the following disclaimer. 10e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * 2. Redistributions in binary form must reproduce the above copyright 11e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * notice, this list of conditions and the following disclaimer in the 12e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * documentation and/or other materials provided with the distribution. 13e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * 14e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 15e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block */ 25e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 26e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#include "config.h" 27e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#include "IDBTransactionBackendImpl.h" 28e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 29e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#if ENABLE(INDEXED_DATABASE) 30e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 3181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#include "IDBBackingStore.h" 32e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#include "IDBDatabaseBackendImpl.h" 334576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang#include "IDBDatabaseException.h" 34bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#include "IDBTransactionCoordinator.h" 35e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 36e8b154fd68f9b33be40a3590e58347f353835f5cSteve Blocknamespace WebCore { 37e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 382fc2651226baac27029e38c9d6ef883fa32084dbSteve BlockPassRefPtr<IDBTransactionBackendImpl> IDBTransactionBackendImpl::create(DOMStringList* objectStores, unsigned short mode, IDBDatabaseBackendImpl* database) 39e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block{ 402fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return adoptRef(new IDBTransactionBackendImpl(objectStores, mode, database)); 41e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block} 42e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 432fc2651226baac27029e38c9d6ef883fa32084dbSteve BlockIDBTransactionBackendImpl::IDBTransactionBackendImpl(DOMStringList* objectStores, unsigned short mode, IDBDatabaseBackendImpl* database) 44e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block : m_objectStoreNames(objectStores) 45e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block , m_mode(mode) 46a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch , m_state(Unused) 47e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block , m_database(database) 4881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch , m_transaction(database->backingStore()->createTransaction()) 49a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch , m_taskTimer(this, &IDBTransactionBackendImpl::taskTimerFired) 50a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch , m_taskEventTimer(this, &IDBTransactionBackendImpl::taskEventTimerFired) 51bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen , m_pendingEvents(0) 52e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block{ 534576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang ASSERT(m_objectStoreNames); 5428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_database->transactionCoordinator()->didCreateTransaction(this); 5528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu} 5628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 5728040489d744e0c5d475a88663056c9040ed5320Teng-Hui ZhuIDBTransactionBackendImpl::~IDBTransactionBackendImpl() 5828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu{ 5928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // It shouldn't be possible for this object to get deleted until it's either complete or aborted. 6028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(m_state == Finished); 61e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block} 62e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 634576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) WangPassRefPtr<IDBObjectStoreBackendInterface> IDBTransactionBackendImpl::objectStore(const String& name, ExceptionCode& ec) 64e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block{ 654576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang if (m_state == Finished) { 664576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang ec = IDBDatabaseException::NOT_ALLOWED_ERR; 674576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang return 0; 684576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang } 694576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang 704576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang // Does a linear search, but it really shouldn't be that slow in practice. 714576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang if (!m_objectStoreNames->isEmpty() && !m_objectStoreNames->contains(name)) { 724576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang ec = IDBDatabaseException::NOT_FOUND_ERR; 73bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen return 0; 744576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang } 754576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang 764576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang RefPtr<IDBObjectStoreBackendInterface> objectStore = m_database->objectStore(name); 774576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang // FIXME: This is only necessary right now beacuse a setVersion transaction could modify things 784576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang // between its creation (where another check occurs) and the .objectStore call. 794576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang // There's a bug to make this impossible in the spec. When we make it impossible here, we 804576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang // can remove this check. 814576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang if (!objectStore) { 824576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang ec = IDBDatabaseException::NOT_FOUND_ERR; 834576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang return 0; 844576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang } 854576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang return objectStore.release(); 86e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block} 87e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 88a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochbool IDBTransactionBackendImpl::scheduleTask(PassOwnPtr<ScriptExecutionContext::Task> task, PassOwnPtr<ScriptExecutionContext::Task> abortTask) 89e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block{ 90a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (m_state == Finished) 91bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen return false; 92bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 93bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_taskQueue.append(task); 94a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (abortTask) 95a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_abortTaskQueue.prepend(abortTask); 96a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 97a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (m_state == Unused) 98bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen start(); 99bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 100bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen return true; 101e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block} 102e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 103e8b154fd68f9b33be40a3590e58347f353835f5cSteve Blockvoid IDBTransactionBackendImpl::abort() 104e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block{ 105a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (m_state == Finished) 106bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen return; 107bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 108f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // The last reference to this object may be released while performing the 109f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // abort steps below. We therefore take a self reference to keep ourselves 110f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // alive while executing this method. 111f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch RefPtr<IDBTransactionBackendImpl> self(this); 112f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 113bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_state = Finished; 114a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_taskTimer.stop(); 115a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_taskEventTimer.stop(); 116bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_transaction->rollback(); 117a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 118a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // Run the abort tasks, if any. 119a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch while (!m_abortTaskQueue.isEmpty()) { 120a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch OwnPtr<ScriptExecutionContext::Task> task(m_abortTaskQueue.first().release()); 121a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_abortTaskQueue.removeFirst(); 122a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch task->performTask(0); 123a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 124a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 125e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block m_callbacks->onAbort(); 126bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_database->transactionCoordinator()->didFinishTransaction(this); 12728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ASSERT(!m_database->transactionCoordinator()->isActive(this)); 12828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_database = 0; 129bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 130bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 131bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenvoid IDBTransactionBackendImpl::didCompleteTaskEvents() 132bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 133a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (m_state == Finished) 134a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 135bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 136a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(m_state == Running); 137a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(m_pendingEvents); 138bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_pendingEvents--; 139bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 140a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!m_taskEventTimer.isActive()) 141a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_taskEventTimer.startOneShot(0); 142bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 143bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 144bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenvoid IDBTransactionBackendImpl::run() 145bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 146a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(m_state == StartPending || m_state == Running); 147a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(!m_taskTimer.isActive()); 148bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 149a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_taskTimer.startOneShot(0); 150bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 151bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 152bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenvoid IDBTransactionBackendImpl::start() 153bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 154a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(m_state == Unused); 155bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 156a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_state = StartPending; 157bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_database->transactionCoordinator()->didStartTransaction(this); 158bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 159bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 160bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsenvoid IDBTransactionBackendImpl::commit() 161bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 162f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // The last reference to this object may be released while performing the 163f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // commit steps below. We therefore take a self reference to keep ourselves 164f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // alive while executing this method. 165f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch RefPtr<IDBTransactionBackendImpl> self(this); 166a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(m_state == Running); 167bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 168bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_state = Finished; 169bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_transaction->commit(); 170a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_callbacks->onComplete(); 171bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_database->transactionCoordinator()->didFinishTransaction(this); 17228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu m_database = 0; 173bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen} 174bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 175a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid IDBTransactionBackendImpl::taskTimerFired(Timer<IDBTransactionBackendImpl>*) 176bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen{ 177bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen ASSERT(!m_taskQueue.isEmpty()); 178a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 179a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (m_state == StartPending) { 180a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_transaction->begin(); 181a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_state = Running; 1822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block } 183bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen 184bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen TaskQueue queue; 185bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen queue.swap(m_taskQueue); 186e14391e94c850b8bd03680c23b38978db68687a8John Reck while (!queue.isEmpty() && m_state != Finished) { 1872fc2651226baac27029e38c9d6ef883fa32084dbSteve Block ASSERT(m_state == Running); 188bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen OwnPtr<ScriptExecutionContext::Task> task(queue.first().release()); 189bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen queue.removeFirst(); 190bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen m_pendingEvents++; 191bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen task->performTask(0); 192bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen } 193e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block} 194e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 195a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid IDBTransactionBackendImpl::taskEventTimerFired(Timer<IDBTransactionBackendImpl>*) 196a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 197a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(m_state == Running); 198a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 199a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!m_pendingEvents && m_taskQueue.isEmpty()) { 200a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // The last task event has completed and the task 201a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // queue is empty. Commit the transaction. 202a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch commit(); 203a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 204a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch } 205a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 206a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // We are still waiting for other events to complete. However, 207a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // the task queue is non-empty and the timer is inactive. 208a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // We can therfore schedule the timer again. 209a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!m_taskQueue.isEmpty() && !m_taskTimer.isActive()) 210a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_taskTimer.startOneShot(0); 211a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 212a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 213e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block}; 214e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 215e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#endif // ENABLE(INDEXED_DATABASE) 216