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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ActorsParent.h"
10 #include "SimpleDBCommon.h"
17 #include "ErrorList.h"
18 #include "MainThreadUtils.h"
19 #include "mozilla/AlreadyAddRefed.h"
20 #include "mozilla/Assertions.h"
21 #include "mozilla/Atomics.h"
22 #include "mozilla/DebugOnly.h"
23 #include "mozilla/Maybe.h"
24 #include "mozilla/Preferences.h"
25 #include "mozilla/RefPtr.h"
26 #include "mozilla/Result.h"
27 #include "mozilla/ResultExtensions.h"
28 #include "mozilla/SpinEventLoopUntil.h"
29 #include "mozilla/StaticPtr.h"
30 #include "mozilla/Unused.h"
31 #include "mozilla/Variant.h"
32 #include "mozilla/dom/PBackgroundSDBConnection.h"
33 #include "mozilla/dom/PBackgroundSDBConnectionParent.h"
34 #include "mozilla/dom/PBackgroundSDBRequestParent.h"
35 #include "mozilla/dom/ipc/IdType.h"
36 #include "mozilla/dom/quota/Client.h"
37 #include "mozilla/dom/quota/ClientImpl.h"
38 #include "mozilla/dom/quota/DirectoryLock.h"
39 #include "mozilla/dom/quota/FileStreams.h"
40 #include "mozilla/dom/quota/MemoryOutputStream.h"
41 #include "mozilla/dom/quota/QuotaCommon.h"
42 #include "mozilla/dom/quota/QuotaManager.h"
43 #include "mozilla/dom/quota/ResultExtensions.h"
44 #include "mozilla/dom/quota/UsageInfo.h"
45 #include "mozilla/ipc/BackgroundParent.h"
46 #include "mozilla/ipc/BackgroundUtils.h"
47 #include "mozilla/ipc/PBackgroundParent.h"
48 #include "mozilla/ipc/PBackgroundSharedTypes.h"
49 #include "mozilla/ipc/ProtocolUtils.h"
53 #include "nsIDirectoryEnumerator.h"
54 #include "nsIEventTarget.h"
56 #include "nsIFileStreams.h"
57 #include "nsIInputStream.h"
58 #include "nsIOutputStream.h"
59 #include "nsIRunnable.h"
60 #include "nsISeekableStream.h"
61 #include "nsISupports.h"
62 #include "nsIThread.h"
63 #include "nsLiteralString.h"
65 #include "nsStringFwd.h"
66 #include "nsStringStream.h"
68 #include "nsTLiteralString.h"
69 #include "nsTStringRepr.h"
70 #include "nsThreadUtils.h"
74 namespace mozilla::dom
{
76 using namespace mozilla::dom::quota
;
77 using namespace mozilla::ipc
;
81 /*******************************************************************************
83 ******************************************************************************/
85 const uint32_t kCopyBufferSize
= 32768;
87 constexpr auto kSDBSuffix
= u
".sdb"_ns
;
89 /*******************************************************************************
90 * Actor class declarations
91 ******************************************************************************/
93 class StreamHelper final
: public Runnable
{
94 nsCOMPtr
<nsIEventTarget
> mOwningEventTarget
;
95 nsCOMPtr
<nsIFileStream
> mFileStream
;
96 nsCOMPtr
<nsIRunnable
> mCallback
;
99 StreamHelper(nsIFileStream
* aFileStream
, nsIRunnable
* aCallback
);
104 ~StreamHelper() override
;
106 void RunOnBackgroundThread();
108 void RunOnIOThread();
113 class Connection final
: public PBackgroundSDBConnectionParent
{
114 RefPtr
<DirectoryLock
> mDirectoryLock
;
115 nsCOMPtr
<nsIFileStream
> mFileStream
;
116 const PrincipalInfo mPrincipalInfo
;
120 PersistenceType mPersistenceType
;
121 bool mRunningRequest
;
123 bool mAllowedToClose
;
124 bool mActorDestroyed
;
127 Connection(PersistenceType aPersistenceType
,
128 const PrincipalInfo
& aPrincipalInfo
);
130 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::Connection
)
132 Maybe
<DirectoryLock
&> MaybeDirectoryLockRef() const {
133 AssertIsOnBackgroundThread();
135 return ToMaybeRef(mDirectoryLock
.get());
138 nsIFileStream
* GetFileStream() const {
139 AssertIsOnIOThread();
144 PersistenceType
GetPersistenceType() const { return mPersistenceType
; }
146 const PrincipalInfo
& GetPrincipalInfo() const {
147 MOZ_ASSERT(NS_IsMainThread());
149 return mPrincipalInfo
;
152 const nsCString
& Origin() const {
153 AssertIsOnBackgroundThread();
154 MOZ_ASSERT(!mOrigin
.IsEmpty());
159 const nsString
& Name() const {
160 AssertIsOnBackgroundThread();
161 MOZ_ASSERT(!mName
.IsEmpty());
168 void OnRequestFinished();
170 void OnOpen(const nsACString
& aOrigin
, const nsAString
& aName
,
171 already_AddRefed
<DirectoryLock
> aDirectoryLock
,
172 already_AddRefed
<nsIFileStream
> aFileStream
);
181 void MaybeCloseStream();
183 bool VerifyRequestParams(const SDBRequestParams
& aParams
) const;
186 virtual void ActorDestroy(ActorDestroyReason aWhy
) override
;
188 mozilla::ipc::IPCResult
RecvDeleteMe() override
;
190 virtual PBackgroundSDBRequestParent
* AllocPBackgroundSDBRequestParent(
191 const SDBRequestParams
& aParams
) override
;
193 virtual mozilla::ipc::IPCResult
RecvPBackgroundSDBRequestConstructor(
194 PBackgroundSDBRequestParent
* aActor
,
195 const SDBRequestParams
& aParams
) override
;
197 virtual bool DeallocPBackgroundSDBRequestParent(
198 PBackgroundSDBRequestParent
* aActor
) override
;
201 class ConnectionOperationBase
: public Runnable
,
202 public PBackgroundSDBRequestParent
{
203 nsCOMPtr
<nsIEventTarget
> mOwningEventTarget
;
204 RefPtr
<Connection
> mConnection
;
205 nsresult mResultCode
;
206 Atomic
<bool> mOperationMayProceed
;
207 bool mActorDestroyed
;
210 nsIEventTarget
* OwningEventTarget() const {
211 MOZ_ASSERT(mOwningEventTarget
);
213 return mOwningEventTarget
;
216 bool IsOnOwningThread() const {
217 MOZ_ASSERT(mOwningEventTarget
);
220 return NS_SUCCEEDED(mOwningEventTarget
->IsOnCurrentThread(¤t
)) &&
224 void AssertIsOnOwningThread() const {
225 MOZ_ASSERT(IsOnBackgroundThread());
226 MOZ_ASSERT(IsOnOwningThread());
229 Connection
* GetConnection() const {
230 MOZ_ASSERT(mConnection
);
235 nsresult
ResultCode() const { return mResultCode
; }
237 void MaybeSetFailureCode(nsresult aErrorCode
) {
238 MOZ_ASSERT(NS_FAILED(aErrorCode
));
240 if (NS_SUCCEEDED(mResultCode
)) {
241 mResultCode
= aErrorCode
;
245 // May be called on any thread, but you should call IsActorDestroyed() if
246 // you know you're on the background thread because it is slightly faster.
247 bool OperationMayProceed() const { return mOperationMayProceed
; }
249 bool IsActorDestroyed() const {
250 AssertIsOnOwningThread();
252 return mActorDestroyed
;
255 // May be overridden by subclasses if they need to perform work on the
256 // background thread before being dispatched but must always call the base
257 // class implementation. Returning false will kill the child actors and
261 virtual nsresult
Dispatch();
263 // This callback will be called on the background thread before releasing the
264 // final reference to this request object. Subclasses may perform any
265 // additional cleanup here but must always call the base class implementation.
266 virtual void Cleanup();
269 ConnectionOperationBase(Connection
* aConnection
)
270 : Runnable("dom::ConnectionOperationBase"),
271 mOwningEventTarget(GetCurrentEventTarget()),
272 mConnection(aConnection
),
274 mOperationMayProceed(true),
275 mActorDestroyed(false) {
276 AssertIsOnOwningThread();
279 ~ConnectionOperationBase() override
;
285 // Methods that subclasses must implement.
286 virtual nsresult
DoDatabaseWork(nsIFileStream
* aFileStream
) = 0;
288 // Subclasses use this override to set the IPDL response value.
289 virtual void GetResponse(SDBRequestResponse
& aResponse
) = 0;
291 // A method that subclasses may implement.
292 virtual void OnSuccess();
299 void ActorDestroy(ActorDestroyReason aWhy
) override
;
302 class OpenOp final
: public ConnectionOperationBase
,
303 public OpenDirectoryListener
{
305 // Just created on the PBackground thread, dispatched to the main thread.
306 // Next step is FinishOpen.
309 // Ensuring quota manager is created and opening directory on the
310 // PBackground thread. Next step is either SendingResults if quota manager
311 // is not available or DirectoryOpenPending if quota manager is available.
314 // Waiting for directory open allowed on the PBackground thread. The next
315 // step is either SendingResults if directory lock failed to acquire, or
316 // DatabaseWorkOpen if directory lock is acquired.
317 DirectoryOpenPending
,
319 // Waiting to do/doing work on the QuotaManager IO thread. Its next step is
323 // Waiting to send/sending results on the PBackground thread. Next step is
331 const SDBRequestOpenParams mParams
;
332 RefPtr
<DirectoryLock
> mDirectoryLock
;
333 nsCOMPtr
<nsIFileStream
> mFileStream
;
334 // XXX Consider changing this to ClientMetadata.
335 quota::OriginMetadata mOriginMetadata
;
337 bool mFileStreamOpen
;
340 OpenOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
342 nsresult
Dispatch() override
;
349 nsresult
FinishOpen();
351 nsresult
SendToIOThread();
353 nsresult
DatabaseWork();
355 void StreamClosedCallback();
357 // ConnectionOperationBase overrides
358 nsresult
DoDatabaseWork(nsIFileStream
* aFileStream
) override
;
360 void GetResponse(SDBRequestResponse
& aResponse
) override
;
362 void OnSuccess() override
;
364 void Cleanup() override
;
366 NS_DECL_ISUPPORTS_INHERITED
371 // OpenDirectoryListener overrides.
372 void DirectoryLockAcquired(DirectoryLock
* aLock
) override
;
374 void DirectoryLockFailed() override
;
377 class SeekOp final
: public ConnectionOperationBase
{
378 const SDBRequestSeekParams mParams
;
381 SeekOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
384 ~SeekOp() override
= default;
386 nsresult
DoDatabaseWork(nsIFileStream
* aFileStream
) override
;
388 void GetResponse(SDBRequestResponse
& aResponse
) override
;
391 class ReadOp final
: public ConnectionOperationBase
{
392 const SDBRequestReadParams mParams
;
394 RefPtr
<MemoryOutputStream
> mOutputStream
;
397 ReadOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
399 bool Init() override
;
402 ~ReadOp() override
= default;
404 nsresult
DoDatabaseWork(nsIFileStream
* aFileStream
) override
;
406 void GetResponse(SDBRequestResponse
& aResponse
) override
;
409 class WriteOp final
: public ConnectionOperationBase
{
410 const SDBRequestWriteParams mParams
;
412 nsCOMPtr
<nsIInputStream
> mInputStream
;
417 WriteOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
419 bool Init() override
;
422 ~WriteOp() override
= default;
424 nsresult
DoDatabaseWork(nsIFileStream
* aFileStream
) override
;
426 void GetResponse(SDBRequestResponse
& aResponse
) override
;
429 class CloseOp final
: public ConnectionOperationBase
{
431 explicit CloseOp(Connection
* aConnection
);
434 ~CloseOp() override
= default;
436 nsresult
DoDatabaseWork(nsIFileStream
* aFileStream
) override
;
438 void GetResponse(SDBRequestResponse
& aResponse
) override
;
440 void OnSuccess() override
;
443 /*******************************************************************************
444 * Other class declarations
445 ******************************************************************************/
447 class QuotaClient final
: public mozilla::dom::quota::Client
{
448 static QuotaClient
* sInstance
;
453 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(QuotaClient
, override
)
455 Type
GetType() override
;
457 Result
<UsageInfo
, nsresult
> InitOrigin(PersistenceType aPersistenceType
,
458 const OriginMetadata
& aOriginMetadata
,
459 const AtomicBool
& aCanceled
) override
;
461 nsresult
InitOriginWithoutTracking(PersistenceType aPersistenceType
,
462 const OriginMetadata
& aOriginMetadata
,
463 const AtomicBool
& aCanceled
) override
;
465 Result
<UsageInfo
, nsresult
> GetUsageForOrigin(
466 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
467 const AtomicBool
& aCanceled
) override
;
469 void OnOriginClearCompleted(PersistenceType aPersistenceType
,
470 const nsACString
& aOrigin
) override
;
472 void ReleaseIOThreadObjects() override
;
474 void AbortOperationsForLocks(
475 const DirectoryLockIdTable
& aDirectoryLockIds
) override
;
477 void AbortOperationsForProcess(ContentParentId aContentParentId
) override
;
479 void AbortAllOperations() override
;
481 void StartIdleMaintenance() override
;
483 void StopIdleMaintenance() override
;
486 ~QuotaClient() override
;
488 void InitiateShutdown() override
;
489 bool IsShutdownCompleted() const override
;
490 nsCString
GetShutdownStatus() const override
;
491 void ForceKillActors() override
;
492 void FinalizeShutdown() override
;
495 /*******************************************************************************
497 ******************************************************************************/
499 using ConnectionArray
= nsTArray
<NotNull
<RefPtr
<Connection
>>>;
501 StaticAutoPtr
<ConnectionArray
> gOpenConnections
;
503 template <typename Condition
>
504 void AllowToCloseConnectionsMatching(const Condition
& aCondition
) {
505 AssertIsOnBackgroundThread();
507 if (gOpenConnections
) {
508 for (const auto& connection
: *gOpenConnections
) {
509 if (aCondition(*connection
)) {
510 connection
->AllowToClose();
518 /*******************************************************************************
520 ******************************************************************************/
522 PBackgroundSDBConnectionParent
* AllocPBackgroundSDBConnectionParent(
523 const PersistenceType
& aPersistenceType
,
524 const PrincipalInfo
& aPrincipalInfo
) {
525 AssertIsOnBackgroundThread();
527 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
531 if (NS_WARN_IF(!IsValidPersistenceType(aPersistenceType
))) {
532 MOZ_CRASH_UNLESS_FUZZING();
536 if (NS_WARN_IF(aPrincipalInfo
.type() == PrincipalInfo::TNullPrincipalInfo
)) {
537 MOZ_CRASH_UNLESS_FUZZING();
541 if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(aPrincipalInfo
))) {
542 MOZ_CRASH_UNLESS_FUZZING();
546 RefPtr
<Connection
> actor
= new Connection(aPersistenceType
, aPrincipalInfo
);
548 return actor
.forget().take();
551 bool RecvPBackgroundSDBConnectionConstructor(
552 PBackgroundSDBConnectionParent
* aActor
,
553 const PersistenceType
& aPersistenceType
,
554 const PrincipalInfo
& aPrincipalInfo
) {
555 AssertIsOnBackgroundThread();
557 MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
562 bool DeallocPBackgroundSDBConnectionParent(
563 PBackgroundSDBConnectionParent
* aActor
) {
564 AssertIsOnBackgroundThread();
567 RefPtr
<Connection
> actor
= dont_AddRef(static_cast<Connection
*>(aActor
));
573 already_AddRefed
<mozilla::dom::quota::Client
> CreateQuotaClient() {
574 AssertIsOnBackgroundThread();
576 RefPtr
<QuotaClient
> client
= new QuotaClient();
577 return client
.forget();
580 } // namespace simpledb
582 /*******************************************************************************
584 ******************************************************************************/
586 StreamHelper::StreamHelper(nsIFileStream
* aFileStream
, nsIRunnable
* aCallback
)
587 : Runnable("dom::StreamHelper"),
588 mOwningEventTarget(GetCurrentEventTarget()),
589 mFileStream(aFileStream
),
590 mCallback(aCallback
) {
591 AssertIsOnBackgroundThread();
592 MOZ_ASSERT(aFileStream
);
593 MOZ_ASSERT(aCallback
);
596 StreamHelper::~StreamHelper() {
597 MOZ_ASSERT(!mFileStream
);
598 MOZ_ASSERT(!mCallback
);
601 void StreamHelper::AsyncClose() {
602 AssertIsOnBackgroundThread();
604 QuotaManager
* quotaManager
= QuotaManager::Get();
605 MOZ_ASSERT(quotaManager
);
608 quotaManager
->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL
));
611 void StreamHelper::RunOnBackgroundThread() {
612 AssertIsOnBackgroundThread();
614 nsCOMPtr
<nsIFileStream
> fileStream
;
615 mFileStream
.swap(fileStream
);
617 nsCOMPtr
<nsIRunnable
> callback
;
618 mCallback
.swap(callback
);
623 void StreamHelper::RunOnIOThread() {
624 AssertIsOnIOThread();
625 MOZ_ASSERT(mFileStream
);
627 nsCOMPtr
<nsIInputStream
> inputStream
= do_QueryInterface(mFileStream
);
628 MOZ_ASSERT(inputStream
);
630 nsresult rv
= inputStream
->Close();
631 Unused
<< NS_WARN_IF(NS_FAILED(rv
));
633 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
));
637 StreamHelper::Run() {
638 MOZ_ASSERT(mCallback
);
640 if (IsOnBackgroundThread()) {
641 RunOnBackgroundThread();
649 /*******************************************************************************
651 ******************************************************************************/
653 Connection::Connection(PersistenceType aPersistenceType
,
654 const PrincipalInfo
& aPrincipalInfo
)
655 : mPrincipalInfo(aPrincipalInfo
),
656 mPersistenceType(aPersistenceType
),
657 mRunningRequest(false),
659 mAllowedToClose(false),
660 mActorDestroyed(false) {
661 AssertIsOnBackgroundThread();
662 MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
665 Connection::~Connection() {
666 MOZ_ASSERT(!mRunningRequest
);
668 MOZ_ASSERT(mActorDestroyed
);
671 void Connection::OnNewRequest() {
672 AssertIsOnBackgroundThread();
673 MOZ_ASSERT(!mRunningRequest
);
675 mRunningRequest
= true;
678 void Connection::OnRequestFinished() {
679 AssertIsOnBackgroundThread();
680 MOZ_ASSERT(mRunningRequest
);
682 mRunningRequest
= false;
687 void Connection::OnOpen(const nsACString
& aOrigin
, const nsAString
& aName
,
688 already_AddRefed
<DirectoryLock
> aDirectoryLock
,
689 already_AddRefed
<nsIFileStream
> aFileStream
) {
690 AssertIsOnBackgroundThread();
691 MOZ_ASSERT(!aOrigin
.IsEmpty());
692 MOZ_ASSERT(!aName
.IsEmpty());
693 MOZ_ASSERT(mOrigin
.IsEmpty());
694 MOZ_ASSERT(mName
.IsEmpty());
695 MOZ_ASSERT(!mDirectoryLock
);
696 MOZ_ASSERT(!mFileStream
);
701 mDirectoryLock
= aDirectoryLock
;
702 mFileStream
= aFileStream
;
705 if (!gOpenConnections
) {
706 gOpenConnections
= new ConnectionArray();
709 gOpenConnections
->AppendElement(WrapNotNullUnchecked(this));
712 void Connection::OnClose() {
713 AssertIsOnBackgroundThread();
714 MOZ_ASSERT(!mOrigin
.IsEmpty());
715 MOZ_ASSERT(mDirectoryLock
);
716 MOZ_ASSERT(mFileStream
);
721 mDirectoryLock
= nullptr;
722 mFileStream
= nullptr;
725 MOZ_ASSERT(gOpenConnections
);
726 gOpenConnections
->RemoveElement(this);
728 if (gOpenConnections
->IsEmpty()) {
729 gOpenConnections
= nullptr;
732 if (mAllowedToClose
&& !mActorDestroyed
) {
733 Unused
<< SendClosed();
737 void Connection::AllowToClose() {
738 AssertIsOnBackgroundThread();
740 if (mAllowedToClose
) {
744 mAllowedToClose
= true;
746 if (!mActorDestroyed
) {
747 Unused
<< SendAllowToClose();
753 void Connection::MaybeCloseStream() {
754 AssertIsOnBackgroundThread();
756 if (!mRunningRequest
&& mOpen
&& mAllowedToClose
) {
757 nsCOMPtr
<nsIRunnable
> callback
= NewRunnableMethod(
758 "dom::Connection::OnClose", this, &Connection::OnClose
);
760 RefPtr
<StreamHelper
> helper
= new StreamHelper(mFileStream
, callback
);
761 helper
->AsyncClose();
765 bool Connection::VerifyRequestParams(const SDBRequestParams
& aParams
) const {
766 AssertIsOnBackgroundThread();
767 MOZ_ASSERT(aParams
.type() != SDBRequestParams::T__None
);
769 switch (aParams
.type()) {
770 case SDBRequestParams::TSDBRequestOpenParams
: {
771 if (NS_WARN_IF(mOpen
)) {
772 MOZ_CRASH_UNLESS_FUZZING();
779 case SDBRequestParams::TSDBRequestSeekParams
:
780 case SDBRequestParams::TSDBRequestReadParams
:
781 case SDBRequestParams::TSDBRequestWriteParams
:
782 case SDBRequestParams::TSDBRequestCloseParams
: {
783 if (NS_WARN_IF(!mOpen
)) {
784 MOZ_CRASH_UNLESS_FUZZING();
792 MOZ_CRASH("Should never get here!");
798 void Connection::ActorDestroy(ActorDestroyReason aWhy
) {
799 AssertIsOnBackgroundThread();
800 MOZ_ASSERT(!mActorDestroyed
);
802 mActorDestroyed
= true;
807 mozilla::ipc::IPCResult
Connection::RecvDeleteMe() {
808 AssertIsOnBackgroundThread();
809 MOZ_ASSERT(!mActorDestroyed
);
811 IProtocol
* mgr
= Manager();
812 if (!PBackgroundSDBConnectionParent::Send__delete__(this)) {
813 return IPC_FAIL_NO_REASON(mgr
);
819 PBackgroundSDBRequestParent
* Connection::AllocPBackgroundSDBRequestParent(
820 const SDBRequestParams
& aParams
) {
821 AssertIsOnBackgroundThread();
822 MOZ_ASSERT(aParams
.type() != SDBRequestParams::T__None
);
824 if (aParams
.type() == SDBRequestParams::TSDBRequestOpenParams
&&
825 NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
829 if (mAllowedToClose
) {
834 // Always verify parameters in DEBUG builds!
835 bool trustParams
= false;
837 PBackgroundParent
* backgroundActor
= Manager();
838 MOZ_ASSERT(backgroundActor
);
840 bool trustParams
= !BackgroundParent::IsOtherProcessActor(backgroundActor
);
843 if (NS_WARN_IF(!trustParams
&& !VerifyRequestParams(aParams
))) {
844 MOZ_CRASH_UNLESS_FUZZING();
848 if (NS_WARN_IF(mRunningRequest
)) {
849 MOZ_CRASH_UNLESS_FUZZING();
853 RefPtr
<ConnectionOperationBase
> actor
;
855 switch (aParams
.type()) {
856 case SDBRequestParams::TSDBRequestOpenParams
:
857 actor
= new OpenOp(this, aParams
);
860 case SDBRequestParams::TSDBRequestSeekParams
:
861 actor
= new SeekOp(this, aParams
);
864 case SDBRequestParams::TSDBRequestReadParams
:
865 actor
= new ReadOp(this, aParams
);
868 case SDBRequestParams::TSDBRequestWriteParams
:
869 actor
= new WriteOp(this, aParams
);
872 case SDBRequestParams::TSDBRequestCloseParams
:
873 actor
= new CloseOp(this);
877 MOZ_CRASH("Should never get here!");
880 // Transfer ownership to IPDL.
881 return actor
.forget().take();
884 mozilla::ipc::IPCResult
Connection::RecvPBackgroundSDBRequestConstructor(
885 PBackgroundSDBRequestParent
* aActor
, const SDBRequestParams
& aParams
) {
886 AssertIsOnBackgroundThread();
888 MOZ_ASSERT(aParams
.type() != SDBRequestParams::T__None
);
889 MOZ_ASSERT_IF(aParams
.type() == SDBRequestParams::TSDBRequestOpenParams
,
890 !QuotaClient::IsShuttingDownOnBackgroundThread());
891 MOZ_ASSERT(!mAllowedToClose
);
892 MOZ_ASSERT(!mRunningRequest
);
894 auto* op
= static_cast<ConnectionOperationBase
*>(aActor
);
896 if (NS_WARN_IF(!op
->Init())) {
898 return IPC_FAIL_NO_REASON(this);
901 if (NS_WARN_IF(NS_FAILED(op
->Dispatch()))) {
903 return IPC_FAIL_NO_REASON(this);
909 bool Connection::DeallocPBackgroundSDBRequestParent(
910 PBackgroundSDBRequestParent
* aActor
) {
911 AssertIsOnBackgroundThread();
914 // Transfer ownership back from IPDL.
915 RefPtr
<ConnectionOperationBase
> actor
=
916 dont_AddRef(static_cast<ConnectionOperationBase
*>(aActor
));
920 /*******************************************************************************
921 * ConnectionOperationBase
922 ******************************************************************************/
924 ConnectionOperationBase::~ConnectionOperationBase() {
927 "ConnectionOperationBase::Cleanup() was not called by a subclass!");
928 MOZ_ASSERT(mActorDestroyed
);
931 bool ConnectionOperationBase::Init() {
932 AssertIsOnBackgroundThread();
933 MOZ_ASSERT(mConnection
);
935 mConnection
->OnNewRequest();
940 nsresult
ConnectionOperationBase::Dispatch() {
941 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
942 IsActorDestroyed()) {
943 return NS_ERROR_ABORT
;
946 QuotaManager
* quotaManager
= QuotaManager::Get();
947 MOZ_ASSERT(quotaManager
);
949 nsresult rv
= quotaManager
->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL
);
950 if (NS_WARN_IF(NS_FAILED(rv
))) {
957 void ConnectionOperationBase::Cleanup() {
958 AssertIsOnOwningThread();
959 MOZ_ASSERT(mConnection
);
961 mConnection
->OnRequestFinished();
963 mConnection
= nullptr;
966 void ConnectionOperationBase::SendResults() {
967 AssertIsOnOwningThread();
969 if (IsActorDestroyed()) {
970 MaybeSetFailureCode(NS_ERROR_FAILURE
);
972 SDBRequestResponse response
;
974 if (NS_SUCCEEDED(mResultCode
)) {
975 GetResponse(response
);
977 MOZ_ASSERT(response
.type() != SDBRequestResponse::T__None
);
978 MOZ_ASSERT(response
.type() != SDBRequestResponse::Tnsresult
);
980 response
= mResultCode
;
983 Unused
<< PBackgroundSDBRequestParent::Send__delete__(this, response
);
985 if (NS_SUCCEEDED(mResultCode
)) {
993 void ConnectionOperationBase::DatabaseWork() {
994 AssertIsOnIOThread();
995 MOZ_ASSERT(NS_SUCCEEDED(mResultCode
));
997 if (!OperationMayProceed()) {
998 // The operation was canceled in some way, likely because the child process
1000 mResultCode
= NS_ERROR_ABORT
;
1002 nsIFileStream
* fileStream
= mConnection
->GetFileStream();
1003 MOZ_ASSERT(fileStream
);
1005 nsresult rv
= DoDatabaseWork(fileStream
);
1006 if (NS_FAILED(rv
)) {
1011 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
));
1014 void ConnectionOperationBase::OnSuccess() { AssertIsOnOwningThread(); }
1017 ConnectionOperationBase::Run() {
1018 if (IsOnBackgroundThread()) {
1027 void ConnectionOperationBase::ActorDestroy(ActorDestroyReason aWhy
) {
1028 AssertIsOnBackgroundThread();
1030 mOperationMayProceed
= false;
1031 mActorDestroyed
= true;
1034 OpenOp::OpenOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1035 : ConnectionOperationBase(aConnection
),
1036 mParams(aParams
.get_SDBRequestOpenParams()),
1037 mState(State::Initial
),
1038 mFileStreamOpen(false) {
1039 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestOpenParams
);
1043 MOZ_ASSERT(!mDirectoryLock
);
1044 MOZ_ASSERT(!mFileStream
);
1045 MOZ_ASSERT(!mFileStreamOpen
);
1046 MOZ_ASSERT_IF(OperationMayProceed(),
1047 mState
== State::Initial
|| mState
== State::Completed
);
1050 nsresult
OpenOp::Dispatch() {
1051 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
1056 nsresult
OpenOp::Open() {
1057 MOZ_ASSERT(NS_IsMainThread());
1058 MOZ_ASSERT(mState
== State::Initial
);
1060 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
1061 !OperationMayProceed()) {
1062 return NS_ERROR_ABORT
;
1065 if (NS_WARN_IF(!Preferences::GetBool(kPrefSimpleDBEnabled
, false))) {
1066 return NS_ERROR_UNEXPECTED
;
1069 PersistenceType persistenceType
= GetConnection()->GetPersistenceType();
1071 const PrincipalInfo
& principalInfo
= GetConnection()->GetPrincipalInfo();
1073 if (principalInfo
.type() == PrincipalInfo::TSystemPrincipalInfo
) {
1074 mOriginMetadata
= {QuotaManager::GetInfoForChrome(), persistenceType
};
1076 MOZ_ASSERT(principalInfo
.type() == PrincipalInfo::TContentPrincipalInfo
);
1078 QM_TRY_INSPECT(const auto& principal
,
1079 PrincipalInfoToPrincipal(principalInfo
));
1081 QM_TRY_UNWRAP(auto principalMetadata
,
1082 QuotaManager::GetInfoFromPrincipal(principal
));
1084 mOriginMetadata
= {std::move(principalMetadata
), persistenceType
};
1087 mState
= State::FinishOpen
;
1088 MOZ_ALWAYS_SUCCEEDS(OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL
));
1093 nsresult
OpenOp::FinishOpen() {
1094 AssertIsOnOwningThread();
1095 MOZ_ASSERT(!mOriginMetadata
.mOrigin
.IsEmpty());
1096 MOZ_ASSERT(!mDirectoryLock
);
1097 MOZ_ASSERT(mState
== State::FinishOpen
);
1099 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
1100 IsActorDestroyed()) {
1101 return NS_ERROR_ABORT
;
1104 if (gOpenConnections
) {
1105 for (const auto& connection
: *gOpenConnections
) {
1106 if (connection
->Origin() == mOriginMetadata
.mOrigin
&&
1107 connection
->Name() == mParams
.name()) {
1108 return NS_ERROR_STORAGE_BUSY
;
1113 QM_TRY(QuotaManager::EnsureCreated());
1115 // Open the directory
1116 MOZ_ASSERT(QuotaManager::Get());
1118 RefPtr
<DirectoryLock
> directoryLock
=
1119 QuotaManager::Get()->CreateDirectoryLock(
1120 GetConnection()->GetPersistenceType(), mOriginMetadata
,
1121 mozilla::dom::quota::Client::SDB
,
1122 /* aExclusive */ false);
1124 mState
= State::DirectoryOpenPending
;
1125 directoryLock
->Acquire(this);
1130 nsresult
OpenOp::SendToIOThread() {
1131 AssertIsOnOwningThread();
1132 MOZ_ASSERT(mState
== State::DirectoryOpenPending
);
1134 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
1135 IsActorDestroyed()) {
1136 return NS_ERROR_ABORT
;
1140 new FileStream(GetConnection()->GetPersistenceType(), mOriginMetadata
,
1141 mozilla::dom::quota::Client::SDB
);
1143 QuotaManager
* quotaManager
= QuotaManager::Get();
1144 MOZ_ASSERT(quotaManager
);
1146 // Must set this before dispatching otherwise we will race with the IO thread.
1147 mState
= State::DatabaseWorkOpen
;
1149 nsresult rv
= quotaManager
->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL
);
1150 if (NS_WARN_IF(NS_FAILED(rv
))) {
1157 nsresult
OpenOp::DatabaseWork() {
1158 AssertIsOnIOThread();
1159 MOZ_ASSERT(mState
== State::DatabaseWorkOpen
);
1160 MOZ_ASSERT(mFileStream
);
1161 MOZ_ASSERT(!mFileStreamOpen
);
1163 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
1164 !OperationMayProceed()) {
1165 return NS_ERROR_ABORT
;
1168 QuotaManager
* quotaManager
= QuotaManager::Get();
1169 MOZ_ASSERT(quotaManager
);
1171 QM_TRY(MOZ_TO_RESULT(quotaManager
->EnsureStorageIsInitialized()));
1174 const auto& dbDirectory
,
1175 ([persistenceType
= GetConnection()->GetPersistenceType(), "aManager
,
1177 -> mozilla::Result
<std::pair
<nsCOMPtr
<nsIFile
>, bool>, nsresult
> {
1178 if (persistenceType
== PERSISTENCE_TYPE_PERSISTENT
) {
1179 QM_TRY_RETURN(quotaManager
->EnsurePersistentOriginIsInitialized(
1184 MOZ_TO_RESULT(quotaManager
->EnsureTemporaryStorageIsInitialized()));
1185 QM_TRY_RETURN(quotaManager
->EnsureTemporaryOriginIsInitialized(
1186 persistenceType
, mOriginMetadata
));
1188 .map([](const auto& res
) { return res
.first
; })));
1191 dbDirectory
->Append(NS_LITERAL_STRING_FROM_CSTRING(SDB_DIRECTORY_NAME
));
1192 if (NS_WARN_IF(NS_FAILED(rv
))) {
1197 rv
= dbDirectory
->Exists(&exists
);
1198 if (NS_WARN_IF(NS_FAILED(rv
))) {
1203 rv
= dbDirectory
->Create(nsIFile::DIRECTORY_TYPE
, 0755);
1204 if (NS_WARN_IF(NS_FAILED(rv
))) {
1211 MOZ_ASSERT(NS_SUCCEEDED(dbDirectory
->IsDirectory(&isDirectory
)));
1212 MOZ_ASSERT(isDirectory
);
1216 nsCOMPtr
<nsIFile
> dbFile
;
1217 rv
= dbDirectory
->Clone(getter_AddRefs(dbFile
));
1218 if (NS_WARN_IF(NS_FAILED(rv
))) {
1222 rv
= dbFile
->Append(mParams
.name() + kSDBSuffix
);
1223 if (NS_WARN_IF(NS_FAILED(rv
))) {
1227 nsString databaseFilePath
;
1228 rv
= dbFile
->GetPath(databaseFilePath
);
1229 if (NS_WARN_IF(NS_FAILED(rv
))) {
1233 rv
= mFileStream
->Init(dbFile
, PR_RDWR
| PR_CREATE_FILE
, 0644, 0);
1234 if (NS_WARN_IF(NS_FAILED(rv
))) {
1238 mFileStreamOpen
= true;
1240 rv
= DoDatabaseWork(mFileStream
);
1241 if (NS_WARN_IF(NS_FAILED(rv
))) {
1245 // Must set mState before dispatching otherwise we will race with the owning
1247 mState
= State::SendingResults
;
1249 rv
= OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL
);
1250 if (NS_WARN_IF(NS_FAILED(rv
))) {
1257 void OpenOp::StreamClosedCallback() {
1258 AssertIsOnOwningThread();
1259 MOZ_ASSERT(NS_FAILED(ResultCode()));
1260 MOZ_ASSERT(mDirectoryLock
);
1261 MOZ_ASSERT(mFileStream
);
1262 MOZ_ASSERT(mFileStreamOpen
);
1264 mDirectoryLock
= nullptr;
1265 mFileStream
= nullptr;
1266 mFileStreamOpen
= false;
1269 nsresult
OpenOp::DoDatabaseWork(nsIFileStream
* aFileStream
) {
1270 AssertIsOnIOThread();
1275 void OpenOp::GetResponse(SDBRequestResponse
& aResponse
) {
1276 AssertIsOnOwningThread();
1278 aResponse
= SDBRequestOpenResponse();
1281 void OpenOp::OnSuccess() {
1282 AssertIsOnOwningThread();
1283 MOZ_ASSERT(NS_SUCCEEDED(ResultCode()));
1284 MOZ_ASSERT(!mOriginMetadata
.mOrigin
.IsEmpty());
1285 MOZ_ASSERT(mDirectoryLock
);
1286 MOZ_ASSERT(mFileStream
);
1287 MOZ_ASSERT(mFileStreamOpen
);
1289 RefPtr
<DirectoryLock
> directoryLock
;
1290 nsCOMPtr
<nsIFileStream
> fileStream
;
1292 mDirectoryLock
.swap(directoryLock
);
1293 mFileStream
.swap(fileStream
);
1294 mFileStreamOpen
= false;
1296 GetConnection()->OnOpen(mOriginMetadata
.mOrigin
, mParams
.name(),
1297 directoryLock
.forget(), fileStream
.forget());
1300 void OpenOp::Cleanup() {
1301 AssertIsOnOwningThread();
1302 MOZ_ASSERT_IF(mFileStreamOpen
, mFileStream
);
1304 if (mFileStream
&& mFileStreamOpen
) {
1305 // If we have an initialized file stream then the operation must have failed
1306 // and there must be a directory lock too.
1307 MOZ_ASSERT(NS_FAILED(ResultCode()));
1308 MOZ_ASSERT(mDirectoryLock
);
1310 // We must close the stream on the I/O thread before releasing it on this
1311 // thread. The directory lock can't be released either.
1312 nsCOMPtr
<nsIRunnable
> callback
=
1313 NewRunnableMethod("dom::OpenOp::StreamClosedCallback", this,
1314 &OpenOp::StreamClosedCallback
);
1316 RefPtr
<StreamHelper
> helper
= new StreamHelper(mFileStream
, callback
);
1317 helper
->AsyncClose();
1319 MOZ_ASSERT(!mFileStreamOpen
);
1321 mDirectoryLock
= nullptr;
1322 mFileStream
= nullptr;
1325 ConnectionOperationBase::Cleanup();
1328 NS_IMPL_ISUPPORTS_INHERITED0(OpenOp
, ConnectionOperationBase
)
1335 case State::Initial
:
1339 case State::FinishOpen
:
1343 case State::DatabaseWorkOpen
:
1344 rv
= DatabaseWork();
1347 case State::SendingResults
:
1352 MOZ_CRASH("Bad state!");
1355 if (NS_WARN_IF(NS_FAILED(rv
)) && mState
!= State::SendingResults
) {
1356 MaybeSetFailureCode(rv
);
1358 // Must set mState before dispatching otherwise we will race with the owning
1360 mState
= State::SendingResults
;
1362 if (IsOnOwningThread()) {
1365 MOZ_ALWAYS_SUCCEEDS(
1366 OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL
));
1373 void OpenOp::DirectoryLockAcquired(DirectoryLock
* aLock
) {
1374 AssertIsOnOwningThread();
1375 MOZ_ASSERT(mState
== State::DirectoryOpenPending
);
1376 MOZ_ASSERT(!mDirectoryLock
);
1378 mDirectoryLock
= aLock
;
1380 nsresult rv
= SendToIOThread();
1381 if (NS_WARN_IF(NS_FAILED(rv
))) {
1382 MaybeSetFailureCode(rv
);
1384 // The caller holds a strong reference to us, no need for a self reference
1385 // before calling Run().
1387 mState
= State::SendingResults
;
1388 MOZ_ALWAYS_SUCCEEDS(Run());
1394 void OpenOp::DirectoryLockFailed() {
1395 AssertIsOnOwningThread();
1396 MOZ_ASSERT(mState
== State::DirectoryOpenPending
);
1397 MOZ_ASSERT(!mDirectoryLock
);
1399 MaybeSetFailureCode(NS_ERROR_FAILURE
);
1401 // The caller holds a strong reference to us, no need for a self reference
1402 // before calling Run().
1404 mState
= State::SendingResults
;
1405 MOZ_ALWAYS_SUCCEEDS(Run());
1408 SeekOp::SeekOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1409 : ConnectionOperationBase(aConnection
),
1410 mParams(aParams
.get_SDBRequestSeekParams()) {
1411 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestSeekParams
);
1414 nsresult
SeekOp::DoDatabaseWork(nsIFileStream
* aFileStream
) {
1415 AssertIsOnIOThread();
1416 MOZ_ASSERT(aFileStream
);
1418 nsCOMPtr
<nsISeekableStream
> seekableStream
= do_QueryInterface(aFileStream
);
1419 MOZ_ASSERT(seekableStream
);
1422 seekableStream
->Seek(nsISeekableStream::NS_SEEK_SET
, mParams
.offset());
1424 if (NS_WARN_IF(NS_FAILED(rv
))) {
1431 void SeekOp::GetResponse(SDBRequestResponse
& aResponse
) {
1432 aResponse
= SDBRequestSeekResponse();
1435 ReadOp::ReadOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1436 : ConnectionOperationBase(aConnection
),
1437 mParams(aParams
.get_SDBRequestReadParams()) {
1438 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestReadParams
);
1441 bool ReadOp::Init() {
1442 AssertIsOnOwningThread();
1444 if (NS_WARN_IF(!ConnectionOperationBase::Init())) {
1448 mOutputStream
= MemoryOutputStream::Create(mParams
.size());
1449 if (NS_WARN_IF(!mOutputStream
)) {
1456 nsresult
ReadOp::DoDatabaseWork(nsIFileStream
* aFileStream
) {
1457 AssertIsOnIOThread();
1458 MOZ_ASSERT(aFileStream
);
1460 nsCOMPtr
<nsIInputStream
> inputStream
= do_QueryInterface(aFileStream
);
1461 MOZ_ASSERT(inputStream
);
1465 uint64_t offset
= 0;
1468 char copyBuffer
[kCopyBufferSize
];
1470 uint64_t max
= mParams
.size() - offset
;
1475 uint32_t count
= sizeof(copyBuffer
);
1481 rv
= inputStream
->Read(copyBuffer
, count
, &numRead
);
1482 if (NS_WARN_IF(NS_FAILED(rv
))) {
1491 rv
= mOutputStream
->Write(copyBuffer
, numRead
, &numWrite
);
1492 if (NS_WARN_IF(NS_FAILED(rv
))) {
1496 if (NS_WARN_IF(numWrite
!= numRead
)) {
1497 return NS_ERROR_FAILURE
;
1503 MOZ_ASSERT(offset
== mParams
.size());
1505 MOZ_ALWAYS_SUCCEEDS(mOutputStream
->Close());
1510 void ReadOp::GetResponse(SDBRequestResponse
& aResponse
) {
1511 aResponse
= SDBRequestReadResponse(mOutputStream
->Data());
1514 WriteOp::WriteOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1515 : ConnectionOperationBase(aConnection
),
1516 mParams(aParams
.get_SDBRequestWriteParams()),
1518 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestWriteParams
);
1521 bool WriteOp::Init() {
1522 AssertIsOnOwningThread();
1524 if (NS_WARN_IF(!ConnectionOperationBase::Init())) {
1528 const nsCString
& string
= mParams
.data();
1530 nsCOMPtr
<nsIInputStream
> inputStream
;
1531 nsresult rv
= NS_NewCStringInputStream(getter_AddRefs(inputStream
), string
);
1532 if (NS_WARN_IF(NS_FAILED(rv
))) {
1536 mInputStream
= std::move(inputStream
);
1537 mSize
= string
.Length();
1542 nsresult
WriteOp::DoDatabaseWork(nsIFileStream
* aFileStream
) {
1543 AssertIsOnIOThread();
1544 MOZ_ASSERT(aFileStream
);
1546 nsCOMPtr
<nsIOutputStream
> outputStream
= do_QueryInterface(aFileStream
);
1547 MOZ_ASSERT(outputStream
);
1552 char copyBuffer
[kCopyBufferSize
];
1555 rv
= mInputStream
->Read(copyBuffer
, sizeof(copyBuffer
), &numRead
);
1556 if (NS_WARN_IF(NS_FAILED(rv
))) {
1565 rv
= outputStream
->Write(copyBuffer
, numRead
, &numWrite
);
1566 if (NS_WARN_IF(NS_FAILED(rv
))) {
1570 if (NS_WARN_IF(numWrite
!= numRead
)) {
1571 return NS_ERROR_FAILURE
;
1575 MOZ_ALWAYS_SUCCEEDS(mInputStream
->Close());
1580 void WriteOp::GetResponse(SDBRequestResponse
& aResponse
) {
1581 aResponse
= SDBRequestWriteResponse();
1584 CloseOp::CloseOp(Connection
* aConnection
)
1585 : ConnectionOperationBase(aConnection
) {}
1587 nsresult
CloseOp::DoDatabaseWork(nsIFileStream
* aFileStream
) {
1588 AssertIsOnIOThread();
1589 MOZ_ASSERT(aFileStream
);
1591 nsCOMPtr
<nsIInputStream
> inputStream
= do_QueryInterface(aFileStream
);
1592 MOZ_ASSERT(inputStream
);
1594 nsresult rv
= inputStream
->Close();
1595 if (NS_WARN_IF(NS_FAILED(rv
))) {
1602 void CloseOp::GetResponse(SDBRequestResponse
& aResponse
) {
1603 aResponse
= SDBRequestCloseResponse();
1606 void CloseOp::OnSuccess() {
1607 AssertIsOnOwningThread();
1609 GetConnection()->OnClose();
1612 /*******************************************************************************
1614 ******************************************************************************/
1616 QuotaClient
* QuotaClient::sInstance
= nullptr;
1618 QuotaClient::QuotaClient() {
1619 AssertIsOnBackgroundThread();
1620 MOZ_ASSERT(!sInstance
, "We expect this to be a singleton!");
1625 QuotaClient::~QuotaClient() {
1626 AssertIsOnBackgroundThread();
1627 MOZ_ASSERT(sInstance
== this, "We expect this to be a singleton!");
1629 sInstance
= nullptr;
1632 mozilla::dom::quota::Client::Type
QuotaClient::GetType() {
1633 return QuotaClient::SDB
;
1636 Result
<UsageInfo
, nsresult
> QuotaClient::InitOrigin(
1637 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
1638 const AtomicBool
& aCanceled
) {
1639 AssertIsOnIOThread();
1641 return GetUsageForOrigin(aPersistenceType
, aOriginMetadata
, aCanceled
);
1644 nsresult
QuotaClient::InitOriginWithoutTracking(
1645 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
1646 const AtomicBool
& aCanceled
) {
1647 AssertIsOnIOThread();
1652 Result
<UsageInfo
, nsresult
> QuotaClient::GetUsageForOrigin(
1653 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
1654 const AtomicBool
& aCanceled
) {
1655 AssertIsOnIOThread();
1657 QuotaManager
* quotaManager
= QuotaManager::Get();
1658 MOZ_ASSERT(quotaManager
);
1660 QM_TRY_UNWRAP(auto directory
, quotaManager
->GetDirectoryForOrigin(
1661 aPersistenceType
, aOriginMetadata
.mOrigin
));
1663 MOZ_ASSERT(directory
);
1666 directory
->Append(NS_LITERAL_STRING_FROM_CSTRING(SDB_DIRECTORY_NAME
));
1667 if (NS_WARN_IF(NS_FAILED(rv
))) {
1671 DebugOnly
<bool> exists
;
1672 MOZ_ASSERT(NS_SUCCEEDED(directory
->Exists(&exists
)) && exists
);
1674 QM_TRY_RETURN(ReduceEachFileAtomicCancelable(
1675 *directory
, aCanceled
, UsageInfo
{},
1676 [](UsageInfo usageInfo
,
1677 const nsCOMPtr
<nsIFile
>& file
) -> Result
<UsageInfo
, nsresult
> {
1678 QM_TRY_INSPECT(const bool& isDirectory
,
1679 MOZ_TO_RESULT_INVOKE_MEMBER(file
, IsDirectory
));
1682 Unused
<< WARN_IF_FILE_IS_UNKNOWN(*file
);
1687 QM_TRY(MOZ_TO_RESULT(file
->GetLeafName(leafName
)));
1689 if (StringEndsWith(leafName
, kSDBSuffix
)) {
1690 QM_TRY_INSPECT(const int64_t& fileSize
,
1691 MOZ_TO_RESULT_INVOKE_MEMBER(file
, GetFileSize
));
1693 MOZ_ASSERT(fileSize
>= 0);
1696 UsageInfo
{DatabaseUsageType(Some(uint64_t(fileSize
)))};
1699 Unused
<< WARN_IF_FILE_IS_UNKNOWN(*file
);
1705 void QuotaClient::OnOriginClearCompleted(PersistenceType aPersistenceType
,
1706 const nsACString
& aOrigin
) {
1707 AssertIsOnIOThread();
1710 void QuotaClient::ReleaseIOThreadObjects() { AssertIsOnIOThread(); }
1712 void QuotaClient::AbortOperationsForLocks(
1713 const DirectoryLockIdTable
& aDirectoryLockIds
) {
1714 AssertIsOnBackgroundThread();
1716 AllowToCloseConnectionsMatching([&aDirectoryLockIds
](const auto& connection
) {
1717 // If the connections is registered in gOpenConnections then it must have
1718 // a directory lock.
1719 return IsLockForObjectContainedInLockTable(connection
, aDirectoryLockIds
);
1723 void QuotaClient::AbortOperationsForProcess(ContentParentId aContentParentId
) {
1724 AssertIsOnBackgroundThread();
1727 void QuotaClient::AbortAllOperations() {
1728 AssertIsOnBackgroundThread();
1730 AllowToCloseConnectionsMatching([](const auto&) { return true; });
1733 void QuotaClient::StartIdleMaintenance() { AssertIsOnBackgroundThread(); }
1735 void QuotaClient::StopIdleMaintenance() { AssertIsOnBackgroundThread(); }
1737 void QuotaClient::InitiateShutdown() {
1738 AssertIsOnBackgroundThread();
1740 if (gOpenConnections
) {
1741 for (const auto& connection
: *gOpenConnections
) {
1742 connection
->AllowToClose();
1747 bool QuotaClient::IsShutdownCompleted() const { return !gOpenConnections
; }
1749 void QuotaClient::ForceKillActors() {
1750 // Currently we don't implement killing actors (are there any to kill here?).
1753 nsCString
QuotaClient::GetShutdownStatus() const {
1754 // XXX Gather information here.
1755 return "To be implemented"_ns
;
1758 void QuotaClient::FinalizeShutdown() {
1759 // Nothing to do here.
1762 } // namespace mozilla::dom