Modern IDB: IDBObjectStore.deleteIndex() support.
[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 "IDBKeyRangeData.h"
35 #include "IndexKey.h"
36 #include "Logging.h"
37 #include "MemoryBackingStoreTransaction.h"
38
39 #include <wtf/NeverDestroyed.h>
40
41 using namespace JSC;
42
43 namespace WebCore {
44 namespace IDBServer {
45
46 std::unique_ptr<MemoryObjectStore> MemoryObjectStore::create(const IDBObjectStoreInfo& info)
47 {
48     return std::make_unique<MemoryObjectStore>(info);
49 }
50
51 MemoryObjectStore::MemoryObjectStore(const IDBObjectStoreInfo& info)
52     : m_info(info)
53 {
54 }
55
56 MemoryObjectStore::~MemoryObjectStore()
57 {
58     ASSERT(!m_writeTransaction);
59 }
60
61 MemoryIndex* MemoryObjectStore::indexForIdentifier(uint64_t identifier)
62 {
63     ASSERT(identifier);
64     return m_indexesByIdentifier.get(identifier);
65 }
66
67 void MemoryObjectStore::writeTransactionStarted(MemoryBackingStoreTransaction& transaction)
68 {
69     LOG(IndexedDB, "MemoryObjectStore::writeTransactionStarted");
70
71     ASSERT(!m_writeTransaction);
72     m_writeTransaction = &transaction;
73 }
74
75 void MemoryObjectStore::writeTransactionFinished(MemoryBackingStoreTransaction& transaction)
76 {
77     LOG(IndexedDB, "MemoryObjectStore::writeTransactionFinished");
78
79     ASSERT_UNUSED(transaction, m_writeTransaction == &transaction);
80     m_writeTransaction = nullptr;
81 }
82
83 IDBError MemoryObjectStore::createIndex(MemoryBackingStoreTransaction& transaction, const IDBIndexInfo& info)
84 {
85     LOG(IndexedDB, "MemoryObjectStore::createIndex");
86
87     if (!m_writeTransaction || !m_writeTransaction->isVersionChange() || m_writeTransaction != &transaction)
88         return IDBError(IDBExceptionCode::ConstraintError);
89
90     ASSERT(!m_indexesByIdentifier.contains(info.identifier()));
91     auto index = MemoryIndex::create(info, *this);
92
93     // If there was an error populating the new index, then the current records in the object store violate its contraints
94     auto error = populateIndexWithExistingRecords(*index);
95     if (!error.isNull())
96         return error;
97
98     m_info.addExistingIndex(info);
99     transaction.addNewIndex(*index);
100     registerIndex(WTF::move(index));
101
102     return { };
103 }
104
105 void MemoryObjectStore::maybeRestoreDeletedIndex(std::unique_ptr<MemoryIndex> index)
106 {
107     LOG(IndexedDB, "MemoryObjectStore::maybeRestoreDeletedIndex");
108
109     ASSERT(index);
110
111     if (m_info.hasIndex(index->info().name()))
112         return;
113
114     m_info.addExistingIndex(index->info());
115
116     ASSERT(!m_indexesByIdentifier.contains(index->info().identifier()));
117     index->clearIndexValueStore();
118     auto error = populateIndexWithExistingRecords(*index);
119
120     // Since this index was installed in the object store before this transaction started,
121     // assuming things were in a valid state then, we should definitely be able to successfully
122     // repopulate the index with the object store's pre-transaction records.
123     ASSERT_UNUSED(error, error.isNull());
124
125     registerIndex(WTF::move(index));
126 }
127
128 std::unique_ptr<MemoryIndex> MemoryObjectStore::takeIndexByName(const String& name)
129 {
130     auto rawIndex = m_indexesByName.take(name);
131     if (!rawIndex)
132         return nullptr;
133
134     auto index = m_indexesByIdentifier.take(rawIndex->info().identifier());
135     ASSERT(index);
136
137     return index;
138 }
139
140 IDBError MemoryObjectStore::deleteIndex(MemoryBackingStoreTransaction& transaction, const String& indexName)
141 {
142     LOG(IndexedDB, "MemoryObjectStore::deleteIndex");
143
144     if (!m_writeTransaction || !m_writeTransaction->isVersionChange() || m_writeTransaction != &transaction)
145         return IDBError(IDBExceptionCode::ConstraintError);
146     
147     auto index = takeIndexByName(indexName);
148     ASSERT(index);
149     if (!index)
150         return IDBError(IDBExceptionCode::ConstraintError);
151
152     m_info.deleteIndex(indexName);
153     transaction.indexDeleted(WTF::move(index));
154
155     return { };
156 }
157
158 bool MemoryObjectStore::containsRecord(const IDBKeyData& key)
159 {
160     if (!m_keyValueStore)
161         return false;
162
163     return m_keyValueStore->contains(key);
164 }
165
166 void MemoryObjectStore::clear()
167 {
168     LOG(IndexedDB, "MemoryObjectStore::clear");
169     ASSERT(m_writeTransaction);
170
171     m_writeTransaction->objectStoreCleared(*this, WTF::move(m_keyValueStore), WTF::move(m_orderedKeys));
172     for (auto& index : m_indexesByIdentifier.values())
173         index->objectStoreCleared();
174
175     for (auto& cursor : m_cursors.values())
176         cursor->objectStoreCleared();
177 }
178
179 void MemoryObjectStore::replaceKeyValueStore(std::unique_ptr<KeyValueMap>&& store, std::unique_ptr<std::set<IDBKeyData>>&& orderedKeys)
180 {
181     ASSERT(m_writeTransaction);
182     ASSERT(m_writeTransaction->isAborting());
183
184     m_keyValueStore = WTF::move(store);
185     m_orderedKeys = WTF::move(orderedKeys);
186 }
187
188 void MemoryObjectStore::deleteRecord(const IDBKeyData& key)
189 {
190     LOG(IndexedDB, "MemoryObjectStore::deleteRecord");
191
192     ASSERT(m_writeTransaction);
193
194     if (!m_keyValueStore) {
195         m_writeTransaction->recordValueChanged(*this, key, nullptr);
196         return;
197     }
198
199     ASSERT(m_orderedKeys);
200
201     auto iterator = m_keyValueStore->find(key);
202     if (iterator == m_keyValueStore->end()) {
203         m_writeTransaction->recordValueChanged(*this, key, nullptr);
204         return;
205     }
206
207     m_writeTransaction->recordValueChanged(*this, key, &iterator->value);
208     m_keyValueStore->remove(iterator);
209     m_orderedKeys->erase(key);
210
211     updateIndexesForDeleteRecord(key);
212     updateCursorsForDeleteRecord(key);
213 }
214
215 void MemoryObjectStore::deleteRange(const IDBKeyRangeData& inputRange)
216 {
217     LOG(IndexedDB, "MemoryObjectStore::deleteRange");
218
219     ASSERT(m_writeTransaction);
220
221     if (inputRange.isExactlyOneKey()) {
222         deleteRecord(inputRange.lowerKey);
223         return;
224     }
225
226     IDBKeyRangeData range = inputRange;
227     while (true) {
228         auto key = lowestKeyWithRecordInRange(range);
229         if (key.isNull())
230             break;
231
232         deleteRecord(key);
233
234         range.lowerKey = key;
235         range.lowerOpen = true;
236     }
237 }
238
239 IDBError MemoryObjectStore::addRecord(MemoryBackingStoreTransaction& transaction, const IDBKeyData& keyData, const ThreadSafeDataBuffer& value)
240 {
241     LOG(IndexedDB, "MemoryObjectStore::addRecord");
242
243     ASSERT(m_writeTransaction);
244     ASSERT_UNUSED(transaction, m_writeTransaction == &transaction);
245     ASSERT(!m_keyValueStore || !m_keyValueStore->contains(keyData));
246     ASSERT(!m_orderedKeys || m_orderedKeys->find(keyData) == m_orderedKeys->end());
247
248     if (!m_keyValueStore) {
249         ASSERT(!m_orderedKeys);
250         m_keyValueStore = std::make_unique<KeyValueMap>();
251         m_orderedKeys = std::make_unique<std::set<IDBKeyData>>();
252     }
253
254     auto mapResult = m_keyValueStore->set(keyData, value);
255     ASSERT(mapResult.isNewEntry);
256     auto listResult = m_orderedKeys->insert(keyData);
257     ASSERT(listResult.second);
258
259     // If there was an error indexing this addition, then revert it.
260     auto error = updateIndexesForPutRecord(keyData, value);
261     if (!error.isNull()) {
262         m_keyValueStore->remove(mapResult.iterator);
263         m_orderedKeys->erase(listResult.first);
264     } else
265         updateCursorsForPutRecord(listResult.first);
266
267     return error;
268 }
269
270 static VM& indexVM()
271 {
272     ASSERT(!isMainThread());
273     static NeverDestroyed<RefPtr<VM>> vm = VM::create();
274     return *vm.get();
275 }
276
277 static ExecState& indexGlobalExec()
278 {
279     ASSERT(!isMainThread());
280     static NeverDestroyed<Strong<JSGlobalObject>> globalObject;
281     static bool initialized = false;
282     if (!initialized) {
283         globalObject.get().set(indexVM(), JSGlobalObject::create(indexVM(), JSGlobalObject::createStructure(indexVM(), jsNull())));
284         initialized = true;
285     }
286
287     RELEASE_ASSERT(globalObject.get()->globalExec());
288     return *globalObject.get()->globalExec();
289 }
290
291 void MemoryObjectStore::updateCursorsForPutRecord(std::set<IDBKeyData>::iterator iterator)
292 {
293     for (auto& cursor : m_cursors.values())
294         cursor->keyAdded(iterator);
295 }
296
297 void MemoryObjectStore::updateCursorsForDeleteRecord(const IDBKeyData& key)
298 {
299     for (auto& cursor : m_cursors.values())
300         cursor->keyDeleted(key);
301 }
302
303 void MemoryObjectStore::updateIndexesForDeleteRecord(const IDBKeyData& value)
304 {
305     for (auto* index : m_indexesByName.values())
306         index->removeEntriesWithValueKey(value);
307 }
308
309 IDBError MemoryObjectStore::updateIndexesForPutRecord(const IDBKeyData& key, const ThreadSafeDataBuffer& value)
310 {
311     JSLockHolder locker(indexVM());
312
313     auto jsValue = idbValueDataToJSValue(indexGlobalExec(), value);
314     if (jsValue.isUndefinedOrNull())
315         return { };
316
317     IDBError error;
318     Vector<std::pair<MemoryIndex*, IndexKey>> changedIndexRecords;
319
320     for (auto* index : m_indexesByName.values()) {
321         IndexKey indexKey;
322         generateIndexKeyForValue(indexGlobalExec(), index->info(), jsValue, indexKey);
323
324         if (indexKey.isNull())
325             continue;
326
327         error = index->putIndexKey(key, indexKey);
328         if (!error.isNull())
329             break;
330
331         changedIndexRecords.append(std::make_pair(index, indexKey));
332     }
333
334     // If any of the index puts failed, revert all of the ones that went through.
335     if (!error.isNull()) {
336         for (auto& record : changedIndexRecords)
337             record.first->removeRecord(key, record.second);
338     }
339
340     return error;
341 }
342
343
344 IDBError MemoryObjectStore::populateIndexWithExistingRecords(MemoryIndex& index)
345 {
346     if (!m_keyValueStore)
347         return { };
348
349     JSLockHolder locker(indexVM());
350
351     for (auto iterator : *m_keyValueStore) {
352         auto jsValue = idbValueDataToJSValue(indexGlobalExec(), iterator.value);
353         if (jsValue.isUndefinedOrNull())
354             return { };
355
356         IndexKey indexKey;
357         generateIndexKeyForValue(indexGlobalExec(), index.info(), jsValue, indexKey);
358
359         if (indexKey.isNull())
360             continue;
361
362         IDBError error = index.putIndexKey(iterator.key, indexKey);
363         if (!error.isNull())
364             return error;
365     }
366
367     return { };
368 }
369
370 uint64_t MemoryObjectStore::countForKeyRange(uint64_t indexIdentifier, const IDBKeyRangeData& inRange) const
371 {
372     LOG(IndexedDB, "MemoryObjectStore::countForKeyRange");
373
374     if (indexIdentifier) {
375         auto* index = m_indexesByIdentifier.get(indexIdentifier);
376         ASSERT(index);
377         return index->countForKeyRange(inRange);
378     }
379
380     if (!m_keyValueStore)
381         return 0;
382
383     uint64_t count = 0;
384     IDBKeyRangeData range = inRange;
385     while (true) {
386         auto key = lowestKeyWithRecordInRange(range);
387         if (key.isNull())
388             break;
389
390         ++count;
391         range.lowerKey = key;
392         range.lowerOpen = true;
393     }
394
395     return count;
396 }
397
398 ThreadSafeDataBuffer MemoryObjectStore::valueForKey(const IDBKeyData& key) const
399 {
400     if (!m_keyValueStore)
401         return { };
402
403     return m_keyValueStore->get(key);
404 }
405
406 ThreadSafeDataBuffer MemoryObjectStore::valueForKeyRange(const IDBKeyRangeData& keyRangeData) const
407 {
408     LOG(IndexedDB, "MemoryObjectStore::valueForKey");
409
410     IDBKeyData key = lowestKeyWithRecordInRange(keyRangeData);
411     if (key.isNull())
412         return ThreadSafeDataBuffer();
413
414     ASSERT(m_keyValueStore);
415     return m_keyValueStore->get(key);
416 }
417
418 IDBGetResult MemoryObjectStore::indexValueForKeyRange(uint64_t indexIdentifier, IndexedDB::IndexRecordType recordType, const IDBKeyRangeData& range) const
419 {
420     LOG(IndexedDB, "MemoryObjectStore::indexValueForKeyRange");
421
422     auto* index = m_indexesByIdentifier.get(indexIdentifier);
423     ASSERT(index);
424     return index->getResultForKeyRange(recordType, range);
425 }
426
427 IDBKeyData MemoryObjectStore::lowestKeyWithRecordInRange(const IDBKeyRangeData& keyRangeData) const
428 {
429     if (!m_keyValueStore)
430         return { };
431
432     if (keyRangeData.isExactlyOneKey() && m_keyValueStore->contains(keyRangeData.lowerKey))
433         return keyRangeData.lowerKey;
434
435     ASSERT(m_orderedKeys);
436
437     auto lowestInRange = m_orderedKeys->lower_bound(keyRangeData.lowerKey);
438
439     if (lowestInRange == m_orderedKeys->end())
440         return { };
441
442     if (keyRangeData.lowerOpen && *lowestInRange == keyRangeData.lowerKey)
443         ++lowestInRange;
444
445     if (lowestInRange == m_orderedKeys->end())
446         return { };
447
448     if (!keyRangeData.upperKey.isNull()) {
449         if (lowestInRange->compare(keyRangeData.upperKey) > 0)
450             return { };
451         if (keyRangeData.upperOpen && *lowestInRange == keyRangeData.upperKey)
452             return { };
453     }
454
455     return *lowestInRange;
456 }
457
458 void MemoryObjectStore::registerIndex(std::unique_ptr<MemoryIndex>&& index)
459 {
460     ASSERT(index);
461     ASSERT(!m_indexesByIdentifier.contains(index->info().identifier()));
462     ASSERT(!m_indexesByName.contains(index->info().name()));
463
464     m_indexesByName.set(index->info().name(), index.get());
465     m_indexesByIdentifier.set(index->info().identifier(), WTF::move(index));
466 }
467
468 void MemoryObjectStore::unregisterIndex(MemoryIndex& index)
469 {
470     ASSERT(m_indexesByIdentifier.contains(index.info().identifier()));
471     ASSERT(m_indexesByName.contains(index.info().name()));
472
473     m_indexesByName.remove(index.info().name());
474     m_indexesByIdentifier.remove(index.info().identifier());
475 }
476
477 MemoryObjectStoreCursor* MemoryObjectStore::maybeOpenCursor(const IDBCursorInfo& info)
478 {
479     auto result = m_cursors.add(info.identifier(), nullptr);
480     if (!result.isNewEntry)
481         return nullptr;
482
483     result.iterator->value = MemoryObjectStoreCursor::create(*this, info);
484     return result.iterator->value.get();
485 }
486
487 } // namespace IDBServer
488 } // namespace WebCore
489
490 #endif // ENABLE(INDEXED_DATABASE)