Improve use of NeverDestroyed
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / server / MemoryObjectStore.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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "MemoryObjectStore.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "IDBBindingUtilities.h"
32 #include "IDBDatabaseException.h"
33 #include "IDBError.h"
34 #include "IDBGetAllResult.h"
35 #include "IDBKeyRangeData.h"
36 #include "IDBValue.h"
37 #include "IndexKey.h"
38 #include "Logging.h"
39 #include "MemoryBackingStoreTransaction.h"
40 #include "UniqueIDBDatabase.h"
41 #include <runtime/JSCJSValue.h>
42 #include <runtime/JSCJSValueInlines.h>
43 #include <runtime/JSLock.h>
44
45 using namespace JSC;
46
47 namespace WebCore {
48 namespace IDBServer {
49
50 Ref<MemoryObjectStore> MemoryObjectStore::create(const IDBObjectStoreInfo& info)
51 {
52     return adoptRef(*new MemoryObjectStore(info));
53 }
54
55 MemoryObjectStore::MemoryObjectStore(const IDBObjectStoreInfo& info)
56     : m_info(info)
57 {
58 }
59
60 MemoryObjectStore::~MemoryObjectStore()
61 {
62     m_writeTransaction = nullptr;
63 }
64
65 MemoryIndex* MemoryObjectStore::indexForIdentifier(uint64_t identifier)
66 {
67     ASSERT(identifier);
68     return m_indexesByIdentifier.get(identifier);
69 }
70
71 void MemoryObjectStore::writeTransactionStarted(MemoryBackingStoreTransaction& transaction)
72 {
73     LOG(IndexedDB, "MemoryObjectStore::writeTransactionStarted");
74
75     ASSERT(!m_writeTransaction);
76     m_writeTransaction = &transaction;
77 }
78
79 void MemoryObjectStore::writeTransactionFinished(MemoryBackingStoreTransaction& transaction)
80 {
81     LOG(IndexedDB, "MemoryObjectStore::writeTransactionFinished");
82
83     ASSERT_UNUSED(transaction, m_writeTransaction == &transaction);
84     m_writeTransaction = nullptr;
85 }
86
87 IDBError MemoryObjectStore::createIndex(MemoryBackingStoreTransaction& transaction, const IDBIndexInfo& info)
88 {
89     LOG(IndexedDB, "MemoryObjectStore::createIndex");
90
91     if (!m_writeTransaction || !m_writeTransaction->isVersionChange() || m_writeTransaction != &transaction)
92         return IDBError(IDBDatabaseException::ConstraintError);
93
94     ASSERT(!m_indexesByIdentifier.contains(info.identifier()));
95     auto index = MemoryIndex::create(info, *this);
96
97     // If there was an error populating the new index, then the current records in the object store violate its contraints
98     auto error = populateIndexWithExistingRecords(index.get());
99     if (!error.isNull())
100         return error;
101
102     m_info.addExistingIndex(info);
103     transaction.addNewIndex(index.get());
104     registerIndex(WTFMove(index));
105
106     return { };
107 }
108
109 void MemoryObjectStore::maybeRestoreDeletedIndex(Ref<MemoryIndex>&& index)
110 {
111     LOG(IndexedDB, "MemoryObjectStore::maybeRestoreDeletedIndex");
112
113     if (m_info.hasIndex(index->info().name()))
114         return;
115
116     m_info.addExistingIndex(index->info());
117
118     ASSERT(!m_indexesByIdentifier.contains(index->info().identifier()));
119     index->clearIndexValueStore();
120     auto error = populateIndexWithExistingRecords(index.get());
121
122     // Since this index was installed in the object store before this transaction started,
123     // assuming things were in a valid state then, we should definitely be able to successfully
124     // repopulate the index with the object store's pre-transaction records.
125     ASSERT_UNUSED(error, error.isNull());
126
127     registerIndex(WTFMove(index));
128 }
129
130 RefPtr<MemoryIndex> MemoryObjectStore::takeIndexByIdentifier(uint64_t indexIdentifier)
131 {
132     auto indexByIdentifier = m_indexesByIdentifier.take(indexIdentifier);
133     if (!indexByIdentifier)
134         return nullptr;
135
136     auto index = m_indexesByName.take(indexByIdentifier->info().name());
137     ASSERT(index);
138
139     return index;
140 }
141
142 IDBError MemoryObjectStore::deleteIndex(MemoryBackingStoreTransaction& transaction, uint64_t indexIdentifier)
143 {
144     LOG(IndexedDB, "MemoryObjectStore::deleteIndex");
145
146     if (!m_writeTransaction || !m_writeTransaction->isVersionChange() || m_writeTransaction != &transaction)
147         return IDBError(IDBDatabaseException::ConstraintError);
148     
149     auto index = takeIndexByIdentifier(indexIdentifier);
150     ASSERT(index);
151     if (!index)
152         return IDBError(IDBDatabaseException::ConstraintError);
153
154     m_info.deleteIndex(indexIdentifier);
155     transaction.indexDeleted(*index);
156
157     return { };
158 }
159
160 void MemoryObjectStore::deleteAllIndexes(MemoryBackingStoreTransaction& transaction)
161 {
162     Vector<uint64_t> indexIdentifiers;
163     indexIdentifiers.reserveInitialCapacity(m_indexesByName.size());
164
165     for (auto& index : m_indexesByName.values())
166         indexIdentifiers.uncheckedAppend(index->info().identifier());
167
168     for (auto identifier : indexIdentifiers)
169         deleteIndex(transaction, identifier);
170 }
171
172 bool MemoryObjectStore::containsRecord(const IDBKeyData& key)
173 {
174     if (!m_keyValueStore)
175         return false;
176
177     return m_keyValueStore->contains(key);
178 }
179
180 void MemoryObjectStore::clear()
181 {
182     LOG(IndexedDB, "MemoryObjectStore::clear");
183     ASSERT(m_writeTransaction);
184
185     m_writeTransaction->objectStoreCleared(*this, WTFMove(m_keyValueStore), WTFMove(m_orderedKeys));
186     for (auto& index : m_indexesByIdentifier.values())
187         index->objectStoreCleared();
188
189     for (auto& cursor : m_cursors.values())
190         cursor->objectStoreCleared();
191 }
192
193 void MemoryObjectStore::replaceKeyValueStore(std::unique_ptr<KeyValueMap>&& store, std::unique_ptr<IDBKeyDataSet>&& orderedKeys)
194 {
195     ASSERT(m_writeTransaction);
196     ASSERT(m_writeTransaction->isAborting());
197
198     m_keyValueStore = WTFMove(store);
199     m_orderedKeys = WTFMove(orderedKeys);
200 }
201
202 void MemoryObjectStore::deleteRecord(const IDBKeyData& key)
203 {
204     LOG(IndexedDB, "MemoryObjectStore::deleteRecord");
205
206     ASSERT(m_writeTransaction);
207
208     if (!m_keyValueStore) {
209         m_writeTransaction->recordValueChanged(*this, key, nullptr);
210         return;
211     }
212
213     ASSERT(m_orderedKeys);
214
215     auto iterator = m_keyValueStore->find(key);
216     if (iterator == m_keyValueStore->end()) {
217         m_writeTransaction->recordValueChanged(*this, key, nullptr);
218         return;
219     }
220
221     m_writeTransaction->recordValueChanged(*this, key, &iterator->value);
222     m_keyValueStore->remove(iterator);
223     m_orderedKeys->erase(key);
224
225     updateIndexesForDeleteRecord(key);
226     updateCursorsForDeleteRecord(key);
227 }
228
229 void MemoryObjectStore::deleteRange(const IDBKeyRangeData& inputRange)
230 {
231     LOG(IndexedDB, "MemoryObjectStore::deleteRange");
232
233     ASSERT(m_writeTransaction);
234
235     if (inputRange.isExactlyOneKey()) {
236         deleteRecord(inputRange.lowerKey);
237         return;
238     }
239
240     IDBKeyRangeData range = inputRange;
241     while (true) {
242         auto key = lowestKeyWithRecordInRange(range);
243         if (key.isNull())
244             break;
245
246         deleteRecord(key);
247
248         range.lowerKey = key;
249         range.lowerOpen = true;
250     }
251 }
252
253 IDBError MemoryObjectStore::addRecord(MemoryBackingStoreTransaction& transaction, const IDBKeyData& keyData, const IDBValue& value)
254 {
255     LOG(IndexedDB, "MemoryObjectStore::addRecord");
256
257     ASSERT(m_writeTransaction);
258     ASSERT_UNUSED(transaction, m_writeTransaction == &transaction);
259     ASSERT(!m_keyValueStore || !m_keyValueStore->contains(keyData));
260     ASSERT(!m_orderedKeys || m_orderedKeys->find(keyData) == m_orderedKeys->end());
261
262     if (!m_keyValueStore) {
263         ASSERT(!m_orderedKeys);
264         m_keyValueStore = std::make_unique<KeyValueMap>();
265         m_orderedKeys = std::make_unique<IDBKeyDataSet>();
266     }
267
268     auto mapResult = m_keyValueStore->set(keyData, value.data());
269     ASSERT(mapResult.isNewEntry);
270     auto listResult = m_orderedKeys->insert(keyData);
271     ASSERT(listResult.second);
272
273     // If there was an error indexing this addition, then revert it.
274     auto error = updateIndexesForPutRecord(keyData, value.data());
275     if (!error.isNull()) {
276         m_keyValueStore->remove(mapResult.iterator);
277         m_orderedKeys->erase(listResult.first);
278     } else
279         updateCursorsForPutRecord(listResult.first);
280
281     return error;
282 }
283
284 void MemoryObjectStore::updateCursorsForPutRecord(IDBKeyDataSet::iterator iterator)
285 {
286     for (auto& cursor : m_cursors.values())
287         cursor->keyAdded(iterator);
288 }
289
290 void MemoryObjectStore::updateCursorsForDeleteRecord(const IDBKeyData& key)
291 {
292     for (auto& cursor : m_cursors.values())
293         cursor->keyDeleted(key);
294 }
295
296 void MemoryObjectStore::updateIndexesForDeleteRecord(const IDBKeyData& value)
297 {
298     for (auto& index : m_indexesByName.values())
299         index->removeEntriesWithValueKey(value);
300 }
301
302 IDBError MemoryObjectStore::updateIndexesForPutRecord(const IDBKeyData& key, const ThreadSafeDataBuffer& value)
303 {
304     JSLockHolder locker(UniqueIDBDatabase::databaseThreadVM());
305
306     auto jsValue = deserializeIDBValueToJSValue(UniqueIDBDatabase::databaseThreadExecState(), value);
307     if (jsValue.isUndefinedOrNull())
308         return { };
309
310     IDBError error;
311     Vector<std::pair<MemoryIndex*, IndexKey>> changedIndexRecords;
312
313     for (auto& index : m_indexesByName.values()) {
314         IndexKey indexKey;
315         generateIndexKeyForValue(UniqueIDBDatabase::databaseThreadExecState(), index->info(), jsValue, indexKey);
316
317         if (indexKey.isNull())
318             continue;
319
320         error = index->putIndexKey(key, indexKey);
321         if (!error.isNull())
322             break;
323
324         changedIndexRecords.append(std::make_pair(index.get(), indexKey));
325     }
326
327     // If any of the index puts failed, revert all of the ones that went through.
328     if (!error.isNull()) {
329         for (auto& record : changedIndexRecords)
330             record.first->removeRecord(key, record.second);
331     }
332
333     return error;
334 }
335
336 IDBError MemoryObjectStore::populateIndexWithExistingRecords(MemoryIndex& index)
337 {
338     if (!m_keyValueStore)
339         return { };
340
341     JSLockHolder locker(UniqueIDBDatabase::databaseThreadVM());
342
343     for (auto iterator : *m_keyValueStore) {
344         auto jsValue = deserializeIDBValueToJSValue(UniqueIDBDatabase::databaseThreadExecState(), iterator.value);
345         if (jsValue.isUndefinedOrNull())
346             return { };
347
348         IndexKey indexKey;
349         generateIndexKeyForValue(UniqueIDBDatabase::databaseThreadExecState(), index.info(), jsValue, indexKey);
350
351         if (indexKey.isNull())
352             continue;
353
354         IDBError error = index.putIndexKey(iterator.key, indexKey);
355         if (!error.isNull())
356             return error;
357     }
358
359     return { };
360 }
361
362 uint64_t MemoryObjectStore::countForKeyRange(uint64_t indexIdentifier, const IDBKeyRangeData& inRange) const
363 {
364     LOG(IndexedDB, "MemoryObjectStore::countForKeyRange");
365
366     if (indexIdentifier) {
367         auto* index = m_indexesByIdentifier.get(indexIdentifier);
368         ASSERT(index);
369         return index->countForKeyRange(inRange);
370     }
371
372     if (!m_keyValueStore)
373         return 0;
374
375     uint64_t count = 0;
376     IDBKeyRangeData range = inRange;
377     while (true) {
378         auto key = lowestKeyWithRecordInRange(range);
379         if (key.isNull())
380             break;
381
382         ++count;
383         range.lowerKey = key;
384         range.lowerOpen = true;
385     }
386
387     return count;
388 }
389
390 ThreadSafeDataBuffer MemoryObjectStore::valueForKey(const IDBKeyData& key) const
391 {
392     if (!m_keyValueStore)
393         return { };
394
395     return m_keyValueStore->get(key);
396 }
397
398 ThreadSafeDataBuffer MemoryObjectStore::valueForKeyRange(const IDBKeyRangeData& keyRangeData) const
399 {
400     LOG(IndexedDB, "MemoryObjectStore::valueForKey");
401
402     IDBKeyData key = lowestKeyWithRecordInRange(keyRangeData);
403     if (key.isNull())
404         return ThreadSafeDataBuffer();
405
406     ASSERT(m_keyValueStore);
407     return m_keyValueStore->get(key);
408 }
409
410 void MemoryObjectStore::getAllRecords(const IDBKeyRangeData& keyRangeData, std::optional<uint32_t> count, IndexedDB::GetAllType type, IDBGetAllResult& result) const
411 {
412     result = { type };
413
414     uint32_t targetCount;
415     if (count && count.value())
416         targetCount = count.value();
417     else
418         targetCount = std::numeric_limits<uint32_t>::max();
419
420     IDBKeyRangeData range = keyRangeData;
421     uint32_t currentCount = 0;
422     while (currentCount < targetCount) {
423         IDBKeyData key = lowestKeyWithRecordInRange(range);
424         if (key.isNull())
425             return;
426
427         range.lowerKey = key;
428         range.lowerOpen = true;
429
430         if (type == IndexedDB::GetAllType::Keys)
431             result.addKey(WTFMove(key));
432         else
433             result.addValue(valueForKey(key));
434
435         ++currentCount;
436     }
437 }
438
439 IDBGetResult MemoryObjectStore::indexValueForKeyRange(uint64_t indexIdentifier, IndexedDB::IndexRecordType recordType, const IDBKeyRangeData& range) const
440 {
441     LOG(IndexedDB, "MemoryObjectStore::indexValueForKeyRange");
442
443     auto* index = m_indexesByIdentifier.get(indexIdentifier);
444     ASSERT(index);
445     return index->getResultForKeyRange(recordType, range);
446 }
447
448 IDBKeyData MemoryObjectStore::lowestKeyWithRecordInRange(const IDBKeyRangeData& keyRangeData) const
449 {
450     if (!m_keyValueStore)
451         return { };
452
453     if (keyRangeData.isExactlyOneKey() && m_keyValueStore->contains(keyRangeData.lowerKey))
454         return keyRangeData.lowerKey;
455
456     ASSERT(m_orderedKeys);
457
458     auto lowestInRange = m_orderedKeys->lower_bound(keyRangeData.lowerKey);
459
460     if (lowestInRange == m_orderedKeys->end())
461         return { };
462
463     if (keyRangeData.lowerOpen && *lowestInRange == keyRangeData.lowerKey)
464         ++lowestInRange;
465
466     if (lowestInRange == m_orderedKeys->end())
467         return { };
468
469     if (!keyRangeData.upperKey.isNull()) {
470         if (lowestInRange->compare(keyRangeData.upperKey) > 0)
471             return { };
472         if (keyRangeData.upperOpen && *lowestInRange == keyRangeData.upperKey)
473             return { };
474     }
475
476     return *lowestInRange;
477 }
478
479 void MemoryObjectStore::registerIndex(Ref<MemoryIndex>&& index)
480 {
481     ASSERT(!m_indexesByIdentifier.contains(index->info().identifier()));
482     ASSERT(!m_indexesByName.contains(index->info().name()));
483
484     m_indexesByName.set(index->info().name(), &index.get());
485     m_indexesByIdentifier.set(index->info().identifier(), WTFMove(index));
486 }
487
488 void MemoryObjectStore::unregisterIndex(MemoryIndex& index)
489 {
490     ASSERT(m_indexesByIdentifier.contains(index.info().identifier()));
491     ASSERT(m_indexesByName.contains(index.info().name()));
492
493     m_indexesByName.remove(index.info().name());
494     m_indexesByIdentifier.remove(index.info().identifier());
495 }
496
497 MemoryObjectStoreCursor* MemoryObjectStore::maybeOpenCursor(const IDBCursorInfo& info)
498 {
499     auto result = m_cursors.add(info.identifier(), nullptr);
500     if (!result.isNewEntry)
501         return nullptr;
502
503     result.iterator->value = std::make_unique<MemoryObjectStoreCursor>(*this, info);
504     return result.iterator->value.get();
505 }
506
507 void MemoryObjectStore::renameIndex(MemoryIndex& index, const String& newName)
508 {
509     ASSERT(m_indexesByName.get(index.info().name()) == &index);
510     ASSERT(!m_indexesByName.contains(newName));
511     ASSERT(m_info.infoForExistingIndex(index.info().name()));
512
513     m_info.infoForExistingIndex(index.info().name())->rename(newName);
514     m_indexesByName.set(newName, m_indexesByName.take(index.info().name()));
515     index.rename(newName);
516 }
517
518 } // namespace IDBServer
519 } // namespace WebCore
520
521 #endif // ENABLE(INDEXED_DATABASE)