Modern IDB: Support IDBDatabase.close().
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / server / IDBServer.cpp
1 /*
2  * Copyright (C) 2015 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "IDBServer.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "IDBRequestData.h"
32 #include "IDBResultData.h"
33 #include "Logging.h"
34 #include "MemoryIDBBackingStore.h"
35 #include <wtf/Locker.h>
36 #include <wtf/MainThread.h>
37
38 namespace WebCore {
39 namespace IDBServer {
40
41 Ref<IDBServer> IDBServer::create()
42 {
43     return adoptRef(*new IDBServer());
44 }
45
46 IDBServer::IDBServer()
47 {
48     Locker<Lock> locker(m_databaseThreadCreationLock);
49     m_threadID = createThread(IDBServer::databaseThreadEntry, this, "IndexedDatabase Server");
50 }
51
52 void IDBServer::registerConnection(IDBConnectionToClient& connection)
53 {
54     ASSERT(!m_connectionMap.contains(connection.identifier()));
55     m_connectionMap.set(connection.identifier(), &connection);
56 }
57
58 void IDBServer::unregisterConnection(IDBConnectionToClient& connection)
59 {
60     ASSERT(m_connectionMap.contains(connection.identifier()));
61     ASSERT(m_connectionMap.get(connection.identifier()) == &connection);
62
63     m_connectionMap.remove(connection.identifier());
64 }
65
66 void IDBServer::registerTransaction(UniqueIDBDatabaseTransaction& transaction)
67 {
68     ASSERT(!m_transactions.contains(transaction.info().identifier()));
69     m_transactions.set(transaction.info().identifier(), &transaction);
70 }
71
72 void IDBServer::unregisterTransaction(UniqueIDBDatabaseTransaction& transaction)
73 {
74     ASSERT(m_transactions.contains(transaction.info().identifier()));
75     ASSERT(m_transactions.get(transaction.info().identifier()) == &transaction);
76
77     m_transactions.remove(transaction.info().identifier());
78 }
79
80 void IDBServer::registerDatabaseConnection(UniqueIDBDatabaseConnection& connection)
81 {
82     ASSERT(!m_databaseConnections.contains(connection.identifier()));
83     m_databaseConnections.set(connection.identifier(), &connection);
84 }
85
86 void IDBServer::unregisterDatabaseConnection(UniqueIDBDatabaseConnection& connection)
87 {
88     ASSERT(m_databaseConnections.contains(connection.identifier()));
89     m_databaseConnections.remove(connection.identifier());
90 }
91
92 UniqueIDBDatabase& IDBServer::getOrCreateUniqueIDBDatabase(const IDBDatabaseIdentifier& identifier)
93 {
94     auto uniqueIDBDatabase = m_uniqueIDBDatabaseMap.add(identifier, nullptr);
95     if (uniqueIDBDatabase.isNewEntry)
96         uniqueIDBDatabase.iterator->value = UniqueIDBDatabase::create(*this, identifier);
97
98     return *uniqueIDBDatabase.iterator->value;
99 }
100
101 std::unique_ptr<IDBBackingStore> IDBServer::createBackingStore(const IDBDatabaseIdentifier& identifier)
102 {
103     ASSERT(!isMainThread());
104
105     // FIXME: For now we only have the in-memory backing store, which we'll continue to use for private browsing.
106     // Once it's time for persistent backing stores this is where we'll calculate the correct path on disk
107     // and create it.
108
109     return MemoryIDBBackingStore::create(identifier);
110 }
111
112 void IDBServer::openDatabase(const IDBRequestData& requestData)
113 {
114     LOG(IndexedDB, "IDBServer::openDatabase");
115
116     auto& uniqueIDBDatabase = getOrCreateUniqueIDBDatabase(requestData.databaseIdentifier());
117
118     auto connection = m_connectionMap.get(requestData.requestIdentifier().connectionIdentifier());
119     if (!connection) {
120         // If the connection back to the client is gone, there's no way to open the database as
121         // well as no way to message back failure.
122         return;
123     }
124
125     uniqueIDBDatabase.openDatabaseConnection(*connection, requestData);
126 }
127
128 void IDBServer::deleteDatabase(const IDBRequestData& requestData)
129 {
130     LOG(IndexedDB, "IDBServer::deleteDatabase - %s", requestData.databaseIdentifier().debugString().utf8().data());
131     
132     auto connection = m_connectionMap.get(requestData.requestIdentifier().connectionIdentifier());
133     if (!connection) {
134         // If the connection back to the client is gone, there's no way to delete the database as
135         // well as no way to message back failure.
136         return;
137     }
138     
139     // FIXME: During bringup of modern IDB, the database deletion is a no-op, and is
140     // immediately reported back to the WebProcess as failure.
141     auto result = IDBResultData::error(requestData.requestIdentifier(), IDBError(IDBExceptionCode::Unknown));
142     connection->didDeleteDatabase(result);
143 }
144
145 void IDBServer::commitTransaction(const IDBResourceIdentifier& transactionIdentifier)
146 {
147     LOG(IndexedDB, "IDBServer::commitTransaction");
148
149     auto transaction = m_transactions.get(transactionIdentifier);
150     if (!transaction) {
151         // If there is no transaction there is nothing to commit.
152         // We also have no access to a connection over which to message failure-to-commit.
153         return;
154     }
155
156     transaction->commit();
157 }
158
159 void IDBServer::databaseConnectionClosed(uint64_t databaseConnectionIdentifier)
160 {
161     LOG(IndexedDB, "IDBServer::databaseConnectionClosed");
162
163     auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier);
164     if (!databaseConnection)
165         return;
166
167     databaseConnection->connectionClosedFromClient();
168 }
169
170 void IDBServer::postDatabaseTask(std::unique_ptr<CrossThreadTask>&& task)
171 {
172     ASSERT(isMainThread());
173     m_databaseQueue.append(WTF::move(task));
174 }
175
176 void IDBServer::postDatabaseTaskReply(std::unique_ptr<CrossThreadTask>&& task)
177 {
178     ASSERT(!isMainThread());
179     m_databaseReplyQueue.append(WTF::move(task));
180
181
182     Locker<Lock> locker(m_mainThreadReplyLock);
183     if (m_mainThreadReplyScheduled)
184         return;
185
186     m_mainThreadReplyScheduled = true;
187     callOnMainThread([this] {
188         handleTaskRepliesOnMainThread();
189     });
190 }
191
192 void IDBServer::databaseThreadEntry(void* threadData)
193 {
194     ASSERT(threadData);
195     IDBServer* server = reinterpret_cast<IDBServer*>(threadData);
196     server->databaseRunLoop();
197 }
198
199 void IDBServer::databaseRunLoop()
200 {
201     ASSERT(!isMainThread());
202     {
203         Locker<Lock> locker(m_databaseThreadCreationLock);
204     }
205
206     while (auto task = m_databaseQueue.waitForMessage())
207         task->performTask();
208 }
209
210 void IDBServer::handleTaskRepliesOnMainThread()
211 {
212     {
213         Locker<Lock> locker(m_mainThreadReplyLock);
214         m_mainThreadReplyScheduled = false;
215     }
216
217     while (auto task = m_databaseReplyQueue.tryGetMessage())
218         task->performTask();
219 }
220
221 } // namespace IDBServer
222 } // namespace WebCore
223
224 #endif // ENABLE(INDEXED_DATABASE)