c6378eecf30dcb84bc4a12665672f916669da635
[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::abortTransaction(const IDBResourceIdentifier& transactionIdentifier)
146 {
147     LOG(IndexedDB, "IDBServer::abortTransaction");
148
149     auto transaction = m_transactions.get(transactionIdentifier);
150     if (!transaction) {
151         // If there is no transaction there is nothing to abort.
152         // We also have no access to a connection over which to message failure-to-abort.
153         return;
154     }
155
156     transaction->abort();
157 }
158
159 void IDBServer::createObjectStore(const IDBRequestData& requestData, const IDBObjectStoreInfo& info)
160 {
161     LOG(IndexedDB, "IDBServer::createObjectStore");
162
163     auto transaction = m_transactions.get(requestData.transactionIdentifier());
164     if (!transaction)
165         return;
166
167     ASSERT(transaction->isVersionChange());
168     transaction->createObjectStore(requestData, info);
169 }
170
171 void IDBServer::deleteObjectStore(const IDBRequestData& requestData, const String& objectStoreName)
172 {
173     LOG(IndexedDB, "IDBServer::deleteObjectStore");
174
175     auto transaction = m_transactions.get(requestData.transactionIdentifier());
176     if (!transaction)
177         return;
178
179     ASSERT(transaction->isVersionChange());
180     transaction->deleteObjectStore(requestData, objectStoreName);
181 }
182
183 void IDBServer::clearObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier)
184 {
185     LOG(IndexedDB, "IDBServer::clearObjectStore");
186
187     auto transaction = m_transactions.get(requestData.transactionIdentifier());
188     if (!transaction)
189         return;
190
191     transaction->clearObjectStore(requestData, objectStoreIdentifier);
192 }
193
194 void IDBServer::createIndex(const IDBRequestData& requestData, const IDBIndexInfo& info)
195 {
196     LOG(IndexedDB, "IDBServer::createIndex");
197
198     auto transaction = m_transactions.get(requestData.transactionIdentifier());
199     if (!transaction)
200         return;
201
202     ASSERT(transaction->isVersionChange());
203     transaction->createIndex(requestData, info);
204 }
205
206 void IDBServer::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
207 {
208     LOG(IndexedDB, "IDBServer::putOrAdd");
209
210     auto transaction = m_transactions.get(requestData.transactionIdentifier());
211     if (!transaction)
212         return;
213
214     transaction->putOrAdd(requestData, keyData, valueData, overwriteMode);
215 }
216
217 void IDBServer::getRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData)
218 {
219     LOG(IndexedDB, "IDBServer::getRecord");
220
221     auto transaction = m_transactions.get(requestData.transactionIdentifier());
222     if (!transaction)
223         return;
224
225     transaction->getRecord(requestData, keyRangeData);
226 }
227
228 void IDBServer::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData)
229 {
230     LOG(IndexedDB, "IDBServer::getCount");
231
232     auto transaction = m_transactions.get(requestData.transactionIdentifier());
233     if (!transaction)
234         return;
235
236     transaction->getCount(requestData, keyRangeData);
237 }
238
239 void IDBServer::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData)
240 {
241     LOG(IndexedDB, "IDBServer::deleteRecord");
242
243     auto transaction = m_transactions.get(requestData.transactionIdentifier());
244     if (!transaction)
245         return;
246
247     transaction->deleteRecord(requestData, keyRangeData);
248 }
249
250 void IDBServer::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info)
251 {
252     LOG(IndexedDB, "IDBServer::openCursor");
253
254     auto transaction = m_transactions.get(requestData.transactionIdentifier());
255     if (!transaction)
256         return;
257
258     transaction->openCursor(requestData, info);
259 }
260
261 void IDBServer::iterateCursor(const IDBRequestData& requestData, const IDBKeyData& key, unsigned long count)
262 {
263     LOG(IndexedDB, "IDBServer::iterateCursor");
264
265     auto transaction = m_transactions.get(requestData.transactionIdentifier());
266     if (!transaction)
267         return;
268
269     transaction->iterateCursor(requestData, key, count);
270 }
271
272 void IDBServer::establishTransaction(uint64_t databaseConnectionIdentifier, const IDBTransactionInfo& info)
273 {
274     LOG(IndexedDB, "IDBServer::establishTransaction");
275
276     auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier);
277     if (!databaseConnection)
278         return;
279
280     databaseConnection->establishTransaction(info);
281 }
282
283 void IDBServer::commitTransaction(const IDBResourceIdentifier& transactionIdentifier)
284 {
285     LOG(IndexedDB, "IDBServer::commitTransaction");
286
287     auto transaction = m_transactions.get(transactionIdentifier);
288     if (!transaction) {
289         // If there is no transaction there is nothing to commit.
290         // We also have no access to a connection over which to message failure-to-commit.
291         return;
292     }
293
294     transaction->commit();
295 }
296
297 void IDBServer::databaseConnectionClosed(uint64_t databaseConnectionIdentifier)
298 {
299     LOG(IndexedDB, "IDBServer::databaseConnectionClosed");
300
301     auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier);
302     if (!databaseConnection)
303         return;
304
305     databaseConnection->connectionClosedFromClient();
306 }
307
308 void IDBServer::postDatabaseTask(std::unique_ptr<CrossThreadTask>&& task)
309 {
310     ASSERT(isMainThread());
311     m_databaseQueue.append(WTF::move(task));
312 }
313
314 void IDBServer::postDatabaseTaskReply(std::unique_ptr<CrossThreadTask>&& task)
315 {
316     ASSERT(!isMainThread());
317     m_databaseReplyQueue.append(WTF::move(task));
318
319
320     Locker<Lock> locker(m_mainThreadReplyLock);
321     if (m_mainThreadReplyScheduled)
322         return;
323
324     m_mainThreadReplyScheduled = true;
325     callOnMainThread([this] {
326         handleTaskRepliesOnMainThread();
327     });
328 }
329
330 void IDBServer::databaseThreadEntry(void* threadData)
331 {
332     ASSERT(threadData);
333     IDBServer* server = reinterpret_cast<IDBServer*>(threadData);
334     server->databaseRunLoop();
335 }
336
337 void IDBServer::databaseRunLoop()
338 {
339     ASSERT(!isMainThread());
340     {
341         Locker<Lock> locker(m_databaseThreadCreationLock);
342     }
343
344     while (auto task = m_databaseQueue.waitForMessage())
345         task->performTask();
346 }
347
348 void IDBServer::handleTaskRepliesOnMainThread()
349 {
350     {
351         Locker<Lock> locker(m_mainThreadReplyLock);
352         m_mainThreadReplyScheduled = false;
353     }
354
355     while (auto task = m_databaseReplyQueue.tryGetMessage())
356         task->performTask();
357 }
358
359 } // namespace IDBServer
360 } // namespace WebCore
361
362 #endif // ENABLE(INDEXED_DATABASE)