1/*
2 * Copyright (C) 2007, 2008, 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 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28#include "config.h"
29#include "DatabaseTask.h"
30
31#if ENABLE(SQL_DATABASE)
32
33#include "Database.h"
34#include "DatabaseBackend.h"
35#include "Logging.h"
36
37namespace WebCore {
38
39DatabaseTaskSynchronizer::DatabaseTaskSynchronizer()
40    : m_taskCompleted(false)
41#ifndef NDEBUG
42    , m_hasCheckedForTermination(false)
43#endif
44{
45}
46
47void DatabaseTaskSynchronizer::waitForTaskCompletion()
48{
49    m_synchronousMutex.lock();
50    while (!m_taskCompleted)
51        m_synchronousCondition.wait(m_synchronousMutex);
52    m_synchronousMutex.unlock();
53}
54
55void DatabaseTaskSynchronizer::taskCompleted()
56{
57    m_synchronousMutex.lock();
58    m_taskCompleted = true;
59    m_synchronousCondition.signal();
60    m_synchronousMutex.unlock();
61}
62
63DatabaseTask::DatabaseTask(DatabaseBackend* database, DatabaseTaskSynchronizer* synchronizer)
64    : m_database(database)
65    , m_synchronizer(synchronizer)
66#if !LOG_DISABLED
67    , m_complete(false)
68#endif
69{
70}
71
72DatabaseTask::~DatabaseTask()
73{
74#if !LOG_DISABLED
75    ASSERT(m_complete || !m_synchronizer);
76#endif
77}
78
79void DatabaseTask::performTask()
80{
81    // Database tasks are meant to be used only once, so make sure this one hasn't been performed before.
82#if !LOG_DISABLED
83    ASSERT(!m_complete);
84#endif
85
86    LOG(StorageAPI, "Performing %s %p\n", debugTaskName(), this);
87
88#if !PLATFORM(IOS)
89    m_database->resetAuthorizer();
90#else
91    if (m_database)
92        m_database->resetAuthorizer();
93#endif
94
95    doPerformTask();
96
97    if (m_synchronizer)
98        m_synchronizer->taskCompleted();
99
100#if !LOG_DISABLED
101    m_complete = true;
102#endif
103}
104
105// *** DatabaseOpenTask ***
106// Opens the database file and verifies the version matches the expected version.
107
108DatabaseBackend::DatabaseOpenTask::DatabaseOpenTask(DatabaseBackend* database, bool setVersionInNewDatabase, DatabaseTaskSynchronizer* synchronizer, DatabaseError& error, String& errorMessage, bool& success)
109    : DatabaseTask(database, synchronizer)
110    , m_setVersionInNewDatabase(setVersionInNewDatabase)
111    , m_error(error)
112    , m_errorMessage(errorMessage)
113    , m_success(success)
114{
115    ASSERT(synchronizer); // A task with output parameters is supposed to be synchronous.
116}
117
118void DatabaseBackend::DatabaseOpenTask::doPerformTask()
119{
120    String errorMessage;
121    m_success = database()->performOpenAndVerify(m_setVersionInNewDatabase, m_error, errorMessage);
122    if (!m_success)
123        m_errorMessage = errorMessage.isolatedCopy();
124}
125
126#if !LOG_DISABLED
127const char* DatabaseBackend::DatabaseOpenTask::debugTaskName() const
128{
129    return "DatabaseOpenTask";
130}
131#endif
132
133// *** DatabaseCloseTask ***
134// Closes the database.
135
136DatabaseBackend::DatabaseCloseTask::DatabaseCloseTask(DatabaseBackend* database, DatabaseTaskSynchronizer* synchronizer)
137    : DatabaseTask(database, synchronizer)
138{
139}
140
141void DatabaseBackend::DatabaseCloseTask::doPerformTask()
142{
143    Database::from(database())->close();
144}
145
146#if !LOG_DISABLED
147const char* DatabaseBackend::DatabaseCloseTask::debugTaskName() const
148{
149    return "DatabaseCloseTask";
150}
151#endif
152
153// *** DatabaseTransactionTask ***
154// Starts a transaction that will report its results via a callback.
155
156DatabaseBackend::DatabaseTransactionTask::DatabaseTransactionTask(PassRefPtr<SQLTransactionBackend> transaction)
157    : DatabaseTask(Database::from(transaction->database()), 0)
158    , m_transaction(transaction)
159    , m_didPerformTask(false)
160{
161}
162
163DatabaseBackend::DatabaseTransactionTask::~DatabaseTransactionTask()
164{
165    // If the task is being destructed without the transaction ever being run,
166    // then we must either have an error or an interruption. Give the
167    // transaction a chance to clean up since it may not have been able to
168    // run to its clean up state.
169
170    // Transaction phase 2 cleanup. See comment on "What happens if a
171    // transaction is interrupted?" at the top of SQLTransactionBackend.cpp.
172
173    if (!m_didPerformTask)
174        m_transaction->notifyDatabaseThreadIsShuttingDown();
175}
176
177#if PLATFORM(IOS)
178bool Database::DatabaseTransactionTask::shouldPerformWhilePaused() const
179{
180    return m_transaction->shouldPerformWhilePaused();
181}
182#endif
183
184void DatabaseBackend::DatabaseTransactionTask::doPerformTask()
185{
186    m_transaction->performNextStep();
187    m_didPerformTask = true;
188}
189
190#if !LOG_DISABLED
191const char* DatabaseBackend::DatabaseTransactionTask::debugTaskName() const
192{
193    return "DatabaseTransactionTask";
194}
195#endif
196
197// *** DatabaseTableNamesTask ***
198// Retrieves a list of all tables in the database - for WebInspector support.
199
200DatabaseBackend::DatabaseTableNamesTask::DatabaseTableNamesTask(DatabaseBackend* database, DatabaseTaskSynchronizer* synchronizer, Vector<String>& names)
201    : DatabaseTask(database, synchronizer)
202    , m_tableNames(names)
203{
204    ASSERT(synchronizer); // A task with output parameters is supposed to be synchronous.
205}
206
207void DatabaseBackend::DatabaseTableNamesTask::doPerformTask()
208{
209    m_tableNames = Database::from(database())->performGetTableNames();
210}
211
212#if !LOG_DISABLED
213const char* DatabaseBackend::DatabaseTableNamesTask::debugTaskName() const
214{
215    return "DatabaseTableNamesTask";
216}
217#endif
218
219} // namespace WebCore
220
221#endif
222