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(PassRefPtr<DatabaseContext> databaseContext,const String & name,const String & expectedVersion,const String & displayName,unsigned long estimatedSize)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
openAndVerifyVersion(bool setVersionInNewDatabase,DatabaseError & error,String & errorMessage)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
performOpenAndVerify(bool setVersionInNewDatabase,DatabaseError & error,String & errorMessage)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
close()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
runTransaction(PassRefPtr<SQLTransaction> transaction,bool readOnly,const ChangeVersionData * data)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
inProgressTransactionCompleted()121 void DatabaseBackend::inProgressTransactionCompleted()
122 {
123 MutexLocker locker(m_transactionInProgressMutex);
124 m_transactionInProgress = false;
125 scheduleTransaction();
126 }
127
scheduleTransaction()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
scheduleTransactionStep(SQLTransactionBackend * transaction)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
transactionClient() const155 SQLTransactionClient* DatabaseBackend::transactionClient() const
156 {
157 return databaseContext()->databaseThread()->transactionClient();
158 }
159
transactionCoordinator() const160 SQLTransactionCoordinator* DatabaseBackend::transactionCoordinator() const
161 {
162 return databaseContext()->databaseThread()->transactionCoordinator();
163 }
164
165 } // namespace WebCore
166