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 | |
39 | namespace WebCore { |
40 | namespace IDBServer { |
41 | |
42 | std::unique_ptr<MemoryBackingStoreTransaction> MemoryBackingStoreTransaction::create(MemoryIDBBackingStore& backingStore, const IDBTransactionInfo& info) |
43 | { |
44 | return std::make_unique<MemoryBackingStoreTransaction>(backingStore, info); |
45 | } |
46 | |
47 | MemoryBackingStoreTransaction::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 | |
59 | MemoryBackingStoreTransaction::~MemoryBackingStoreTransaction() |
60 | { |
61 | ASSERT(!m_inProgress); |
62 | } |
63 | |
64 | void 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 | |
74 | void 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 | |
84 | void 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 | |
94 | void 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 | |
111 | void 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 | |
125 | void 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 | |
137 | void 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 | |
153 | void 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 | |
163 | void 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 | |
173 | void 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 | |
184 | void 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 | |
210 | void 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 | |
273 | void MemoryBackingStoreTransaction::commit() |
274 | { |
275 | LOG(IndexedDB, "MemoryBackingStoreTransaction::commit()" ); |
276 | |
277 | finish(); |
278 | } |
279 | |
280 | void 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 | |