Modern IDB: Add transactions and create/delete object store to SQLite backend
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / server / MemoryIDBBackingStore.cpp
1 /*
2  * Copyright (C) 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "MemoryIDBBackingStore.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "IDBCursorInfo.h"
32 #include "IDBIndexInfo.h"
33 #include "IDBKeyRangeData.h"
34 #include "Logging.h"
35 #include "MemoryObjectStore.h"
36 #include "MemoryObjectStoreCursor.h"
37
38 namespace WebCore {
39 namespace IDBServer {
40
41 // The IndexedDB spec states the value you can get from the key generator is 2^53
42 static uint64_t maxGeneratedKeyValue = 0x20000000000000;
43
44 std::unique_ptr<MemoryIDBBackingStore> MemoryIDBBackingStore::create(const IDBDatabaseIdentifier& identifier)
45 {
46     return std::make_unique<MemoryIDBBackingStore>(identifier);
47 }
48
49 MemoryIDBBackingStore::MemoryIDBBackingStore(const IDBDatabaseIdentifier& identifier)
50     : m_identifier(identifier)
51 {
52 }
53
54 MemoryIDBBackingStore::~MemoryIDBBackingStore()
55 {
56 }
57
58 const IDBDatabaseInfo& MemoryIDBBackingStore::getOrEstablishDatabaseInfo()
59 {
60     if (!m_databaseInfo)
61         m_databaseInfo = std::make_unique<IDBDatabaseInfo>(m_identifier.databaseName(), 0);
62
63     return *m_databaseInfo;
64 }
65
66 void MemoryIDBBackingStore::setDatabaseInfo(const IDBDatabaseInfo& info)
67 {
68     // It is not valid to directly set database info on a backing store that hasn't already set its own database info.
69     ASSERT(m_databaseInfo);
70
71     m_databaseInfo = std::make_unique<IDBDatabaseInfo>(info);
72 }
73
74 IDBError MemoryIDBBackingStore::beginTransaction(const IDBTransactionInfo& info)
75 {
76     LOG(IndexedDB, "MemoryIDBBackingStore::beginTransaction");
77
78     if (m_transactions.contains(info.identifier()))
79         return IDBError(IDBDatabaseException::InvalidStateError, "Backing store asked to create transaction it already has a record of");
80
81     auto transaction = MemoryBackingStoreTransaction::create(*this, info);
82
83     // VersionChange transactions are scoped to "every object store".
84     if (transaction->isVersionChange()) {
85         for (auto& objectStore : m_objectStoresByIdentifier.values())
86             transaction->addExistingObjectStore(*objectStore);
87     } else if (transaction->isWriting()) {
88         for (auto& iterator : m_objectStoresByName) {
89             if (info.objectStores().contains(iterator.key))
90                 transaction->addExistingObjectStore(*iterator.value);
91         }
92     }
93
94     m_transactions.set(info.identifier(), WTFMove(transaction));
95
96     return IDBError();
97 }
98
99 IDBError MemoryIDBBackingStore::abortTransaction(const IDBResourceIdentifier& transactionIdentifier)
100 {
101     LOG(IndexedDB, "MemoryIDBBackingStore::abortTransaction - %s", transactionIdentifier.loggingString().utf8().data());
102
103     auto transaction = m_transactions.take(transactionIdentifier);
104     if (!transaction)
105         return IDBError(IDBDatabaseException::InvalidStateError, "Backing store asked to abort transaction it didn't have record of");
106
107     transaction->abort();
108
109     return IDBError();
110 }
111
112 IDBError MemoryIDBBackingStore::commitTransaction(const IDBResourceIdentifier& transactionIdentifier)
113 {
114     LOG(IndexedDB, "MemoryIDBBackingStore::commitTransaction - %s", transactionIdentifier.loggingString().utf8().data());
115
116     auto transaction = m_transactions.take(transactionIdentifier);
117     if (!transaction)
118         return IDBError(IDBDatabaseException::InvalidStateError, "Backing store asked to commit transaction it didn't have record of");
119
120     transaction->commit();
121
122     return IDBError();
123 }
124
125 IDBError MemoryIDBBackingStore::createObjectStore(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& info)
126 {
127     LOG(IndexedDB, "MemoryIDBBackingStore::createObjectStore - adding OS %s with ID %" PRIu64, info.name().utf8().data(), info.identifier());
128
129     ASSERT(m_databaseInfo);
130     if (m_databaseInfo->hasObjectStore(info.name()))
131         return IDBError(IDBDatabaseException::ConstraintError);
132
133     ASSERT(!m_objectStoresByIdentifier.contains(info.identifier()));
134     auto objectStore = MemoryObjectStore::create(info);
135
136     m_databaseInfo->addExistingObjectStore(info);
137
138     auto rawTransaction = m_transactions.get(transactionIdentifier);
139     ASSERT(rawTransaction);
140     ASSERT(rawTransaction->isVersionChange());
141
142     rawTransaction->addNewObjectStore(objectStore.get());
143     registerObjectStore(WTFMove(objectStore));
144
145     return IDBError();
146 }
147
148 IDBError MemoryIDBBackingStore::deleteObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
149 {
150     LOG(IndexedDB, "MemoryIDBBackingStore::deleteObjectStore");
151
152     ASSERT(m_databaseInfo);
153     if (!m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier))
154         return IDBError(IDBDatabaseException::ConstraintError);
155
156     auto transaction = m_transactions.get(transactionIdentifier);
157     ASSERT(transaction);
158     ASSERT(transaction->isVersionChange());
159
160     auto objectStore = takeObjectStoreByIdentifier(objectStoreIdentifier);
161     ASSERT(objectStore);
162     if (!objectStore)
163         return IDBError(IDBDatabaseException::ConstraintError);
164
165     m_databaseInfo->deleteObjectStore(objectStore->info().name());
166     transaction->objectStoreDeleted(*objectStore);
167
168     return IDBError();
169 }
170
171 IDBError MemoryIDBBackingStore::clearObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
172 {
173     LOG(IndexedDB, "MemoryIDBBackingStore::clearObjectStore");
174     ASSERT(objectStoreIdentifier);
175
176     ASSERT_UNUSED(transactionIdentifier, m_transactions.contains(transactionIdentifier));
177
178 #ifndef NDEBUG
179     auto transaction = m_transactions.get(transactionIdentifier);
180     ASSERT(transaction->isWriting());
181 #endif
182
183     auto objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
184     if (!objectStore)
185         return IDBError(IDBDatabaseException::ConstraintError);
186
187     objectStore->clear();
188
189     return IDBError();
190 }
191
192 IDBError MemoryIDBBackingStore::createIndex(const IDBResourceIdentifier& transactionIdentifier, const IDBIndexInfo& info)
193 {
194     LOG(IndexedDB, "MemoryIDBBackingStore::createIndex");
195
196     auto rawTransaction = m_transactions.get(transactionIdentifier);
197     ASSERT(rawTransaction);
198     ASSERT(rawTransaction->isVersionChange());
199
200     auto* objectStore = m_objectStoresByIdentifier.get(info.objectStoreIdentifier());
201     if (!objectStore)
202         return IDBError(IDBDatabaseException::ConstraintError);
203
204     return objectStore->createIndex(*rawTransaction, info);
205 }
206
207 IDBError MemoryIDBBackingStore::deleteIndex(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const String& indexName)
208 {
209     LOG(IndexedDB, "MemoryIDBBackingStore::deleteIndex");
210
211     auto rawTransaction = m_transactions.get(transactionIdentifier);
212     ASSERT(rawTransaction);
213     ASSERT(rawTransaction->isVersionChange());
214
215     auto* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
216     if (!objectStore)
217         return IDBError(IDBDatabaseException::ConstraintError);
218
219     return objectStore->deleteIndex(*rawTransaction, indexName);
220 }
221
222 void MemoryIDBBackingStore::removeObjectStoreForVersionChangeAbort(MemoryObjectStore& objectStore)
223 {
224     LOG(IndexedDB, "MemoryIDBBackingStore::removeObjectStoreForVersionChangeAbort");
225
226     if (!m_objectStoresByIdentifier.contains(objectStore.info().identifier()))
227         return;
228
229     ASSERT(m_objectStoresByIdentifier.get(objectStore.info().identifier()) == &objectStore);
230
231     unregisterObjectStore(objectStore);
232 }
233
234 void MemoryIDBBackingStore::restoreObjectStoreForVersionChangeAbort(Ref<MemoryObjectStore>&& objectStore)
235 {
236     registerObjectStore(WTFMove(objectStore));
237 }
238
239 IDBError MemoryIDBBackingStore::keyExistsInObjectStore(const IDBResourceIdentifier&, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, bool& keyExists)
240 {
241     LOG(IndexedDB, "MemoryIDBBackingStore::keyExistsInObjectStore");
242
243     ASSERT(objectStoreIdentifier);
244
245     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
246     RELEASE_ASSERT(objectStore);
247
248     keyExists = objectStore->containsRecord(keyData);
249     return IDBError();
250 }
251
252 IDBError MemoryIDBBackingStore::deleteRange(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range)
253 {
254     LOG(IndexedDB, "MemoryIDBBackingStore::deleteRange");
255
256     ASSERT(objectStoreIdentifier);
257
258     if (!m_transactions.contains(transactionIdentifier))
259         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to delete from"));
260
261     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
262     if (!objectStore)
263         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found"));
264
265     objectStore->deleteRange(range);
266     return IDBError();
267 }
268
269 IDBError MemoryIDBBackingStore::addRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const ThreadSafeDataBuffer& value)
270 {
271     LOG(IndexedDB, "MemoryIDBBackingStore::addRecord");
272
273     ASSERT(objectStoreIdentifier);
274
275     auto transaction = m_transactions.get(transactionIdentifier);
276     if (!transaction)
277         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to put record"));
278
279     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
280     if (!objectStore)
281         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found to put record"));
282
283     return objectStore->addRecord(*transaction, keyData, value);
284 }
285
286 IDBError MemoryIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range, ThreadSafeDataBuffer& outValue)
287 {
288     LOG(IndexedDB, "MemoryIDBBackingStore::getRecord");
289
290     ASSERT(objectStoreIdentifier);
291
292     if (!m_transactions.contains(transactionIdentifier))
293         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to get record"));
294
295     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
296     if (!objectStore)
297         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found"));
298
299     outValue = objectStore->valueForKeyRange(range);
300     return IDBError();
301 }
302
303 IDBError MemoryIDBBackingStore::getIndexRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, IndexedDB::IndexRecordType recordType, const IDBKeyRangeData& range, IDBGetResult& outValue)
304 {
305     LOG(IndexedDB, "MemoryIDBBackingStore::getIndexRecord");
306
307     ASSERT(objectStoreIdentifier);
308
309     if (!m_transactions.contains(transactionIdentifier))
310         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to get record"));
311
312     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
313     if (!objectStore)
314         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found"));
315
316     outValue = objectStore->indexValueForKeyRange(indexIdentifier, recordType, range);
317     return IDBError();
318 }
319
320 IDBError MemoryIDBBackingStore::getCount(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData& range, uint64_t& outCount)
321 {
322     LOG(IndexedDB, "MemoryIDBBackingStore::getCount");
323
324     ASSERT(objectStoreIdentifier);
325
326     if (!m_transactions.contains(transactionIdentifier))
327         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to get count"));
328
329     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
330     if (!objectStore)
331         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found"));
332
333     outCount = objectStore->countForKeyRange(indexIdentifier, range);
334
335     return IDBError();
336 }
337
338 IDBError MemoryIDBBackingStore::generateKeyNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t& keyNumber)
339 {
340     LOG(IndexedDB, "MemoryIDBBackingStore::generateKeyNumber");
341     ASSERT(objectStoreIdentifier);
342     ASSERT_UNUSED(transactionIdentifier, m_transactions.contains(transactionIdentifier));
343     ASSERT_UNUSED(transactionIdentifier, m_transactions.get(transactionIdentifier)->isWriting());
344
345     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
346     RELEASE_ASSERT(objectStore);
347
348     keyNumber = objectStore->currentKeyGeneratorValue();
349     if (keyNumber > maxGeneratedKeyValue)
350         return { IDBDatabaseException::ConstraintError, "Cannot generate new key value over 2^53 for object store operation" };
351
352     objectStore->setKeyGeneratorValue(keyNumber + 1);
353
354     return IDBError();
355 }
356
357 IDBError MemoryIDBBackingStore::revertGeneratedKeyNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t keyNumber)
358 {
359     LOG(IndexedDB, "MemoryIDBBackingStore::revertGeneratedKeyNumber");
360     ASSERT(objectStoreIdentifier);
361     ASSERT_UNUSED(transactionIdentifier, m_transactions.contains(transactionIdentifier));
362     ASSERT_UNUSED(transactionIdentifier, m_transactions.get(transactionIdentifier)->isWriting());
363
364     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
365     RELEASE_ASSERT(objectStore);
366
367     objectStore->setKeyGeneratorValue(keyNumber);
368
369     return { };
370 }
371
372 IDBError MemoryIDBBackingStore::maybeUpdateKeyGeneratorNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, double newKeyNumber)
373 {
374     LOG(IndexedDB, "MemoryIDBBackingStore::maybeUpdateKeyGeneratorNumber");
375     ASSERT(objectStoreIdentifier);
376     ASSERT_UNUSED(transactionIdentifier, m_transactions.contains(transactionIdentifier));
377     ASSERT_UNUSED(transactionIdentifier, m_transactions.get(transactionIdentifier)->isWriting());
378
379     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
380     RELEASE_ASSERT(objectStore);
381
382     if (newKeyNumber < objectStore->currentKeyGeneratorValue())
383         return { };
384
385     uint64_t newKeyInteger(newKeyNumber);
386     if (newKeyInteger <= uint64_t(newKeyNumber))
387         ++newKeyInteger;
388
389     ASSERT(newKeyInteger > uint64_t(newKeyNumber));
390
391     objectStore->setKeyGeneratorValue(newKeyInteger);
392
393     return { };
394 }
395
396 IDBError MemoryIDBBackingStore::openCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo& info, IDBGetResult& outData)
397 {
398     LOG(IndexedDB, "MemoryIDBBackingStore::openCursor");
399
400     ASSERT(!MemoryCursor::cursorForIdentifier(info.identifier()));
401
402     if (!m_transactions.contains(transactionIdentifier))
403         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found in which to open a cursor"));
404
405     switch (info.cursorSource()) {
406     case IndexedDB::CursorSource::ObjectStore: {
407         auto* objectStore = m_objectStoresByIdentifier.get(info.sourceIdentifier());
408         if (!objectStore)
409             return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found"));
410
411         MemoryCursor* cursor = objectStore->maybeOpenCursor(info);
412         if (!cursor)
413             return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("Could not create object store cursor in backing store"));
414
415         cursor->currentData(outData);
416         break;
417     }
418     case IndexedDB::CursorSource::Index:
419         auto* objectStore = m_objectStoresByIdentifier.get(info.objectStoreIdentifier());
420         if (!objectStore)
421             return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found"));
422
423         auto* index = objectStore->indexForIdentifier(info.sourceIdentifier());
424         if (!index)
425             return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store index found"));
426
427         MemoryCursor* cursor = index->maybeOpenCursor(info);
428         if (!cursor)
429             return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("Could not create index cursor in backing store"));
430
431         cursor->currentData(outData);
432         break;
433     }
434
435     return { };
436 }
437
438 IDBError MemoryIDBBackingStore::iterateCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBKeyData& key, uint32_t count, IDBGetResult& outData)
439 {
440     LOG(IndexedDB, "MemoryIDBBackingStore::iterateCursor");
441
442     if (!m_transactions.contains(transactionIdentifier))
443         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found in which to iterate cursor"));
444
445     auto* cursor = MemoryCursor::cursorForIdentifier(cursorIdentifier);
446     if (!cursor)
447         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store cursor found in which to iterate cursor"));
448
449     cursor->iterate(key, count, outData);
450
451     return { };
452 }
453
454 void MemoryIDBBackingStore::registerObjectStore(Ref<MemoryObjectStore>&& objectStore)
455 {
456     ASSERT(!m_objectStoresByIdentifier.contains(objectStore->info().identifier()));
457     ASSERT(!m_objectStoresByName.contains(objectStore->info().name()));
458
459     m_objectStoresByName.set(objectStore->info().name(), &objectStore.get());
460     m_objectStoresByIdentifier.set(objectStore->info().identifier(), WTFMove(objectStore));
461 }
462
463 void MemoryIDBBackingStore::unregisterObjectStore(MemoryObjectStore& objectStore)
464 {
465     ASSERT(m_objectStoresByIdentifier.contains(objectStore.info().identifier()));
466     ASSERT(m_objectStoresByName.contains(objectStore.info().name()));
467
468     m_objectStoresByName.remove(objectStore.info().name());
469     m_objectStoresByIdentifier.remove(objectStore.info().identifier());
470 }
471
472 RefPtr<MemoryObjectStore> MemoryIDBBackingStore::takeObjectStoreByIdentifier(uint64_t identifier)
473 {
474     auto objectStoreByIdentifier = m_objectStoresByIdentifier.take(identifier);
475     if (!objectStoreByIdentifier)
476         return nullptr;
477
478     auto objectStore = m_objectStoresByName.take(objectStoreByIdentifier->info().name());
479     ASSERT_UNUSED(objectStore, objectStore);
480
481     return objectStoreByIdentifier;
482 }
483
484 void MemoryIDBBackingStore::deleteBackingStore()
485 {
486     // The in-memory IDB backing store doesn't need to do any cleanup when it is deleted.
487 }
488
489 } // namespace IDBServer
490 } // namespace WebCore
491
492 #endif // ENABLE(INDEXED_DATABASE)