Modern IDB: Support IDBDatabase.transaction() (and transaction scheduling in general).
[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 "Logging.h"
32 #include "MemoryObjectStore.h"
33
34 namespace WebCore {
35 namespace IDBServer {
36
37 std::unique_ptr<MemoryIDBBackingStore> MemoryIDBBackingStore::create(const IDBDatabaseIdentifier& identifier)
38 {
39     return std::make_unique<MemoryIDBBackingStore>(identifier);
40 }
41
42 MemoryIDBBackingStore::MemoryIDBBackingStore(const IDBDatabaseIdentifier& identifier)
43     : m_identifier(identifier)
44 {
45 }
46
47 MemoryIDBBackingStore::~MemoryIDBBackingStore()
48 {
49 }
50
51 const IDBDatabaseInfo& MemoryIDBBackingStore::getOrEstablishDatabaseInfo()
52 {
53     if (!m_databaseInfo)
54         m_databaseInfo = std::make_unique<IDBDatabaseInfo>(m_identifier.databaseName(), 0);
55
56     return *m_databaseInfo;
57 }
58
59 void MemoryIDBBackingStore::setDatabaseInfo(const IDBDatabaseInfo& info)
60 {
61     // It is not valid to directly set database info on a backing store that hasn't already set its own database info.
62     ASSERT(m_databaseInfo);
63
64     m_databaseInfo = std::make_unique<IDBDatabaseInfo>(info);
65 }
66
67 IDBError MemoryIDBBackingStore::beginTransaction(const IDBTransactionInfo& info)
68 {
69     LOG(IndexedDB, "MemoryIDBBackingStore::beginTransaction");
70
71     if (m_transactions.contains(info.identifier()))
72         return IDBError(IDBExceptionCode::InvalidStateError, "Backing store asked to create transaction it already has a record of");
73
74     auto transaction = MemoryBackingStoreTransaction::create(*this, info);
75
76     // VersionChange transactions are scoped to "every object store".
77     if (transaction->isVersionChange()) {
78         for (auto& objectStore : m_objectStoresByIdentifier.values())
79             transaction->addExistingObjectStore(*objectStore);
80     } else if (transaction->isWriting()) {
81         for (auto& iterator : m_objectStoresByName) {
82             if (info.objectStores().contains(iterator.key))
83                 transaction->addExistingObjectStore(*iterator.value);
84         }
85     }
86
87     m_transactions.set(info.identifier(), WTF::move(transaction));
88
89     return IDBError();
90 }
91
92 IDBError MemoryIDBBackingStore::abortTransaction(const IDBResourceIdentifier& transactionIdentifier)
93 {
94     LOG(IndexedDB, "MemoryIDBBackingStore::abortTransaction");
95
96     auto transaction = m_transactions.take(transactionIdentifier);
97     if (!transaction)
98         return IDBError(IDBExceptionCode::InvalidStateError, "Backing store asked to abort transaction it didn't have record of");
99
100     transaction->abort();
101
102     return IDBError();
103 }
104
105 IDBError MemoryIDBBackingStore::commitTransaction(const IDBResourceIdentifier& transactionIdentifier)
106 {
107     LOG(IndexedDB, "MemoryIDBBackingStore::commitTransaction");
108
109     auto transaction = m_transactions.take(transactionIdentifier);
110     if (!transaction)
111         return IDBError(IDBExceptionCode::InvalidStateError, "Backing store asked to commit transaction it didn't have record of");
112
113     transaction->commit();
114
115     return IDBError();
116 }
117
118 IDBError MemoryIDBBackingStore::createObjectStore(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& info)
119 {
120     LOG(IndexedDB, "MemoryIDBBackingStore::createObjectStore");
121
122     ASSERT(m_databaseInfo);
123     if (m_databaseInfo->hasObjectStore(info.name()))
124         return IDBError(IDBExceptionCode::ConstraintError);
125
126     ASSERT(!m_objectStoresByIdentifier.contains(info.identifier()));
127     auto objectStore = MemoryObjectStore::create(info);
128
129     m_databaseInfo->addExistingObjectStore(info);
130
131     auto rawTransaction = m_transactions.get(transactionIdentifier);
132     ASSERT(rawTransaction);
133     ASSERT(rawTransaction->isVersionChange());
134
135     rawTransaction->addNewObjectStore(*objectStore);
136     registerObjectStore(WTF::move(objectStore));
137
138     return IDBError();
139 }
140
141 void MemoryIDBBackingStore::removeObjectStoreForVersionChangeAbort(MemoryObjectStore& objectStore)
142 {
143     LOG(IndexedDB, "MemoryIDBBackingStore::removeObjectStoreForVersionChangeAbort");
144
145     ASSERT(m_objectStoresByIdentifier.contains(objectStore.info().identifier()));
146     ASSERT(m_objectStoresByIdentifier.get(objectStore.info().identifier()) == &objectStore);
147
148     unregisterObjectStore(objectStore);
149 }
150
151 IDBError MemoryIDBBackingStore::keyExistsInObjectStore(const IDBResourceIdentifier&, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, bool& keyExists)
152 {
153     LOG(IndexedDB, "MemoryIDBBackingStore::keyExistsInObjectStore");
154
155     ASSERT(objectStoreIdentifier);
156
157     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
158     RELEASE_ASSERT(objectStore);
159
160     keyExists = objectStore->containsRecord(keyData);
161     return IDBError();
162 }
163
164 IDBError MemoryIDBBackingStore::deleteRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData)
165 {
166     LOG(IndexedDB, "MemoryIDBBackingStore::deleteRecord");
167
168     ASSERT(objectStoreIdentifier);
169
170     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
171     RELEASE_ASSERT(objectStore);
172     RELEASE_ASSERT(m_transactions.contains(transactionIdentifier));
173
174     objectStore->deleteRecord(keyData);
175     return IDBError();
176 }
177
178 IDBError MemoryIDBBackingStore::putRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const ThreadSafeDataBuffer& value)
179 {
180     LOG(IndexedDB, "MemoryIDBBackingStore::putRecord");
181
182     ASSERT(objectStoreIdentifier);
183
184     auto transaction = m_transactions.get(transactionIdentifier);
185     if (!transaction)
186         return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral("No backing store transaction found to get record"));
187
188     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
189     if (!objectStore)
190         return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral("No backing store object store found to put record"));
191
192     objectStore->putRecord(*transaction, keyData, value);
193     return IDBError();
194 }
195
196 IDBError MemoryIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, ThreadSafeDataBuffer& outValue)
197 {
198     LOG(IndexedDB, "MemoryIDBBackingStore::getRecord");
199
200     ASSERT(objectStoreIdentifier);
201
202     if (!m_transactions.contains(transactionIdentifier))
203         return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral("No backing store transaction found to get record"));
204
205     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
206     if (!objectStore)
207         return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral("No backing store object store found"));
208
209     outValue = objectStore->valueForKey(keyData);
210     return IDBError();
211 }
212
213 void MemoryIDBBackingStore::registerObjectStore(std::unique_ptr<MemoryObjectStore>&& objectStore)
214 {
215     ASSERT(objectStore);
216     ASSERT(!m_objectStoresByIdentifier.contains(objectStore->info().identifier()));
217     ASSERT(!m_objectStoresByName.contains(objectStore->info().name()));
218
219     m_objectStoresByName.set(objectStore->info().name(), objectStore.get());
220     m_objectStoresByIdentifier.set(objectStore->info().identifier(), WTF::move(objectStore));
221 }
222
223 void MemoryIDBBackingStore::unregisterObjectStore(MemoryObjectStore& objectStore)
224 {
225     ASSERT(m_objectStoresByIdentifier.contains(objectStore.info().identifier()));
226     ASSERT(m_objectStoresByName.contains(objectStore.info().name()));
227
228     m_objectStoresByName.remove(objectStore.info().name());
229     m_objectStoresByIdentifier.remove(objectStore.info().identifier());
230 }
231
232 } // namespace IDBServer
233 } // namespace WebCore
234
235 #endif // ENABLE(INDEXED_DATABASE)