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