1/* 2 * Copyright (C) 2013 Apple 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "modules/webdatabase/DatabaseBackend.h" 28 29#include "platform/Logging.h" 30#include "modules/webdatabase/ChangeVersionData.h" 31#include "modules/webdatabase/ChangeVersionWrapper.h" 32#include "modules/webdatabase/DatabaseContext.h" 33#include "modules/webdatabase/DatabaseTask.h" 34#include "modules/webdatabase/DatabaseThread.h" 35#include "modules/webdatabase/DatabaseTracker.h" 36#include "modules/webdatabase/SQLTransaction.h" 37#include "modules/webdatabase/SQLTransactionBackend.h" 38#include "modules/webdatabase/SQLTransactionClient.h" 39#include "modules/webdatabase/SQLTransactionCoordinator.h" 40 41namespace WebCore { 42 43DatabaseBackend::DatabaseBackend(PassRefPtr<DatabaseContext> databaseContext, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize) 44 : DatabaseBackendBase(databaseContext, name, expectedVersion, displayName, estimatedSize, DatabaseType::Async) 45 , m_transactionInProgress(false) 46 , m_isTransactionQueueEnabled(true) 47{ 48} 49 50bool DatabaseBackend::openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage) 51{ 52 DatabaseTaskSynchronizer synchronizer; 53 if (!databaseContext()->databaseThread() || databaseContext()->databaseThread()->terminationRequested(&synchronizer)) 54 return false; 55 56 DatabaseTracker::tracker().prepareToOpenDatabase(this); 57 bool success = false; 58 OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, error, errorMessage, success); 59 databaseContext()->databaseThread()->scheduleTask(task.release()); 60 synchronizer.waitForTaskCompletion(); 61 62 return success; 63} 64 65bool DatabaseBackend::performOpenAndVerify(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage) 66{ 67 if (DatabaseBackendBase::performOpenAndVerify(setVersionInNewDatabase, error, errorMessage)) { 68 if (databaseContext()->databaseThread()) 69 databaseContext()->databaseThread()->recordDatabaseOpen(this); 70 71 return true; 72 } 73 74 return false; 75} 76 77void DatabaseBackend::close() 78{ 79 ASSERT(databaseContext()->databaseThread()); 80 ASSERT(databaseContext()->databaseThread()->isDatabaseThread()); 81 82 { 83 MutexLocker locker(m_transactionInProgressMutex); 84 85 // Clean up transactions that have not been scheduled yet: 86 // Transaction phase 1 cleanup. See comment on "What happens if a 87 // transaction is interrupted?" at the top of SQLTransactionBackend.cpp. 88 RefPtr<SQLTransactionBackend> transaction; 89 while (!m_transactionQueue.isEmpty()) { 90 transaction = m_transactionQueue.takeFirst(); 91 transaction->notifyDatabaseThreadIsShuttingDown(); 92 } 93 94 m_isTransactionQueueEnabled = false; 95 m_transactionInProgress = false; 96 } 97 98 closeDatabase(); 99 databaseContext()->databaseThread()->recordDatabaseClosed(this); 100} 101 102PassRefPtr<SQLTransactionBackend> DatabaseBackend::runTransaction(PassRefPtr<SQLTransaction> transaction, 103 bool readOnly, const ChangeVersionData* data) 104{ 105 MutexLocker locker(m_transactionInProgressMutex); 106 if (!m_isTransactionQueueEnabled) 107 return 0; 108 109 RefPtr<SQLTransactionWrapper> wrapper; 110 if (data) 111 wrapper = ChangeVersionWrapper::create(data->oldVersion(), data->newVersion()); 112 113 RefPtr<SQLTransactionBackend> transactionBackend = SQLTransactionBackend::create(this, transaction, wrapper, readOnly); 114 m_transactionQueue.append(transactionBackend); 115 if (!m_transactionInProgress) 116 scheduleTransaction(); 117 118 return transactionBackend; 119} 120 121void DatabaseBackend::inProgressTransactionCompleted() 122{ 123 MutexLocker locker(m_transactionInProgressMutex); 124 m_transactionInProgress = false; 125 scheduleTransaction(); 126} 127 128void DatabaseBackend::scheduleTransaction() 129{ 130 ASSERT(!m_transactionInProgressMutex.tryLock()); // Locked by caller. 131 RefPtr<SQLTransactionBackend> transaction; 132 133 if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty()) 134 transaction = m_transactionQueue.takeFirst(); 135 136 if (transaction && databaseContext()->databaseThread()) { 137 OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction); 138 WTF_LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction()); 139 m_transactionInProgress = true; 140 databaseContext()->databaseThread()->scheduleTask(task.release()); 141 } else 142 m_transactionInProgress = false; 143} 144 145void DatabaseBackend::scheduleTransactionStep(SQLTransactionBackend* transaction) 146{ 147 if (!databaseContext()->databaseThread()) 148 return; 149 150 OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction); 151 WTF_LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get()); 152 databaseContext()->databaseThread()->scheduleTask(task.release()); 153} 154 155SQLTransactionClient* DatabaseBackend::transactionClient() const 156{ 157 return databaseContext()->databaseThread()->transactionClient(); 158} 159 160SQLTransactionCoordinator* DatabaseBackend::transactionCoordinator() const 161{ 162 return databaseContext()->databaseThread()->transactionCoordinator(); 163} 164 165} // namespace WebCore 166