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
DatabaseBackend(DatabaseContext * databaseContext,const String & name,const String & expectedVersion,const String & displayName,unsigned long estimatedSize)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
trace(Visitor * visitor)50 void DatabaseBackend::trace(Visitor* visitor)
51 {
52 visitor->trace(m_transactionQueue);
53 DatabaseBackendBase::trace(visitor);
54 }
55
openAndVerifyVersion(bool setVersionInNewDatabase,DatabaseError & error,String & errorMessage)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
performOpenAndVerify(bool setVersionInNewDatabase,DatabaseError & error,String & errorMessage)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
close()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
runTransaction(PassRefPtrWillBeRawPtr<SQLTransaction> transaction,bool readOnly,const ChangeVersionData * data)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
inProgressTransactionCompleted()127 void DatabaseBackend::inProgressTransactionCompleted()
128 {
129 MutexLocker locker(m_transactionInProgressMutex);
130 m_transactionInProgress = false;
131 scheduleTransaction();
132 }
133
scheduleTransaction()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
scheduleTransactionStep(SQLTransactionBackend * transaction)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
transactionClient() const161 SQLTransactionClient* DatabaseBackend::transactionClient() const
162 {
163 return databaseContext()->databaseThread()->transactionClient();
164 }
165
transactionCoordinator() const166 SQLTransactionCoordinator* DatabaseBackend::transactionCoordinator() const
167 {
168 return databaseContext()->databaseThread()->transactionCoordinator();
169 }
170
171 } // namespace WebCore
172