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 41 namespace WebCore { 42 43 DatabaseBackend::DatabaseBackend(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 50 void DatabaseBackend::trace(Visitor* visitor) 51 { 52 visitor->trace(m_transactionQueue); 53 DatabaseBackendBase::trace(visitor); 54 } 55 56 bool DatabaseBackend::openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage) 57 { 58 TaskSynchronizer synchronizer; 59 if (!databaseContext()->databaseThread() || databaseContext()->databaseThread()->terminationRequested(&synchronizer)) 60 return false; 61 62 DatabaseTracker::tracker().prepareToOpenDatabase(this); 63 bool success = false; 64 OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, error, errorMessage, success); 65 databaseContext()->databaseThread()->scheduleTask(task.release()); 66 synchronizer.waitForTaskCompletion(); 67 68 return success; 69 } 70 71 bool DatabaseBackend::performOpenAndVerify(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage) 72 { 73 if (DatabaseBackendBase::performOpenAndVerify(setVersionInNewDatabase, error, errorMessage)) { 74 if (databaseContext()->databaseThread()) 75 databaseContext()->databaseThread()->recordDatabaseOpen(this); 76 77 return true; 78 } 79 80 return false; 81 } 82 83 void DatabaseBackend::close() 84 { 85 ASSERT(databaseContext()->databaseThread()); 86 ASSERT(databaseContext()->databaseThread()->isDatabaseThread()); 87 88 { 89 MutexLocker locker(m_transactionInProgressMutex); 90 91 // Clean up transactions that have not been scheduled yet: 92 // Transaction phase 1 cleanup. See comment on "What happens if a 93 // transaction is interrupted?" at the top of SQLTransactionBackend.cpp. 94 RefPtrWillBeRawPtr<SQLTransactionBackend> transaction = nullptr; 95 while (!m_transactionQueue.isEmpty()) { 96 transaction = m_transactionQueue.takeFirst(); 97 transaction->notifyDatabaseThreadIsShuttingDown(); 98 } 99 100 m_isTransactionQueueEnabled = false; 101 m_transactionInProgress = false; 102 } 103 104 closeDatabase(); 105 databaseContext()->databaseThread()->recordDatabaseClosed(this); 106 } 107 108 PassRefPtrWillBeRawPtr<SQLTransactionBackend> DatabaseBackend::runTransaction(PassRefPtrWillBeRawPtr<SQLTransaction> transaction, 109 bool readOnly, const ChangeVersionData* data) 110 { 111 MutexLocker locker(m_transactionInProgressMutex); 112 if (!m_isTransactionQueueEnabled) 113 return nullptr; 114 115 RefPtrWillBeRawPtr<SQLTransactionWrapper> wrapper = nullptr; 116 if (data) 117 wrapper = ChangeVersionWrapper::create(data->oldVersion(), data->newVersion()); 118 119 RefPtrWillBeRawPtr<SQLTransactionBackend> transactionBackend = SQLTransactionBackend::create(this, transaction, wrapper.release(), readOnly); 120 m_transactionQueue.append(transactionBackend); 121 if (!m_transactionInProgress) 122 scheduleTransaction(); 123 124 return transactionBackend; 125 } 126 127 void DatabaseBackend::inProgressTransactionCompleted() 128 { 129 MutexLocker locker(m_transactionInProgressMutex); 130 m_transactionInProgress = false; 131 scheduleTransaction(); 132 } 133 134 void DatabaseBackend::scheduleTransaction() 135 { 136 ASSERT(!m_transactionInProgressMutex.tryLock()); // Locked by caller. 137 RefPtrWillBeRawPtr<SQLTransactionBackend> transaction = nullptr; 138 139 if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty()) 140 transaction = m_transactionQueue.takeFirst(); 141 142 if (transaction && databaseContext()->databaseThread()) { 143 OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction); 144 WTF_LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction()); 145 m_transactionInProgress = true; 146 databaseContext()->databaseThread()->scheduleTask(task.release()); 147 } else 148 m_transactionInProgress = false; 149 } 150 151 void DatabaseBackend::scheduleTransactionStep(SQLTransactionBackend* transaction) 152 { 153 if (!databaseContext()->databaseThread()) 154 return; 155 156 OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction); 157 WTF_LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get()); 158 databaseContext()->databaseThread()->scheduleTask(task.release()); 159 } 160 161 SQLTransactionClient* DatabaseBackend::transactionClient() const 162 { 163 return databaseContext()->databaseThread()->transactionClient(); 164 } 165 166 SQLTransactionCoordinator* DatabaseBackend::transactionCoordinator() const 167 { 168 return databaseContext()->databaseThread()->transactionCoordinator(); 169 } 170 171 } // namespace WebCore 172