Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
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/. */
7 #ifndef mozilla_dom_indexeddb_idbtransaction_h__
8 #define mozilla_dom_indexeddb_idbtransaction_h__
10 #include "mozilla/Attributes.h"
11 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
13 #include "mozIStorageConnection.h"
14 #include "mozIStorageStatement.h"
15 #include "mozIStorageFunction.h"
16 #include "mozilla/dom/DOMError.h"
17 #include "nsIRunnable.h"
19 #include "nsAutoPtr.h"
20 #include "nsClassHashtable.h"
21 #include "nsHashKeys.h"
22 #include "nsInterfaceHashtable.h"
23 #include "nsRefPtrHashtable.h"
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"
30 class nsIThread;
31 class nsPIDOMWindow;
33 namespace mozilla {
34 class EventChainPreVisitor;
35 } // namespace mozilla
37 BEGIN_INDEXEDDB_NAMESPACE
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;
49 class IDBTransactionListener
50 {
51 public:
52 NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0;
53 NS_IMETHOD_(MozExternalRefCountType) Release() = 0;
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 };
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;
70 public:
71 NS_DECL_ISUPPORTS_INHERITED
72 NS_DECL_NSIRUNNABLE
74 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBTransaction, IDBWrapperCache)
76 enum Mode
77 {
78 READ_ONLY = 0,
79 READ_WRITE,
80 VERSION_CHANGE,
82 // Only needed for IPC serialization helper, should never be used in code.
83 MODE_INVALID
84 };
86 enum ReadyState
87 {
88 INITIAL = 0,
89 LOADING,
90 COMMITTING,
91 DONE
92 };
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 }
104 // nsIDOMEventTarget
105 virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
107 void OnNewRequest();
108 void OnRequestFinished();
109 void OnRequestDisconnected();
111 void RemoveObjectStore(const nsAString& aName);
113 void SetTransactionListener(IDBTransactionListener* aListener);
115 bool StartSavepoint();
116 nsresult ReleaseSavepoint();
117 void RollbackSavepoint();
119 // Only meant to be called on mStorageThread!
120 nsresult GetOrCreateConnection(mozIStorageConnection** aConnection);
122 already_AddRefed<mozIStorageStatement>
123 GetCachedStatement(const nsACString& aQuery);
125 template<int N>
126 already_AddRefed<mozIStorageStatement>
127 GetCachedStatement(const char (&aQuery)[N])
128 {
129 return GetCachedStatement(NS_LITERAL_CSTRING(aQuery));
130 }
132 bool IsOpen() const;
134 bool IsFinished() const
135 {
136 return mReadyState > LOADING;
137 }
139 bool IsWriteAllowed() const
140 {
141 return mMode == READ_WRITE || mMode == VERSION_CHANGE;
142 }
144 bool IsAborted() const
145 {
146 return NS_FAILED(mAbortCode);
147 }
149 // 'Get' prefix is to avoid name collisions with the enum
150 Mode GetMode()
151 {
152 return mMode;
153 }
155 IDBDatabase* Database()
156 {
157 NS_ASSERTION(mDatabase, "This should never be null!");
158 return mDatabase;
159 }
161 DatabaseInfo* DBInfo() const
162 {
163 return mDatabaseInfo;
164 }
166 already_AddRefed<IDBObjectStore>
167 GetOrCreateObjectStore(const nsAString& aName,
168 ObjectStoreInfo* aObjectStoreInfo,
169 bool aCreating);
171 already_AddRefed<FileInfo> GetFileInfo(nsIDOMBlob* aBlob);
172 void AddFileInfo(nsIDOMBlob* aBlob, FileInfo* aFileInfo);
174 void ClearCreatedFileInfos();
176 void
177 SetActor(IndexedDBTransactionChild* aActorChild)
178 {
179 NS_ASSERTION(!aActorChild || !mActorChild, "Shouldn't have more than one!");
180 mActorChild = aActorChild;
181 }
183 void
184 SetActor(IndexedDBTransactionParent* aActorParent)
185 {
186 NS_ASSERTION(!aActorParent || !mActorParent,
187 "Shouldn't have more than one!");
188 mActorParent = aActorParent;
189 }
191 IndexedDBTransactionChild*
192 GetActorChild() const
193 {
194 return mActorChild;
195 }
197 IndexedDBTransactionParent*
198 GetActorParent() const
199 {
200 return mActorParent;
201 }
203 nsresult
204 Abort(IDBRequest* aRequest);
206 nsresult
207 Abort(nsresult aAbortCode);
209 nsresult
210 GetAbortCode() const
211 {
212 return mAbortCode;
213 }
215 #ifdef MOZ_ENABLE_PROFILER_SPS
216 uint64_t
217 GetSerialNumber() const
218 {
219 return mSerialNumber;
220 }
221 #endif
223 // nsWrapperCache
224 virtual JSObject*
225 WrapObject(JSContext* aCx) MOZ_OVERRIDE;
227 // WebIDL
228 nsPIDOMWindow*
229 GetParentObject() const
230 {
231 return GetOwner();
232 }
234 IDBTransactionMode
235 GetMode(ErrorResult& aRv) const;
237 IDBDatabase*
238 Db() const
239 {
240 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
241 return mDatabase;
242 }
244 DOMError*
245 GetError(ErrorResult& aRv);
247 already_AddRefed<IDBObjectStore>
248 ObjectStore(const nsAString& aName, ErrorResult& aRv);
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 }
257 IMPL_EVENT_HANDLER(abort)
258 IMPL_EVENT_HANDLER(complete)
259 IMPL_EVENT_HANDLER(error)
261 already_AddRefed<DOMStringList>
262 GetObjectStoreNames(ErrorResult& aRv);
264 private:
265 nsresult
266 AbortInternal(nsresult aAbortCode,
267 already_AddRefed<mozilla::dom::DOMError> aError);
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);
277 IDBTransaction(IDBDatabase* aDatabase);
278 ~IDBTransaction();
280 nsresult CommitOrRollback();
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;
290 nsInterfaceHashtable<nsCStringHashKey, mozIStorageStatement>
291 mCachedStatements;
293 nsRefPtr<IDBTransactionListener> mListener;
295 // Only touched on the database thread.
296 nsCOMPtr<mozIStorageConnection> mConnection;
298 // Only touched on the database thread.
299 uint32_t mSavepointCount;
301 nsTArray<nsRefPtr<IDBObjectStore> > mCreatedObjectStores;
302 nsTArray<nsRefPtr<IDBObjectStore> > mDeletedObjectStores;
304 nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction;
305 nsRefPtrHashtable<nsISupportsHashKey, FileInfo> mCreatedFileInfos;
307 IndexedDBTransactionChild* mActorChild;
308 IndexedDBTransactionParent* mActorParent;
310 nsresult mAbortCode;
311 #ifdef MOZ_ENABLE_PROFILER_SPS
312 uint64_t mSerialNumber;
313 #endif
314 bool mCreating;
316 #ifdef DEBUG
317 bool mFiredCompleteOrAbort;
318 #endif
319 };
321 class CommitHelper MOZ_FINAL : public nsIRunnable
322 {
323 public:
324 NS_DECL_THREADSAFE_ISUPPORTS
325 NS_DECL_NSIRUNNABLE
327 CommitHelper(IDBTransaction* aTransaction,
328 IDBTransactionListener* aListener,
329 const nsTArray<nsRefPtr<IDBObjectStore> >& mUpdatedObjectStores);
330 CommitHelper(IDBTransaction* aTransaction,
331 nsresult aAbortCode);
332 ~CommitHelper();
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 }
347 private:
348 // Writes new autoincrement counts to database
349 nsresult WriteAutoIncrementCounts();
351 // Updates counts after a successful commit
352 void CommitAutoIncrementCounts();
354 // Reverts counts when a transaction is aborted
355 void RevertAutoIncrementCounts();
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;
364 nsresult mAbortCode;
365 };
367 class UpdateRefcountFunction MOZ_FINAL : public mozIStorageFunction
368 {
369 public:
370 NS_DECL_THREADSAFE_ISUPPORTS
371 NS_DECL_MOZISTORAGEFUNCTION
373 UpdateRefcountFunction(FileManager* aFileManager)
374 : mFileManager(aFileManager), mInSavepoint(false)
375 { }
377 ~UpdateRefcountFunction()
378 { }
380 void StartSavepoint()
381 {
382 MOZ_ASSERT(!mInSavepoint);
383 MOZ_ASSERT(!mSavepointEntriesIndex.Count());
385 mInSavepoint = true;
386 }
388 void ReleaseSavepoint()
389 {
390 MOZ_ASSERT(mInSavepoint);
392 mSavepointEntriesIndex.Clear();
394 mInSavepoint = false;
395 }
397 void RollbackSavepoint()
398 {
399 MOZ_ASSERT(mInSavepoint);
401 mInSavepoint = false;
403 mSavepointEntriesIndex.EnumerateRead(RollbackSavepointCallback, nullptr);
405 mSavepointEntriesIndex.Clear();
406 }
408 void ClearFileInfoEntries()
409 {
410 mFileInfoEntries.Clear();
411 }
413 nsresult WillCommit(mozIStorageConnection* aConnection);
414 void DidCommit();
415 void DidAbort();
417 private:
418 class FileInfoEntry
419 {
420 public:
421 FileInfoEntry(FileInfo* aFileInfo)
422 : mFileInfo(aFileInfo), mDelta(0), mSavepointDelta(0)
423 { }
425 ~FileInfoEntry()
426 { }
428 nsRefPtr<FileInfo> mFileInfo;
429 int32_t mDelta;
430 int32_t mSavepointDelta;
431 };
433 enum UpdateType {
434 eIncrement,
435 eDecrement
436 };
438 class DatabaseUpdateFunction
439 {
440 public:
441 DatabaseUpdateFunction(mozIStorageConnection* aConnection,
442 UpdateRefcountFunction* aFunction)
443 : mConnection(aConnection), mFunction(aFunction), mErrorCode(NS_OK)
444 { }
446 bool Update(int64_t aId, int32_t aDelta);
447 nsresult ErrorCode()
448 {
449 return mErrorCode;
450 }
452 private:
453 nsresult UpdateInternal(int64_t aId, int32_t aDelta);
455 nsCOMPtr<mozIStorageConnection> mConnection;
456 nsCOMPtr<mozIStorageStatement> mUpdateStatement;
457 nsCOMPtr<mozIStorageStatement> mSelectStatement;
458 nsCOMPtr<mozIStorageStatement> mInsertStatement;
460 UpdateRefcountFunction* mFunction;
462 nsresult mErrorCode;
463 };
465 nsresult ProcessValue(mozIStorageValueArray* aValues,
466 int32_t aIndex,
467 UpdateType aUpdateType);
469 nsresult CreateJournals();
471 nsresult RemoveJournals(const nsTArray<int64_t>& aJournals);
473 static PLDHashOperator
474 DatabaseUpdateCallback(const uint64_t& aKey,
475 FileInfoEntry* aValue,
476 void* aUserArg);
478 static PLDHashOperator
479 FileInfoUpdateCallback(const uint64_t& aKey,
480 FileInfoEntry* aValue,
481 void* aUserArg);
483 static PLDHashOperator
484 RollbackSavepointCallback(const uint64_t& aKey,
485 FileInfoEntry* aValue,
486 void* aUserArg);
488 FileManager* mFileManager;
489 nsClassHashtable<nsUint64HashKey, FileInfoEntry> mFileInfoEntries;
490 nsDataHashtable<nsUint64HashKey, FileInfoEntry*> mSavepointEntriesIndex;
492 nsTArray<int64_t> mJournalsToCreateBeforeCommit;
493 nsTArray<int64_t> mJournalsToRemoveAfterCommit;
494 nsTArray<int64_t> mJournalsToRemoveAfterAbort;
496 bool mInSavepoint;
497 };
499 END_INDEXEDDB_NAMESPACE
501 #endif // mozilla_dom_indexeddb_idbtransaction_h__