Modern IDB: storage/indexeddb/lazy-index-population.html fails.
[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 std::unique_ptr<MemoryIDBBackingStore> MemoryIDBBackingStore::create(const IDBDatabaseIdentifier& identifier)
42 {
43     return std::make_unique<MemoryIDBBackingStore>(identifier);
44 }
45
46 MemoryIDBBackingStore::MemoryIDBBackingStore(const IDBDatabaseIdentifier& identifier)
47     : m_identifier(identifier)
48 {
49 }
50
51 MemoryIDBBackingStore::~MemoryIDBBackingStore()
52 {
53 }
54
55 const IDBDatabaseInfo& MemoryIDBBackingStore::getOrEstablishDatabaseInfo()
56 {
57     if (!m_databaseInfo)
58         m_databaseInfo = std::make_unique<IDBDatabaseInfo>(m_identifier.databaseName(), 0);
59
60     return *m_databaseInfo;
61 }
62
63 void MemoryIDBBackingStore::setDatabaseInfo(const IDBDatabaseInfo& info)
64 {
65     // It is not valid to directly set database info on a backing store that hasn't already set its own database info.
66     ASSERT(m_databaseInfo);
67
68     m_databaseInfo = std::make_unique<IDBDatabaseInfo>(info);
69 }
70
71 IDBError MemoryIDBBackingStore::beginTransaction(const IDBTransactionInfo& info)
72 {
73     LOG(IndexedDB, "MemoryIDBBackingStore::beginTransaction");
74
75     if (m_transactions.contains(info.identifier()))
76         return IDBError(IDBDatabaseException::InvalidStateError, "Backing store asked to create transaction it already has a record of");
77
78     auto transaction = MemoryBackingStoreTransaction::create(*this, info);
79
80     // VersionChange transactions are scoped to "every object store".
81     if (transaction->isVersionChange()) {
82         for (auto& objectStore : m_objectStoresByIdentifier.values())
83             transaction->addExistingObjectStore(*objectStore);
84     } else if (transaction->isWriting()) {
85         for (auto& iterator : m_objectStoresByName) {
86             if (info.objectStores().contains(iterator.key))
87                 transaction->addExistingObjectStore(*iterator.value);
88         }
89     }
90
91     m_transactions.set(info.identifier(), WTFMove(transaction));
92
93     return IDBError();
94 }
95
96 IDBError MemoryIDBBackingStore::abortTransaction(const IDBResourceIdentifier& transactionIdentifier)
97 {
98     LOG(IndexedDB, "MemoryIDBBackingStore::abortTransaction - %s", transactionIdentifier.loggingString().utf8().data());
99
100     auto transaction = m_transactions.take(transactionIdentifier);
101     if (!transaction)
102         return IDBError(IDBDatabaseException::InvalidStateError, "Backing store asked to abort transaction it didn't have record of");
103
104     transaction->abort();
105
106     return IDBError();
107 }
108
109 IDBError MemoryIDBBackingStore::commitTransaction(const IDBResourceIdentifier& transactionIdentifier)
110 {
111     LOG(IndexedDB, "MemoryIDBBackingStore::commitTransaction - %s", transactionIdentifier.loggingString().utf8().data());
112
113     auto transaction = m_transactions.take(transactionIdentifier);
114     if (!transaction)
115         return IDBError(IDBDatabaseException::InvalidStateError, "Backing store asked to commit transaction it didn't have record of");
116
117     transaction->commit();
118
119     return IDBError();
120 }
121
122 IDBError MemoryIDBBackingStore::createObjectStore(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& info)
123 {
124     LOG(IndexedDB, "MemoryIDBBackingStore::createObjectStore - adding OS %s with ID %" PRIu64, info.name().utf8().data(), info.identifier());
125
126     ASSERT(m_databaseInfo);
127     if (m_databaseInfo->hasObjectStore(info.name()))
128         return IDBError(IDBDatabaseException::ConstraintError);
129
130     ASSERT(!m_objectStoresByIdentifier.contains(info.identifier()));
131     auto objectStore = MemoryObjectStore::create(info);
132
133     m_databaseInfo->addExistingObjectStore(info);
134
135     auto rawTransaction = m_transactions.get(transactionIdentifier);
136     ASSERT(rawTransaction);
137     ASSERT(rawTransaction->isVersionChange());
138
139     rawTransaction->addNewObjectStore(objectStore.get());
140     registerObjectStore(WTFMove(objectStore));
141
142     return IDBError();
143 }
144
145 IDBError MemoryIDBBackingStore::deleteObjectStore(const IDBResourceIdentifier& transactionIdentifier, const String& objectStoreName)
146 {
147     LOG(IndexedDB, "MemoryIDBBackingStore::deleteObjectStore");
148
149     ASSERT(m_databaseInfo);
150     if (!m_databaseInfo->hasObjectStore(objectStoreName))
151         return IDBError(IDBDatabaseException::ConstraintError);
152
153     auto transaction = m_transactions.get(transactionIdentifier);
154     ASSERT(transaction);
155     ASSERT(transaction->isVersionChange());
156
157     auto objectStore = takeObjectStoreByName(objectStoreName);
158     ASSERT(objectStore);
159     if (!objectStore)
160         return IDBError(IDBDatabaseException::ConstraintError);
161
162     m_databaseInfo->deleteObjectStore(objectStoreName);
163     transaction->objectStoreDeleted(*objectStore);
164
165     return IDBError();
166 }
167
168 IDBError MemoryIDBBackingStore::clearObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
169 {
170     LOG(IndexedDB, "MemoryIDBBackingStore::clearObjectStore");
171     ASSERT(objectStoreIdentifier);
172
173     ASSERT_UNUSED(transactionIdentifier, m_transactions.contains(transactionIdentifier));
174
175 #ifndef NDEBUG
176     auto transaction = m_transactions.get(transactionIdentifier);
177     ASSERT(transaction->isWriting());
178 #endif
179
180     auto objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
181     if (!objectStore)
182         return IDBError(IDBDatabaseException::ConstraintError);
183
184     objectStore->clear();
185
186     return IDBError();
187 }
188
189 IDBError MemoryIDBBackingStore::createIndex(const IDBResourceIdentifier& transactionIdentifier, const IDBIndexInfo& info)
190 {
191     LOG(IndexedDB, "MemoryIDBBackingStore::createIndex");
192
193     auto rawTransaction = m_transactions.get(transactionIdentifier);
194     ASSERT(rawTransaction);
195     ASSERT(rawTransaction->isVersionChange());
196
197     auto* objectStore = m_objectStoresByIdentifier.get(info.objectStoreIdentifier());
198     if (!objectStore)
199         return IDBError(IDBDatabaseException::ConstraintError);
200
201     return objectStore->createIndex(*rawTransaction, info);
202 }
203
204 IDBError MemoryIDBBackingStore::deleteIndex(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const String& indexName)
205 {
206     LOG(IndexedDB, "MemoryIDBBackingStore::deleteIndex");
207
208     auto rawTransaction = m_transactions.get(transactionIdentifier);
209     ASSERT(rawTransaction);
210     ASSERT(rawTransaction->isVersionChange());
211
212     auto* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
213     if (!objectStore)
214         return IDBError(IDBDatabaseException::ConstraintError);
215
216     return objectStore->deleteIndex(*rawTransaction, indexName);
217 }
218
219 void MemoryIDBBackingStore::removeObjectStoreForVersionChangeAbort(MemoryObjectStore& objectStore)
220 {
221     LOG(IndexedDB, "MemoryIDBBackingStore::removeObjectStoreForVersionChangeAbort");
222
223     if (!m_objectStoresByIdentifier.contains(objectStore.info().identifier()))
224         return;
225
226     ASSERT(m_objectStoresByIdentifier.get(objectStore.info().identifier()) == &objectStore);
227
228     unregisterObjectStore(objectStore);
229 }
230
231 void MemoryIDBBackingStore::restoreObjectStoreForVersionChangeAbort(Ref<MemoryObjectStore>&& objectStore)
232 {
233     registerObjectStore(WTFMove(objectStore));
234 }
235
236 IDBError MemoryIDBBackingStore::keyExistsInObjectStore(const IDBResourceIdentifier&, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, bool& keyExists)
237 {
238     LOG(IndexedDB, "MemoryIDBBackingStore::keyExistsInObjectStore");
239
240     ASSERT(objectStoreIdentifier);
241
242     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
243     RELEASE_ASSERT(objectStore);
244
245     keyExists = objectStore->containsRecord(keyData);
246     return IDBError();
247 }
248
249 IDBError MemoryIDBBackingStore::deleteRange(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range)
250 {
251     LOG(IndexedDB, "MemoryIDBBackingStore::deleteRange");
252
253     ASSERT(objectStoreIdentifier);
254
255     if (!m_transactions.contains(transactionIdentifier))
256         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to delete from"));
257
258     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
259     if (!objectStore)
260         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found"));
261
262     objectStore->deleteRange(range);
263     return IDBError();
264 }
265
266 IDBError MemoryIDBBackingStore::addRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const ThreadSafeDataBuffer& value)
267 {
268     LOG(IndexedDB, "MemoryIDBBackingStore::addRecord");
269
270     ASSERT(objectStoreIdentifier);
271
272     auto transaction = m_transactions.get(transactionIdentifier);
273     if (!transaction)
274         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to put record"));
275
276     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
277     if (!objectStore)
278         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found to put record"));
279
280     return objectStore->addRecord(*transaction, keyData, value);
281 }
282
283 IDBError MemoryIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range, ThreadSafeDataBuffer& outValue)
284 {
285     LOG(IndexedDB, "MemoryIDBBackingStore::getRecord");
286
287     ASSERT(objectStoreIdentifier);
288
289     if (!m_transactions.contains(transactionIdentifier))
290         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to get record"));
291
292     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
293     if (!objectStore)
294         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found"));
295
296     outValue = objectStore->valueForKeyRange(range);
297     return IDBError();
298 }
299
300 IDBError MemoryIDBBackingStore::getIndexRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, IndexedDB::IndexRecordType recordType, const IDBKeyRangeData& range, IDBGetResult& outValue)
301 {
302     LOG(IndexedDB, "MemoryIDBBackingStore::getIndexRecord");
303
304     ASSERT(objectStoreIdentifier);
305
306     if (!m_transactions.contains(transactionIdentifier))
307         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to get record"));
308
309     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
310     if (!objectStore)
311         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found"));
312
313     outValue = objectStore->indexValueForKeyRange(indexIdentifier, recordType, range);
314     return IDBError();
315 }
316
317 IDBError MemoryIDBBackingStore::getCount(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData& range, uint64_t& outCount)
318 {
319     LOG(IndexedDB, "MemoryIDBBackingStore::getCount");
320
321     ASSERT(objectStoreIdentifier);
322
323     if (!m_transactions.contains(transactionIdentifier))
324         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to get count"));
325
326     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
327     if (!objectStore)
328         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found"));
329
330     outCount = objectStore->countForKeyRange(indexIdentifier, range);
331
332     return IDBError();
333 }
334
335 IDBError MemoryIDBBackingStore::generateKeyNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t& keyNumber)
336 {
337     LOG(IndexedDB, "MemoryIDBBackingStore::generateKeyNumber");
338     ASSERT(objectStoreIdentifier);
339     ASSERT_UNUSED(transactionIdentifier, m_transactions.contains(transactionIdentifier));
340     ASSERT_UNUSED(transactionIdentifier, m_transactions.get(transactionIdentifier)->isWriting());
341
342     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
343     RELEASE_ASSERT(objectStore);
344
345     keyNumber = objectStore->currentKeyGeneratorValue();
346     objectStore->setKeyGeneratorValue(keyNumber + 1);
347
348     return IDBError();
349 }
350
351 IDBError MemoryIDBBackingStore::maybeUpdateKeyGeneratorNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, double newKeyNumber)
352 {
353     LOG(IndexedDB, "MemoryIDBBackingStore::maybeUpdateKeyGeneratorNumber");
354     ASSERT(objectStoreIdentifier);
355     ASSERT_UNUSED(transactionIdentifier, m_transactions.contains(transactionIdentifier));
356     ASSERT_UNUSED(transactionIdentifier, m_transactions.get(transactionIdentifier)->isWriting());
357
358     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
359     RELEASE_ASSERT(objectStore);
360
361     if (newKeyNumber < objectStore->currentKeyGeneratorValue())
362         return { };
363
364     uint64_t newKeyInteger(newKeyNumber);
365     if (newKeyInteger <= newKeyNumber)
366         ++newKeyInteger;
367
368     ASSERT(newKeyInteger > newKeyNumber);
369
370     objectStore->setKeyGeneratorValue(newKeyInteger);
371
372     return { };
373 }
374
375 IDBError MemoryIDBBackingStore::openCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo& info, IDBGetResult& outData)
376 {
377     LOG(IndexedDB, "MemoryIDBBackingStore::openCursor");
378
379     ASSERT(!MemoryCursor::cursorForIdentifier(info.identifier()));
380
381     if (!m_transactions.contains(transactionIdentifier))
382         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found in which to open a cursor"));
383
384     switch (info.cursorSource()) {
385     case IndexedDB::CursorSource::ObjectStore: {
386         auto* objectStore = m_objectStoresByIdentifier.get(info.sourceIdentifier());
387         if (!objectStore)
388             return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found"));
389
390         MemoryCursor* cursor = objectStore->maybeOpenCursor(info);
391         if (!cursor)
392             return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("Could not create object store cursor in backing store"));
393
394         cursor->currentData(outData);
395         break;
396     }
397     case IndexedDB::CursorSource::Index:
398         auto* objectStore = m_objectStoresByIdentifier.get(info.objectStoreIdentifier());
399         if (!objectStore)
400             return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found"));
401
402         auto* index = objectStore->indexForIdentifier(info.sourceIdentifier());
403         if (!index)
404             return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store index found"));
405
406         MemoryCursor* cursor = index->maybeOpenCursor(info);
407         if (!cursor)
408             return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("Could not create index cursor in backing store"));
409
410         cursor->currentData(outData);
411         break;
412     }
413
414     return { };
415 }
416
417 IDBError MemoryIDBBackingStore::iterateCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBKeyData& key, uint32_t count, IDBGetResult& outData)
418 {
419     LOG(IndexedDB, "MemoryIDBBackingStore::iterateCursor");
420
421     if (!m_transactions.contains(transactionIdentifier))
422         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found in which to iterate cursor"));
423
424     auto* cursor = MemoryCursor::cursorForIdentifier(cursorIdentifier);
425     if (!cursor)
426         return IDBError(IDBDatabaseException::UnknownError, ASCIILiteral("No backing store cursor found in which to iterate cursor"));
427
428     cursor->iterate(key, count, outData);
429
430     return { };
431 }
432
433 void MemoryIDBBackingStore::registerObjectStore(Ref<MemoryObjectStore>&& objectStore)
434 {
435     ASSERT(!m_objectStoresByIdentifier.contains(objectStore->info().identifier()));
436     ASSERT(!m_objectStoresByName.contains(objectStore->info().name()));
437
438     m_objectStoresByName.set(objectStore->info().name(), &objectStore.get());
439     m_objectStoresByIdentifier.set(objectStore->info().identifier(), WTFMove(objectStore));
440 }
441
442 void MemoryIDBBackingStore::unregisterObjectStore(MemoryObjectStore& objectStore)
443 {
444     ASSERT(m_objectStoresByIdentifier.contains(objectStore.info().identifier()));
445     ASSERT(m_objectStoresByName.contains(objectStore.info().name()));
446
447     m_objectStoresByName.remove(objectStore.info().name());
448     m_objectStoresByIdentifier.remove(objectStore.info().identifier());
449 }
450
451 RefPtr<MemoryObjectStore> MemoryIDBBackingStore::takeObjectStoreByName(const String& name)
452 {
453     auto objectStoreByName = m_objectStoresByName.take(name);
454     if (!objectStoreByName)
455         return nullptr;
456
457     auto objectStore = m_objectStoresByIdentifier.take(objectStoreByName->info().identifier());
458     ASSERT(objectStore);
459
460     return objectStore;
461 }
462
463 void MemoryIDBBackingStore::deleteBackingStore()
464 {
465     // The in-memory IDB backing store doesn't need to do any cleanup when it is deleted.
466 }
467
468 } // namespace IDBServer
469 } // namespace WebCore
470
471 #endif // ENABLE(INDEXED_DATABASE)