d5da53dc6565421b23eefe5688696f0b4f44fb8d
[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 bool MemoryObjectStore::containsRecord(const IDBKeyData& key)
106 {
107     if (!m_keyValueStore)
108         return false;
109
110     return m_keyValueStore->contains(key);
111 }
112
113 void MemoryObjectStore::clear()
114 {
115     LOG(IndexedDB, "MemoryObjectStore::clear");
116     ASSERT(m_writeTransaction);
117
118     m_writeTransaction->objectStoreCleared(*this, WTF::move(m_keyValueStore), WTF::move(m_orderedKeys));
119     for (auto& index : m_indexesByIdentifier.values())
120         index->objectStoreCleared();
121
122     for (auto& cursor : m_cursors.values())
123         cursor->objectStoreCleared();
124 }
125
126 void MemoryObjectStore::replaceKeyValueStore(std::unique_ptr<KeyValueMap>&& store, std::unique_ptr<std::set<IDBKeyData>>&& orderedKeys)
127 {
128     ASSERT(m_writeTransaction);
129     ASSERT(m_writeTransaction->isAborting());
130
131     m_keyValueStore = WTF::move(store);
132     m_orderedKeys = WTF::move(orderedKeys);
133 }
134
135 void MemoryObjectStore::deleteRecord(const IDBKeyData& key)
136 {
137     LOG(IndexedDB, "MemoryObjectStore::deleteRecord");
138
139     ASSERT(m_writeTransaction);
140
141     if (!m_keyValueStore) {
142         m_writeTransaction->recordValueChanged(*this, key, nullptr);
143         return;
144     }
145
146     ASSERT(m_orderedKeys);
147
148     auto iterator = m_keyValueStore->find(key);
149     if (iterator == m_keyValueStore->end()) {
150         m_writeTransaction->recordValueChanged(*this, key, nullptr);
151         return;
152     }
153
154     m_writeTransaction->recordValueChanged(*this, key, &iterator->value);
155     m_keyValueStore->remove(iterator);
156     m_orderedKeys->erase(key);
157
158     updateIndexesForDeleteRecord(key);
159     updateCursorsForDeleteRecord(key);
160 }
161
162 void MemoryObjectStore::deleteRange(const IDBKeyRangeData& inputRange)
163 {
164     LOG(IndexedDB, "MemoryObjectStore::deleteRange");
165
166     ASSERT(m_writeTransaction);
167
168     if (inputRange.isExactlyOneKey()) {
169         deleteRecord(inputRange.lowerKey);
170         return;
171     }
172
173     IDBKeyRangeData range = inputRange;
174     while (true) {
175         auto key = lowestKeyWithRecordInRange(range);
176         if (key.isNull())
177             break;
178
179         deleteRecord(key);
180
181         range.lowerKey = key;
182         range.lowerOpen = true;
183     }
184 }
185
186 IDBError MemoryObjectStore::addRecord(MemoryBackingStoreTransaction& transaction, const IDBKeyData& keyData, const ThreadSafeDataBuffer& value)
187 {
188     LOG(IndexedDB, "MemoryObjectStore::addRecord");
189
190     ASSERT(m_writeTransaction);
191     ASSERT_UNUSED(transaction, m_writeTransaction == &transaction);
192     ASSERT(!m_keyValueStore || !m_keyValueStore->contains(keyData));
193     ASSERT(!m_orderedKeys || m_orderedKeys->find(keyData) == m_orderedKeys->end());
194
195     if (!m_keyValueStore) {
196         ASSERT(!m_orderedKeys);
197         m_keyValueStore = std::make_unique<KeyValueMap>();
198         m_orderedKeys = std::make_unique<std::set<IDBKeyData>>();
199     }
200
201     auto mapResult = m_keyValueStore->set(keyData, value);
202     ASSERT(mapResult.isNewEntry);
203     auto listResult = m_orderedKeys->insert(keyData);
204     ASSERT(listResult.second);
205
206     // If there was an error indexing this addition, then revert it.
207     auto error = updateIndexesForPutRecord(keyData, value);
208     if (!error.isNull()) {
209         m_keyValueStore->remove(mapResult.iterator);
210         m_orderedKeys->erase(listResult.first);
211     } else
212         updateCursorsForPutRecord(listResult.first);
213
214     return error;
215 }
216
217 static VM& indexVM()
218 {
219     ASSERT(!isMainThread());
220     static NeverDestroyed<RefPtr<VM>> vm = VM::create();
221     return *vm.get();
222 }
223
224 static ExecState& indexGlobalExec()
225 {
226     ASSERT(!isMainThread());
227     static NeverDestroyed<Strong<JSGlobalObject>> globalObject;
228     static bool initialized = false;
229     if (!initialized) {
230         globalObject.get().set(indexVM(), JSGlobalObject::create(indexVM(), JSGlobalObject::createStructure(indexVM(), jsNull())));
231         initialized = true;
232     }
233
234     RELEASE_ASSERT(globalObject.get()->globalExec());
235     return *globalObject.get()->globalExec();
236 }
237
238 void MemoryObjectStore::updateCursorsForPutRecord(std::set<IDBKeyData>::iterator iterator)
239 {
240     for (auto& cursor : m_cursors.values())
241         cursor->keyAdded(iterator);
242 }
243
244 void MemoryObjectStore::updateCursorsForDeleteRecord(const IDBKeyData& key)
245 {
246     for (auto& cursor : m_cursors.values())
247         cursor->keyDeleted(key);
248 }
249
250 void MemoryObjectStore::updateIndexesForDeleteRecord(const IDBKeyData& value)
251 {
252     for (auto* index : m_indexesByName.values())
253         index->removeEntriesWithValueKey(value);
254 }
255
256 IDBError MemoryObjectStore::updateIndexesForPutRecord(const IDBKeyData& key, const ThreadSafeDataBuffer& value)
257 {
258     JSLockHolder locker(indexVM());
259
260     auto jsValue = idbValueDataToJSValue(indexGlobalExec(), value);
261     if (jsValue.isUndefinedOrNull())
262         return { };
263
264     IDBError error;
265     Vector<std::pair<MemoryIndex*, IndexKey>> changedIndexRecords;
266
267     for (auto* index : m_indexesByName.values()) {
268         IndexKey indexKey;
269         generateIndexKeyForValue(indexGlobalExec(), index->info(), jsValue, indexKey);
270
271         if (indexKey.isNull())
272             continue;
273
274         error = index->putIndexKey(key, indexKey);
275         if (!error.isNull())
276             break;
277
278         changedIndexRecords.append(std::make_pair(index, indexKey));
279     }
280
281     // If any of the index puts failed, revert all of the ones that went through.
282     if (!error.isNull()) {
283         for (auto& record : changedIndexRecords)
284             record.first->removeRecord(key, record.second);
285     }
286
287     return error;
288 }
289
290
291 IDBError MemoryObjectStore::populateIndexWithExistingRecords(MemoryIndex& index)
292 {
293     if (!m_keyValueStore)
294         return { };
295
296     JSLockHolder locker(indexVM());
297
298     for (auto iterator : *m_keyValueStore) {
299         auto jsValue = idbValueDataToJSValue(indexGlobalExec(), iterator.value);
300         if (jsValue.isUndefinedOrNull())
301             return { };
302
303         IndexKey indexKey;
304         generateIndexKeyForValue(indexGlobalExec(), index.info(), jsValue, indexKey);
305
306         if (indexKey.isNull())
307             continue;
308
309         IDBError error = index.putIndexKey(iterator.key, indexKey);
310         if (!error.isNull())
311             return error;
312     }
313
314     return { };
315 }
316
317 uint64_t MemoryObjectStore::countForKeyRange(uint64_t indexIdentifier, const IDBKeyRangeData& inRange) const
318 {
319     LOG(IndexedDB, "MemoryObjectStore::countForKeyRange");
320
321     if (indexIdentifier) {
322         auto* index = m_indexesByIdentifier.get(indexIdentifier);
323         ASSERT(index);
324         return index->countForKeyRange(inRange);
325     }
326
327     if (!m_keyValueStore)
328         return 0;
329
330     uint64_t count = 0;
331     IDBKeyRangeData range = inRange;
332     while (true) {
333         auto key = lowestKeyWithRecordInRange(range);
334         if (key.isNull())
335             break;
336
337         ++count;
338         range.lowerKey = key;
339         range.lowerOpen = true;
340     }
341
342     return count;
343 }
344
345 ThreadSafeDataBuffer MemoryObjectStore::valueForKey(const IDBKeyData& key) const
346 {
347     if (!m_keyValueStore)
348         return { };
349
350     return m_keyValueStore->get(key);
351 }
352
353 ThreadSafeDataBuffer MemoryObjectStore::valueForKeyRange(const IDBKeyRangeData& keyRangeData) const
354 {
355     LOG(IndexedDB, "MemoryObjectStore::valueForKey");
356
357     IDBKeyData key = lowestKeyWithRecordInRange(keyRangeData);
358     if (key.isNull())
359         return ThreadSafeDataBuffer();
360
361     ASSERT(m_keyValueStore);
362     return m_keyValueStore->get(key);
363 }
364
365 IDBGetResult MemoryObjectStore::indexValueForKeyRange(uint64_t indexIdentifier, IndexedDB::IndexRecordType recordType, const IDBKeyRangeData& range) const
366 {
367     LOG(IndexedDB, "MemoryObjectStore::indexValueForKeyRange");
368
369     auto* index = m_indexesByIdentifier.get(indexIdentifier);
370     ASSERT(index);
371     return index->getResultForKeyRange(recordType, range);
372 }
373
374 IDBKeyData MemoryObjectStore::lowestKeyWithRecordInRange(const IDBKeyRangeData& keyRangeData) const
375 {
376     if (!m_keyValueStore)
377         return { };
378
379     if (keyRangeData.isExactlyOneKey() && m_keyValueStore->contains(keyRangeData.lowerKey))
380         return keyRangeData.lowerKey;
381
382     ASSERT(m_orderedKeys);
383
384     auto lowestInRange = m_orderedKeys->lower_bound(keyRangeData.lowerKey);
385
386     if (lowestInRange == m_orderedKeys->end())
387         return { };
388
389     if (keyRangeData.lowerOpen && *lowestInRange == keyRangeData.lowerKey)
390         ++lowestInRange;
391
392     if (lowestInRange == m_orderedKeys->end())
393         return { };
394
395     if (!keyRangeData.upperKey.isNull()) {
396         if (lowestInRange->compare(keyRangeData.upperKey) > 0)
397             return { };
398         if (keyRangeData.upperOpen && *lowestInRange == keyRangeData.upperKey)
399             return { };
400     }
401
402     return *lowestInRange;
403 }
404
405 void MemoryObjectStore::registerIndex(std::unique_ptr<MemoryIndex>&& index)
406 {
407     ASSERT(index);
408     ASSERT(!m_indexesByIdentifier.contains(index->info().identifier()));
409     ASSERT(!m_indexesByName.contains(index->info().name()));
410
411     m_indexesByName.set(index->info().name(), index.get());
412     m_indexesByIdentifier.set(index->info().identifier(), WTF::move(index));
413 }
414
415 void MemoryObjectStore::unregisterIndex(MemoryIndex& index)
416 {
417     ASSERT(m_indexesByIdentifier.contains(index.info().identifier()));
418     ASSERT(m_indexesByName.contains(index.info().name()));
419
420     m_indexesByName.remove(index.info().name());
421     m_indexesByIdentifier.remove(index.info().identifier());
422 }
423
424 MemoryObjectStoreCursor* MemoryObjectStore::maybeOpenCursor(const IDBCursorInfo& info)
425 {
426     auto result = m_cursors.add(info.identifier(), nullptr);
427     if (!result.isNewEntry)
428         return nullptr;
429
430     result.iterator->value = MemoryObjectStoreCursor::create(*this, info);
431     return result.iterator->value.get();
432 }
433
434 } // namespace IDBServer
435 } // namespace WebCore
436
437 #endif // ENABLE(INDEXED_DATABASE)