Modern IDB: Refactor memory objectstore/transaction interation.
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / server / MemoryBackingStoreTransaction.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. ``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 "IndexedDB.h"
33 #include "Logging.h"
34 #include "MemoryIDBBackingStore.h"
35 #include "MemoryObjectStore.h"
36 #include <wtf/TemporaryChange.h>
37
38 namespace WebCore {
39 namespace IDBServer {
40
41 std::unique_ptr<MemoryBackingStoreTransaction> MemoryBackingStoreTransaction::create(MemoryIDBBackingStore& backingStore, const IDBTransactionInfo& info)
42 {
43     return std::make_unique<MemoryBackingStoreTransaction>(backingStore, info);
44 }
45
46 MemoryBackingStoreTransaction::MemoryBackingStoreTransaction(MemoryIDBBackingStore& backingStore, const IDBTransactionInfo& info)
47     : m_backingStore(backingStore)
48     , m_info(info)
49 {
50     if (m_info.mode() == IndexedDB::TransactionMode::VersionChange)
51         m_originalDatabaseInfo = std::make_unique<IDBDatabaseInfo>(m_backingStore.getOrEstablishDatabaseInfo());
52 }
53
54 MemoryBackingStoreTransaction::~MemoryBackingStoreTransaction()
55 {
56     ASSERT(!m_inProgress);
57 }
58
59 void MemoryBackingStoreTransaction::addNewObjectStore(MemoryObjectStore& objectStore)
60 {
61     LOG(IndexedDB, "MemoryBackingStoreTransaction::addNewObjectStore()");
62
63     ASSERT(isVersionChange());
64     m_versionChangeAddedObjectStores.add(&objectStore);
65
66     addExistingObjectStore(objectStore);
67 }
68
69 void MemoryBackingStoreTransaction::addNewIndex(MemoryIndex& index)
70 {
71     LOG(IndexedDB, "MemoryBackingStoreTransaction::addNewIndex()");
72
73     ASSERT(isVersionChange());
74     m_versionChangeAddedIndexes.add(&index);
75
76     addExistingIndex(index);
77 }
78
79 void MemoryBackingStoreTransaction::addExistingIndex(MemoryIndex& index)
80 {
81     LOG(IndexedDB, "MemoryBackingStoreTransaction::addExistingIndex");
82
83     ASSERT(isWriting());
84
85     ASSERT(!m_indexes.contains(&index));
86     m_indexes.add(&index);
87 }
88
89 void MemoryBackingStoreTransaction::addExistingObjectStore(MemoryObjectStore& objectStore)
90 {
91     LOG(IndexedDB, "MemoryBackingStoreTransaction::addExistingObjectStore");
92
93     ASSERT(isWriting());
94
95     ASSERT(!m_objectStores.contains(&objectStore));
96     m_objectStores.add(&objectStore);
97
98     objectStore.writeTransactionStarted(*this);
99
100     m_originalKeyGenerators.add(&objectStore, objectStore.currentKeyGeneratorValue());
101 }
102
103 void MemoryBackingStoreTransaction::objectStoreDeleted(std::unique_ptr<MemoryObjectStore> objectStore)
104 {
105     ASSERT(objectStore);
106     ASSERT(m_objectStores.contains(objectStore.get()));
107     m_objectStores.remove(objectStore.get());
108
109     auto addResult = m_deletedObjectStores.add(objectStore->info().name(), nullptr);
110     if (addResult.isNewEntry)
111         addResult.iterator->value = WTF::move(objectStore);
112 }
113
114 void MemoryBackingStoreTransaction::objectStoreCleared(MemoryObjectStore& objectStore, std::unique_ptr<KeyValueMap>&& keyValueMap)
115 {
116     ASSERT(m_objectStores.contains(&objectStore));
117
118     auto addResult = m_clearedKeyValueMaps.add(&objectStore, nullptr);
119
120     // If this object store has already been cleared during this transaction, we don't need to remember this clearing.
121     if (!addResult.isNewEntry)
122         return;
123
124     // If values had previously been changed during this transaction, fold those changes back into the
125     // cleared key-value map now, so we have exactly the map that will need to be restored if the transaction is aborted.
126     auto originalValues = m_originalValues.take(&objectStore);
127     if (originalValues) {
128         for (auto iterator : *originalValues)
129             keyValueMap->set(iterator.key, iterator.value);
130     }
131
132     addResult.iterator->value = WTF::move(keyValueMap);
133 }
134
135 void MemoryBackingStoreTransaction::recordValueChanged(MemoryObjectStore& objectStore, const IDBKeyData& key, ThreadSafeDataBuffer* value)
136 {
137     ASSERT(m_objectStores.contains(&objectStore));
138
139     if (m_isAborting)
140         return;
141
142     // If this object store had been cleared during the transaction, no point in recording this
143     // individual key/value change as its entire key/value map will be restored upon abort.
144     if (m_clearedKeyValueMaps.contains(&objectStore))
145         return;
146
147     auto originalAddResult = m_originalValues.add(&objectStore, nullptr);
148     if (originalAddResult.isNewEntry)
149         originalAddResult.iterator->value = std::make_unique<KeyValueMap>();
150
151     auto* map = originalAddResult.iterator->value.get();
152
153     auto addResult = map->add(key, ThreadSafeDataBuffer());
154     if (!addResult.isNewEntry)
155         return;
156
157     if (value)
158         addResult.iterator->value = *value;
159 }
160
161 void MemoryBackingStoreTransaction::abort()
162 {
163     LOG(IndexedDB, "MemoryBackingStoreTransaction::abort()");
164
165     TemporaryChange<bool> change(m_isAborting, true);
166
167     // This loop moves the underlying unique_ptrs from out of the m_deleteObjectStores map,
168     // but the entries in the map still remain.
169     for (auto& objectStore : m_deletedObjectStores.values()) {
170         MemoryObjectStore* rawObjectStore = objectStore.get();
171         m_backingStore.restoreObjectStoreForVersionChangeAbort(WTF::move(objectStore));
172
173         ASSERT(!m_objectStores.contains(rawObjectStore));
174         m_objectStores.add(rawObjectStore);
175     }
176
177     // This clears the entries from the map.
178     m_deletedObjectStores.clear();
179
180     if (m_originalDatabaseInfo) {
181         ASSERT(m_info.mode() == IndexedDB::TransactionMode::VersionChange);
182         m_backingStore.setDatabaseInfo(*m_originalDatabaseInfo);
183     }
184
185     for (auto objectStore : m_objectStores) {
186         ASSERT(m_originalKeyGenerators.contains(objectStore));
187         objectStore->setKeyGeneratorValue(m_originalKeyGenerators.get(objectStore));
188
189         auto clearedKeyValueMap = m_clearedKeyValueMaps.take(objectStore);
190         if (clearedKeyValueMap) {
191             objectStore->replaceKeyValueStore(WTF::move(clearedKeyValueMap));
192             continue;
193         }
194
195         auto keyValueMap = m_originalValues.take(objectStore);
196         if (!keyValueMap)
197             continue;
198
199         for (auto entry : *keyValueMap) {
200             objectStore->deleteRecord(entry.key);
201             objectStore->addRecord(*this, entry.key, entry.value);
202         }
203     }
204
205     finish();
206
207     for (auto objectStore : m_versionChangeAddedObjectStores)
208         m_backingStore.removeObjectStoreForVersionChangeAbort(*objectStore);
209 }
210
211 void MemoryBackingStoreTransaction::commit()
212 {
213     LOG(IndexedDB, "MemoryBackingStoreTransaction::commit()");
214
215     finish();
216 }
217
218 void MemoryBackingStoreTransaction::finish()
219 {
220     m_inProgress = false;
221
222     if (!isWriting())
223         return;
224
225     for (auto& objectStore : m_objectStores)
226         objectStore->writeTransactionFinished(*this);
227     for (auto& objectStore : m_deletedObjectStores.values())
228         objectStore->writeTransactionFinished(*this);
229 }
230
231 } // namespace IDBServer
232 } // namespace WebCore
233
234 #endif // ENABLE(INDEXED_DATABASE)