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