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(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 50 bool 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 65 bool 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 77 void 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 102 PassRefPtr<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 121 void DatabaseBackend::inProgressTransactionCompleted() 122 { 123 MutexLocker locker(m_transactionInProgressMutex); 124 m_transactionInProgress = false; 125 scheduleTransaction(); 126 } 127 128 void 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 145 void 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 155 SQLTransactionClient* DatabaseBackend::transactionClient() const 156 { 157 return databaseContext()->databaseThread()->transactionClient(); 158 } 159 160 SQLTransactionCoordinator* DatabaseBackend::transactionCoordinator() const 161 { 162 return databaseContext()->databaseThread()->transactionCoordinator(); 163 } 164 165 } // namespace WebCore 166