IDB: Support createIndex/deleteIndex
[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& metadata, 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     ASSERT(!m_metadata->objectStores.get(objectStoreID).indexes.contains(metadata.id));
447     m_metadata->objectStores.get(objectStoreID).indexes.set(metadata.id, metadata);
448     int64_t addedIndexID = metadata.id;
449
450     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, objectStoreID, addedIndexID, successCallback](bool success) {
451         if (!success) {
452             auto objectStoreFind = m_metadata->objectStores.find(objectStoreID);
453             if (objectStoreFind != m_metadata->objectStores.end())
454                 objectStoreFind->value.indexes.remove(addedIndexID);
455         }
456         successCallback(success);
457     }, [this, objectStoreID, addedIndexID, successCallback]() {
458         auto objectStoreFind = m_metadata->objectStores.find(objectStoreID);
459         if (objectStoreFind != m_metadata->objectStores.end())
460             objectStoreFind->value.indexes.remove(addedIndexID);
461         successCallback(false);
462     });
463
464     uint64_t requestID = request->requestID();
465     m_pendingDatabaseTasks.add(requestID, request.release());
466
467     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::createIndexInBackingStore, requestID, identifier, objectStoreID, metadata));
468 }
469
470 void UniqueIDBDatabase::deleteIndex(const IDBTransactionIdentifier& identifier, int64_t objectStoreID, int64_t indexID, std::function<void(bool)> successCallback)
471 {
472     ASSERT(isMainThread());
473
474     if (!m_acceptingNewRequests) {
475         successCallback(false);
476         return;
477     }
478
479     ASSERT(m_metadata->objectStores.contains(objectStoreID));
480     ASSERT(m_metadata->objectStores.get(objectStoreID).indexes.contains(indexID));
481
482     IDBIndexMetadata metadata = m_metadata->objectStores.get(objectStoreID).indexes.take(indexID);
483
484     RefPtr<AsyncRequest> request = AsyncRequestImpl<bool>::create([this, objectStoreID, metadata, successCallback](bool success) {
485         if (!success) {
486             auto objectStoreFind = m_metadata->objectStores.find(objectStoreID);
487             if (objectStoreFind != m_metadata->objectStores.end())
488                 objectStoreFind->value.indexes.set(metadata.id, metadata);
489         }
490         successCallback(success);
491     }, [this, objectStoreID, metadata, successCallback]() {
492         auto objectStoreFind = m_metadata->objectStores.find(objectStoreID);
493         if (objectStoreFind != m_metadata->objectStores.end())
494             objectStoreFind->value.indexes.set(metadata.id, metadata);
495         successCallback(false);
496     });
497
498     uint64_t requestID = request->requestID();
499     m_pendingDatabaseTasks.add(requestID, request.release());
500
501     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::deleteIndexInBackingStore, requestID, identifier, objectStoreID, indexID));
502 }
503
504 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)
505 {
506     ASSERT(isMainThread());
507
508     if (!m_acceptingNewRequests) {
509         callback(IDBKeyData(), INVALID_STATE_ERR, "Unable to put record into database because it has shut down");
510         return;
511     }
512
513     ASSERT(m_metadata->objectStores.contains(objectStoreID));
514
515     RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBKeyData&, uint32_t, const String&>::create([this, callback](const IDBKeyData& keyData, uint32_t errorCode, const String& errorMessage) {
516         callback(keyData, errorCode, errorMessage);
517     }, [this, callback]() {
518         callback(IDBKeyData(), INVALID_STATE_ERR, "Unable to put record into database");
519     });
520
521     uint64_t requestID = request->requestID();
522     m_pendingDatabaseTasks.add(requestID, request.release());
523
524     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::putRecordInBackingStore, requestID, identifier, m_metadata->objectStores.get(objectStoreID), keyData, value.vector(), putMode, indexIDs, indexKeys));
525 }
526
527 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)
528 {
529     ASSERT(isMainThread());
530
531     if (!m_acceptingNewRequests) {
532         callback(IDBGetResult(), INVALID_STATE_ERR, "Unable to get record from database because it has shut down");
533         return;
534     }
535
536     ASSERT(m_metadata->objectStores.contains(objectStoreID));
537
538     RefPtr<AsyncRequest> request = AsyncRequestImpl<const IDBGetResult&, uint32_t, const String&>::create([this, callback](const IDBGetResult& result, uint32_t errorCode, const String& errorMessage) {
539         callback(result, errorCode, errorMessage);
540     }, [this, callback]() {
541         callback(IDBGetResult(), INVALID_STATE_ERR, "Unable to get record from database");
542     });
543
544     uint64_t requestID = request->requestID();
545     m_pendingDatabaseTasks.add(requestID, request.release());
546
547     postDatabaseTask(createAsyncTask(*this, &UniqueIDBDatabase::getRecordFromBackingStore, requestID, identifier, m_metadata->objectStores.get(objectStoreID), indexID, keyRangeData, cursorType));
548 }
549
550 void UniqueIDBDatabase::openBackingStoreTransaction(const IDBTransactionIdentifier& identifier, const Vector<int64_t>& objectStoreIDs, IndexedDB::TransactionMode mode)
551 {
552     ASSERT(!isMainThread());
553     ASSERT(m_backingStore);
554
555     bool success = m_backingStore->establishTransaction(identifier, objectStoreIDs, mode);
556
557     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
558 }
559
560 void UniqueIDBDatabase::beginBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
561 {
562     ASSERT(!isMainThread());
563     ASSERT(m_backingStore);
564
565     bool success = m_backingStore->beginTransaction(identifier);
566
567     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
568 }
569
570 void UniqueIDBDatabase::commitBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
571 {
572     ASSERT(!isMainThread());
573     ASSERT(m_backingStore);
574
575     bool success = m_backingStore->commitTransaction(identifier);
576
577     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
578 }
579
580 void UniqueIDBDatabase::resetBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
581 {
582     ASSERT(!isMainThread());
583     ASSERT(m_backingStore);
584
585     bool success = m_backingStore->resetTransaction(identifier);
586
587     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
588 }
589
590 void UniqueIDBDatabase::rollbackBackingStoreTransaction(const IDBTransactionIdentifier& identifier)
591 {
592     ASSERT(!isMainThread());
593     ASSERT(m_backingStore);
594
595     bool success = m_backingStore->rollbackTransaction(identifier);
596
597     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCompleteTransactionOperation, identifier, success));
598 }
599
600 void UniqueIDBDatabase::changeDatabaseVersionInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, uint64_t newVersion)
601 {
602     ASSERT(!isMainThread());
603     ASSERT(m_backingStore);
604
605     bool success = m_backingStore->changeDatabaseVersion(identifier, newVersion);
606
607     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didChangeDatabaseVersion, requestID, success));
608 }
609
610 void UniqueIDBDatabase::createObjectStoreInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, const IDBObjectStoreMetadata& metadata)
611 {
612     ASSERT(!isMainThread());
613     ASSERT(m_backingStore);
614
615     bool success = m_backingStore->createObjectStore(identifier, metadata);
616
617     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCreateObjectStore, requestID, success));
618 }
619
620 void UniqueIDBDatabase::deleteObjectStoreInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, int64_t objectStoreID)
621 {
622     ASSERT(!isMainThread());
623     ASSERT(m_backingStore);
624
625     bool success = m_backingStore->deleteObjectStore(identifier, objectStoreID);
626
627     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteObjectStore, requestID, success));
628 }
629
630 void UniqueIDBDatabase::clearObjectStoreInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, int64_t objectStoreID)
631 {
632     ASSERT(!isMainThread());
633     ASSERT(m_backingStore);
634
635     bool success = m_backingStore->clearObjectStore(identifier, objectStoreID);
636
637     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didClearObjectStore, requestID, success));
638 }
639
640 void UniqueIDBDatabase::createIndexInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, int64_t objectStoreID, const WebCore::IDBIndexMetadata& metadata)
641 {
642     ASSERT(!isMainThread());
643     ASSERT(m_backingStore);
644
645     bool success = m_backingStore->createIndex(identifier, objectStoreID, metadata);
646
647     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didCreateIndex, requestID, success));
648 }
649
650 void UniqueIDBDatabase::deleteIndexInBackingStore(uint64_t requestID, const IDBTransactionIdentifier& identifier, int64_t objectStoreID, int64_t indexID)
651 {
652     ASSERT(!isMainThread());
653     ASSERT(m_backingStore);
654
655     bool success = m_backingStore->deleteIndex(identifier, objectStoreID, indexID);
656
657     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didDeleteIndex, requestID, success));
658 }
659
660 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)
661 {
662     ASSERT(!isMainThread());
663     ASSERT(m_backingStore);
664
665     bool keyWasGenerated = false;
666     RefPtr<IDBKey> key;
667
668     if (putMode != IDBDatabaseBackend::CursorUpdate && objectStoreMetadata.autoIncrement && keyData.isNull) {
669         key = m_backingStore->generateKey(transaction, objectStoreMetadata.id);
670         keyWasGenerated = true;
671     } else
672         key = keyData.maybeCreateIDBKey();
673
674     ASSERT(key);
675     ASSERT(key->isValid());
676
677     if (putMode == IDBDatabaseBackend::AddOnly) {
678         bool keyExists;
679         if (!m_backingStore->keyExistsInObjectStore(transaction, objectStoreMetadata.id, *key, keyExists)) {
680             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error checking for key existence")));
681             return;
682         }
683         if (keyExists) {
684             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::ConstraintError, ASCIILiteral("Key already exists in the object store")));
685             return;
686         }
687     }
688
689     // FIXME: The LevelDB port performs "makeIndexWriters" here. Necessary?
690
691     if (!m_backingStore->putRecord(transaction, objectStoreMetadata.id, *key, value.data(), value.size())) {
692         postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error putting a record")));
693         return;
694     }
695
696     // FIXME: The LevelDB port updates index keys here. Necessary?
697
698     if (putMode != IDBDatabaseBackend::CursorUpdate && objectStoreMetadata.autoIncrement && key->type() == IDBKey::NumberType) {
699         if (!m_backingStore->updateKeyGenerator(transaction, objectStoreMetadata.id, *key, keyWasGenerated)) {
700             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(), IDBDatabaseException::UnknownError, ASCIILiteral("Internal backing store error updating key generator")));
701             return;
702         }
703     }
704
705     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didPutRecordInBackingStore, requestID, IDBKeyData(key.get()), 0, String(StringImpl::empty())));
706 }
707
708 void UniqueIDBDatabase::didPutRecordInBackingStore(uint64_t requestID, const IDBKeyData& keyData, uint32_t errorCode, const String& errorMessage)
709 {
710     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
711     ASSERT(request);
712
713     request->completeRequest(keyData, errorCode, errorMessage);
714 }
715
716 void UniqueIDBDatabase::getRecordFromBackingStore(uint64_t requestID, const IDBTransactionIdentifier& transaction, const WebCore::IDBObjectStoreMetadata& objectStoreMetadata, int64_t indexID, const WebCore::IDBKeyRangeData& keyRangeData, WebCore::IndexedDB::CursorType cursorType)
717 {
718     ASSERT(!isMainThread());
719     ASSERT(m_backingStore);
720
721     RefPtr<IDBKeyRange> keyRange = keyRangeData.maybeCreateIDBKeyRange();
722     ASSERT(keyRange);
723     if (!keyRange) {
724         postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Invalid IDBKeyRange requested from backing store")));
725         return;
726     }
727
728     if (indexID == IDBIndexMetadata::InvalidId) {
729         // IDBObjectStore get record
730         RefPtr<SharedBuffer> result;
731
732         if (keyRange->isOnlyKey()) {
733             if (!m_backingStore->getKeyRecordFromObjectStore(transaction, objectStoreMetadata.id, *keyRange->lower(), result))
734                 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get key record from object store in backing store")));
735             else
736                 postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(result.release()), 0, String(StringImpl::empty())));
737
738             return;
739         }
740
741         RefPtr<IDBKey> resultKey;
742
743         if (!m_backingStore->getKeyRangeRecordFromObjectStore(transaction, objectStoreMetadata.id, *keyRange, result, resultKey))
744             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("Failed to get key range record from object store in backing store")));
745         else
746             postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(result.release(), resultKey.release(), IDBKeyPath()), 0, String(StringImpl::empty())));
747
748         return;
749     }
750
751     // IDBIndex get record
752
753     // FIXME: Implement index gets (<rdar://problem/15779642>)
754     postMainThreadTask(createAsyncTask(*this, &UniqueIDBDatabase::didGetRecordFromBackingStore, requestID, IDBGetResult(), IDBDatabaseException::UnknownError, ASCIILiteral("'get' from indexes not supported yet")));
755 }
756
757 void UniqueIDBDatabase::didGetRecordFromBackingStore(uint64_t requestID, const IDBGetResult& result, uint32_t errorCode, const String& errorMessage)
758 {
759     RefPtr<AsyncRequest> request = m_pendingDatabaseTasks.take(requestID);
760     ASSERT(request);
761
762     request->completeRequest(result, errorCode, errorMessage);
763 }
764
765 String UniqueIDBDatabase::absoluteDatabaseDirectory() const
766 {
767     ASSERT(isMainThread());
768     return DatabaseProcess::shared().absoluteIndexedDatabasePathFromDatabaseRelativePath(m_databaseRelativeDirectory);
769 }
770
771 void UniqueIDBDatabase::postMainThreadTask(std::unique_ptr<AsyncTask> task)
772 {
773     ASSERT(!isMainThread());
774
775     if (!m_acceptingNewRequests)
776         return;
777
778     MutexLocker locker(m_mainThreadTaskMutex);
779
780     m_mainThreadTasks.append(std::move(task));
781
782     // Balanced by an adoptRef() in ::performNextMainThreadTask
783     ref();
784     RunLoop::main()->dispatch(bind(&UniqueIDBDatabase::performNextMainThreadTask, this));
785 }
786
787 void UniqueIDBDatabase::performNextMainThreadTask()
788 {
789     ASSERT(isMainThread());
790
791     // Balanced by a ref() in ::postMainThreadTask
792     RefPtr<UniqueIDBDatabase> protector(adoptRef(this));
793
794     std::unique_ptr<AsyncTask> task;
795     {
796         MutexLocker locker(m_mainThreadTaskMutex);
797
798         // This database might be shutting down, in which case the task queue might be empty.
799         if (m_mainThreadTasks.isEmpty())
800             return;
801
802         task = m_mainThreadTasks.takeFirst();
803     }
804
805     task->performTask();
806 }
807
808 void UniqueIDBDatabase::postDatabaseTask(std::unique_ptr<AsyncTask> task)
809 {
810     ASSERT(isMainThread());
811
812     if (!m_acceptingNewRequests)
813         return;
814
815     MutexLocker locker(m_databaseTaskMutex);
816
817     m_databaseTasks.append(std::move(task));
818
819     DatabaseProcess::shared().queue().dispatch(bind(&UniqueIDBDatabase::performNextDatabaseTask, this));
820 }
821
822 void UniqueIDBDatabase::performNextDatabaseTask()
823 {
824     ASSERT(!isMainThread());
825
826     // It is possible that this database might be shutting down on the main thread.
827     // In this case, immediately after releasing m_databaseTaskMutex, this database might get deleted.
828     // We take a ref() to make sure the database is still live while this last task is performed.
829     RefPtr<UniqueIDBDatabase> protector(this);
830
831     std::unique_ptr<AsyncTask> task;
832     {
833         MutexLocker locker(m_databaseTaskMutex);
834
835         // This database might be shutting down on the main thread, in which case the task queue might be empty.
836         if (m_databaseTasks.isEmpty())
837             return;
838
839         task = m_databaseTasks.takeFirst();
840     }
841
842     task->performTask();
843 }
844
845 } // namespace WebKit
846
847 #endif // ENABLE(INDEXED_DATABASE) && ENABLE(DATABASE_PROCESS)