|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifndef mozilla_dom_indexeddb_idbtransaction_h__ |
|
8 #define mozilla_dom_indexeddb_idbtransaction_h__ |
|
9 |
|
10 #include "mozilla/Attributes.h" |
|
11 #include "mozilla/dom/indexedDB/IndexedDatabase.h" |
|
12 |
|
13 #include "mozIStorageConnection.h" |
|
14 #include "mozIStorageStatement.h" |
|
15 #include "mozIStorageFunction.h" |
|
16 #include "mozilla/dom/DOMError.h" |
|
17 #include "nsIRunnable.h" |
|
18 |
|
19 #include "nsAutoPtr.h" |
|
20 #include "nsClassHashtable.h" |
|
21 #include "nsHashKeys.h" |
|
22 #include "nsInterfaceHashtable.h" |
|
23 #include "nsRefPtrHashtable.h" |
|
24 |
|
25 #include "mozilla/dom/IDBTransactionBinding.h" |
|
26 #include "mozilla/dom/indexedDB/IDBDatabase.h" |
|
27 #include "mozilla/dom/indexedDB/IDBWrapperCache.h" |
|
28 #include "mozilla/dom/indexedDB/FileInfo.h" |
|
29 |
|
30 class nsIThread; |
|
31 class nsPIDOMWindow; |
|
32 |
|
33 namespace mozilla { |
|
34 class EventChainPreVisitor; |
|
35 } // namespace mozilla |
|
36 |
|
37 BEGIN_INDEXEDDB_NAMESPACE |
|
38 |
|
39 class AsyncConnectionHelper; |
|
40 class CommitHelper; |
|
41 class IDBRequest; |
|
42 class IndexedDBDatabaseChild; |
|
43 class IndexedDBTransactionChild; |
|
44 class IndexedDBTransactionParent; |
|
45 struct ObjectStoreInfo; |
|
46 class TransactionThreadPool; |
|
47 class UpdateRefcountFunction; |
|
48 |
|
49 class IDBTransactionListener |
|
50 { |
|
51 public: |
|
52 NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0; |
|
53 NS_IMETHOD_(MozExternalRefCountType) Release() = 0; |
|
54 |
|
55 // Called just before dispatching the final events on the transaction. |
|
56 virtual nsresult NotifyTransactionPreComplete(IDBTransaction* aTransaction) = 0; |
|
57 // Called just after dispatching the final events on the transaction. |
|
58 virtual nsresult NotifyTransactionPostComplete(IDBTransaction* aTransaction) = 0; |
|
59 }; |
|
60 |
|
61 class IDBTransaction : public IDBWrapperCache, |
|
62 public nsIRunnable |
|
63 { |
|
64 friend class AsyncConnectionHelper; |
|
65 friend class CommitHelper; |
|
66 friend class IndexedDBDatabaseChild; |
|
67 friend class ThreadObserver; |
|
68 friend class TransactionThreadPool; |
|
69 |
|
70 public: |
|
71 NS_DECL_ISUPPORTS_INHERITED |
|
72 NS_DECL_NSIRUNNABLE |
|
73 |
|
74 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBTransaction, IDBWrapperCache) |
|
75 |
|
76 enum Mode |
|
77 { |
|
78 READ_ONLY = 0, |
|
79 READ_WRITE, |
|
80 VERSION_CHANGE, |
|
81 |
|
82 // Only needed for IPC serialization helper, should never be used in code. |
|
83 MODE_INVALID |
|
84 }; |
|
85 |
|
86 enum ReadyState |
|
87 { |
|
88 INITIAL = 0, |
|
89 LOADING, |
|
90 COMMITTING, |
|
91 DONE |
|
92 }; |
|
93 |
|
94 static already_AddRefed<IDBTransaction> |
|
95 Create(IDBDatabase* aDatabase, |
|
96 const Sequence<nsString>& aObjectStoreNames, |
|
97 Mode aMode, |
|
98 bool aDispatchDelayed) |
|
99 { |
|
100 return CreateInternal(aDatabase, aObjectStoreNames, aMode, aDispatchDelayed, |
|
101 false); |
|
102 } |
|
103 |
|
104 // nsIDOMEventTarget |
|
105 virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE; |
|
106 |
|
107 void OnNewRequest(); |
|
108 void OnRequestFinished(); |
|
109 void OnRequestDisconnected(); |
|
110 |
|
111 void RemoveObjectStore(const nsAString& aName); |
|
112 |
|
113 void SetTransactionListener(IDBTransactionListener* aListener); |
|
114 |
|
115 bool StartSavepoint(); |
|
116 nsresult ReleaseSavepoint(); |
|
117 void RollbackSavepoint(); |
|
118 |
|
119 // Only meant to be called on mStorageThread! |
|
120 nsresult GetOrCreateConnection(mozIStorageConnection** aConnection); |
|
121 |
|
122 already_AddRefed<mozIStorageStatement> |
|
123 GetCachedStatement(const nsACString& aQuery); |
|
124 |
|
125 template<int N> |
|
126 already_AddRefed<mozIStorageStatement> |
|
127 GetCachedStatement(const char (&aQuery)[N]) |
|
128 { |
|
129 return GetCachedStatement(NS_LITERAL_CSTRING(aQuery)); |
|
130 } |
|
131 |
|
132 bool IsOpen() const; |
|
133 |
|
134 bool IsFinished() const |
|
135 { |
|
136 return mReadyState > LOADING; |
|
137 } |
|
138 |
|
139 bool IsWriteAllowed() const |
|
140 { |
|
141 return mMode == READ_WRITE || mMode == VERSION_CHANGE; |
|
142 } |
|
143 |
|
144 bool IsAborted() const |
|
145 { |
|
146 return NS_FAILED(mAbortCode); |
|
147 } |
|
148 |
|
149 // 'Get' prefix is to avoid name collisions with the enum |
|
150 Mode GetMode() |
|
151 { |
|
152 return mMode; |
|
153 } |
|
154 |
|
155 IDBDatabase* Database() |
|
156 { |
|
157 NS_ASSERTION(mDatabase, "This should never be null!"); |
|
158 return mDatabase; |
|
159 } |
|
160 |
|
161 DatabaseInfo* DBInfo() const |
|
162 { |
|
163 return mDatabaseInfo; |
|
164 } |
|
165 |
|
166 already_AddRefed<IDBObjectStore> |
|
167 GetOrCreateObjectStore(const nsAString& aName, |
|
168 ObjectStoreInfo* aObjectStoreInfo, |
|
169 bool aCreating); |
|
170 |
|
171 already_AddRefed<FileInfo> GetFileInfo(nsIDOMBlob* aBlob); |
|
172 void AddFileInfo(nsIDOMBlob* aBlob, FileInfo* aFileInfo); |
|
173 |
|
174 void ClearCreatedFileInfos(); |
|
175 |
|
176 void |
|
177 SetActor(IndexedDBTransactionChild* aActorChild) |
|
178 { |
|
179 NS_ASSERTION(!aActorChild || !mActorChild, "Shouldn't have more than one!"); |
|
180 mActorChild = aActorChild; |
|
181 } |
|
182 |
|
183 void |
|
184 SetActor(IndexedDBTransactionParent* aActorParent) |
|
185 { |
|
186 NS_ASSERTION(!aActorParent || !mActorParent, |
|
187 "Shouldn't have more than one!"); |
|
188 mActorParent = aActorParent; |
|
189 } |
|
190 |
|
191 IndexedDBTransactionChild* |
|
192 GetActorChild() const |
|
193 { |
|
194 return mActorChild; |
|
195 } |
|
196 |
|
197 IndexedDBTransactionParent* |
|
198 GetActorParent() const |
|
199 { |
|
200 return mActorParent; |
|
201 } |
|
202 |
|
203 nsresult |
|
204 Abort(IDBRequest* aRequest); |
|
205 |
|
206 nsresult |
|
207 Abort(nsresult aAbortCode); |
|
208 |
|
209 nsresult |
|
210 GetAbortCode() const |
|
211 { |
|
212 return mAbortCode; |
|
213 } |
|
214 |
|
215 #ifdef MOZ_ENABLE_PROFILER_SPS |
|
216 uint64_t |
|
217 GetSerialNumber() const |
|
218 { |
|
219 return mSerialNumber; |
|
220 } |
|
221 #endif |
|
222 |
|
223 // nsWrapperCache |
|
224 virtual JSObject* |
|
225 WrapObject(JSContext* aCx) MOZ_OVERRIDE; |
|
226 |
|
227 // WebIDL |
|
228 nsPIDOMWindow* |
|
229 GetParentObject() const |
|
230 { |
|
231 return GetOwner(); |
|
232 } |
|
233 |
|
234 IDBTransactionMode |
|
235 GetMode(ErrorResult& aRv) const; |
|
236 |
|
237 IDBDatabase* |
|
238 Db() const |
|
239 { |
|
240 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
|
241 return mDatabase; |
|
242 } |
|
243 |
|
244 DOMError* |
|
245 GetError(ErrorResult& aRv); |
|
246 |
|
247 already_AddRefed<IDBObjectStore> |
|
248 ObjectStore(const nsAString& aName, ErrorResult& aRv); |
|
249 |
|
250 void |
|
251 Abort(ErrorResult& aRv) |
|
252 { |
|
253 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
|
254 aRv = AbortInternal(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR, nullptr); |
|
255 } |
|
256 |
|
257 IMPL_EVENT_HANDLER(abort) |
|
258 IMPL_EVENT_HANDLER(complete) |
|
259 IMPL_EVENT_HANDLER(error) |
|
260 |
|
261 already_AddRefed<DOMStringList> |
|
262 GetObjectStoreNames(ErrorResult& aRv); |
|
263 |
|
264 private: |
|
265 nsresult |
|
266 AbortInternal(nsresult aAbortCode, |
|
267 already_AddRefed<mozilla::dom::DOMError> aError); |
|
268 |
|
269 // Should only be called directly through IndexedDBDatabaseChild. |
|
270 static already_AddRefed<IDBTransaction> |
|
271 CreateInternal(IDBDatabase* aDatabase, |
|
272 const Sequence<nsString>& aObjectStoreNames, |
|
273 Mode aMode, |
|
274 bool aDispatchDelayed, |
|
275 bool aIsVersionChangeTransactionChild); |
|
276 |
|
277 IDBTransaction(IDBDatabase* aDatabase); |
|
278 ~IDBTransaction(); |
|
279 |
|
280 nsresult CommitOrRollback(); |
|
281 |
|
282 nsRefPtr<IDBDatabase> mDatabase; |
|
283 nsRefPtr<DatabaseInfo> mDatabaseInfo; |
|
284 nsRefPtr<DOMError> mError; |
|
285 nsTArray<nsString> mObjectStoreNames; |
|
286 ReadyState mReadyState; |
|
287 Mode mMode; |
|
288 uint32_t mPendingRequests; |
|
289 |
|
290 nsInterfaceHashtable<nsCStringHashKey, mozIStorageStatement> |
|
291 mCachedStatements; |
|
292 |
|
293 nsRefPtr<IDBTransactionListener> mListener; |
|
294 |
|
295 // Only touched on the database thread. |
|
296 nsCOMPtr<mozIStorageConnection> mConnection; |
|
297 |
|
298 // Only touched on the database thread. |
|
299 uint32_t mSavepointCount; |
|
300 |
|
301 nsTArray<nsRefPtr<IDBObjectStore> > mCreatedObjectStores; |
|
302 nsTArray<nsRefPtr<IDBObjectStore> > mDeletedObjectStores; |
|
303 |
|
304 nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction; |
|
305 nsRefPtrHashtable<nsISupportsHashKey, FileInfo> mCreatedFileInfos; |
|
306 |
|
307 IndexedDBTransactionChild* mActorChild; |
|
308 IndexedDBTransactionParent* mActorParent; |
|
309 |
|
310 nsresult mAbortCode; |
|
311 #ifdef MOZ_ENABLE_PROFILER_SPS |
|
312 uint64_t mSerialNumber; |
|
313 #endif |
|
314 bool mCreating; |
|
315 |
|
316 #ifdef DEBUG |
|
317 bool mFiredCompleteOrAbort; |
|
318 #endif |
|
319 }; |
|
320 |
|
321 class CommitHelper MOZ_FINAL : public nsIRunnable |
|
322 { |
|
323 public: |
|
324 NS_DECL_THREADSAFE_ISUPPORTS |
|
325 NS_DECL_NSIRUNNABLE |
|
326 |
|
327 CommitHelper(IDBTransaction* aTransaction, |
|
328 IDBTransactionListener* aListener, |
|
329 const nsTArray<nsRefPtr<IDBObjectStore> >& mUpdatedObjectStores); |
|
330 CommitHelper(IDBTransaction* aTransaction, |
|
331 nsresult aAbortCode); |
|
332 ~CommitHelper(); |
|
333 |
|
334 template<class T> |
|
335 bool AddDoomedObject(nsCOMPtr<T>& aCOMPtr) |
|
336 { |
|
337 if (aCOMPtr) { |
|
338 if (!mDoomedObjects.AppendElement(do_QueryInterface(aCOMPtr))) { |
|
339 NS_ERROR("Out of memory!"); |
|
340 return false; |
|
341 } |
|
342 aCOMPtr = nullptr; |
|
343 } |
|
344 return true; |
|
345 } |
|
346 |
|
347 private: |
|
348 // Writes new autoincrement counts to database |
|
349 nsresult WriteAutoIncrementCounts(); |
|
350 |
|
351 // Updates counts after a successful commit |
|
352 void CommitAutoIncrementCounts(); |
|
353 |
|
354 // Reverts counts when a transaction is aborted |
|
355 void RevertAutoIncrementCounts(); |
|
356 |
|
357 nsRefPtr<IDBTransaction> mTransaction; |
|
358 nsRefPtr<IDBTransactionListener> mListener; |
|
359 nsCOMPtr<mozIStorageConnection> mConnection; |
|
360 nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction; |
|
361 nsAutoTArray<nsCOMPtr<nsISupports>, 10> mDoomedObjects; |
|
362 nsAutoTArray<nsRefPtr<IDBObjectStore>, 10> mAutoIncrementObjectStores; |
|
363 |
|
364 nsresult mAbortCode; |
|
365 }; |
|
366 |
|
367 class UpdateRefcountFunction MOZ_FINAL : public mozIStorageFunction |
|
368 { |
|
369 public: |
|
370 NS_DECL_THREADSAFE_ISUPPORTS |
|
371 NS_DECL_MOZISTORAGEFUNCTION |
|
372 |
|
373 UpdateRefcountFunction(FileManager* aFileManager) |
|
374 : mFileManager(aFileManager), mInSavepoint(false) |
|
375 { } |
|
376 |
|
377 ~UpdateRefcountFunction() |
|
378 { } |
|
379 |
|
380 void StartSavepoint() |
|
381 { |
|
382 MOZ_ASSERT(!mInSavepoint); |
|
383 MOZ_ASSERT(!mSavepointEntriesIndex.Count()); |
|
384 |
|
385 mInSavepoint = true; |
|
386 } |
|
387 |
|
388 void ReleaseSavepoint() |
|
389 { |
|
390 MOZ_ASSERT(mInSavepoint); |
|
391 |
|
392 mSavepointEntriesIndex.Clear(); |
|
393 |
|
394 mInSavepoint = false; |
|
395 } |
|
396 |
|
397 void RollbackSavepoint() |
|
398 { |
|
399 MOZ_ASSERT(mInSavepoint); |
|
400 |
|
401 mInSavepoint = false; |
|
402 |
|
403 mSavepointEntriesIndex.EnumerateRead(RollbackSavepointCallback, nullptr); |
|
404 |
|
405 mSavepointEntriesIndex.Clear(); |
|
406 } |
|
407 |
|
408 void ClearFileInfoEntries() |
|
409 { |
|
410 mFileInfoEntries.Clear(); |
|
411 } |
|
412 |
|
413 nsresult WillCommit(mozIStorageConnection* aConnection); |
|
414 void DidCommit(); |
|
415 void DidAbort(); |
|
416 |
|
417 private: |
|
418 class FileInfoEntry |
|
419 { |
|
420 public: |
|
421 FileInfoEntry(FileInfo* aFileInfo) |
|
422 : mFileInfo(aFileInfo), mDelta(0), mSavepointDelta(0) |
|
423 { } |
|
424 |
|
425 ~FileInfoEntry() |
|
426 { } |
|
427 |
|
428 nsRefPtr<FileInfo> mFileInfo; |
|
429 int32_t mDelta; |
|
430 int32_t mSavepointDelta; |
|
431 }; |
|
432 |
|
433 enum UpdateType { |
|
434 eIncrement, |
|
435 eDecrement |
|
436 }; |
|
437 |
|
438 class DatabaseUpdateFunction |
|
439 { |
|
440 public: |
|
441 DatabaseUpdateFunction(mozIStorageConnection* aConnection, |
|
442 UpdateRefcountFunction* aFunction) |
|
443 : mConnection(aConnection), mFunction(aFunction), mErrorCode(NS_OK) |
|
444 { } |
|
445 |
|
446 bool Update(int64_t aId, int32_t aDelta); |
|
447 nsresult ErrorCode() |
|
448 { |
|
449 return mErrorCode; |
|
450 } |
|
451 |
|
452 private: |
|
453 nsresult UpdateInternal(int64_t aId, int32_t aDelta); |
|
454 |
|
455 nsCOMPtr<mozIStorageConnection> mConnection; |
|
456 nsCOMPtr<mozIStorageStatement> mUpdateStatement; |
|
457 nsCOMPtr<mozIStorageStatement> mSelectStatement; |
|
458 nsCOMPtr<mozIStorageStatement> mInsertStatement; |
|
459 |
|
460 UpdateRefcountFunction* mFunction; |
|
461 |
|
462 nsresult mErrorCode; |
|
463 }; |
|
464 |
|
465 nsresult ProcessValue(mozIStorageValueArray* aValues, |
|
466 int32_t aIndex, |
|
467 UpdateType aUpdateType); |
|
468 |
|
469 nsresult CreateJournals(); |
|
470 |
|
471 nsresult RemoveJournals(const nsTArray<int64_t>& aJournals); |
|
472 |
|
473 static PLDHashOperator |
|
474 DatabaseUpdateCallback(const uint64_t& aKey, |
|
475 FileInfoEntry* aValue, |
|
476 void* aUserArg); |
|
477 |
|
478 static PLDHashOperator |
|
479 FileInfoUpdateCallback(const uint64_t& aKey, |
|
480 FileInfoEntry* aValue, |
|
481 void* aUserArg); |
|
482 |
|
483 static PLDHashOperator |
|
484 RollbackSavepointCallback(const uint64_t& aKey, |
|
485 FileInfoEntry* aValue, |
|
486 void* aUserArg); |
|
487 |
|
488 FileManager* mFileManager; |
|
489 nsClassHashtable<nsUint64HashKey, FileInfoEntry> mFileInfoEntries; |
|
490 nsDataHashtable<nsUint64HashKey, FileInfoEntry*> mSavepointEntriesIndex; |
|
491 |
|
492 nsTArray<int64_t> mJournalsToCreateBeforeCommit; |
|
493 nsTArray<int64_t> mJournalsToRemoveAfterCommit; |
|
494 nsTArray<int64_t> mJournalsToRemoveAfterAbort; |
|
495 |
|
496 bool mInSavepoint; |
|
497 }; |
|
498 |
|
499 END_INDEXEDDB_NAMESPACE |
|
500 |
|
501 #endif // mozilla_dom_indexeddb_idbtransaction_h__ |