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 "MemoryBackingStoreTransaction.h"
28
29#if ENABLE(INDEXED_DATABASE)
30
31#include "IDBKeyRangeData.h"
32#include "IDBValue.h"
33#include "IndexedDB.h"
34#include "Logging.h"
35#include "MemoryIDBBackingStore.h"
36#include "MemoryObjectStore.h"
37#include <wtf/SetForScope.h>
38
39namespace WebCore {
40namespace IDBServer {
41
42std::unique_ptr<MemoryBackingStoreTransaction> MemoryBackingStoreTransaction::create(MemoryIDBBackingStore& backingStore, const IDBTransactionInfo& info)
43{
44 return std::make_unique<MemoryBackingStoreTransaction>(backingStore, info);
45}
46
47MemoryBackingStoreTransaction::MemoryBackingStoreTransaction(MemoryIDBBackingStore& backingStore, const IDBTransactionInfo& info)
48 : m_backingStore(backingStore)
49 , m_info(info)
50{
51 if (m_info.mode() == IDBTransactionMode::Versionchange) {
52 IDBDatabaseInfo info;
53 auto error = m_backingStore.getOrEstablishDatabaseInfo(info);
54 if (error.isNull())
55 m_originalDatabaseInfo = std::make_unique<IDBDatabaseInfo>(info);
56 }
57}
58
59MemoryBackingStoreTransaction::~MemoryBackingStoreTransaction()
60{
61 ASSERT(!m_inProgress);
62}
63
64void MemoryBackingStoreTransaction::addNewObjectStore(MemoryObjectStore& objectStore)
65{
66 LOG(IndexedDB, "MemoryBackingStoreTransaction::addNewObjectStore()");
67
68 ASSERT(isVersionChange());
69 m_versionChangeAddedObjectStores.add(&objectStore);
70
71 addExistingObjectStore(objectStore);
72}
73
74void MemoryBackingStoreTransaction::addNewIndex(MemoryIndex& index)
75{
76 LOG(IndexedDB, "MemoryBackingStoreTransaction::addNewIndex()");
77
78 ASSERT(isVersionChange());
79 m_versionChangeAddedIndexes.add(&index);
80
81 addExistingIndex(index);
82}
83
84void MemoryBackingStoreTransaction::addExistingIndex(MemoryIndex& index)
85{
86 LOG(IndexedDB, "MemoryBackingStoreTransaction::addExistingIndex");
87
88 ASSERT(isWriting());
89
90 ASSERT(!m_indexes.contains(&index));
91 m_indexes.add(&index);
92}
93
94void MemoryBackingStoreTransaction::indexDeleted(Ref<MemoryIndex>&& index)
95{
96 m_indexes.remove(&index.get());
97
98 // If this MemoryIndex belongs to an object store that will not get restored if this transaction aborts,
99 // then we can forget about it altogether.
100 auto& objectStore = index->objectStore();
101 if (auto deletedObjectStore = m_deletedObjectStores.get(objectStore.info().name())) {
102 if (deletedObjectStore != &objectStore)
103 return;
104 }
105
106 auto addResult = m_deletedIndexes.add(index->info().name(), nullptr);
107 if (addResult.isNewEntry)
108 addResult.iterator->value = WTFMove(index);
109}
110
111void MemoryBackingStoreTransaction::addExistingObjectStore(MemoryObjectStore& objectStore)
112{
113 LOG(IndexedDB, "MemoryBackingStoreTransaction::addExistingObjectStore");
114
115 ASSERT(isWriting());
116
117 ASSERT(!m_objectStores.contains(&objectStore));
118 m_objectStores.add(&objectStore);
119
120 objectStore.writeTransactionStarted(*this);
121
122 m_originalKeyGenerators.add(&objectStore, objectStore.currentKeyGeneratorValue());
123}
124
125void MemoryBackingStoreTransaction::objectStoreDeleted(Ref<MemoryObjectStore>&& objectStore)
126{
127 ASSERT(m_objectStores.contains(&objectStore.get()));
128 m_objectStores.remove(&objectStore.get());
129
130 objectStore->deleteAllIndexes(*this);
131
132 auto addResult = m_deletedObjectStores.add(objectStore->info().name(), nullptr);
133 if (addResult.isNewEntry)
134 addResult.iterator->value = WTFMove(objectStore);
135}
136
137void MemoryBackingStoreTransaction::objectStoreCleared(MemoryObjectStore& objectStore, std::unique_ptr<KeyValueMap>&& keyValueMap, std::unique_ptr<IDBKeyDataSet>&& orderedKeys)
138{
139 ASSERT(m_objectStores.contains(&objectStore));
140
141 auto addResult = m_clearedKeyValueMaps.add(&objectStore, nullptr);
142
143 // If this object store has already been cleared during this transaction, we shouldn't remember this clearing.
144 if (!addResult.isNewEntry)
145 return;
146
147 addResult.iterator->value = WTFMove(keyValueMap);
148
149 ASSERT(!m_clearedOrderedKeys.contains(&objectStore));
150 m_clearedOrderedKeys.add(&objectStore, WTFMove(orderedKeys));
151}
152
153void MemoryBackingStoreTransaction::objectStoreRenamed(MemoryObjectStore& objectStore, const String& oldName)
154{
155 ASSERT(m_objectStores.contains(&objectStore));
156 ASSERT(m_info.mode() == IDBTransactionMode::Versionchange);
157
158 // We only care about the first rename in a given transaction, because if the transaction is aborted we want
159 // to go back to the first 'oldName'
160 m_originalObjectStoreNames.add(&objectStore, oldName);
161}
162
163void MemoryBackingStoreTransaction::indexRenamed(MemoryIndex& index, const String& oldName)
164{
165 ASSERT(m_objectStores.contains(&index.objectStore()));
166 ASSERT(m_info.mode() == IDBTransactionMode::Versionchange);
167
168 // We only care about the first rename in a given transaction, because if the transaction is aborted we want
169 // to go back to the first 'oldName'
170 m_originalIndexNames.add(&index, oldName);
171}
172
173void MemoryBackingStoreTransaction::indexCleared(MemoryIndex& index, std::unique_ptr<IndexValueStore>&& valueStore)
174{
175 auto addResult = m_clearedIndexValueStores.add(&index, nullptr);
176
177 // If this index has already been cleared during this transaction, we shouldn't remember this clearing.
178 if (!addResult.isNewEntry)
179 return;
180
181 addResult.iterator->value = WTFMove(valueStore);
182}
183
184void MemoryBackingStoreTransaction::recordValueChanged(MemoryObjectStore& objectStore, const IDBKeyData& key, ThreadSafeDataBuffer* value)
185{
186 ASSERT(m_objectStores.contains(&objectStore));
187
188 if (m_isAborting)
189 return;
190
191 // If this object store had been cleared during the transaction, no point in recording this
192 // individual key/value change as its entire key/value map will be restored upon abort.
193 if (m_clearedKeyValueMaps.contains(&objectStore))
194 return;
195
196 auto originalAddResult = m_originalValues.add(&objectStore, nullptr);
197 if (originalAddResult.isNewEntry)
198 originalAddResult.iterator->value = std::make_unique<KeyValueMap>();
199
200 auto* map = originalAddResult.iterator->value.get();
201
202 auto addResult = map->add(key, ThreadSafeDataBuffer());
203 if (!addResult.isNewEntry)
204 return;
205
206 if (value)
207 addResult.iterator->value = *value;
208}
209
210void MemoryBackingStoreTransaction::abort()
211{
212 LOG(IndexedDB, "MemoryBackingStoreTransaction::abort()");
213
214 SetForScope<bool> change(m_isAborting, true);
215
216 for (const auto& iterator : m_originalIndexNames)
217 iterator.key->rename(iterator.value);
218 m_originalIndexNames.clear();
219
220 for (const auto& iterator : m_originalObjectStoreNames)
221 iterator.key->rename(iterator.value);
222 m_originalObjectStoreNames.clear();
223
224 for (const auto& objectStore : m_versionChangeAddedObjectStores)
225 m_backingStore.removeObjectStoreForVersionChangeAbort(*objectStore);
226 m_versionChangeAddedObjectStores.clear();
227
228 for (auto& objectStore : m_deletedObjectStores.values()) {
229 m_backingStore.restoreObjectStoreForVersionChangeAbort(*objectStore);
230 ASSERT(!m_objectStores.contains(objectStore.get()));
231 m_objectStores.add(objectStore);
232 }
233 m_deletedObjectStores.clear();
234
235 if (m_originalDatabaseInfo) {
236 ASSERT(m_info.mode() == IDBTransactionMode::Versionchange);
237 m_backingStore.setDatabaseInfo(*m_originalDatabaseInfo);
238 }
239
240 // Restore cleared index value stores before we re-insert values into object stores
241 // because inserting those values will regenerate the appropriate index values.
242 for (auto& iterator : m_clearedIndexValueStores)
243 iterator.key->replaceIndexValueStore(WTFMove(iterator.value));
244 m_clearedIndexValueStores.clear();
245
246 for (auto& objectStore : m_objectStores) {
247 ASSERT(m_originalKeyGenerators.contains(objectStore.get()));
248 objectStore->setKeyGeneratorValue(m_originalKeyGenerators.get(objectStore.get()));
249
250 auto clearedKeyValueMap = m_clearedKeyValueMaps.take(objectStore.get());
251 if (clearedKeyValueMap) {
252 ASSERT(m_clearedOrderedKeys.contains(objectStore.get()));
253 objectStore->replaceKeyValueStore(WTFMove(clearedKeyValueMap), m_clearedOrderedKeys.take(objectStore.get()));
254 }
255
256 auto keyValueMap = m_originalValues.take(objectStore.get());
257 if (!keyValueMap)
258 continue;
259
260 for (const auto& entry : *keyValueMap) {
261 objectStore->deleteRecord(entry.key);
262 objectStore->addRecord(*this, entry.key, { entry.value });
263 }
264 }
265
266 for (auto& index : m_deletedIndexes.values())
267 index->objectStore().maybeRestoreDeletedIndex(*index);
268 m_deletedIndexes.clear();
269
270 finish();
271}
272
273void MemoryBackingStoreTransaction::commit()
274{
275 LOG(IndexedDB, "MemoryBackingStoreTransaction::commit()");
276
277 finish();
278}
279
280void MemoryBackingStoreTransaction::finish()
281{
282 m_inProgress = false;
283
284 if (!isWriting())
285 return;
286
287 for (auto& objectStore : m_objectStores)
288 objectStore->writeTransactionFinished(*this);
289 for (auto& objectStore : m_deletedObjectStores.values())
290 objectStore->writeTransactionFinished(*this);
291}
292
293} // namespace IDBServer
294} // namespace WebCore
295
296#endif // ENABLE(INDEXED_DATABASE)
297