/src/mozilla-central/dom/indexedDB/IDBTransaction.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=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 | | #include "IDBTransaction.h" |
8 | | |
9 | | #include "BackgroundChildImpl.h" |
10 | | #include "IDBDatabase.h" |
11 | | #include "IDBEvents.h" |
12 | | #include "IDBObjectStore.h" |
13 | | #include "IDBRequest.h" |
14 | | #include "mozilla/ErrorResult.h" |
15 | | #include "mozilla/EventDispatcher.h" |
16 | | #include "mozilla/dom/DOMException.h" |
17 | | #include "mozilla/dom/DOMStringList.h" |
18 | | #include "mozilla/dom/WorkerRef.h" |
19 | | #include "mozilla/dom/WorkerPrivate.h" |
20 | | #include "mozilla/ipc/BackgroundChild.h" |
21 | | #include "mozilla/ScopeExit.h" |
22 | | #include "nsAutoPtr.h" |
23 | | #include "nsPIDOMWindow.h" |
24 | | #include "nsQueryObject.h" |
25 | | #include "nsServiceManagerUtils.h" |
26 | | #include "nsTHashtable.h" |
27 | | #include "ProfilerHelpers.h" |
28 | | #include "ReportInternalError.h" |
29 | | |
30 | | // Include this last to avoid path problems on Windows. |
31 | | #include "ActorsChild.h" |
32 | | |
33 | | namespace mozilla { |
34 | | namespace dom { |
35 | | |
36 | | using namespace mozilla::dom::indexedDB; |
37 | | using namespace mozilla::ipc; |
38 | | |
39 | | IDBTransaction::IDBTransaction(IDBDatabase* aDatabase, |
40 | | const nsTArray<nsString>& aObjectStoreNames, |
41 | | Mode aMode) |
42 | | : IDBWrapperCache(aDatabase) |
43 | | , mDatabase(aDatabase) |
44 | | , mObjectStoreNames(aObjectStoreNames) |
45 | | , mLoggingSerialNumber(0) |
46 | | , mNextObjectStoreId(0) |
47 | | , mNextIndexId(0) |
48 | | , mAbortCode(NS_OK) |
49 | | , mPendingRequestCount(0) |
50 | | , mLineNo(0) |
51 | | , mColumn(0) |
52 | | , mReadyState(IDBTransaction::INITIAL) |
53 | | , mMode(aMode) |
54 | | , mCreating(false) |
55 | | , mRegistered(false) |
56 | | , mAbortedByScript(false) |
57 | | , mNotedActiveTransaction(false) |
58 | | #ifdef DEBUG |
59 | | , mSentCommitOrAbort(false) |
60 | | , mFiredCompleteOrAbort(false) |
61 | | #endif |
62 | 0 | { |
63 | 0 | MOZ_ASSERT(aDatabase); |
64 | 0 | aDatabase->AssertIsOnOwningThread(); |
65 | 0 |
|
66 | 0 | mBackgroundActor.mNormalBackgroundActor = nullptr; |
67 | 0 |
|
68 | 0 | BackgroundChildImpl::ThreadLocal* threadLocal = |
69 | 0 | BackgroundChildImpl::GetThreadLocalForCurrentThread(); |
70 | 0 | MOZ_ASSERT(threadLocal); |
71 | 0 |
|
72 | 0 | ThreadLocal* idbThreadLocal = threadLocal->mIndexedDBThreadLocal; |
73 | 0 | MOZ_ASSERT(idbThreadLocal); |
74 | 0 |
|
75 | 0 | const_cast<int64_t&>(mLoggingSerialNumber) = |
76 | 0 | idbThreadLocal->NextTransactionSN(aMode); |
77 | 0 |
|
78 | | #ifdef DEBUG |
79 | | if (!aObjectStoreNames.IsEmpty()) { |
80 | | nsTArray<nsString> sortedNames(aObjectStoreNames); |
81 | | sortedNames.Sort(); |
82 | | |
83 | | const uint32_t count = sortedNames.Length(); |
84 | | MOZ_ASSERT(count == aObjectStoreNames.Length()); |
85 | | |
86 | | // Make sure the array is properly sorted. |
87 | | for (uint32_t index = 0; index < count; index++) { |
88 | | MOZ_ASSERT(aObjectStoreNames[index] == sortedNames[index]); |
89 | | } |
90 | | |
91 | | // Make sure there are no duplicates in our objectStore names. |
92 | | for (uint32_t index = 0; index < count - 1; index++) { |
93 | | MOZ_ASSERT(sortedNames[index] != sortedNames[index + 1]); |
94 | | } |
95 | | } |
96 | | #endif |
97 | | } |
98 | | |
99 | | IDBTransaction::~IDBTransaction() |
100 | 0 | { |
101 | 0 | AssertIsOnOwningThread(); |
102 | 0 | MOZ_ASSERT(!mPendingRequestCount); |
103 | 0 | MOZ_ASSERT(!mCreating); |
104 | 0 | MOZ_ASSERT(!mNotedActiveTransaction); |
105 | 0 | MOZ_ASSERT(mSentCommitOrAbort); |
106 | 0 | MOZ_ASSERT_IF(mMode == VERSION_CHANGE && |
107 | 0 | mBackgroundActor.mVersionChangeBackgroundActor, |
108 | 0 | mFiredCompleteOrAbort); |
109 | 0 | MOZ_ASSERT_IF(mMode != VERSION_CHANGE && |
110 | 0 | mBackgroundActor.mNormalBackgroundActor, |
111 | 0 | mFiredCompleteOrAbort); |
112 | 0 |
|
113 | 0 | if (mRegistered) { |
114 | 0 | mDatabase->UnregisterTransaction(this); |
115 | | #ifdef DEBUG |
116 | | mRegistered = false; |
117 | | #endif |
118 | | } |
119 | 0 |
|
120 | 0 | if (mMode == VERSION_CHANGE) { |
121 | 0 | if (auto* actor = mBackgroundActor.mVersionChangeBackgroundActor) { |
122 | 0 | actor->SendDeleteMeInternal(/* aFailedConstructor */ false); |
123 | 0 |
|
124 | 0 | MOZ_ASSERT(!mBackgroundActor.mVersionChangeBackgroundActor, |
125 | 0 | "SendDeleteMeInternal should have cleared!"); |
126 | 0 | } |
127 | 0 | } else if (auto* actor = mBackgroundActor.mNormalBackgroundActor) { |
128 | 0 | actor->SendDeleteMeInternal(); |
129 | 0 |
|
130 | 0 | MOZ_ASSERT(!mBackgroundActor.mNormalBackgroundActor, |
131 | 0 | "SendDeleteMeInternal should have cleared!"); |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | | // static |
136 | | already_AddRefed<IDBTransaction> |
137 | | IDBTransaction::CreateVersionChange( |
138 | | IDBDatabase* aDatabase, |
139 | | BackgroundVersionChangeTransactionChild* aActor, |
140 | | IDBOpenDBRequest* aOpenRequest, |
141 | | int64_t aNextObjectStoreId, |
142 | | int64_t aNextIndexId) |
143 | 0 | { |
144 | 0 | MOZ_ASSERT(aDatabase); |
145 | 0 | aDatabase->AssertIsOnOwningThread(); |
146 | 0 | MOZ_ASSERT(aActor); |
147 | 0 | MOZ_ASSERT(aOpenRequest); |
148 | 0 | MOZ_ASSERT(aNextObjectStoreId > 0); |
149 | 0 | MOZ_ASSERT(aNextIndexId > 0); |
150 | 0 |
|
151 | 0 | nsTArray<nsString> emptyObjectStoreNames; |
152 | 0 |
|
153 | 0 | RefPtr<IDBTransaction> transaction = |
154 | 0 | new IDBTransaction(aDatabase, |
155 | 0 | emptyObjectStoreNames, |
156 | 0 | VERSION_CHANGE); |
157 | 0 | aOpenRequest->GetCallerLocation(transaction->mFilename, |
158 | 0 | &transaction->mLineNo, &transaction->mColumn); |
159 | 0 |
|
160 | 0 | transaction->SetScriptOwner(aDatabase->GetScriptOwner()); |
161 | 0 |
|
162 | 0 | transaction->NoteActiveTransaction(); |
163 | 0 |
|
164 | 0 | transaction->mBackgroundActor.mVersionChangeBackgroundActor = aActor; |
165 | 0 | transaction->mNextObjectStoreId = aNextObjectStoreId; |
166 | 0 | transaction->mNextIndexId = aNextIndexId; |
167 | 0 |
|
168 | 0 | aDatabase->RegisterTransaction(transaction); |
169 | 0 | transaction->mRegistered = true; |
170 | 0 |
|
171 | 0 | return transaction.forget(); |
172 | 0 | } |
173 | | |
174 | | // static |
175 | | already_AddRefed<IDBTransaction> |
176 | | IDBTransaction::Create(JSContext* aCx, IDBDatabase* aDatabase, |
177 | | const nsTArray<nsString>& aObjectStoreNames, |
178 | | Mode aMode) |
179 | 0 | { |
180 | 0 | MOZ_ASSERT(aDatabase); |
181 | 0 | aDatabase->AssertIsOnOwningThread(); |
182 | 0 | MOZ_ASSERT(!aObjectStoreNames.IsEmpty()); |
183 | 0 | MOZ_ASSERT(aMode == READ_ONLY || |
184 | 0 | aMode == READ_WRITE || |
185 | 0 | aMode == READ_WRITE_FLUSH || |
186 | 0 | aMode == CLEANUP); |
187 | 0 |
|
188 | 0 | RefPtr<IDBTransaction> transaction = |
189 | 0 | new IDBTransaction(aDatabase, aObjectStoreNames, aMode); |
190 | 0 | IDBRequest::CaptureCaller(aCx, transaction->mFilename, &transaction->mLineNo, |
191 | 0 | &transaction->mColumn); |
192 | 0 |
|
193 | 0 | transaction->SetScriptOwner(aDatabase->GetScriptOwner()); |
194 | 0 |
|
195 | 0 | if (!NS_IsMainThread()) { |
196 | 0 | WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); |
197 | 0 | MOZ_ASSERT(workerPrivate); |
198 | 0 |
|
199 | 0 | workerPrivate->AssertIsOnWorkerThread(); |
200 | 0 |
|
201 | 0 | RefPtr<StrongWorkerRef> workerRef = |
202 | 0 | StrongWorkerRef::Create(workerPrivate, "IDBTransaction", |
203 | 0 | [transaction]() { |
204 | 0 | transaction->AssertIsOnOwningThread(); |
205 | 0 | if (!transaction->IsCommittingOrDone()) { |
206 | 0 | IDB_REPORT_INTERNAL_ERR(); |
207 | 0 | transaction->AbortInternal(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR, |
208 | 0 | nullptr); |
209 | 0 | } |
210 | 0 | }); |
211 | 0 | if (NS_WARN_IF(!workerRef)) { |
212 | 0 | // Silence the destructor assertion if we never made this object live. |
213 | | #ifdef DEBUG |
214 | | MOZ_ASSERT(!transaction->mSentCommitOrAbort); |
215 | | transaction->mSentCommitOrAbort = true; |
216 | | #endif |
217 | | return nullptr; |
218 | 0 | } |
219 | 0 |
|
220 | 0 | transaction->mWorkerRef = std::move(workerRef); |
221 | 0 | } |
222 | 0 |
|
223 | 0 | nsCOMPtr<nsIRunnable> runnable = do_QueryObject(transaction); |
224 | 0 | nsContentUtils::AddPendingIDBTransaction(runnable.forget()); |
225 | 0 |
|
226 | 0 | transaction->mCreating = true; |
227 | 0 |
|
228 | 0 | aDatabase->RegisterTransaction(transaction); |
229 | 0 | transaction->mRegistered = true; |
230 | 0 |
|
231 | 0 | return transaction.forget(); |
232 | 0 | } |
233 | | |
234 | | // static |
235 | | IDBTransaction* |
236 | | IDBTransaction::GetCurrent() |
237 | 0 | { |
238 | 0 | using namespace mozilla::ipc; |
239 | 0 |
|
240 | 0 | MOZ_ASSERT(BackgroundChild::GetForCurrentThread()); |
241 | 0 |
|
242 | 0 | BackgroundChildImpl::ThreadLocal* threadLocal = |
243 | 0 | BackgroundChildImpl::GetThreadLocalForCurrentThread(); |
244 | 0 | MOZ_ASSERT(threadLocal); |
245 | 0 |
|
246 | 0 | ThreadLocal* idbThreadLocal = threadLocal->mIndexedDBThreadLocal; |
247 | 0 | MOZ_ASSERT(idbThreadLocal); |
248 | 0 |
|
249 | 0 | return idbThreadLocal->GetCurrentTransaction(); |
250 | 0 | } |
251 | | |
252 | | #ifdef DEBUG |
253 | | |
254 | | void |
255 | | IDBTransaction::AssertIsOnOwningThread() const |
256 | | { |
257 | | MOZ_ASSERT(mDatabase); |
258 | | mDatabase->AssertIsOnOwningThread(); |
259 | | } |
260 | | |
261 | | #endif // DEBUG |
262 | | |
263 | | void |
264 | | IDBTransaction::SetBackgroundActor(indexedDB::BackgroundTransactionChild* aBackgroundActor) |
265 | 0 | { |
266 | 0 | AssertIsOnOwningThread(); |
267 | 0 | MOZ_ASSERT(aBackgroundActor); |
268 | 0 | MOZ_ASSERT(!mBackgroundActor.mNormalBackgroundActor); |
269 | 0 | MOZ_ASSERT(mMode != VERSION_CHANGE); |
270 | 0 |
|
271 | 0 | NoteActiveTransaction(); |
272 | 0 |
|
273 | 0 | mBackgroundActor.mNormalBackgroundActor = aBackgroundActor; |
274 | 0 | } |
275 | | |
276 | | BackgroundRequestChild* |
277 | | IDBTransaction::StartRequest(IDBRequest* aRequest, const RequestParams& aParams) |
278 | 0 | { |
279 | 0 | AssertIsOnOwningThread(); |
280 | 0 | MOZ_ASSERT(aRequest); |
281 | 0 | MOZ_ASSERT(aParams.type() != RequestParams::T__None); |
282 | 0 |
|
283 | 0 | BackgroundRequestChild* actor = new BackgroundRequestChild(aRequest); |
284 | 0 |
|
285 | 0 | if (mMode == VERSION_CHANGE) { |
286 | 0 | MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor); |
287 | 0 |
|
288 | 0 | mBackgroundActor.mVersionChangeBackgroundActor-> |
289 | 0 | SendPBackgroundIDBRequestConstructor(actor, aParams); |
290 | 0 | } else { |
291 | 0 | MOZ_ASSERT(mBackgroundActor.mNormalBackgroundActor); |
292 | 0 |
|
293 | 0 | mBackgroundActor.mNormalBackgroundActor-> |
294 | 0 | SendPBackgroundIDBRequestConstructor(actor, aParams); |
295 | 0 | } |
296 | 0 |
|
297 | 0 | MOZ_ASSERT(actor->GetActorEventTarget(), |
298 | 0 | "The event target shall be inherited from its manager actor."); |
299 | 0 |
|
300 | 0 | // Balanced in BackgroundRequestChild::Recv__delete__(). |
301 | 0 | OnNewRequest(); |
302 | 0 |
|
303 | 0 | return actor; |
304 | 0 | } |
305 | | |
306 | | void |
307 | | IDBTransaction::OpenCursor(BackgroundCursorChild* aBackgroundActor, |
308 | | const OpenCursorParams& aParams) |
309 | 0 | { |
310 | 0 | AssertIsOnOwningThread(); |
311 | 0 | MOZ_ASSERT(aBackgroundActor); |
312 | 0 | MOZ_ASSERT(aParams.type() != OpenCursorParams::T__None); |
313 | 0 |
|
314 | 0 | if (mMode == VERSION_CHANGE) { |
315 | 0 | MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor); |
316 | 0 |
|
317 | 0 | mBackgroundActor.mVersionChangeBackgroundActor-> |
318 | 0 | SendPBackgroundIDBCursorConstructor(aBackgroundActor, aParams); |
319 | 0 | } else { |
320 | 0 | MOZ_ASSERT(mBackgroundActor.mNormalBackgroundActor); |
321 | 0 |
|
322 | 0 | mBackgroundActor.mNormalBackgroundActor-> |
323 | 0 | SendPBackgroundIDBCursorConstructor(aBackgroundActor, aParams); |
324 | 0 | } |
325 | 0 |
|
326 | 0 | MOZ_ASSERT(aBackgroundActor->GetActorEventTarget(), |
327 | 0 | "The event target shall be inherited from its manager actor."); |
328 | 0 |
|
329 | 0 | // Balanced in BackgroundCursorChild::RecvResponse(). |
330 | 0 | OnNewRequest(); |
331 | 0 | } |
332 | | |
333 | | void |
334 | | IDBTransaction::RefreshSpec(bool aMayDelete) |
335 | 0 | { |
336 | 0 | AssertIsOnOwningThread(); |
337 | 0 |
|
338 | 0 | for (uint32_t count = mObjectStores.Length(), index = 0; |
339 | 0 | index < count; |
340 | 0 | index++) { |
341 | 0 | mObjectStores[index]->RefreshSpec(aMayDelete); |
342 | 0 | } |
343 | 0 |
|
344 | 0 | for (uint32_t count = mDeletedObjectStores.Length(), index = 0; |
345 | 0 | index < count; |
346 | 0 | index++) { |
347 | 0 | mDeletedObjectStores[index]->RefreshSpec(false); |
348 | 0 | } |
349 | 0 | } |
350 | | |
351 | | void |
352 | | IDBTransaction::OnNewRequest() |
353 | 0 | { |
354 | 0 | AssertIsOnOwningThread(); |
355 | 0 |
|
356 | 0 | if (!mPendingRequestCount) { |
357 | 0 | MOZ_ASSERT(INITIAL == mReadyState); |
358 | 0 | mReadyState = LOADING; |
359 | 0 | } |
360 | 0 |
|
361 | 0 | ++mPendingRequestCount; |
362 | 0 | } |
363 | | |
364 | | void |
365 | | IDBTransaction::OnRequestFinished(bool aActorDestroyedNormally) |
366 | 0 | { |
367 | 0 | AssertIsOnOwningThread(); |
368 | 0 | MOZ_ASSERT(mPendingRequestCount); |
369 | 0 |
|
370 | 0 | --mPendingRequestCount; |
371 | 0 |
|
372 | 0 | if (!mPendingRequestCount) { |
373 | 0 | mReadyState = COMMITTING; |
374 | 0 |
|
375 | 0 | if (aActorDestroyedNormally) { |
376 | 0 | if (NS_SUCCEEDED(mAbortCode)) { |
377 | 0 | SendCommit(); |
378 | 0 | } else { |
379 | 0 | SendAbort(mAbortCode); |
380 | 0 | } |
381 | 0 | } else { |
382 | 0 | // Don't try to send any more messages to the parent if the request actor |
383 | 0 | // was killed. |
384 | | #ifdef DEBUG |
385 | | MOZ_ASSERT(!mSentCommitOrAbort); |
386 | | mSentCommitOrAbort = true; |
387 | | #endif |
388 | 0 | IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld]: " |
389 | 0 | "Request actor was killed, transaction will be aborted", |
390 | 0 | "IndexedDB %s: C T[%lld]: IDBTransaction abort", |
391 | 0 | IDB_LOG_ID_STRING(), |
392 | 0 | LoggingSerialNumber()); |
393 | 0 | } |
394 | 0 | } |
395 | 0 | } |
396 | | |
397 | | void |
398 | | IDBTransaction::SendCommit() |
399 | 0 | { |
400 | 0 | AssertIsOnOwningThread(); |
401 | 0 | MOZ_ASSERT(NS_SUCCEEDED(mAbortCode)); |
402 | 0 | MOZ_ASSERT(IsCommittingOrDone()); |
403 | 0 | MOZ_ASSERT(!mSentCommitOrAbort); |
404 | 0 | MOZ_ASSERT(!mPendingRequestCount); |
405 | 0 |
|
406 | 0 | // Don't do this in the macro because we always need to increment the serial |
407 | 0 | // number to keep in sync with the parent. |
408 | 0 | const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); |
409 | 0 |
|
410 | 0 | IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " |
411 | 0 | "All requests complete, committing transaction", |
412 | 0 | "IndexedDB %s: C T[%lld] R[%llu]: IDBTransaction commit", |
413 | 0 | IDB_LOG_ID_STRING(), |
414 | 0 | LoggingSerialNumber(), |
415 | 0 | requestSerialNumber); |
416 | 0 |
|
417 | 0 | if (mMode == VERSION_CHANGE) { |
418 | 0 | MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor); |
419 | 0 | mBackgroundActor.mVersionChangeBackgroundActor->SendCommit(); |
420 | 0 | } else { |
421 | 0 | MOZ_ASSERT(mBackgroundActor.mNormalBackgroundActor); |
422 | 0 | mBackgroundActor.mNormalBackgroundActor->SendCommit(); |
423 | 0 | } |
424 | 0 |
|
425 | | #ifdef DEBUG |
426 | | mSentCommitOrAbort = true; |
427 | | #endif |
428 | | } |
429 | | |
430 | | void |
431 | | IDBTransaction::SendAbort(nsresult aResultCode) |
432 | 0 | { |
433 | 0 | AssertIsOnOwningThread(); |
434 | 0 | MOZ_ASSERT(NS_FAILED(aResultCode)); |
435 | 0 | MOZ_ASSERT(IsCommittingOrDone()); |
436 | 0 | MOZ_ASSERT(!mSentCommitOrAbort); |
437 | 0 |
|
438 | 0 | // Don't do this in the macro because we always need to increment the serial |
439 | 0 | // number to keep in sync with the parent. |
440 | 0 | const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); |
441 | 0 |
|
442 | 0 | IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " |
443 | 0 | "Aborting transaction with result 0x%x", |
444 | 0 | "IndexedDB %s: C T[%lld] R[%llu]: IDBTransaction abort (0x%x)", |
445 | 0 | IDB_LOG_ID_STRING(), |
446 | 0 | LoggingSerialNumber(), |
447 | 0 | requestSerialNumber, |
448 | 0 | aResultCode); |
449 | 0 |
|
450 | 0 | if (mMode == VERSION_CHANGE) { |
451 | 0 | MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor); |
452 | 0 | mBackgroundActor.mVersionChangeBackgroundActor->SendAbort(aResultCode); |
453 | 0 | } else { |
454 | 0 | MOZ_ASSERT(mBackgroundActor.mNormalBackgroundActor); |
455 | 0 | mBackgroundActor.mNormalBackgroundActor->SendAbort(aResultCode); |
456 | 0 | } |
457 | 0 |
|
458 | | #ifdef DEBUG |
459 | | mSentCommitOrAbort = true; |
460 | | #endif |
461 | | } |
462 | | |
463 | | void |
464 | | IDBTransaction::NoteActiveTransaction() |
465 | 0 | { |
466 | 0 | AssertIsOnOwningThread(); |
467 | 0 | MOZ_ASSERT(!mNotedActiveTransaction); |
468 | 0 |
|
469 | 0 | mDatabase->NoteActiveTransaction(); |
470 | 0 | mNotedActiveTransaction = true; |
471 | 0 | } |
472 | | |
473 | | void |
474 | | IDBTransaction::MaybeNoteInactiveTransaction() |
475 | 0 | { |
476 | 0 | AssertIsOnOwningThread(); |
477 | 0 |
|
478 | 0 | if (mNotedActiveTransaction) { |
479 | 0 | mDatabase->NoteInactiveTransaction(); |
480 | 0 | mNotedActiveTransaction = false; |
481 | 0 | } |
482 | 0 | } |
483 | | |
484 | | bool |
485 | | IDBTransaction::IsOpen() const |
486 | 0 | { |
487 | 0 | AssertIsOnOwningThread(); |
488 | 0 |
|
489 | 0 | // If we haven't started anything then we're open. |
490 | 0 | if (mReadyState == IDBTransaction::INITIAL) { |
491 | 0 | return true; |
492 | 0 | } |
493 | 0 | |
494 | 0 | // If we've already started then we need to check to see if we still have the |
495 | 0 | // mCreating flag set. If we do (i.e. we haven't returned to the event loop |
496 | 0 | // from the time we were created) then we are open. Otherwise check the |
497 | 0 | // currently running transaction to see if it's the same. We only allow other |
498 | 0 | // requests to be made if this transaction is currently running. |
499 | 0 | if (mReadyState == IDBTransaction::LOADING && |
500 | 0 | (mCreating || GetCurrent() == this)) { |
501 | 0 | return true; |
502 | 0 | } |
503 | 0 | |
504 | 0 | return false; |
505 | 0 | } |
506 | | |
507 | | void |
508 | | IDBTransaction::GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo, |
509 | | uint32_t* aColumn) const |
510 | 0 | { |
511 | 0 | AssertIsOnOwningThread(); |
512 | 0 | MOZ_ASSERT(aLineNo); |
513 | 0 | MOZ_ASSERT(aColumn); |
514 | 0 |
|
515 | 0 | aFilename = mFilename; |
516 | 0 | *aLineNo = mLineNo; |
517 | 0 | *aColumn = mColumn; |
518 | 0 | } |
519 | | |
520 | | already_AddRefed<IDBObjectStore> |
521 | | IDBTransaction::CreateObjectStore(const ObjectStoreSpec& aSpec) |
522 | 0 | { |
523 | 0 | AssertIsOnOwningThread(); |
524 | 0 | MOZ_ASSERT(aSpec.metadata().id()); |
525 | 0 | MOZ_ASSERT(VERSION_CHANGE == mMode); |
526 | 0 | MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor); |
527 | 0 | MOZ_ASSERT(IsOpen()); |
528 | 0 |
|
529 | | #ifdef DEBUG |
530 | | { |
531 | | const nsString& name = aSpec.metadata().name(); |
532 | | |
533 | | for (uint32_t count = mObjectStores.Length(), index = 0; |
534 | | index < count; |
535 | | index++) { |
536 | | MOZ_ASSERT(mObjectStores[index]->Name() != name); |
537 | | } |
538 | | } |
539 | | #endif |
540 | |
|
541 | 0 | MOZ_ALWAYS_TRUE(mBackgroundActor.mVersionChangeBackgroundActor-> |
542 | 0 | SendCreateObjectStore(aSpec.metadata())); |
543 | 0 |
|
544 | 0 | RefPtr<IDBObjectStore> objectStore = IDBObjectStore::Create(this, aSpec); |
545 | 0 | MOZ_ASSERT(objectStore); |
546 | 0 |
|
547 | 0 | mObjectStores.AppendElement(objectStore); |
548 | 0 |
|
549 | 0 | return objectStore.forget(); |
550 | 0 | } |
551 | | |
552 | | void |
553 | | IDBTransaction::DeleteObjectStore(int64_t aObjectStoreId) |
554 | 0 | { |
555 | 0 | AssertIsOnOwningThread(); |
556 | 0 | MOZ_ASSERT(aObjectStoreId); |
557 | 0 | MOZ_ASSERT(VERSION_CHANGE == mMode); |
558 | 0 | MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor); |
559 | 0 | MOZ_ASSERT(IsOpen()); |
560 | 0 |
|
561 | 0 | MOZ_ALWAYS_TRUE(mBackgroundActor.mVersionChangeBackgroundActor-> |
562 | 0 | SendDeleteObjectStore(aObjectStoreId)); |
563 | 0 |
|
564 | 0 | for (uint32_t count = mObjectStores.Length(), index = 0; |
565 | 0 | index < count; |
566 | 0 | index++) { |
567 | 0 | RefPtr<IDBObjectStore>& objectStore = mObjectStores[index]; |
568 | 0 |
|
569 | 0 | if (objectStore->Id() == aObjectStoreId) { |
570 | 0 | objectStore->NoteDeletion(); |
571 | 0 |
|
572 | 0 | RefPtr<IDBObjectStore>* deletedObjectStore = |
573 | 0 | mDeletedObjectStores.AppendElement(); |
574 | 0 | deletedObjectStore->swap(mObjectStores[index]); |
575 | 0 |
|
576 | 0 | mObjectStores.RemoveElementAt(index); |
577 | 0 | break; |
578 | 0 | } |
579 | 0 | } |
580 | 0 | } |
581 | | |
582 | | void |
583 | | IDBTransaction::RenameObjectStore(int64_t aObjectStoreId, |
584 | | const nsAString& aName) |
585 | 0 | { |
586 | 0 | AssertIsOnOwningThread(); |
587 | 0 | MOZ_ASSERT(aObjectStoreId); |
588 | 0 | MOZ_ASSERT(VERSION_CHANGE == mMode); |
589 | 0 | MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor); |
590 | 0 | MOZ_ASSERT(IsOpen()); |
591 | 0 |
|
592 | 0 | MOZ_ALWAYS_TRUE(mBackgroundActor.mVersionChangeBackgroundActor-> |
593 | 0 | SendRenameObjectStore(aObjectStoreId, nsString(aName))); |
594 | 0 | } |
595 | | |
596 | | void |
597 | | IDBTransaction::CreateIndex(IDBObjectStore* aObjectStore, |
598 | | const indexedDB::IndexMetadata& aMetadata) |
599 | 0 | { |
600 | 0 | AssertIsOnOwningThread(); |
601 | 0 | MOZ_ASSERT(aObjectStore); |
602 | 0 | MOZ_ASSERT(aMetadata.id()); |
603 | 0 | MOZ_ASSERT(VERSION_CHANGE == mMode); |
604 | 0 | MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor); |
605 | 0 | MOZ_ASSERT(IsOpen()); |
606 | 0 |
|
607 | 0 | MOZ_ALWAYS_TRUE(mBackgroundActor.mVersionChangeBackgroundActor-> |
608 | 0 | SendCreateIndex(aObjectStore->Id(), aMetadata)); |
609 | 0 | } |
610 | | |
611 | | void |
612 | | IDBTransaction::DeleteIndex(IDBObjectStore* aObjectStore, |
613 | | int64_t aIndexId) |
614 | 0 | { |
615 | 0 | AssertIsOnOwningThread(); |
616 | 0 | MOZ_ASSERT(aObjectStore); |
617 | 0 | MOZ_ASSERT(aIndexId); |
618 | 0 | MOZ_ASSERT(VERSION_CHANGE == mMode); |
619 | 0 | MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor); |
620 | 0 | MOZ_ASSERT(IsOpen()); |
621 | 0 |
|
622 | 0 | MOZ_ALWAYS_TRUE(mBackgroundActor.mVersionChangeBackgroundActor-> |
623 | 0 | SendDeleteIndex(aObjectStore->Id(), aIndexId)); |
624 | 0 | } |
625 | | |
626 | | void |
627 | | IDBTransaction::RenameIndex(IDBObjectStore* aObjectStore, |
628 | | int64_t aIndexId, |
629 | | const nsAString& aName) |
630 | 0 | { |
631 | 0 | AssertIsOnOwningThread(); |
632 | 0 | MOZ_ASSERT(aObjectStore); |
633 | 0 | MOZ_ASSERT(aIndexId); |
634 | 0 | MOZ_ASSERT(VERSION_CHANGE == mMode); |
635 | 0 | MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor); |
636 | 0 | MOZ_ASSERT(IsOpen()); |
637 | 0 |
|
638 | 0 | MOZ_ALWAYS_TRUE(mBackgroundActor.mVersionChangeBackgroundActor-> |
639 | 0 | SendRenameIndex(aObjectStore->Id(), |
640 | 0 | aIndexId, |
641 | 0 | nsString(aName))); |
642 | 0 | } |
643 | | |
644 | | void |
645 | | IDBTransaction::AbortInternal(nsresult aAbortCode, |
646 | | already_AddRefed<DOMException> aError) |
647 | 0 | { |
648 | 0 | AssertIsOnOwningThread(); |
649 | 0 | MOZ_ASSERT(NS_FAILED(aAbortCode)); |
650 | 0 | MOZ_ASSERT(!IsCommittingOrDone()); |
651 | 0 |
|
652 | 0 | RefPtr<DOMException> error = aError; |
653 | 0 |
|
654 | 0 | const bool isVersionChange = mMode == VERSION_CHANGE; |
655 | 0 | const bool isInvalidated = mDatabase->IsInvalidated(); |
656 | 0 | bool needToSendAbort = mReadyState == INITIAL; |
657 | 0 |
|
658 | 0 | mAbortCode = aAbortCode; |
659 | 0 | mReadyState = DONE; |
660 | 0 | mError = error.forget(); |
661 | 0 |
|
662 | 0 | if (isVersionChange) { |
663 | 0 | // If a version change transaction is aborted, we must revert the world |
664 | 0 | // back to its previous state unless we're being invalidated after the |
665 | 0 | // transaction already completed. |
666 | 0 | if (!isInvalidated) { |
667 | 0 | mDatabase->RevertToPreviousState(); |
668 | 0 | } |
669 | 0 |
|
670 | 0 | // We do the reversion only for the mObjectStores/mDeletedObjectStores but |
671 | 0 | // not for the mIndexes/mDeletedIndexes of each IDBObjectStore because it's |
672 | 0 | // time-consuming(O(m*n)) and mIndexes/mDeletedIndexes won't be used anymore |
673 | 0 | // in IDBObjectStore::(Create|Delete)Index() and IDBObjectStore::Index() in |
674 | 0 | // which all the executions are returned earlier by !transaction->IsOpen(). |
675 | 0 |
|
676 | 0 | const nsTArray<ObjectStoreSpec>& specArray = |
677 | 0 | mDatabase->Spec()->objectStores(); |
678 | 0 |
|
679 | 0 | if (specArray.IsEmpty()) { |
680 | 0 | mObjectStores.Clear(); |
681 | 0 | mDeletedObjectStores.Clear(); |
682 | 0 | } else { |
683 | 0 | nsTHashtable<nsUint64HashKey> validIds(specArray.Length()); |
684 | 0 |
|
685 | 0 | for (uint32_t specCount = specArray.Length(), specIndex = 0; |
686 | 0 | specIndex < specCount; |
687 | 0 | specIndex++) { |
688 | 0 | const int64_t objectStoreId = specArray[specIndex].metadata().id(); |
689 | 0 | MOZ_ASSERT(objectStoreId); |
690 | 0 |
|
691 | 0 | validIds.PutEntry(uint64_t(objectStoreId)); |
692 | 0 | } |
693 | 0 |
|
694 | 0 | for (uint32_t objCount = mObjectStores.Length(), objIndex = 0; |
695 | 0 | objIndex < objCount; |
696 | 0 | /* incremented conditionally */) { |
697 | 0 | const int64_t objectStoreId = mObjectStores[objIndex]->Id(); |
698 | 0 | MOZ_ASSERT(objectStoreId); |
699 | 0 |
|
700 | 0 | if (validIds.Contains(uint64_t(objectStoreId))) { |
701 | 0 | objIndex++; |
702 | 0 | } else { |
703 | 0 | mObjectStores.RemoveElementAt(objIndex); |
704 | 0 | objCount--; |
705 | 0 | } |
706 | 0 | } |
707 | 0 |
|
708 | 0 | if (!mDeletedObjectStores.IsEmpty()) { |
709 | 0 | for (uint32_t objCount = mDeletedObjectStores.Length(), objIndex = 0; |
710 | 0 | objIndex < objCount; |
711 | 0 | objIndex++) { |
712 | 0 | const int64_t objectStoreId = mDeletedObjectStores[objIndex]->Id(); |
713 | 0 | MOZ_ASSERT(objectStoreId); |
714 | 0 |
|
715 | 0 | if (validIds.Contains(uint64_t(objectStoreId))) { |
716 | 0 | RefPtr<IDBObjectStore>* objectStore = |
717 | 0 | mObjectStores.AppendElement(); |
718 | 0 | objectStore->swap(mDeletedObjectStores[objIndex]); |
719 | 0 | } |
720 | 0 | } |
721 | 0 | mDeletedObjectStores.Clear(); |
722 | 0 | } |
723 | 0 | } |
724 | 0 | } |
725 | 0 |
|
726 | 0 | // Fire the abort event if there are no outstanding requests. Otherwise the |
727 | 0 | // abort event will be fired when all outstanding requests finish. |
728 | 0 | if (needToSendAbort) { |
729 | 0 | SendAbort(aAbortCode); |
730 | 0 | } |
731 | 0 |
|
732 | 0 | if (isVersionChange) { |
733 | 0 | mDatabase->Close(); |
734 | 0 | } |
735 | 0 | } |
736 | | |
737 | | void |
738 | | IDBTransaction::Abort(IDBRequest* aRequest) |
739 | 0 | { |
740 | 0 | AssertIsOnOwningThread(); |
741 | 0 | MOZ_ASSERT(aRequest); |
742 | 0 |
|
743 | 0 | if (IsCommittingOrDone()) { |
744 | 0 | // Already started (and maybe finished) the commit or abort so there is |
745 | 0 | // nothing to do here. |
746 | 0 | return; |
747 | 0 | } |
748 | 0 | |
749 | 0 | ErrorResult rv; |
750 | 0 | RefPtr<DOMException> error = aRequest->GetError(rv); |
751 | 0 |
|
752 | 0 | AbortInternal(aRequest->GetErrorCode(), error.forget()); |
753 | 0 | } |
754 | | |
755 | | void |
756 | | IDBTransaction::Abort(nsresult aErrorCode) |
757 | 0 | { |
758 | 0 | AssertIsOnOwningThread(); |
759 | 0 |
|
760 | 0 | if (IsCommittingOrDone()) { |
761 | 0 | // Already started (and maybe finished) the commit or abort so there is |
762 | 0 | // nothing to do here. |
763 | 0 | return; |
764 | 0 | } |
765 | 0 | |
766 | 0 | RefPtr<DOMException> error = DOMException::Create(aErrorCode); |
767 | 0 | AbortInternal(aErrorCode, error.forget()); |
768 | 0 | } |
769 | | |
770 | | void |
771 | | IDBTransaction::Abort(ErrorResult& aRv) |
772 | 0 | { |
773 | 0 | AssertIsOnOwningThread(); |
774 | 0 |
|
775 | 0 | if (IsCommittingOrDone()) { |
776 | 0 | aRv = NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; |
777 | 0 | return; |
778 | 0 | } |
779 | 0 | |
780 | 0 | AbortInternal(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR, nullptr); |
781 | 0 |
|
782 | 0 | MOZ_ASSERT(!mAbortedByScript); |
783 | 0 | mAbortedByScript = true; |
784 | 0 | } |
785 | | |
786 | | void |
787 | | IDBTransaction::FireCompleteOrAbortEvents(nsresult aResult) |
788 | 0 | { |
789 | 0 | AssertIsOnOwningThread(); |
790 | 0 | MOZ_ASSERT(!mFiredCompleteOrAbort); |
791 | 0 |
|
792 | 0 | mReadyState = DONE; |
793 | 0 |
|
794 | | #ifdef DEBUG |
795 | | mFiredCompleteOrAbort = true; |
796 | | #endif |
797 | |
|
798 | 0 | // Make sure we drop the WorkerRef when this function completes. |
799 | 0 | auto scopeExit = MakeScopeExit([&] { |
800 | 0 | mWorkerRef = nullptr; |
801 | 0 | }); |
802 | 0 |
|
803 | 0 | RefPtr<Event> event; |
804 | 0 | if (NS_SUCCEEDED(aResult)) { |
805 | 0 | event = CreateGenericEvent(this, |
806 | 0 | nsDependentString(kCompleteEventType), |
807 | 0 | eDoesNotBubble, |
808 | 0 | eNotCancelable); |
809 | 0 | MOZ_ASSERT(event); |
810 | 0 | } else { |
811 | 0 | if (aResult == NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR) { |
812 | 0 | mDatabase->SetQuotaExceeded(); |
813 | 0 | } |
814 | 0 |
|
815 | 0 | if (!mError && !mAbortedByScript) { |
816 | 0 | mError = DOMException::Create(aResult); |
817 | 0 | } |
818 | 0 |
|
819 | 0 | event = CreateGenericEvent(this, |
820 | 0 | nsDependentString(kAbortEventType), |
821 | 0 | eDoesBubble, |
822 | 0 | eNotCancelable); |
823 | 0 | MOZ_ASSERT(event); |
824 | 0 | } |
825 | 0 |
|
826 | 0 | if (NS_SUCCEEDED(mAbortCode)) { |
827 | 0 | IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld]: " |
828 | 0 | "Firing 'complete' event", |
829 | 0 | "IndexedDB %s: C T[%lld]: IDBTransaction 'complete' event", |
830 | 0 | IDB_LOG_ID_STRING(), |
831 | 0 | mLoggingSerialNumber); |
832 | 0 | } else { |
833 | 0 | IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld]: " |
834 | 0 | "Firing 'abort' event with error 0x%x", |
835 | 0 | "IndexedDB %s: C T[%lld]: IDBTransaction 'abort' event (0x%x)", |
836 | 0 | IDB_LOG_ID_STRING(), |
837 | 0 | mLoggingSerialNumber, |
838 | 0 | mAbortCode); |
839 | 0 | } |
840 | 0 |
|
841 | 0 | IgnoredErrorResult rv; |
842 | 0 | DispatchEvent(*event, rv); |
843 | 0 | if (rv.Failed()) { |
844 | 0 | NS_WARNING("DispatchEvent failed!"); |
845 | 0 | } |
846 | 0 |
|
847 | 0 | // Normally, we note inactive transaction here instead of |
848 | 0 | // IDBTransaction::ClearBackgroundActor() because here is the earliest place |
849 | 0 | // to know that it becomes non-blocking to allow the scheduler to start the |
850 | 0 | // preemption as soon as it can. |
851 | 0 | // Note: If the IDBTransaction object is held by the script, |
852 | 0 | // ClearBackgroundActor() will be done in ~IDBTransaction() until garbage |
853 | 0 | // collected after its window is closed which prevents us to preempt its |
854 | 0 | // window immediately after committed. |
855 | 0 | MaybeNoteInactiveTransaction(); |
856 | 0 | } |
857 | | |
858 | | int64_t |
859 | | IDBTransaction::NextObjectStoreId() |
860 | 0 | { |
861 | 0 | AssertIsOnOwningThread(); |
862 | 0 | MOZ_ASSERT(VERSION_CHANGE == mMode); |
863 | 0 |
|
864 | 0 | return mNextObjectStoreId++; |
865 | 0 | } |
866 | | |
867 | | int64_t |
868 | | IDBTransaction::NextIndexId() |
869 | 0 | { |
870 | 0 | AssertIsOnOwningThread(); |
871 | 0 | MOZ_ASSERT(VERSION_CHANGE == mMode); |
872 | 0 |
|
873 | 0 | return mNextIndexId++; |
874 | 0 | } |
875 | | |
876 | | nsPIDOMWindowInner* |
877 | | IDBTransaction::GetParentObject() const |
878 | 0 | { |
879 | 0 | AssertIsOnOwningThread(); |
880 | 0 |
|
881 | 0 | return mDatabase->GetParentObject(); |
882 | 0 | } |
883 | | |
884 | | IDBTransactionMode |
885 | | IDBTransaction::GetMode(ErrorResult& aRv) const |
886 | 0 | { |
887 | 0 | AssertIsOnOwningThread(); |
888 | 0 |
|
889 | 0 | switch (mMode) { |
890 | 0 | case READ_ONLY: |
891 | 0 | return IDBTransactionMode::Readonly; |
892 | 0 |
|
893 | 0 | case READ_WRITE: |
894 | 0 | return IDBTransactionMode::Readwrite; |
895 | 0 |
|
896 | 0 | case READ_WRITE_FLUSH: |
897 | 0 | return IDBTransactionMode::Readwriteflush; |
898 | 0 |
|
899 | 0 | case CLEANUP: |
900 | 0 | return IDBTransactionMode::Cleanup; |
901 | 0 |
|
902 | 0 | case VERSION_CHANGE: |
903 | 0 | return IDBTransactionMode::Versionchange; |
904 | 0 |
|
905 | 0 | case MODE_INVALID: |
906 | 0 | default: |
907 | 0 | MOZ_CRASH("Bad mode!"); |
908 | 0 | } |
909 | 0 | } |
910 | | |
911 | | DOMException* |
912 | | IDBTransaction::GetError() const |
913 | 0 | { |
914 | 0 | AssertIsOnOwningThread(); |
915 | 0 |
|
916 | 0 | return mError; |
917 | 0 | } |
918 | | |
919 | | already_AddRefed<DOMStringList> |
920 | | IDBTransaction::ObjectStoreNames() const |
921 | 0 | { |
922 | 0 | AssertIsOnOwningThread(); |
923 | 0 |
|
924 | 0 | if (mMode == IDBTransaction::VERSION_CHANGE) { |
925 | 0 | return mDatabase->ObjectStoreNames(); |
926 | 0 | } |
927 | 0 | |
928 | 0 | RefPtr<DOMStringList> list = new DOMStringList(); |
929 | 0 | list->StringArray() = mObjectStoreNames; |
930 | 0 | return list.forget(); |
931 | 0 | } |
932 | | |
933 | | already_AddRefed<IDBObjectStore> |
934 | | IDBTransaction::ObjectStore(const nsAString& aName, ErrorResult& aRv) |
935 | 0 | { |
936 | 0 | AssertIsOnOwningThread(); |
937 | 0 |
|
938 | 0 | if (IsCommittingOrDone()) { |
939 | 0 | aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); |
940 | 0 | return nullptr; |
941 | 0 | } |
942 | 0 | |
943 | 0 | const ObjectStoreSpec* spec = nullptr; |
944 | 0 |
|
945 | 0 | if (IDBTransaction::VERSION_CHANGE == mMode || |
946 | 0 | mObjectStoreNames.Contains(aName)) { |
947 | 0 | const nsTArray<ObjectStoreSpec>& objectStores = |
948 | 0 | mDatabase->Spec()->objectStores(); |
949 | 0 |
|
950 | 0 | for (uint32_t count = objectStores.Length(), index = 0; |
951 | 0 | index < count; |
952 | 0 | index++) { |
953 | 0 | const ObjectStoreSpec& objectStore = objectStores[index]; |
954 | 0 | if (objectStore.metadata().name() == aName) { |
955 | 0 | spec = &objectStore; |
956 | 0 | break; |
957 | 0 | } |
958 | 0 | } |
959 | 0 | } |
960 | 0 |
|
961 | 0 | if (!spec) { |
962 | 0 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR); |
963 | 0 | return nullptr; |
964 | 0 | } |
965 | 0 | |
966 | 0 | const int64_t desiredId = spec->metadata().id(); |
967 | 0 |
|
968 | 0 | RefPtr<IDBObjectStore> objectStore; |
969 | 0 |
|
970 | 0 | for (uint32_t count = mObjectStores.Length(), index = 0; |
971 | 0 | index < count; |
972 | 0 | index++) { |
973 | 0 | RefPtr<IDBObjectStore>& existingObjectStore = mObjectStores[index]; |
974 | 0 |
|
975 | 0 | if (existingObjectStore->Id() == desiredId) { |
976 | 0 | objectStore = existingObjectStore; |
977 | 0 | break; |
978 | 0 | } |
979 | 0 | } |
980 | 0 |
|
981 | 0 | if (!objectStore) { |
982 | 0 | objectStore = IDBObjectStore::Create(this, *spec); |
983 | 0 | MOZ_ASSERT(objectStore); |
984 | 0 |
|
985 | 0 | mObjectStores.AppendElement(objectStore); |
986 | 0 | } |
987 | 0 |
|
988 | 0 | return objectStore.forget(); |
989 | 0 | } |
990 | | |
991 | | NS_IMPL_ADDREF_INHERITED(IDBTransaction, IDBWrapperCache) |
992 | | NS_IMPL_RELEASE_INHERITED(IDBTransaction, IDBWrapperCache) |
993 | | |
994 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBTransaction) |
995 | 0 | NS_INTERFACE_MAP_ENTRY(nsIRunnable) |
996 | 0 | NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache) |
997 | | |
998 | | NS_IMPL_CYCLE_COLLECTION_CLASS(IDBTransaction) |
999 | | |
1000 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBTransaction, |
1001 | 0 | IDBWrapperCache) |
1002 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDatabase) |
1003 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError) |
1004 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStores) |
1005 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeletedObjectStores) |
1006 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
1007 | | |
1008 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBTransaction, IDBWrapperCache) |
1009 | 0 | // Don't unlink mDatabase! |
1010 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mError) |
1011 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mObjectStores) |
1012 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeletedObjectStores) |
1013 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
1014 | | |
1015 | | JSObject* |
1016 | | IDBTransaction::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
1017 | 0 | { |
1018 | 0 | AssertIsOnOwningThread(); |
1019 | 0 |
|
1020 | 0 | return IDBTransaction_Binding::Wrap(aCx, this, aGivenProto); |
1021 | 0 | } |
1022 | | |
1023 | | void |
1024 | | IDBTransaction::GetEventTargetParent(EventChainPreVisitor& aVisitor) |
1025 | 0 | { |
1026 | 0 | AssertIsOnOwningThread(); |
1027 | 0 |
|
1028 | 0 | aVisitor.mCanHandle = true; |
1029 | 0 | aVisitor.SetParentTarget(mDatabase, false); |
1030 | 0 | } |
1031 | | |
1032 | | NS_IMETHODIMP |
1033 | | IDBTransaction::Run() |
1034 | 0 | { |
1035 | 0 | AssertIsOnOwningThread(); |
1036 | 0 |
|
1037 | 0 | // We're back at the event loop, no longer newborn. |
1038 | 0 | mCreating = false; |
1039 | 0 |
|
1040 | 0 | // Maybe commit if there were no requests generated. |
1041 | 0 | if (mReadyState == IDBTransaction::INITIAL) { |
1042 | 0 | mReadyState = DONE; |
1043 | 0 |
|
1044 | 0 | SendCommit(); |
1045 | 0 | } |
1046 | 0 |
|
1047 | 0 | return NS_OK; |
1048 | 0 | } |
1049 | | |
1050 | | } // namespace dom |
1051 | | } // namespace mozilla |