b9f4e206d20e53568294ef027e03cbabdb8aad92
[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 "SQLiteIDBBackingStore.h"
36 #include <wtf/Locker.h>
37 #include <wtf/MainThread.h>
38
39 namespace WebCore {
40 namespace IDBServer {
41
42 Ref<IDBServer> IDBServer::create()
43 {
44     return adoptRef(*new IDBServer());
45 }
46
47 Ref<IDBServer> IDBServer::create(const String& databaseDirectoryPath)
48 {
49     return adoptRef(*new IDBServer(databaseDirectoryPath));
50 }
51
52 IDBServer::IDBServer()
53 {
54     Locker<Lock> locker(m_databaseThreadCreationLock);
55     m_threadID = createThread(IDBServer::databaseThreadEntry, this, "IndexedDatabase Server");
56 }
57
58 IDBServer::IDBServer(const String& databaseDirectoryPath)
59     : m_databaseDirectoryPath(databaseDirectoryPath)
60 {
61     LOG(IndexedDB, "IDBServer created at path %s", databaseDirectoryPath.utf8().data());
62
63     Locker<Lock> locker(m_databaseThreadCreationLock);
64     m_threadID = createThread(IDBServer::databaseThreadEntry, this, "IndexedDatabase Server");
65 }
66
67 void IDBServer::registerConnection(IDBConnectionToClient& connection)
68 {
69     ASSERT(!m_connectionMap.contains(connection.identifier()));
70     m_connectionMap.set(connection.identifier(), &connection);
71 }
72
73 void IDBServer::unregisterConnection(IDBConnectionToClient& connection)
74 {
75     ASSERT(m_connectionMap.contains(connection.identifier()));
76     ASSERT(m_connectionMap.get(connection.identifier()) == &connection);
77
78     m_connectionMap.remove(connection.identifier());
79 }
80
81 void IDBServer::registerTransaction(UniqueIDBDatabaseTransaction& transaction)
82 {
83     ASSERT(!m_transactions.contains(transaction.info().identifier()));
84     m_transactions.set(transaction.info().identifier(), &transaction);
85 }
86
87 void IDBServer::unregisterTransaction(UniqueIDBDatabaseTransaction& transaction)
88 {
89     ASSERT(m_transactions.contains(transaction.info().identifier()));
90     ASSERT(m_transactions.get(transaction.info().identifier()) == &transaction);
91
92     m_transactions.remove(transaction.info().identifier());
93 }
94
95 void IDBServer::registerDatabaseConnection(UniqueIDBDatabaseConnection& connection)
96 {
97     ASSERT(!m_databaseConnections.contains(connection.identifier()));
98     m_databaseConnections.set(connection.identifier(), &connection);
99 }
100
101 void IDBServer::unregisterDatabaseConnection(UniqueIDBDatabaseConnection& connection)
102 {
103     ASSERT(m_databaseConnections.contains(connection.identifier()));
104     m_databaseConnections.remove(connection.identifier());
105 }
106
107 UniqueIDBDatabase& IDBServer::getOrCreateUniqueIDBDatabase(const IDBDatabaseIdentifier& identifier)
108 {
109     auto uniqueIDBDatabase = m_uniqueIDBDatabaseMap.add(identifier, nullptr);
110     if (uniqueIDBDatabase.isNewEntry)
111         uniqueIDBDatabase.iterator->value = UniqueIDBDatabase::create(*this, identifier);
112
113     return *uniqueIDBDatabase.iterator->value;
114 }
115
116 std::unique_ptr<IDBBackingStore> IDBServer::createBackingStore(const IDBDatabaseIdentifier& identifier)
117 {
118     ASSERT(!isMainThread());
119
120     if (m_databaseDirectoryPath.isEmpty())
121         return MemoryIDBBackingStore::create(identifier);
122
123     return std::make_unique<SQLiteIDBBackingStore>(identifier, m_databaseDirectoryPath);
124 }
125
126 void IDBServer::openDatabase(const IDBRequestData& requestData)
127 {
128     LOG(IndexedDB, "IDBServer::openDatabase");
129
130     auto& uniqueIDBDatabase = getOrCreateUniqueIDBDatabase(requestData.databaseIdentifier());
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 open the database as
135         // well as no way to message back failure.
136         return;
137     }
138
139     uniqueIDBDatabase.openDatabaseConnection(*connection, requestData);
140 }
141
142 void IDBServer::deleteDatabase(const IDBRequestData& requestData)
143 {
144     LOG(IndexedDB, "IDBServer::deleteDatabase - %s", requestData.databaseIdentifier().debugString().utf8().data());
145     
146     auto connection = m_connectionMap.get(requestData.requestIdentifier().connectionIdentifier());
147     if (!connection) {
148         // If the connection back to the client is gone, there's no way to delete the database as
149         // well as no way to message back failure.
150         return;
151     }
152
153     auto* database = m_uniqueIDBDatabaseMap.get(requestData.databaseIdentifier());
154     if (!database) {
155         connection->didDeleteDatabase(IDBResultData::deleteDatabaseSuccess(requestData.requestIdentifier(), IDBDatabaseInfo(requestData.databaseIdentifier().databaseName(), 0)));
156         return;
157     }
158
159     database->handleDelete(*connection, requestData);
160 }
161
162 void IDBServer::deleteUniqueIDBDatabase(UniqueIDBDatabase& database)
163 {
164     LOG(IndexedDB, "IDBServer::deleteUniqueIDBDatabase");
165
166     auto deletedDatabase = m_uniqueIDBDatabaseMap.take(database.identifier());
167     ASSERT_UNUSED(deletedDatabase, deletedDatabase.get() == &database);
168 }
169
170 void IDBServer::abortTransaction(const IDBResourceIdentifier& transactionIdentifier)
171 {
172     LOG(IndexedDB, "IDBServer::abortTransaction");
173
174     auto transaction = m_transactions.get(transactionIdentifier);
175     if (!transaction) {
176         // If there is no transaction there is nothing to abort.
177         // We also have no access to a connection over which to message failure-to-abort.
178         return;
179     }
180
181     transaction->abort();
182 }
183
184 void IDBServer::createObjectStore(const IDBRequestData& requestData, const IDBObjectStoreInfo& info)
185 {
186     LOG(IndexedDB, "IDBServer::createObjectStore");
187
188     auto transaction = m_transactions.get(requestData.transactionIdentifier());
189     if (!transaction)
190         return;
191
192     ASSERT(transaction->isVersionChange());
193     transaction->createObjectStore(requestData, info);
194 }
195
196 void IDBServer::deleteObjectStore(const IDBRequestData& requestData, const String& objectStoreName)
197 {
198     LOG(IndexedDB, "IDBServer::deleteObjectStore");
199
200     auto transaction = m_transactions.get(requestData.transactionIdentifier());
201     if (!transaction)
202         return;
203
204     ASSERT(transaction->isVersionChange());
205     transaction->deleteObjectStore(requestData, objectStoreName);
206 }
207
208 void IDBServer::clearObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier)
209 {
210     LOG(IndexedDB, "IDBServer::clearObjectStore");
211
212     auto transaction = m_transactions.get(requestData.transactionIdentifier());
213     if (!transaction)
214         return;
215
216     transaction->clearObjectStore(requestData, objectStoreIdentifier);
217 }
218
219 void IDBServer::createIndex(const IDBRequestData& requestData, const IDBIndexInfo& info)
220 {
221     LOG(IndexedDB, "IDBServer::createIndex");
222
223     auto transaction = m_transactions.get(requestData.transactionIdentifier());
224     if (!transaction)
225         return;
226
227     ASSERT(transaction->isVersionChange());
228     transaction->createIndex(requestData, info);
229 }
230
231 void IDBServer::deleteIndex(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, const String& indexName)
232 {
233     LOG(IndexedDB, "IDBServer::deleteIndex");
234
235     auto transaction = m_transactions.get(requestData.transactionIdentifier());
236     if (!transaction)
237         return;
238
239     ASSERT(transaction->isVersionChange());
240     transaction->deleteIndex(requestData, objectStoreIdentifier, indexName);
241 }
242
243 void IDBServer::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
244 {
245     LOG(IndexedDB, "IDBServer::putOrAdd");
246
247     auto transaction = m_transactions.get(requestData.transactionIdentifier());
248     if (!transaction)
249         return;
250
251     transaction->putOrAdd(requestData, keyData, valueData, overwriteMode);
252 }
253
254 void IDBServer::getRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData)
255 {
256     LOG(IndexedDB, "IDBServer::getRecord");
257
258     auto transaction = m_transactions.get(requestData.transactionIdentifier());
259     if (!transaction)
260         return;
261
262     transaction->getRecord(requestData, keyRangeData);
263 }
264
265 void IDBServer::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData)
266 {
267     LOG(IndexedDB, "IDBServer::getCount");
268
269     auto transaction = m_transactions.get(requestData.transactionIdentifier());
270     if (!transaction)
271         return;
272
273     transaction->getCount(requestData, keyRangeData);
274 }
275
276 void IDBServer::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData)
277 {
278     LOG(IndexedDB, "IDBServer::deleteRecord");
279
280     auto transaction = m_transactions.get(requestData.transactionIdentifier());
281     if (!transaction)
282         return;
283
284     transaction->deleteRecord(requestData, keyRangeData);
285 }
286
287 void IDBServer::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info)
288 {
289     LOG(IndexedDB, "IDBServer::openCursor");
290
291     auto transaction = m_transactions.get(requestData.transactionIdentifier());
292     if (!transaction)
293         return;
294
295     transaction->openCursor(requestData, info);
296 }
297
298 void IDBServer::iterateCursor(const IDBRequestData& requestData, const IDBKeyData& key, unsigned long count)
299 {
300     LOG(IndexedDB, "IDBServer::iterateCursor");
301
302     auto transaction = m_transactions.get(requestData.transactionIdentifier());
303     if (!transaction)
304         return;
305
306     transaction->iterateCursor(requestData, key, count);
307 }
308
309 void IDBServer::establishTransaction(uint64_t databaseConnectionIdentifier, const IDBTransactionInfo& info)
310 {
311     LOG(IndexedDB, "IDBServer::establishTransaction");
312
313     auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier);
314     if (!databaseConnection)
315         return;
316
317     databaseConnection->establishTransaction(info);
318 }
319
320 void IDBServer::commitTransaction(const IDBResourceIdentifier& transactionIdentifier)
321 {
322     LOG(IndexedDB, "IDBServer::commitTransaction");
323
324     auto transaction = m_transactions.get(transactionIdentifier);
325     if (!transaction) {
326         // If there is no transaction there is nothing to commit.
327         // We also have no access to a connection over which to message failure-to-commit.
328         return;
329     }
330
331     transaction->commit();
332 }
333
334 void IDBServer::didFinishHandlingVersionChangeTransaction(const IDBResourceIdentifier& transactionIdentifier)
335 {
336     LOG(IndexedDB, "IDBServer::didFinishHandlingVersionChangeTransaction");
337
338     auto transaction = m_transactions.get(transactionIdentifier);
339     if (!transaction)
340         return;
341
342     transaction->didFinishHandlingVersionChange();
343 }
344
345 void IDBServer::databaseConnectionClosed(uint64_t databaseConnectionIdentifier)
346 {
347     LOG(IndexedDB, "IDBServer::databaseConnectionClosed");
348
349     auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier);
350     if (!databaseConnection)
351         return;
352
353     databaseConnection->connectionClosedFromClient();
354 }
355
356 void IDBServer::abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier)
357 {
358     LOG(IndexedDB, "IDBServer::abortOpenAndUpgradeNeeded");
359
360     auto transaction = m_transactions.get(transactionIdentifier);
361     if (transaction)
362         transaction->abortWithoutCallback();
363
364     auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier);
365     if (!databaseConnection)
366         return;
367
368     databaseConnection->connectionClosedFromClient();
369 }
370
371 void IDBServer::didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier)
372 {
373     LOG(IndexedDB, "IDBServer::didFireVersionChangeEvent");
374
375     if (auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier))
376         databaseConnection->didFireVersionChangeEvent(requestIdentifier);
377 }
378
379 void IDBServer::postDatabaseTask(std::unique_ptr<CrossThreadTask>&& task)
380 {
381     ASSERT(isMainThread());
382     m_databaseQueue.append(WTFMove(task));
383 }
384
385 void IDBServer::postDatabaseTaskReply(std::unique_ptr<CrossThreadTask>&& task)
386 {
387     ASSERT(!isMainThread());
388     m_databaseReplyQueue.append(WTFMove(task));
389
390
391     Locker<Lock> locker(m_mainThreadReplyLock);
392     if (m_mainThreadReplyScheduled)
393         return;
394
395     m_mainThreadReplyScheduled = true;
396     callOnMainThread([this] {
397         handleTaskRepliesOnMainThread();
398     });
399 }
400
401 void IDBServer::databaseThreadEntry(void* threadData)
402 {
403     ASSERT(threadData);
404     IDBServer* server = reinterpret_cast<IDBServer*>(threadData);
405     server->databaseRunLoop();
406 }
407
408 void IDBServer::databaseRunLoop()
409 {
410     ASSERT(!isMainThread());
411     {
412         Locker<Lock> locker(m_databaseThreadCreationLock);
413     }
414
415     while (auto task = m_databaseQueue.waitForMessage())
416         task->performTask();
417 }
418
419 void IDBServer::handleTaskRepliesOnMainThread()
420 {
421     {
422         Locker<Lock> locker(m_mainThreadReplyLock);
423         m_mainThreadReplyScheduled = false;
424     }
425
426     while (auto task = m_databaseReplyQueue.tryGetMessage())
427         task->performTask();
428 }
429
430 } // namespace IDBServer
431 } // namespace WebCore
432
433 #endif // ENABLE(INDEXED_DATABASE)