IDB: Implement IDBObjectStore.count()
[WebKit-https.git] / Source / WebKit2 / DatabaseProcess / IndexedDB / UniqueIDBDatabase.cpp
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. 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 "UniqueIDBDatabase.h"
28
29 #if ENABLE(INDEXED_DATABASE) && ENABLE(DATABASE_PROCESS)
30
31 #include "AsyncRequest.h"
32 #include "AsyncTask.h"
33 #include "DataReference.h"
34 #include "DatabaseProcess.h"
35 #include "DatabaseProcessIDBConnection.h"
36 #include "UniqueIDBDatabaseBackingStoreSQLite.h"
37 #include "WebCrossThreadCopier.h"
38 #include <WebCore/FileSystem.h>
39 #include <WebCore/IDBDatabaseBackend.h>
40 #include <WebCore/IDBDatabaseMetadata.h>
41 #include <WebCore/IDBGetResult.h>
42 #include <WebCore/IDBKeyData.h>
43 #include <WebCore/IDBKeyRangeData.h>
44 #include <wtf/MainThread.h>
45 #include <wtf/text/WTFString.h>
46
47 using namespace WebCore;
48
49 namespace WebKit {
50
51 UniqueIDBDatabase::UniqueIDBDatabase(const UniqueIDBDatabaseIdentifier& identifier)
52     : m_identifier(identifier)
53     , m_acceptingNewRequests(true)
54     , m_didGetMetadataFromBackingStore(false)
55 {
56     m_inMemory = !canShareDatabases(identifier.openingOrigin(), identifier.mainFrameOrigin());
57     if (m_inMemory)
58         return;
59
60     // Each unique Indexed Database exists in a directory named for the database, which exists in a directory representing its opening origin.
61     m_databaseRelativeDirectory = pathByAppendingComponent(databaseFilenameIdentifier(identifier.openingOrigin()), filenameForDatabaseName());
62
63     DatabaseProcess::shared().ensureIndexedDatabaseRelativePathExists(m_databaseRelativeDirectory);
64 }
65
66 UniqueIDBDatabase::~UniqueIDBDatabase()
67 {
68     ASSERT(!m_acceptingNewRequests);
69     ASSERT(m_pendingMetadataRequests.isEmpty());
70 }
71
72 String UniqueIDBDatabase::filenameForDatabaseName() const
73 {
74     ASSERT(!m_identifier.databaseName().isNull());
75
76     if (m_identifier.databaseName().isEmpty())
77         return "%00";
78
79     String filename = encodeForFileName(m_identifier.databaseName());
80     filename.replace('.', "%2E");
81
82     return filename;
83 }
84
85 String UniqueIDBDatabase::databaseFilenameIdentifier(const SecurityOriginData& originData) const
86 {
87     RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::create(originData.protocol, originData.host, originData.port);
88     return securityOrigin->databaseIdentifier();
89 }
90
91 bool UniqueIDBDatabase::canShareDatabases(const SecurityOriginData& openingOrigin, const SecurityOriginData& mainFrameOrigin) const
92 {
93     // For now, an origin's database access is predicated on equality with the other origin.
94     // We might need to make this more nuanced later.
95     return openingOrigin == mainFrameOrigin;
96 }
97
98 void UniqueIDBDatabase::registerConnection(DatabaseProcessIDBConnection& connection)
99 {
100     ASSERT(!m_connections.contains(&connection));
101     m_connections.add(&connection);
102 }
103
104 void UniqueIDBDatabase::unregisterConnection(DatabaseProcessIDBConnection& connection)
105 {
106     ASSERT(m_connections.contains(&connection));
107     m_connections.remove(&connection);
108
109     if (m_connections.isEmpty()) {
110         shutdown();
111         DatabaseProcess::shared().removeUniqueIDBDatabase(*this);
112     }
113 }
114
115 void UniqueIDBDatabase::shutdown()
116 {
117     ASSERT(isMainThread());
118
119     m_acceptingNewRequests = false;
120
121     {
122         MutexLocker locker(m_databaseTaskMutex);
123         m_databaseTasks.clear();
124     }
125
126     {
127         MutexLocker locker(m_mainThreadTaskMutex);
128         m_mainThreadTasks.clear();
129     }
130
131     for (const auto& it : m_pendingMetadataRequests)
132         it->requestAborted();
133
134     for (const auto& it : m_pendingTransactionRequests)
135         it.value->requestAborted();
136
137     for (const auto& it : m_pendingDatabaseTasks)
138         it.value->requestAborted();
139         
140     // Balanced by an adoptRef in ::didShutdownBackingStore()
141     ref();
142
143     DatabaseProcess::shared().queue().dispatch(bind(&UniqueIDBDatabase::shutdownBackingStore, this));
144 }
145
146 void UniqueIDBDatabase::shutdownBackingStore()
147 {
148     ASSERT(!isMainThread());
149     if (m_backingStore)
150         m_backingStore.clear();
151
152     RunLoop::main()->dispatch(bind(&UniqueIDBDatabase::didShutdownBackingStore, this));
153 }
154
155 void UniqueIDBDatabase::didShutdownBackingStore()
156 {
157     ASSERT(isMainThread());
158
159     // Balanced by a ref in ::shutdown()
160     RefPtr<UniqueIDBDatabase> protector(adoptRef(this));
161 }
162
163 void UniqueIDBDatabase::getOrEstablishIDBDatabaseMetadata(std::function<void(bool, const IDBDatabaseMetadata&)> completionCallback)
164 {
165     ASSERT(isMainThread());
166
167     if (!m_acceptingNewRequests) {
168         completionCallback(false, IDBDatabaseMetadata());
169         return;
170     }
171
172     // If we've already retrieved metadata from the backing store, return it now.
173     if (m_didGetMetadataFromBackingStore) {
174         if (m_metadata)
175             completionCallback(true, *m_metadata);
176         else
177             completionCallback(false, IDBDatabaseMetadata());
178
179         return;
180     }
181
182     // If this is the first unanswered metadata request, then later we need to
183     // post a task to open the backing store and get metadata.
184     bool shouldOpenBackingStore = m_pendingMetadataRequests.isEmpty();
185
186     // Then remember this metadata request to be answered later.
187     RefPtr<AsyncRequest> request = AsyncRequestImpl<>::create([completionCallback, this]() {
188         completionCallback(!!m_metadata, m_metadata ? *m_metadata : IDBDatabaseMetadata());
189     }, [completionCallback]() {
190         // The boolean flag to the completion callback represents whether the
191         // attempt to get/establish metadata succeeded or failed.
192         // Since we're aborting the attempt, it failed, so we always pass in false.
193         completionCallback(false, IDBDatabaseMetadata());
194     });
195
196     m_pendingMetadataRequests.append(request.release());
197
198     if (shouldOpenBackingStore)
199         postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::openBackingStoreAndReadMetadata, m_identifier, absoluteDatabaseDirectory()));
200 }
201
202 void UniqueIDBDatabase::openBackingStoreAndReadMetadata(const UniqueIDBDatabaseIdentifier& identifier, const String& databaseDirectory)
203 {
204     ASSERT(!isMainThread());
205     ASSERT(!m_backingStore);
206
207     if (m_inMemory) {
208         LOG_ERROR("Support for in-memory databases not yet implemented");
209         return;
210     }
211
212     m_backingStore = UniqueIDBDatabaseBackingStoreSQLite::create(identifier, databaseDirectory);
213     std::unique_ptr<IDBDatabaseMetadata> metadata = m_backingStore->getOrEstablishMetadata();
214
215     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didOpenBackingStoreAndReadMetadata, metadata ? *metadata : IDBDatabaseMetadata(), !!metadata));
216 }
217
218 void UniqueIDBDatabase::didOpenBackingStoreAndReadMetadata(const IDBDatabaseMetadata& metadata, bool success)
219 {
220     ASSERT(isMainThread());
221     ASSERT(!m_metadata);
222
223     m_didGetMetadataFromBackingStore = true;
224
225     if (success)
226         m_metadata = std::make_unique<IDBDatabaseMetadata>(metadata);
227
228     while (!m_pendingMetadataRequests.isEmpty()) {
229         RefPtr<AsyncRequest> request = m_pendingMetadataRequests.takeFirst();
230         request->completeRequest();
231     }
232 }
233
234 void UniqueIDBDatabase::openTransaction(const IDBIdentifier& transactionIdentifier, const Vector<int64_t>& objectStoreIDs, IndexedDB::TransactionMode mode, std::function<void(bool)> successCallback)
235 {
236     postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::openBackingStoreTransaction, transactionIdentifier, objectStoreIDs, mode), successCallback);
237 }
238
239 void UniqueIDBDatabase::beginTransaction(const IDBIdentifier& transactionIdentifier, std::function<void(bool)> successCallback)
240 {
241     postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::beginBackingStoreTransaction, transactionIdentifier), successCallback);
242 }
243
244 void UniqueIDBDatabase::commitTransaction(const IDBIdentifier& transactionIdentifier, std::function<void(bool)> successCallback)
245 {
246     postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::commitBackingStoreTransaction, transactionIdentifier), successCallback);
247 }
248
249 void UniqueIDBDatabase::resetTransaction(const IDBIdentifier& transactionIdentifier, std::function<void(bool)> successCallback)
250 {
251     postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::resetBackingStoreTransaction, transactionIdentifier), successCallback);
252 }
253
254 void UniqueIDBDatabase::rollbackTransaction(const IDBIdentifier& transactionIdentifier, std::function<void(bool)> successCallback)
255 {
256     postTransactionOperation(transactionIdentifier, createAsyncTask(*this, &UniqueIDBDatabase::rollbackBackingStoreTransaction, transactionIdentifier), successCallback);
257 }
258
259 void UniqueIDBDatabase::postTransactionOperation(const IDBIdentifier& transactionIdentifier, std::unique_ptr<AsyncTask> task, std::function<void(bool)> successCallback)
260 {
261     ASSERT(isMainThread());
262
263     if (!m_acceptingNewRequests) {
264         successCallback(false);
265         return;
266     }
267
268     if (m_pendingTransactionRequests.contains(transactionIdentifier)) {
269         LOG_ERROR("Attempting to queue an operation for a transaction that already has an operation pending. Each transaction should only have one operation pending at a time.");
270         successCallback(false);
271         return;
272     }
273
274     postDatabaseTask(std::move(task));
275
276     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([successCallback](bool success) {
277         successCallback(success);
278     }, [successCallback]() {
279         successCallback(false);
280     });
281
282     m_pendingTransactionRequests.add(transactionIdentifier, request.release());
283 }
284
285 void UniqueIDBDatabase::didCompleteTransactionOperation(const IDBIdentifier& transactionIdentifier, bool success)
286 {
287     ASSERT(isMainThread());
288
289     RefPtr<AsyncRequest> request = m_pendingTransactionRequests.take(transactionIdentifier);
290     if (!request)
291         return;
292
293     request->completeRequest(success);
294 }
295
296 void UniqueIDBDatabase::changeDatabaseVersion(const IDBIdentifier& transactionIdentifier, uint64_t newVersion, std::function<void(bool)> successCallback)
297 {
298     ASSERT(isMainThread());
299
300     if (!m_acceptingNewRequests) {
301         successCallback(false);
302         return;
303     }
304
305     uint64_t oldVersion = m_metadata->version;
306     m_metadata->version = newVersion;
307
308     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, oldVersion, successCallback](bool success) {
309         if (!success)
310             m_metadata->version = oldVersion;
311         successCallback(success);
312     }, [this, oldVersion, successCallback]() {
313         m_metadata->version = oldVersion;
314         successCallback(false);
315     });
316
317     uint64_t requestID = request->requestID();
318     m_pendingDatabaseTasks.add(requestID, request.release());
319
320     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::changeDatabaseVersionInBackingStore, requestID, transactionIdentifier, newVersion));
321 }
322
323 void UniqueIDBDatabase::didChangeDatabaseVersion(uint64_t requestID, bool success)
324 {
325     didCompleteBoolRequest(requestID, success);
326 }
327
328 void UniqueIDBDatabase::didCreateObjectStore(uint64_t requestID, bool success)
329 {
330     didCompleteBoolRequest(requestID, success);
331 }
332
333 void UniqueIDBDatabase::didDeleteObjectStore(uint64_t requestID, bool success)
334 {
335     didCompleteBoolRequest(requestID, success);
336 }
337
338 void UniqueIDBDatabase::didClearObjectStore(uint64_t requestID, bool success)
339 {
340     didCompleteBoolRequest(requestID, success);
341 }
342
343 void UniqueIDBDatabase::didCreateIndex(uint64_t requestID, bool success)
344 {
345     didCompleteBoolRequest(requestID, success);
346 }
347
348 void UniqueIDBDatabase::didDeleteIndex(uint64_t requestID, bool success)
349 {
350     didCompleteBoolRequest(requestID, success);
351 }
352
353 void UniqueIDBDatabase::didCompleteBoolRequest(uint64_t requestID, bool success)
354 {
355     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
356     ASSERT(request);
357
358     request->completeRequest(success);
359 }
360
361 void UniqueIDBDatabase::createObjectStore(const IDBIdentifier& transactionIdentifier, const IDBObjectStoreMetadata& metadata, std::function<void(bool)> successCallback)
362 {
363     ASSERT(isMainThread());
364
365     if (!m_acceptingNewRequests) {
366         successCallback(false);
367         return;
368     }
369
370     ASSERT(!m_metadata->objectStores.contains(metadata.id));
371     m_metadata->objectStores.set(metadata.id, metadata);
372     int64_t addedObjectStoreID = metadata.id;
373
374     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, addedObjectStoreID, successCallback](bool success) {
375         if (!success)
376             m_metadata->objectStores.remove(addedObjectStoreID);
377         successCallback(success);
378     }, [this, addedObjectStoreID, successCallback]() {
379         m_metadata->objectStores.remove(addedObjectStoreID);
380         successCallback(false);
381     });
382
383     uint64_t requestID = request->requestID();
384     m_pendingDatabaseTasks.add(requestID, request.release());
385
386     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::createObjectStoreInBackingStore, requestID, transactionIdentifier, metadata));
387 }
388
389 void UniqueIDBDatabase::deleteObjectStore(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, std::function<void(bool)> successCallback)
390 {
391     ASSERT(isMainThread());
392
393     if (!m_acceptingNewRequests) {
394         successCallback(false);
395         return;
396     }
397
398     ASSERT(m_metadata->objectStores.contains(objectStoreID));
399     IDBObjectStoreMetadata metadata = m_metadata->objectStores.take(objectStoreID);
400
401     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, metadata, successCallback](bool success) {
402         if (!success)
403             m_metadata->objectStores.set(metadata.id, metadata);
404         successCallback(success);
405     }, [this, metadata, successCallback]() {
406         m_metadata->objectStores.set(metadata.id, metadata);
407         successCallback(false);
408     });
409
410     uint64_t requestID = request->requestID();
411     m_pendingDatabaseTasks.add(requestID, request.release());
412
413     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::deleteObjectStoreInBackingStore, requestID, transactionIdentifier, objectStoreID));
414 }
415
416 void UniqueIDBDatabase::clearObjectStore(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, std::function<void(bool)> successCallback)
417 {
418     ASSERT(isMainThread());
419
420     if (!m_acceptingNewRequests) {
421         successCallback(false);
422         return;
423     }
424
425     ASSERT(m_metadata->objectStores.contains(objectStoreID));
426
427     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, successCallback](bool success) {
428         successCallback(success);
429     }, [this, successCallback]() {
430         successCallback(false);
431     });
432
433     uint64_t requestID = request->requestID();
434     m_pendingDatabaseTasks.add(requestID, request.release());
435
436     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::clearObjectStoreInBackingStore, requestID, transactionIdentifier, objectStoreID));
437 }
438
439 void UniqueIDBDatabase::createIndex(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBIndexMetadata& metadata, std::function<void(bool)> successCallback)
440 {
441     ASSERT(isMainThread());
442
443     if (!m_acceptingNewRequests) {
444         successCallback(false);
445         return;
446     }
447
448     ASSERT(m_metadata->objectStores.contains(objectStoreID));
449     ASSERT(!m_metadata->objectStores.get(objectStoreID).indexes.contains(metadata.id));
450     m_metadata->objectStores.get(objectStoreID).indexes.set(metadata.id, metadata);
451     int64_t addedIndexID = metadata.id;
452
453     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, objectStoreID, addedIndexID, successCallback](bool success) {
454         if (!success) {
455             auto objectStoreFind = m_metadata->objectStores.find(objectStoreID);
456             if (objectStoreFind != m_metadata->objectStores.end())
457                 objectStoreFind->value.indexes.remove(addedIndexID);
458         }
459         successCallback(success);
460     }, [this, objectStoreID, addedIndexID, successCallback]() {
461         auto objectStoreFind = m_metadata->objectStores.find(objectStoreID);
462         if (objectStoreFind != m_metadata->objectStores.end())
463             objectStoreFind->value.indexes.remove(addedIndexID);
464         successCallback(false);
465     });
466
467     uint64_t requestID = request->requestID();
468     m_pendingDatabaseTasks.add(requestID, request.release());
469
470     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::createIndexInBackingStore, requestID, transactionIdentifier, objectStoreID, metadata));
471 }
472
473 void UniqueIDBDatabase::deleteIndex(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, std::function<void(bool)> successCallback)
474 {
475     ASSERT(isMainThread());
476
477     if (!m_acceptingNewRequests) {
478         successCallback(false);
479         return;
480     }
481
482     ASSERT(m_metadata->objectStores.contains(objectStoreID));
483     ASSERT(m_metadata->objectStores.get(objectStoreID).indexes.contains(indexID));
484
485     IDBIndexMetadata metadata = m_metadata->objectStores.get(objectStoreID).indexes.take(indexID);
486
487     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, objectStoreID, metadata, successCallback](bool success) {
488         if (!success) {
489             auto objectStoreFind = m_metadata->objectStores.find(objectStoreID);
490             if (objectStoreFind != m_metadata->objectStores.end())
491                 objectStoreFind->value.indexes.set(metadata.id, metadata);
492         }
493         successCallback(success);
494     }, [this, objectStoreID, metadata, successCallback]() {
495         auto objectStoreFind = m_metadata->objectStores.find(objectStoreID);
496         if (objectStoreFind != m_metadata->objectStores.end())
497             objectStoreFind->value.indexes.set(metadata.id, metadata);
498         successCallback(false);
499     });
500
501     uint64_t requestID = request->requestID();
502     m_pendingDatabaseTasks.add(requestID, request.release());
503
504     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::deleteIndexInBackingStore, requestID, transactionIdentifier, objectStoreID, indexID));
505 }
506
507 void UniqueIDBDatabase::putRecord(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBKeyData& keyData, const IPC::DataReference& value, int64_t putMode, const Vector<int64_t>& indexIDs, const Vector<Vector<IDBKeyData>>& indexKeys, std::function<void(const IDBKeyData&, uint32_t, const String&)> callback)
508 {
509     ASSERT(isMainThread());
510
511     if (!m_acceptingNewRequests) {
512         callback(IDBKeyData(), INVALID_STATE_ERR, "Unable to put record into database because it has shut down");
513         return;
514     }
515
516     ASSERT(m_metadata->objectStores.contains(objectStoreID));
517
518     RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBKeyData&, uint32_t, const String&>::create([this, callback](const IDBKeyData& keyData, uint32_t errorCode, const String& errorMessage) {
519         callback(keyData, errorCode, errorMessage);
520     }, [this, callback]() {
521         callback(IDBKeyData(), INVALID_STATE_ERR, "Unable to put record into database");
522     });
523
524     uint64_t requestID = request->requestID();
525     m_pendingDatabaseTasks.add(requestID, request.release());
526
527     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::putRecordInBackingStore, requestID, transactionIdentifier, m_metadata->objectStores.get(objectStoreID), keyData, value.vector(), putMode, indexIDs, indexKeys));
528 }
529
530 void UniqueIDBDatabase::getRecord(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, const IDBKeyRangeData& keyRangeData, IndexedDB::CursorType cursorType, std::function<void(const IDBGetResult&, uint32_t, const String&)> callback)
531 {
532     ASSERT(isMainThread());
533
534     if (!m_acceptingNewRequests) {
535         callback(IDBGetResult(), INVALID_STATE_ERR, "Unable to get record from database because it has shut down");
536         return;
537     }
538
539     ASSERT(m_metadata->objectStores.contains(objectStoreID));
540
541     RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBGetResult&, uint32_t, const String&>::create([this, callback](const IDBGetResult& result, uint32_t errorCode, const String& errorMessage) {
542         callback(result, errorCode, errorMessage);
543     }, [this, callback]() {
544         callback(IDBGetResult(), INVALID_STATE_ERR, "Unable to get record from database");
545     });
546
547     uint64_t requestID = request->requestID();
548     m_pendingDatabaseTasks.add(requestID, request.release());
549
550     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::getRecordFromBackingStore, requestID, transactionIdentifier, m_metadata->objectStores.get(objectStoreID), indexID, keyRangeData, cursorType));
551 }
552
553 void UniqueIDBDatabase::openCursor(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, IndexedDB::CursorDirection cursorDirection, IndexedDB::CursorType cursorType, IDBDatabaseBackend::TaskType taskType, const IDBKeyRangeData& keyRangeData, std::function<void(int64_t, uint32_t, const String&)> callback)
554 {
555     ASSERT(isMainThread());
556
557     if (!m_acceptingNewRequests) {
558         callback(0, INVALID_STATE_ERR, "Unable to open cursor in database because it has shut down");
559         return;
560     }
561
562     ASSERT(m_metadata->objectStores.contains(objectStoreID));
563
564     RefPtr<AsyncRequest> request = AsyncRequestImpl<int64_t, uint32_t, const String&>::create([this, callback](int64_t cursorID, uint32_t errorCode, const String& errorMessage) {
565         callback(cursorID, errorCode, errorMessage);
566     }, [this, callback]() {
567         callback(0, INVALID_STATE_ERR, "Unable to get record from database");
568     });
569
570     uint64_t requestID = request->requestID();
571     m_pendingDatabaseTasks.add(requestID, request.release());
572
573     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::openCursorInBackingStore, requestID, transactionIdentifier, objectStoreID, indexID, cursorDirection, cursorType, taskType, keyRangeData));
574 }
575
576 void UniqueIDBDatabase::cursorAdvance(const IDBIdentifier& cursorIdentifier, uint64_t count, std::function<void(IDBKeyData, IDBKeyData, PassRefPtr<SharedBuffer>, uint32_t, const String&)> callback)
577 {
578     ASSERT(isMainThread());
579
580     if (!m_acceptingNewRequests) {
581         callback(nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to advance cursor in database because it has shut down");
582         return;
583     }
584
585     RefPtr<AsyncRequest> request = AsyncRequestImpl<IDBKeyData, IDBKeyData, PassRefPtr<SharedBuffer>, uint32_t, const String&>::create([this, callback](IDBKeyData key, IDBKeyData primaryKey, PassRefPtr<SharedBuffer> value, uint32_t errorCode, const String& errorMessage) {
586         callback(key, primaryKey, value, errorCode, errorMessage);
587     }, [this, callback]() {
588         callback(nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to advance cursor in database");
589     });
590
591     uint64_t requestID = request->requestID();
592     m_pendingDatabaseTasks.add(requestID, request.release());
593
594     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::advanceCursorInBackingStore, requestID, cursorIdentifier, count));
595 }
596
597 void UniqueIDBDatabase::cursorIterate(const IDBIdentifier& cursorIdentifier, const IDBKeyData& key, std::function<void(IDBKeyData, IDBKeyData, PassRefPtr<SharedBuffer>, uint32_t, const String&)> callback)
598 {
599     ASSERT(isMainThread());
600
601     if (!m_acceptingNewRequests) {
602         callback(nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to iterate cursor in database because it has shut down");
603         return;
604     }
605
606     RefPtr<AsyncRequest> request = AsyncRequestImpl<IDBKeyData, IDBKeyData, PassRefPtr<SharedBuffer>, uint32_t, const String&>::create([this, callback](IDBKeyData key, IDBKeyData primaryKey, PassRefPtr<SharedBuffer> value, uint32_t errorCode, const String& errorMessage) {
607         callback(key, primaryKey, value, errorCode, errorMessage);
608     }, [this, callback]() {
609         callback(nullptr, nullptr, nullptr, INVALID_STATE_ERR, "Unable to iterate cursor in database");
610     });
611
612     uint64_t requestID = request->requestID();
613     m_pendingDatabaseTasks.add(requestID, request.release());
614
615     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::iterateCursorInBackingStore, requestID, cursorIdentifier, key));
616 }
617
618 void UniqueIDBDatabase::count(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, const IDBKeyRangeData& keyRangeData, std::function<void(int64_t, uint32_t, const String&)> callback)
619 {
620     ASSERT(isMainThread());
621
622     if (!m_acceptingNewRequests) {
623         callback(0, INVALID_STATE_ERR, "Unable to get count from database because it has shut down");
624         return;
625     }
626
627     RefPtr<AsyncRequest> request = AsyncRequestImpl<int64_t, uint32_t, const String&>::create([this, callback](int64_t count, uint32_t errorCode, const String& errorMessage) {
628         callback(count, errorCode, errorMessage);
629     }, [this, callback]() {
630         callback(0, INVALID_STATE_ERR, "Unable to get count from database");
631     });
632
633     uint64_t requestID = request->requestID();
634     m_pendingDatabaseTasks.add(requestID, request.release());
635
636     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::countInBackingStore, requestID, transactionIdentifier, objectStoreID, indexID, keyRangeData));
637 }
638
639 void UniqueIDBDatabase::openBackingStoreTransaction(const IDBIdentifier& transactionIdentifier, const Vector<int64_t>& objectStoreIDs, IndexedDB::TransactionMode mode)
640 {
641     ASSERT(!isMainThread());
642     ASSERT(m_backingStore);
643
644     bool success = m_backingStore->establishTransaction(transactionIdentifier, objectStoreIDs, mode);
645
646     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success));
647 }
648
649 void UniqueIDBDatabase::beginBackingStoreTransaction(const IDBIdentifier& transactionIdentifier)
650 {
651     ASSERT(!isMainThread());
652     ASSERT(m_backingStore);
653
654     bool success = m_backingStore->beginTransaction(transactionIdentifier);
655
656     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success));
657 }
658
659 void UniqueIDBDatabase::commitBackingStoreTransaction(const IDBIdentifier& transactionIdentifier)
660 {
661     ASSERT(!isMainThread());
662     ASSERT(m_backingStore);
663
664     bool success = m_backingStore->commitTransaction(transactionIdentifier);
665
666     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success));
667 }
668
669 void UniqueIDBDatabase::resetBackingStoreTransaction(const IDBIdentifier& transactionIdentifier)
670 {
671     ASSERT(!isMainThread());
672     ASSERT(m_backingStore);
673
674     bool success = m_backingStore->resetTransaction(transactionIdentifier);
675
676     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success));
677 }
678
679 void UniqueIDBDatabase::rollbackBackingStoreTransaction(const IDBIdentifier& transactionIdentifier)
680 {
681     ASSERT(!isMainThread());
682     ASSERT(m_backingStore);
683
684     bool success = m_backingStore->rollbackTransaction(transactionIdentifier);
685
686     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, transactionIdentifier, success));
687 }
688
689 void UniqueIDBDatabase::changeDatabaseVersionInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, uint64_t newVersion)
690 {
691     ASSERT(!isMainThread());
692     ASSERT(m_backingStore);
693
694     bool success = m_backingStore->changeDatabaseVersion(transactionIdentifier, newVersion);
695
696     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didChangeDatabaseVersion, requestID, success));
697 }
698
699 void UniqueIDBDatabase::createObjectStoreInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, const IDBObjectStoreMetadata& metadata)
700 {
701     ASSERT(!isMainThread());
702     ASSERT(m_backingStore);
703
704     bool success = m_backingStore->createObjectStore(transactionIdentifier, metadata);
705
706     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCreateObjectStore, requestID, success));
707 }
708
709 void UniqueIDBDatabase::deleteObjectStoreInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID)
710 {
711     ASSERT(!isMainThread());
712     ASSERT(m_backingStore);
713
714     bool success = m_backingStore->deleteObjectStore(transactionIdentifier, objectStoreID);
715
716     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteObjectStore, requestID, success));
717 }
718
719 void UniqueIDBDatabase::clearObjectStoreInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID)
720 {
721     ASSERT(!isMainThread());
722     ASSERT(m_backingStore);
723
724     bool success = m_backingStore->clearObjectStore(transactionIdentifier, objectStoreID);
725
726     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didClearObjectStore, requestID, success));
727 }
728
729 void UniqueIDBDatabase::createIndexInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBIndexMetadata& metadata)
730 {
731     ASSERT(!isMainThread());
732     ASSERT(m_backingStore);
733
734     bool success = m_backingStore->createIndex(transactionIdentifier, objectStoreID, metadata);
735
736     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCreateIndex, requestID, success));
737 }
738
739 void UniqueIDBDatabase::deleteIndexInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID)
740 {
741     ASSERT(!isMainThread());
742     ASSERT(m_backingStore);
743
744     bool success = m_backingStore->deleteIndex(transactionIdentifier, objectStoreID, indexID);
745
746     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteIndex, requestID, success));
747 }
748
749 void UniqueIDBDatabase::putRecordInBackingStore(uint64_t requestID, const IDBIdentifier& transaction, const IDBObjectStoreMetadata& objectStoreMetadata, const IDBKeyData& keyData, const Vector<uint8_t>& value, int64_t putMode, const Vector<int64_t>& indexIDs, const Vector<Vector<IDBKeyData>>& indexKeys)
750 {
751     ASSERT(!isMainThread());
752     ASSERT(m_backingStore);
753
754     bool keyWasGenerated = false;
755     RefPtr<IDBKey> key;
756
757     if (putMode != IDBDatabaseBackend::CursorUpdate && objectStoreMetadata.autoIncrement && keyData.isNull) {
758         key = m_backingStore->generateKey(transaction, objectStoreMetadata.id);
759         keyWasGenerated = true;
760     } else
761         key = keyData.maybeCreateIDBKey();
762
763     ASSERT(key);
764     ASSERT(key->isValid());
765
766     if (putMode == IDBDatabaseBackend::AddOnly) {
767         bool keyExists;
768         if (!m_backingStore->keyExistsInObjectStore(transaction, objectStoreMetadata.id, *key, keyExists)) {
769             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error checking for key existence")));
770             return;
771         }
772         if (keyExists) {
773             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::ConstraintError, ASCIILiteral("Key already exists in the object store")));
774             return;
775         }
776     }
777
778     // FIXME: The LevelDB port performs "makeIndexWriters" here. Necessary?
779
780     if (!m_backingStore->putRecord(transaction, objectStoreMetadata.id, *key, value.data(), value.size())) {
781         postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error putting a record")));
782         return;
783     }
784
785     // FIXME: The LevelDB port updates index keys here. Necessary?
786
787     if (putMode != IDBDatabaseBackend::CursorUpdate && objectStoreMetadata.autoIncrement && key->type() == IDBKey::NumberType) {
788         if (!m_backingStore->updateKeyGenerator(transaction, objectStoreMetadata.id, *key, keyWasGenerated)) {
789             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error updating key generator")));
790             return;
791         }
792     }
793
794     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(key.get()), 0, String(StringImpl::empty())));
795 }
796
797 void UniqueIDBDatabase::didPutRecordInBackingStore(uint64_t requestID, const IDBKeyData& keyData, uint32_t errorCode, const String& errorMessage)
798 {
799     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
800     ASSERT(request);
801
802     request->completeRequest(keyData, errorCode, errorMessage);
803 }
804
805 void UniqueIDBDatabase::getRecordFromBackingStore(uint64_t requestID, const IDBIdentifier& transaction, const IDBObjectStoreMetadata& objectStoreMetadata, int64_t indexID, const IDBKeyRangeData& keyRangeData, IndexedDB::CursorType cursorType)
806 {
807     ASSERT(!isMainThread());
808     ASSERT(m_backingStore);
809
810     RefPtr<IDBKeyRange> keyRange = keyRangeData.maybeCreateIDBKeyRange();
811     ASSERT(keyRange);
812     if (!keyRange) {
813         postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Invalid IDBKeyRange requested from backing store")));
814         return;
815     }
816
817     if (indexID == IDBIndexMetadata::InvalidId) {
818         // IDBObjectStore get record
819         RefPtr<SharedBuffer> result;
820
821         if (keyRange->isOnlyKey()) {
822             if (!m_backingStore->getKeyRecordFromObjectStore(transaction, objectStoreMetadata.id, *keyRange->lower(), result))
823                 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get key record from object store in backing store")));
824             else
825                 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(result.release()), 0, String(StringImpl::empty())));
826
827             return;
828         }
829
830         RefPtr<IDBKey> resultKey;
831
832         if (!m_backingStore->getKeyRangeRecordFromObjectStore(transaction, objectStoreMetadata.id, *keyRange, result, resultKey))
833             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get key range record from object store in backing store")));
834         else
835             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(result.release(), resultKey.release(), IDBKeyPath()), 0, String(StringImpl::empty())));
836
837         return;
838     }
839
840     // IDBIndex get record
841
842     // FIXME: Implement index gets (<rdar://problem/15779642>)
843     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("'get' from indexes not supported yet")));
844 }
845
846 void UniqueIDBDatabase::didGetRecordFromBackingStore(uint64_t requestID, const IDBGetResult& result, uint32_t errorCode, const String& errorMessage)
847 {
848     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
849     ASSERT(request);
850
851     request->completeRequest(result, errorCode, errorMessage);
852 }
853
854 void UniqueIDBDatabase::openCursorInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, IndexedDB::CursorDirection, IndexedDB::CursorType, IDBDatabaseBackend::TaskType, const IDBKeyRangeData&)
855 {
856     // FIXME: Implement
857
858     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didOpenCursorInBackingStore, requestID, 0, IDBDatabaseException::UnknownError, ASCIILiteral("advancing cursors in backing store not supported yet")));
859 }
860
861 void UniqueIDBDatabase::didOpenCursorInBackingStore(uint64_t requestID, int64_t cursorID, uint32_t errorCode, const String& errorMessage)
862 {
863     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
864     ASSERT(request);
865
866     request->completeRequest(cursorID, errorCode, errorMessage);
867 }
868
869 void UniqueIDBDatabase::advanceCursorInBackingStore(uint64_t requestID, const IDBIdentifier& cursorIdentifier, uint64_t count)
870 {
871     // FIXME: Implement
872
873     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didAdvanceCursorInBackingStore, requestID, IDBKeyData(), IDBKeyData(), Vector<char>(), IDBDatabaseException::UnknownError, ASCIILiteral("advancing cursors in backing store not supported yet")));
874 }
875
876 void UniqueIDBDatabase::didAdvanceCursorInBackingStore(uint64_t requestID, const IDBKeyData& key, const IDBKeyData& primaryKey, const Vector<char>& value, uint32_t errorCode, const String& errorMessage)
877 {
878     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
879     ASSERT(request);
880
881     request->completeRequest(key, primaryKey, SharedBuffer::create(value.data(), value.size()), errorCode, errorMessage);
882 }
883
884 void UniqueIDBDatabase::iterateCursorInBackingStore(uint64_t requestID, const IDBIdentifier& cursorIdentifier, const IDBKeyData&)
885 {
886     // FIXME: Implement
887
888     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didIterateCursorInBackingStore, requestID, IDBKeyData(), IDBKeyData(), Vector<char>(), IDBDatabaseException::UnknownError, ASCIILiteral("iterating cursors in backing store not supported yet")));
889 }
890
891 void UniqueIDBDatabase::didIterateCursorInBackingStore(uint64_t requestID, const IDBKeyData& key, const IDBKeyData& primaryKey, const Vector<char>& value, uint32_t errorCode, const String& errorMessage)
892 {
893     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
894     ASSERT(request);
895
896     request->completeRequest(key, primaryKey, SharedBuffer::create(value.data(), value.size()), errorCode, errorMessage);
897 }
898
899 void UniqueIDBDatabase::countInBackingStore(uint64_t requestID, const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, const IDBKeyRangeData&)
900 {
901     // FIXME: Implement
902
903     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCountInBackingStore, requestID, 0, IDBDatabaseException::UnknownError, ASCIILiteral("counting in backing store not supported yet")));
904 }
905
906 void UniqueIDBDatabase::didCountInBackingStore(uint64_t requestID, int64_t count, uint32_t errorCode, const String& errorMessage)
907 {
908     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
909     ASSERT(request);
910
911     request->completeRequest(count, errorCode, errorMessage);
912 }
913
914 String UniqueIDBDatabase::absoluteDatabaseDirectory() const
915 {
916     ASSERT(isMainThread());
917     return DatabaseProcess::shared().absoluteIndexedDatabasePathFromDatabaseRelativePath(m_databaseRelativeDirectory);
918 }
919
920 void UniqueIDBDatabase::postMainThreadTask(std::unique_ptr<AsyncTask> task)
921 {
922     ASSERT(!isMainThread());
923
924     if (!m_acceptingNewRequests)
925         return;
926
927     MutexLocker locker(m_mainThreadTaskMutex);
928
929     m_mainThreadTasks.append(std::move(task));
930
931     // Balanced by an adoptRef() in ::performNextMainThreadTask
932     ref();
933     RunLoop::main()->dispatch(bind(&UniqueIDBDatabase::performNextMainThreadTask, this));
934 }
935
936 void UniqueIDBDatabase::performNextMainThreadTask()
937 {
938     ASSERT(isMainThread());
939
940     // Balanced by a ref() in ::postMainThreadTask
941     RefPtr<UniqueIDBDatabase> protector(adoptRef(this));
942
943     std::unique_ptr<AsyncTask> task;
944     {
945         MutexLocker locker(m_mainThreadTaskMutex);
946
947         // This database might be shutting down, in which case the task queue might be empty.
948         if (m_mainThreadTasks.isEmpty())
949             return;
950
951         task = m_mainThreadTasks.takeFirst();
952     }
953
954     task->performTask();
955 }
956
957 void UniqueIDBDatabase::postDatabaseTask(std::unique_ptr<AsyncTask> task)
958 {
959     ASSERT(isMainThread());
960
961     if (!m_acceptingNewRequests)
962         return;
963
964     MutexLocker locker(m_databaseTaskMutex);
965
966     m_databaseTasks.append(std::move(task));
967
968     DatabaseProcess::shared().queue().dispatch(bind(&UniqueIDBDatabase::performNextDatabaseTask, this));
969 }
970
971 void UniqueIDBDatabase::performNextDatabaseTask()
972 {
973     ASSERT(!isMainThread());
974
975     // It is possible that this database might be shutting down on the main thread.
976     // In this case, immediately after releasing m_databaseTaskMutex, this database might get deleted.
977     // We take a ref() to make sure the database is still live while this last task is performed.
978     RefPtr<UniqueIDBDatabase> protector(this);
979
980     std::unique_ptr<AsyncTask> task;
981     {
982         MutexLocker locker(m_databaseTaskMutex);
983
984         // This database might be shutting down on the main thread, in which case the task queue might be empty.
985         if (m_databaseTasks.isEmpty())
986             return;
987
988         task = m_databaseTasks.takeFirst();
989     }
990
991     task->performTask();
992 }
993
994 } // namespace WebKit
995
996 #endif // ENABLE(INDEXED_DATABASE) && ENABLE(DATABASE_PROCESS)