1d4288ea5e05e089493e86518206b4229275b85d
[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, post a task to open the backing store and get metadata.
183     if (m_pendingMetadataRequests.isEmpty())
184         postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::openBackingStoreAndReadMetadata, m_identifier, absoluteDatabaseDirectory()));
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
199 void UniqueIDBDatabase::openBackingStoreAndReadMetadata(const UniqueIDBDatabaseIdentifier& identifier, const String& databaseDirectory)
200 {
201     ASSERT(!isMainThread());
202     ASSERT(!m_backingStore);
203
204     if (m_inMemory) {
205         LOG_ERROR("Support for in-memory databases not yet implemented");
206         return;
207     }
208
209     m_backingStore = UniqueIDBDatabaseBackingStoreSQLite::create(identifier, databaseDirectory);
210     std::unique_ptr<IDBDatabaseMetadata> metadata = m_backingStore->getOrEstablishMetadata();
211
212     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didOpenBackingStoreAndReadMetadata, metadata ? *metadata : IDBDatabaseMetadata(), !!metadata));
213 }
214
215 void UniqueIDBDatabase::didOpenBackingStoreAndReadMetadata(const IDBDatabaseMetadata& metadata, bool success)
216 {
217     ASSERT(isMainThread());
218     ASSERT(!m_metadata);
219
220     m_didGetMetadataFromBackingStore = true;
221
222     if (success)
223         m_metadata = std::make_unique<IDBDatabaseMetadata>(metadata);
224
225     while (!m_pendingMetadataRequests.isEmpty()) {
226         RefPtr<AsyncRequest> request = m_pendingMetadataRequests.takeFirst();
227         request->completeRequest();
228     }
229 }
230
231 void UniqueIDBDatabase::openTransaction(const IDBTransactionIdentifier& identifier, const Vector<int64_t>& objectStoreIDs, IndexedDB::TransactionMode mode, std::function<void(bool)> successCallback)
232 {
233     postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::openBackingStoreTransaction, identifier, objectStoreIDs, mode), successCallback);
234 }
235
236 void UniqueIDBDatabase::beginTransaction(const IDBTransactionIdentifier& identifier, std::function<void(bool)> successCallback)
237 {
238     postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::beginBackingStoreTransaction, identifier), successCallback);
239 }
240
241 void UniqueIDBDatabase::commitTransaction(const IDBTransactionIdentifier& identifier, std::function<void(bool)> successCallback)
242 {
243     postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::commitBackingStoreTransaction, identifier), successCallback);
244 }
245
246 void UniqueIDBDatabase::resetTransaction(const IDBTransactionIdentifier& identifier, std::function<void(bool)> successCallback)
247 {
248     postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::resetBackingStoreTransaction, identifier), successCallback);
249 }
250
251 void UniqueIDBDatabase::rollbackTransaction(const IDBTransactionIdentifier& identifier, std::function<void(bool)> successCallback)
252 {
253     postTransactionOperation(identifier, createAsyncTask(*this, &UniqueIDBDatabase::rollbackBackingStoreTransaction, identifier), successCallback);
254 }
255
256 void UniqueIDBDatabase::postTransactionOperation(const IDBTransactionIdentifier& identifier, std::unique_ptr<AsyncTask> task, std::function<void(bool)> successCallback)
257 {
258     ASSERT(isMainThread());
259
260     if (!m_acceptingNewRequests) {
261         successCallback(false);
262         return;
263     }
264
265     if (m_pendingTransactionRequests.contains(identifier)) {
266         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.");
267         successCallback(false);
268         return;
269     }
270
271     postDatabaseTask(std::move(task));
272
273     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([successCallback](bool success) {
274         successCallback(success);
275     }, [successCallback]() {
276         successCallback(false);
277     });
278
279     m_pendingTransactionRequests.add(identifier, request.release());
280 }
281
282 void UniqueIDBDatabase::didCompleteTransactionOperation(const IDBTransactionIdentifier& identifier, bool success)
283 {
284     ASSERT(isMainThread());
285
286     RefPtr<AsyncRequest> request = m_pendingTransactionRequests.take(identifier);
287     if (!request)
288         return;
289
290     request->completeRequest(success);
291 }
292
293 void UniqueIDBDatabase::changeDatabaseVersion(const IDBTransactionIdentifier& identifier, uint64_t newVersion, std::function<void(bool)> successCallback)
294 {
295     ASSERT(isMainThread());
296
297     if (!m_acceptingNewRequests) {
298         successCallback(false);
299         return;
300     }
301
302     uint64_t oldVersion = m_metadata->version;
303     m_metadata->version = newVersion;
304
305     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, oldVersion, successCallback](bool success) {
306         if (!success)
307             m_metadata->version = oldVersion;
308         successCallback(success);
309     }, [this, oldVersion, successCallback]() {
310         m_metadata->version = oldVersion;
311         successCallback(false);
312     });
313
314     uint64_t requestID = request->requestID();
315     m_pendingDatabaseTasks.add(requestID, request.release());
316
317     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::changeDatabaseVersionInBackingStore, requestID, identifier, newVersion));
318 }
319
320 void UniqueIDBDatabase::didChangeDatabaseVersion(uint64_t requestID, bool success)
321 {
322     didCompleteBoolRequest(requestID, success);
323 }
324
325 void UniqueIDBDatabase::didCreateObjectStore(uint64_t requestID, bool success)
326 {
327     didCompleteBoolRequest(requestID, success);
328 }
329
330 void UniqueIDBDatabase::didDeleteObjectStore(uint64_t requestID, bool success)
331 {
332     didCompleteBoolRequest(requestID, success);
333 }
334
335 void UniqueIDBDatabase::didClearObjectStore(uint64_t requestID, bool success)
336 {
337     didCompleteBoolRequest(requestID, success);
338 }
339
340 void UniqueIDBDatabase::didCreateIndex(uint64_t requestID, bool success)
341 {
342     didCompleteBoolRequest(requestID, success);
343 }
344
345 void UniqueIDBDatabase::didDeleteIndex(uint64_t requestID, bool success)
346 {
347     didCompleteBoolRequest(requestID, success);
348 }
349
350 void UniqueIDBDatabase::didCompleteBoolRequest(uint64_t requestID, bool success)
351 {
352     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
353     ASSERT(request);
354
355     request->completeRequest(success);
356 }
357
358 void UniqueIDBDatabase::createObjectStore(const IDBTransactionIdentifier& identifier, const IDBObjectStoreMetadata& metadata, std::function<void(bool)> successCallback)
359 {
360     ASSERT(isMainThread());
361
362     if (!m_acceptingNewRequests) {
363         successCallback(false);
364         return;
365     }
366
367     ASSERT(!m_metadata->objectStores.contains(metadata.id));
368     m_metadata->objectStores.set(metadata.id, metadata);
369     int64_t addedObjectStoreID = metadata.id;
370
371     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, addedObjectStoreID, successCallback](bool success) {
372         if (!success)
373             m_metadata->objectStores.remove(addedObjectStoreID);
374         successCallback(success);
375     }, [this, addedObjectStoreID, successCallback]() {
376         m_metadata->objectStores.remove(addedObjectStoreID);
377         successCallback(false);
378     });
379
380     uint64_t requestID = request->requestID();
381     m_pendingDatabaseTasks.add(requestID, request.release());
382
383     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::createObjectStoreInBackingStore, requestID, identifier, metadata));
384 }
385
386 void UniqueIDBDatabase::deleteObjectStore(const IDBTransactionIdentifier& identifier, int64_t objectStoreID, std::function<void(bool)> successCallback)
387 {
388     ASSERT(isMainThread());
389
390     if (!m_acceptingNewRequests) {
391         successCallback(false);
392         return;
393     }
394
395     ASSERT(m_metadata->objectStores.contains(objectStoreID));
396     IDBObjectStoreMetadata metadata = m_metadata->objectStores.take(objectStoreID);
397
398     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, metadata, successCallback](bool success) {
399         if (!success)
400             m_metadata->objectStores.set(metadata.id, metadata);
401         successCallback(success);
402     }, [this, metadata, successCallback]() {
403         m_metadata->objectStores.set(metadata.id, metadata);
404         successCallback(false);
405     });
406
407     uint64_t requestID = request->requestID();
408     m_pendingDatabaseTasks.add(requestID, request.release());
409
410     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::deleteObjectStoreInBackingStore, requestID, identifier, objectStoreID));
411 }
412
413 void UniqueIDBDatabase::clearObjectStore(const IDBTransactionIdentifier& identifier, int64_t objectStoreID, std::function<void(bool)> successCallback)
414 {
415     ASSERT(isMainThread());
416
417     if (!m_acceptingNewRequests) {
418         successCallback(false);
419         return;
420     }
421
422     ASSERT(m_metadata->objectStores.contains(objectStoreID));
423
424     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, successCallback](bool success) {
425         successCallback(success);
426     }, [this, successCallback]() {
427         successCallback(false);
428     });
429
430     uint64_t requestID = request->requestID();
431     m_pendingDatabaseTasks.add(requestID, request.release());
432
433     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::clearObjectStoreInBackingStore, requestID, identifier, objectStoreID));
434 }
435
436 void UniqueIDBDatabase::createIndex(const IDBTransactionIdentifier& identifier, int64_t objectStoreID, const WebCore::IDBIndexMetadata& indexMetadata, std::function<void(bool)> successCallback)
437 {
438     ASSERT(isMainThread());
439
440     if (!m_acceptingNewRequests) {
441         successCallback(false);
442         return;
443     }
444
445     ASSERT(m_metadata->objectStores.contains(objectStoreID));
446
447     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, successCallback](bool success) {
448         successCallback(success);
449     }, [this, successCallback]() {
450         successCallback(false);
451     });
452
453     uint64_t requestID = request->requestID();
454     m_pendingDatabaseTasks.add(requestID, request.release());
455
456     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::createIndexInBackingStore, requestID, identifier, objectStoreID, indexMetadata));
457 }
458
459 void UniqueIDBDatabase::deleteIndex(const IDBTransactionIdentifier& identifier, int64_t objectStoreID, int64_t indexID, std::function<void(bool)> successCallback)
460 {
461     ASSERT(isMainThread());
462
463     if (!m_acceptingNewRequests) {
464         successCallback(false);
465         return;
466     }
467
468     ASSERT(m_metadata->objectStores.contains(objectStoreID));
469     ASSERT(m_metadata->objectStores.get(objectStoreID).indexes.contains(indexID));
470
471     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, successCallback](bool success) {
472         successCallback(success);
473     }, [this, successCallback]() {
474         successCallback(false);
475     });
476
477     uint64_t requestID = request->requestID();
478     m_pendingDatabaseTasks.add(requestID, request.release());
479
480     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::deleteIndexInBackingStore, requestID, identifier, objectStoreID, indexID));
481 }
482
483 void UniqueIDBDatabase::putRecord(const IDBTransactionIdentifier& identifier, 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)
484 {
485     ASSERT(isMainThread());
486
487     if (!m_acceptingNewRequests) {
488         callback(IDBKeyData(), INVALID_STATE_ERR, "Unable to put record into database because it has shut down");
489         return;
490     }
491
492     ASSERT(m_metadata->objectStores.contains(objectStoreID));
493
494     RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBKeyData&, uint32_t, const String&>::create([this, callback](const IDBKeyData& keyData, uint32_t errorCode, const String& errorMessage) {
495         callback(keyData, errorCode, errorMessage);
496     }, [this, callback]() {
497         callback(IDBKeyData(), INVALID_STATE_ERR, "Unable to put record into database");
498     });
499
500     uint64_t requestID = request->requestID();
501     m_pendingDatabaseTasks.add(requestID, request.release());
502
503     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::putRecordInBackingStore, requestID, identifier, m_metadata->objectStores.get(objectStoreID), keyData, value.vector(), putMode, indexIDs, indexKeys));
504 }
505
506 void UniqueIDBDatabase::getRecord(const IDBTransactionIdentifier& identifier, int64_t objectStoreID, int64_t indexID, const WebCore::IDBKeyRangeData& keyRangeData, WebCore::IndexedDB::CursorType cursorType, std::function<void(const WebCore::IDBGetResult&, uint32_t, const String&)> callback)
507 {
508     ASSERT(isMainThread());
509
510     if (!m_acceptingNewRequests) {
511         callback(IDBGetResult(), INVALID_STATE_ERR, "Unable to get record from database because it has shut down");
512         return;
513     }
514
515     ASSERT(m_metadata->objectStores.contains(objectStoreID));
516
517     RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBGetResult&, uint32_t, const String&>::create([this, callback](const IDBGetResult& result, uint32_t errorCode, const String& errorMessage) {
518         callback(result, errorCode, errorMessage);
519     }, [this, callback]() {
520         callback(IDBGetResult(), INVALID_STATE_ERR, "Unable to get record from database");
521     });
522
523     uint64_t requestID = request->requestID();
524     m_pendingDatabaseTasks.add(requestID, request.release());
525
526     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::getRecordFromBackingStore, requestID, identifier, m_metadata->objectStores.get(objectStoreID), indexID, keyRangeData, cursorType));
527 }
528
529 void UniqueIDBDatabase::openBackingStoreTransaction(const IDBTransactionIdentifier& identifier, const Vector<int64_t>& objectStoreIDs, IndexedDB::TransactionMode mode)
530 {
531     ASSERT(!isMainThread());
532     ASSERT(m_backingStore);
533
534     bool success = m_backingStore->establishTransaction(identifier, objectStoreIDs, mode);
535
536     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
537 }
538
539 void UniqueIDBDatabase::beginBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
540 {
541     ASSERT(!isMainThread());
542     ASSERT(m_backingStore);
543
544     bool success = m_backingStore->beginTransaction(identifier);
545
546     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
547 }
548
549 void UniqueIDBDatabase::commitBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
550 {
551     ASSERT(!isMainThread());
552     ASSERT(m_backingStore);
553
554     bool success = m_backingStore->commitTransaction(identifier);
555
556     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
557 }
558
559 void UniqueIDBDatabase::resetBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
560 {
561     ASSERT(!isMainThread());
562     ASSERT(m_backingStore);
563
564     bool success = m_backingStore->resetTransaction(identifier);
565
566     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
567 }
568
569 void UniqueIDBDatabase::rollbackBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
570 {
571     ASSERT(!isMainThread());
572     ASSERT(m_backingStore);
573
574     bool success = m_backingStore->rollbackTransaction(identifier);
575
576     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
577 }
578
579 void UniqueIDBDatabase::changeDatabaseVersionInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, uint64_t newVersion)
580 {
581     ASSERT(!isMainThread());
582     ASSERT(m_backingStore);
583
584     bool success = m_backingStore->changeDatabaseVersion(identifier, newVersion);
585
586     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didChangeDatabaseVersion, requestID, success));
587 }
588
589 void UniqueIDBDatabase::createObjectStoreInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, const IDBObjectStoreMetadata& metadata)
590 {
591     ASSERT(!isMainThread());
592     ASSERT(m_backingStore);
593
594     bool success = m_backingStore->createObjectStore(identifier, metadata);
595
596     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCreateObjectStore, requestID, success));
597 }
598
599 void UniqueIDBDatabase::deleteObjectStoreInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, int64_t objectStoreID)
600 {
601     ASSERT(!isMainThread());
602     ASSERT(m_backingStore);
603
604     bool success = m_backingStore->deleteObjectStore(identifier, objectStoreID);
605
606     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteObjectStore, requestID, success));
607 }
608
609 void UniqueIDBDatabase::clearObjectStoreInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, int64_t objectStoreID)
610 {
611     ASSERT(!isMainThread());
612     ASSERT(m_backingStore);
613
614     bool success = m_backingStore->clearObjectStore(identifier, objectStoreID);
615
616     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didClearObjectStore, requestID, success));
617 }
618
619 void UniqueIDBDatabase::createIndexInBackingStore(uint64_t requestID, const IDBTransactionIdentifier&, int64_t objectStoreID, const WebCore::IDBIndexMetadata&)
620 {
621     // FIXME: Actually create in the backing store.
622     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCreateIndex, requestID, false));
623 }
624
625 void UniqueIDBDatabase::deleteIndexInBackingStore(uint64_t requestID, const IDBTransactionIdentifier&, int64_t objectStoreID, int64_t indexID)
626 {
627     // FIXME: Actually delete from the backing store.
628     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteIndex, requestID, false));
629 }
630
631 void UniqueIDBDatabase::putRecordInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& 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)
632 {
633     ASSERT(!isMainThread());
634     ASSERT(m_backingStore);
635
636     bool keyWasGenerated = false;
637     RefPtr<IDBKey> key;
638
639     if (putMode != IDBDatabaseBackend::CursorUpdate && objectStoreMetadata.autoIncrement && keyData.isNull) {
640         key = m_backingStore->generateKey(transaction, objectStoreMetadata.id);
641         keyWasGenerated = true;
642     } else
643         key = keyData.maybeCreateIDBKey();
644
645     ASSERT(key);
646     ASSERT(key->isValid());
647
648     if (putMode == IDBDatabaseBackend::AddOnly) {
649         bool keyExists;
650         if (!m_backingStore->keyExistsInObjectStore(transaction, objectStoreMetadata.id, *key, keyExists)) {
651             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error checking for key existence")));
652             return;
653         }
654         if (keyExists) {
655             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::ConstraintError, ASCIILiteral("Key already exists in the object store")));
656             return;
657         }
658     }
659
660     // FIXME: The LevelDB port performs "makeIndexWriters" here. Necessary?
661
662     if (!m_backingStore->putRecord(transaction, objectStoreMetadata.id, *key, value.data(), value.size())) {
663         postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error putting a record")));
664         return;
665     }
666
667     // FIXME: The LevelDB port updates index keys here. Necessary?
668
669     if (putMode != IDBDatabaseBackend::CursorUpdate && objectStoreMetadata.autoIncrement && key->type() == IDBKey::NumberType) {
670         if (!m_backingStore->updateKeyGenerator(transaction, objectStoreMetadata.id, *key, keyWasGenerated)) {
671             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error updating key generator")));
672             return;
673         }
674     }
675
676     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(key.get()), 0, String(StringImpl::empty())));
677 }
678
679 void UniqueIDBDatabase::didPutRecordInBackingStore(uint64_t requestID, const IDBKeyData& keyData, uint32_t errorCode, const String& errorMessage)
680 {
681     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
682     ASSERT(request);
683
684     request->completeRequest(keyData, errorCode, errorMessage);
685 }
686
687 void UniqueIDBDatabase::getRecordFromBackingStore(uint64_t requestID, const IDBTransactionIdentifier& transaction, const WebCore::IDBObjectStoreMetadata& objectStoreMetadata, int64_t indexID, const WebCore::IDBKeyRangeData& keyRangeData, WebCore::IndexedDB::CursorType cursorType)
688 {
689     ASSERT(!isMainThread());
690     ASSERT(m_backingStore);
691
692     RefPtr<IDBKeyRange> keyRange = keyRangeData.maybeCreateIDBKeyRange();
693     ASSERT(keyRange);
694     if (!keyRange) {
695         postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Invalid IDBKeyRange requested from backing store")));
696         return;
697     }
698
699     if (indexID == IDBIndexMetadata::InvalidId) {
700         // IDBObjectStore get record
701         RefPtr<SharedBuffer> result;
702
703         if (keyRange->isOnlyKey()) {
704             if (!m_backingStore->getKeyRecordFromObjectStore(transaction, objectStoreMetadata.id, *keyRange->lower(), result))
705                 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get key record from object store in backing store")));
706             else
707                 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(result.release()), 0, String(StringImpl::empty())));
708
709             return;
710         }
711
712         RefPtr<IDBKey> resultKey;
713
714         if (!m_backingStore->getKeyRangeRecordFromObjectStore(transaction, objectStoreMetadata.id, *keyRange, result, resultKey))
715             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get key range record from object store in backing store")));
716         else
717             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(result.release(), resultKey.release(), IDBKeyPath()), 0, String(StringImpl::empty())));
718
719         return;
720     }
721
722     // IDBIndex get record
723
724     // FIXME: Implement index gets (<rdar://problem/15779642>)
725     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("'get' from indexes not supported yet")));
726 }
727
728 void UniqueIDBDatabase::didGetRecordFromBackingStore(uint64_t requestID, const IDBGetResult& result, uint32_t errorCode, const String& errorMessage)
729 {
730     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
731     ASSERT(request);
732
733     request->completeRequest(result, errorCode, errorMessage);
734 }
735
736 String UniqueIDBDatabase::absoluteDatabaseDirectory() const
737 {
738     ASSERT(isMainThread());
739     return DatabaseProcess::shared().absoluteIndexedDatabasePathFromDatabaseRelativePath(m_databaseRelativeDirectory);
740 }
741
742 void UniqueIDBDatabase::postMainThreadTask(std::unique_ptr<AsyncTask> task)
743 {
744     ASSERT(!isMainThread());
745
746     if (!m_acceptingNewRequests)
747         return;
748
749     MutexLocker locker(m_mainThreadTaskMutex);
750
751     m_mainThreadTasks.append(std::move(task));
752
753     // Balanced by an adoptRef() in ::performNextMainThreadTask
754     ref();
755     RunLoop::main()->dispatch(bind(&UniqueIDBDatabase::performNextMainThreadTask, this));
756 }
757
758 void UniqueIDBDatabase::performNextMainThreadTask()
759 {
760     ASSERT(isMainThread());
761
762     // Balanced by a ref() in ::postMainThreadTask
763     RefPtr<UniqueIDBDatabase> protector(adoptRef(this));
764
765     std::unique_ptr<AsyncTask> task;
766     {
767         MutexLocker locker(m_mainThreadTaskMutex);
768
769         // This database might be shutting down, in which case the task queue might be empty.
770         if (m_mainThreadTasks.isEmpty())
771             return;
772
773         task = m_mainThreadTasks.takeFirst();
774     }
775
776     task->performTask();
777 }
778
779 void UniqueIDBDatabase::postDatabaseTask(std::unique_ptr<AsyncTask> task)
780 {
781     ASSERT(isMainThread());
782
783     if (!m_acceptingNewRequests)
784         return;
785
786     MutexLocker locker(m_databaseTaskMutex);
787
788     m_databaseTasks.append(std::move(task));
789
790     DatabaseProcess::shared().queue().dispatch(bind(&UniqueIDBDatabase::performNextDatabaseTask, this));
791 }
792
793 void UniqueIDBDatabase::performNextDatabaseTask()
794 {
795     ASSERT(!isMainThread());
796
797     // It is possible that this database might be shutting down on the main thread.
798     // In this case, immediately after releasing m_databaseTaskMutex, this database might get deleted.
799     // We take a ref() to make sure the database is still live while this last task is performed.
800     RefPtr<UniqueIDBDatabase> protector(this);
801
802     std::unique_ptr<AsyncTask> task;
803     {
804         MutexLocker locker(m_databaseTaskMutex);
805
806         // This database might be shutting down on the main thread, in which case the task queue might be empty.
807         if (m_databaseTasks.isEmpty())
808             return;
809
810         task = m_databaseTasks.takeFirst();
811     }
812
813     task->performTask();
814 }
815
816 } // namespace WebKit
817
818 #endif // ENABLE(INDEXED_DATABASE) && ENABLE(DATABASE_PROCESS)