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#pragma once
27
28#if ENABLE(INDEXED_DATABASE)
29
30#include "EventTarget.h"
31#include "IDBActiveDOMObject.h"
32#include "IDBError.h"
33#include "IDBGetAllRecordsData.h"
34#include "IDBGetRecordData.h"
35#include "IDBKeyRangeData.h"
36#include "IDBOpenDBRequest.h"
37#include "IDBTransactionInfo.h"
38#include "IDBTransactionMode.h"
39#include "IndexedDB.h"
40#include "Timer.h"
41#include <wtf/Deque.h>
42#include <wtf/HashMap.h>
43
44namespace WebCore {
45
46class DOMException;
47class DOMStringList;
48class IDBCursor;
49class IDBCursorInfo;
50class IDBDatabase;
51class IDBIndex;
52class IDBIndexInfo;
53class IDBKey;
54class IDBKeyData;
55class IDBObjectStore;
56class IDBObjectStoreInfo;
57class IDBResultData;
58class SerializedScriptValue;
59
60struct IDBIterateCursorData;
61struct IDBKeyRangeData;
62
63namespace IDBClient {
64class IDBConnectionProxy;
65class TransactionOperation;
66}
67
68class IDBTransaction final : public ThreadSafeRefCounted<IDBTransaction>, public EventTargetWithInlineData, public IDBActiveDOMObject {
69 WTF_MAKE_ISO_ALLOCATED(IDBTransaction);
70public:
71 static Ref<IDBTransaction> create(IDBDatabase&, const IDBTransactionInfo&);
72 static Ref<IDBTransaction> create(IDBDatabase&, const IDBTransactionInfo&, IDBOpenDBRequest&);
73
74 ~IDBTransaction() final;
75
76 // IDBTransaction IDL
77 Ref<DOMStringList> objectStoreNames() const;
78 IDBTransactionMode mode() const { return m_info.mode(); }
79 IDBDatabase* db();
80 DOMException* error() const;
81 ExceptionOr<Ref<IDBObjectStore>> objectStore(const String& name);
82 ExceptionOr<void> abort();
83
84 EventTargetInterface eventTargetInterface() const final { return IDBTransactionEventTargetInterfaceType; }
85 ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); }
86 void refEventTarget() final { ThreadSafeRefCounted::ref(); }
87 void derefEventTarget() final { ThreadSafeRefCounted::deref(); }
88 using EventTarget::dispatchEvent;
89 void dispatchEvent(Event&) final;
90
91 using ThreadSafeRefCounted<IDBTransaction>::ref;
92 using ThreadSafeRefCounted<IDBTransaction>::deref;
93
94 const char* activeDOMObjectName() const final;
95 bool canSuspendForDocumentSuspension() const final;
96 bool hasPendingActivity() const final;
97 void stop() final;
98
99 const IDBTransactionInfo& info() const { return m_info; }
100 IDBDatabase& database() { return m_database.get(); }
101 const IDBDatabase& database() const { return m_database.get(); }
102 IDBDatabaseInfo* originalDatabaseInfo() const { return m_info.originalDatabaseInfo(); }
103
104 void didStart(const IDBError&);
105 void didAbort(const IDBError&);
106 void didCommit(const IDBError&);
107
108 bool isVersionChange() const { return mode() == IDBTransactionMode::Versionchange; }
109 bool isReadOnly() const { return mode() == IDBTransactionMode::Readonly; }
110 bool isActive() const;
111
112 Ref<IDBObjectStore> createObjectStore(const IDBObjectStoreInfo&);
113 void renameObjectStore(IDBObjectStore&, const String& newName);
114 std::unique_ptr<IDBIndex> createIndex(IDBObjectStore&, const IDBIndexInfo&);
115 void renameIndex(IDBIndex&, const String& newName);
116
117 Ref<IDBRequest> requestPutOrAdd(JSC::ExecState&, IDBObjectStore&, RefPtr<IDBKey>&&, SerializedScriptValue&, IndexedDB::ObjectStoreOverwriteMode);
118 Ref<IDBRequest> requestGetRecord(JSC::ExecState&, IDBObjectStore&, const IDBGetRecordData&);
119 Ref<IDBRequest> requestGetAllObjectStoreRecords(JSC::ExecState&, IDBObjectStore&, const IDBKeyRangeData&, IndexedDB::GetAllType, Optional<uint32_t> count);
120 Ref<IDBRequest> requestGetAllIndexRecords(JSC::ExecState&, IDBIndex&, const IDBKeyRangeData&, IndexedDB::GetAllType, Optional<uint32_t> count);
121 Ref<IDBRequest> requestDeleteRecord(JSC::ExecState&, IDBObjectStore&, const IDBKeyRangeData&);
122 Ref<IDBRequest> requestClearObjectStore(JSC::ExecState&, IDBObjectStore&);
123 Ref<IDBRequest> requestCount(JSC::ExecState&, IDBObjectStore&, const IDBKeyRangeData&);
124 Ref<IDBRequest> requestCount(JSC::ExecState&, IDBIndex&, const IDBKeyRangeData&);
125 Ref<IDBRequest> requestGetValue(JSC::ExecState&, IDBIndex&, const IDBKeyRangeData&);
126 Ref<IDBRequest> requestGetKey(JSC::ExecState&, IDBIndex&, const IDBKeyRangeData&);
127 Ref<IDBRequest> requestOpenCursor(JSC::ExecState&, IDBObjectStore&, const IDBCursorInfo&);
128 Ref<IDBRequest> requestOpenCursor(JSC::ExecState&, IDBIndex&, const IDBCursorInfo&);
129 void iterateCursor(IDBCursor&, const IDBIterateCursorData&);
130
131 void deleteObjectStore(const String& objectStoreName);
132 void deleteIndex(uint64_t objectStoreIdentifier, const String& indexName);
133
134 void addRequest(IDBRequest&);
135 void removeRequest(IDBRequest&);
136
137 void abortDueToFailedRequest(DOMException&);
138
139 void activate();
140 void deactivate();
141
142 void operationCompletedOnServer(const IDBResultData&, IDBClient::TransactionOperation&);
143 void operationCompletedOnClient(IDBClient::TransactionOperation&);
144
145 void finishedDispatchEventForRequest(IDBRequest&);
146
147 bool isFinishedOrFinishing() const;
148 bool isFinished() const { return m_state == IndexedDB::TransactionState::Finished; }
149 bool didDispatchAbortOrCommit() const { return m_didDispatchAbortOrCommit; }
150
151 IDBClient::IDBConnectionProxy& connectionProxy();
152
153 void connectionClosedFromServer(const IDBError&);
154
155 void visitReferencedObjectStores(JSC::SlotVisitor&) const;
156
157 WEBCORE_EXPORT static std::atomic<unsigned> numberOfIDBTransactions;
158
159private:
160 IDBTransaction(IDBDatabase&, const IDBTransactionInfo&, IDBOpenDBRequest*);
161
162 void commit();
163
164 void internalAbort();
165 void notifyDidAbort(const IDBError&);
166 void finishAbortOrCommit();
167 void abortInProgressOperations(const IDBError&);
168
169 void scheduleOperation(Ref<IDBClient::TransactionOperation>&&);
170 void pendingOperationTimerFired();
171 void completedOperationTimerFired();
172
173 void fireOnComplete();
174 void fireOnAbort();
175 void enqueueEvent(Ref<Event>&&);
176
177 Ref<IDBRequest> requestIndexRecord(JSC::ExecState&, IDBIndex&, IndexedDB::IndexRecordType, const IDBKeyRangeData&);
178
179 void commitOnServer(IDBClient::TransactionOperation&);
180 void abortOnServerAndCancelRequests(IDBClient::TransactionOperation&);
181
182 void createObjectStoreOnServer(IDBClient::TransactionOperation&, const IDBObjectStoreInfo&);
183 void didCreateObjectStoreOnServer(const IDBResultData&);
184
185 void renameObjectStoreOnServer(IDBClient::TransactionOperation&, const uint64_t& objectStoreIdentifier, const String& newName);
186 void didRenameObjectStoreOnServer(const IDBResultData&);
187
188 void createIndexOnServer(IDBClient::TransactionOperation&, const IDBIndexInfo&);
189 void didCreateIndexOnServer(const IDBResultData&);
190
191 void renameIndexOnServer(IDBClient::TransactionOperation&, const uint64_t& objectStoreIdentifier, const uint64_t& indexIdentifier, const String& newName);
192 void didRenameIndexOnServer(const IDBResultData&);
193
194 void clearObjectStoreOnServer(IDBClient::TransactionOperation&, const uint64_t& objectStoreIdentifier);
195 void didClearObjectStoreOnServer(IDBRequest&, const IDBResultData&);
196
197 void putOrAddOnServer(IDBClient::TransactionOperation&, RefPtr<IDBKey>, RefPtr<SerializedScriptValue>, const IndexedDB::ObjectStoreOverwriteMode&);
198 void didPutOrAddOnServer(IDBRequest&, const IDBResultData&);
199
200 void getRecordOnServer(IDBClient::TransactionOperation&, const IDBGetRecordData&);
201 void didGetRecordOnServer(IDBRequest&, const IDBResultData&);
202
203 void getAllRecordsOnServer(IDBClient::TransactionOperation&, const IDBGetAllRecordsData&);
204 void didGetAllRecordsOnServer(IDBRequest&, const IDBResultData&);
205
206 void getCountOnServer(IDBClient::TransactionOperation&, const IDBKeyRangeData&);
207 void didGetCountOnServer(IDBRequest&, const IDBResultData&);
208
209 void deleteRecordOnServer(IDBClient::TransactionOperation&, const IDBKeyRangeData&);
210 void didDeleteRecordOnServer(IDBRequest&, const IDBResultData&);
211
212 void deleteObjectStoreOnServer(IDBClient::TransactionOperation&, const String& objectStoreName);
213 void didDeleteObjectStoreOnServer(const IDBResultData&);
214
215 void deleteIndexOnServer(IDBClient::TransactionOperation&, const uint64_t& objectStoreIdentifier, const String& indexName);
216 void didDeleteIndexOnServer(const IDBResultData&);
217
218 Ref<IDBRequest> doRequestOpenCursor(JSC::ExecState&, Ref<IDBCursor>&&);
219 void openCursorOnServer(IDBClient::TransactionOperation&, const IDBCursorInfo&);
220 void didOpenCursorOnServer(IDBRequest&, const IDBResultData&);
221
222 void iterateCursorOnServer(IDBClient::TransactionOperation&, const IDBIterateCursorData&);
223 void didIterateCursorOnServer(IDBRequest&, const IDBResultData&);
224
225 void transitionedToFinishing(IndexedDB::TransactionState);
226
227 void establishOnServer();
228
229 void completeNoncursorRequest(IDBRequest&, const IDBResultData&);
230 void completeCursorRequest(IDBRequest&, const IDBResultData&);
231
232 void schedulePendingOperationTimer();
233 void scheduleCompletedOperationTimer();
234
235 Ref<IDBDatabase> m_database;
236 IDBTransactionInfo m_info;
237
238 IndexedDB::TransactionState m_state { IndexedDB::TransactionState::Inactive };
239 bool m_startedOnServer { false };
240
241 IDBError m_idbError;
242 RefPtr<DOMException> m_domError;
243
244 Timer m_pendingOperationTimer;
245 Timer m_completedOperationTimer;
246 std::unique_ptr<Timer> m_activationTimer;
247
248 RefPtr<IDBOpenDBRequest> m_openDBRequest;
249
250 Deque<RefPtr<IDBClient::TransactionOperation>> m_pendingTransactionOperationQueue;
251 Deque<IDBClient::TransactionOperation*> m_transactionOperationsInProgressQueue;
252 Deque<std::pair<RefPtr<IDBClient::TransactionOperation>, IDBResultData>> m_completedOnServerQueue;
253 Deque<RefPtr<IDBClient::TransactionOperation>> m_abortQueue;
254
255 HashMap<IDBResourceIdentifier, RefPtr<IDBClient::TransactionOperation>> m_transactionOperationMap;
256
257 mutable Lock m_referencedObjectStoreLock;
258 HashMap<String, std::unique_ptr<IDBObjectStore>> m_referencedObjectStores;
259 HashMap<uint64_t, std::unique_ptr<IDBObjectStore>> m_deletedObjectStores;
260
261 HashSet<RefPtr<IDBRequest>> m_openRequests;
262 RefPtr<IDBRequest> m_currentlyCompletingRequest;
263
264 bool m_contextStopped { false };
265 bool m_didDispatchAbortOrCommit { false };
266};
267
268class TransactionActivator {
269 WTF_MAKE_NONCOPYABLE(TransactionActivator);
270public:
271 TransactionActivator(IDBTransaction* transaction)
272 : m_transaction(transaction)
273 {
274 if (m_transaction)
275 m_transaction->activate();
276 }
277
278 ~TransactionActivator()
279 {
280 if (m_transaction)
281 m_transaction->deactivate();
282 }
283
284private:
285 IDBTransaction* m_transaction;
286};
287
288} // namespace WebCore
289
290#endif // ENABLE(INDEXED_DATABASE)
291