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 "MemoryIndex.h"
28
29#if ENABLE(INDEXED_DATABASE)
30
31#include "IDBError.h"
32#include "IDBGetAllResult.h"
33#include "IDBGetResult.h"
34#include "IDBKeyRangeData.h"
35#include "IndexKey.h"
36#include "Logging.h"
37#include "MemoryBackingStoreTransaction.h"
38#include "MemoryIndexCursor.h"
39#include "MemoryObjectStore.h"
40#include "ThreadSafeDataBuffer.h"
41
42namespace WebCore {
43namespace IDBServer {
44
45Ref<MemoryIndex> MemoryIndex::create(const IDBIndexInfo& info, MemoryObjectStore& objectStore)
46{
47 return adoptRef(*new MemoryIndex(info, objectStore));
48}
49
50MemoryIndex::MemoryIndex(const IDBIndexInfo& info, MemoryObjectStore& objectStore)
51 : m_info(info)
52 , m_objectStore(objectStore)
53{
54}
55
56MemoryIndex::~MemoryIndex() = default;
57
58void MemoryIndex::cursorDidBecomeClean(MemoryIndexCursor& cursor)
59{
60 m_cleanCursors.add(&cursor);
61}
62
63void MemoryIndex::cursorDidBecomeDirty(MemoryIndexCursor& cursor)
64{
65 m_cleanCursors.remove(&cursor);
66}
67
68void MemoryIndex::objectStoreCleared()
69{
70 auto transaction = m_objectStore.writeTransaction();
71 ASSERT(transaction);
72
73 transaction->indexCleared(*this, WTFMove(m_records));
74
75 notifyCursorsOfAllRecordsChanged();
76}
77
78void MemoryIndex::notifyCursorsOfValueChange(const IDBKeyData& indexKey, const IDBKeyData& primaryKey)
79{
80 for (auto* cursor : copyToVector(m_cleanCursors))
81 cursor->indexValueChanged(indexKey, primaryKey);
82}
83
84void MemoryIndex::notifyCursorsOfAllRecordsChanged()
85{
86 for (auto* cursor : copyToVector(m_cleanCursors))
87 cursor->indexRecordsAllChanged();
88
89 ASSERT(m_cleanCursors.isEmpty());
90}
91
92void MemoryIndex::clearIndexValueStore()
93{
94 ASSERT(m_objectStore.writeTransaction());
95 ASSERT(m_objectStore.writeTransaction()->isAborting());
96
97 m_records = nullptr;
98}
99
100void MemoryIndex::replaceIndexValueStore(std::unique_ptr<IndexValueStore>&& valueStore)
101{
102 ASSERT(m_objectStore.writeTransaction());
103 ASSERT(m_objectStore.writeTransaction()->isAborting());
104
105 m_records = WTFMove(valueStore);
106}
107
108IDBGetResult MemoryIndex::getResultForKeyRange(IndexedDB::IndexRecordType type, const IDBKeyRangeData& range) const
109{
110 LOG(IndexedDB, "MemoryIndex::getResultForKeyRange - %s", range.loggingString().utf8().data());
111
112 if (!m_records)
113 return { };
114
115 IDBKeyData keyToLookFor;
116 if (range.isExactlyOneKey())
117 keyToLookFor = range.lowerKey;
118 else
119 keyToLookFor = m_records->lowestKeyWithRecordInRange(range);
120
121 if (keyToLookFor.isNull())
122 return { };
123
124 const IDBKeyData* keyValue = m_records->lowestValueForKey(keyToLookFor);
125
126 if (!keyValue)
127 return { };
128
129 return type == IndexedDB::IndexRecordType::Key ? IDBGetResult(*keyValue) : IDBGetResult(*keyValue, m_objectStore.valueForKeyRange(*keyValue), m_objectStore.info().keyPath());
130}
131
132uint64_t MemoryIndex::countForKeyRange(const IDBKeyRangeData& inRange)
133{
134 LOG(IndexedDB, "MemoryIndex::countForKeyRange");
135
136 if (!m_records)
137 return 0;
138
139 uint64_t count = 0;
140 IDBKeyRangeData range = inRange;
141 while (true) {
142 auto key = m_records->lowestKeyWithRecordInRange(range);
143 if (key.isNull())
144 break;
145
146 count += m_records->countForKey(key);
147
148 range.lowerKey = key;
149 range.lowerOpen = true;
150 }
151
152 return count;
153}
154
155void MemoryIndex::getAllRecords(const IDBKeyRangeData& keyRangeData, Optional<uint32_t> count, IndexedDB::GetAllType type, IDBGetAllResult& result) const
156{
157 LOG(IndexedDB, "MemoryIndex::getAllRecords");
158
159 result = { type, m_objectStore.info().keyPath() };
160
161 if (!m_records)
162 return;
163
164 uint32_t targetCount;
165 if (count && count.value())
166 targetCount = count.value();
167 else
168 targetCount = std::numeric_limits<uint32_t>::max();
169
170 IDBKeyRangeData range = keyRangeData;
171 uint32_t currentCount = 0;
172 while (currentCount < targetCount) {
173 auto key = m_records->lowestKeyWithRecordInRange(range);
174 if (key.isNull())
175 return;
176
177 range.lowerKey = key;
178 range.lowerOpen = true;
179
180 auto allValues = m_records->allValuesForKey(key, targetCount - currentCount);
181 for (auto& keyValue : allValues) {
182 result.addKey(IDBKeyData(keyValue));
183 if (type == IndexedDB::GetAllType::Values)
184 result.addValue(m_objectStore.valueForKeyRange(keyValue));
185 }
186
187 currentCount += allValues.size();
188 }
189}
190
191
192IDBError MemoryIndex::putIndexKey(const IDBKeyData& valueKey, const IndexKey& indexKey)
193{
194 LOG(IndexedDB, "MemoryIndex::provisionalPutIndexKey");
195
196 if (!m_records) {
197 m_records = std::make_unique<IndexValueStore>(m_info.unique());
198 notifyCursorsOfAllRecordsChanged();
199 }
200
201 if (!m_info.multiEntry()) {
202 IDBKeyData key = indexKey.asOneKey();
203 IDBError result = m_records->addRecord(key, valueKey);
204 notifyCursorsOfValueChange(key, valueKey);
205 return result;
206 }
207
208 Vector<IDBKeyData> keys = indexKey.multiEntry();
209
210 if (m_info.unique()) {
211 for (auto& key : keys) {
212 if (m_records->contains(key))
213 return IDBError(ConstraintError);
214 }
215 }
216
217 for (auto& key : keys) {
218 auto error = m_records->addRecord(key, valueKey);
219 ASSERT_UNUSED(error, error.isNull());
220 notifyCursorsOfValueChange(key, valueKey);
221 }
222
223 return IDBError { };
224}
225
226void MemoryIndex::removeRecord(const IDBKeyData& valueKey, const IndexKey& indexKey)
227{
228 LOG(IndexedDB, "MemoryIndex::removeRecord");
229
230 ASSERT(m_records);
231
232 if (!m_info.multiEntry()) {
233 IDBKeyData key = indexKey.asOneKey();
234 m_records->removeRecord(key, valueKey);
235 notifyCursorsOfValueChange(key, valueKey);
236 return;
237 }
238
239 Vector<IDBKeyData> keys = indexKey.multiEntry();
240 for (auto& key : keys) {
241 m_records->removeRecord(key, valueKey);
242 notifyCursorsOfValueChange(key, valueKey);
243 }
244}
245
246void MemoryIndex::removeEntriesWithValueKey(const IDBKeyData& valueKey)
247{
248 LOG(IndexedDB, "MemoryIndex::removeEntriesWithValueKey");
249
250 if (!m_records)
251 return;
252
253 m_records->removeEntriesWithValueKey(*this, valueKey);
254}
255
256MemoryIndexCursor* MemoryIndex::maybeOpenCursor(const IDBCursorInfo& info)
257{
258 auto result = m_cursors.add(info.identifier(), nullptr);
259 if (!result.isNewEntry)
260 return nullptr;
261
262 result.iterator->value = std::make_unique<MemoryIndexCursor>(*this, info);
263 return result.iterator->value.get();
264}
265
266} // namespace IDBServer
267} // namespace WebCore
268
269#endif // ENABLE(INDEXED_DATABASE)
270