Bug 1803062 - Read, write and close streams on the task queue; r=dom-storage-reviewers,jesup

This patch adds the last required piece for having fully async close of
FileSystemSyncAccessHandles.

Differential Revision: https://phabricator.services.mozilla.com/D163939
This commit is contained in:
Jan Varga 2022-12-16 06:38:09 +00:00
parent 3120da2b93
commit 41e58b31bb
3 changed files with 56 additions and 21 deletions

View File

@ -22,6 +22,7 @@
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRef.h"
#include "mozilla/dom/fs/TargetPtrHolder.h"
#include "mozilla/dom/quota/QuotaCommon.h"
#include "mozilla/dom/quota/ResultExtensions.h"
#include "nsNetCID.h"
@ -35,15 +36,10 @@ namespace {
const uint32_t kStreamCopyBlockSize = 1024 * 1024;
nsresult AsyncCopy(nsIInputStream* aSource, nsIOutputStream* aSink,
const nsAsyncCopyMode aMode, const bool aCloseSource,
const bool aCloseSink,
nsISerialEventTarget* aIOTarget, const nsAsyncCopyMode aMode,
const bool aCloseSource, const bool aCloseSink,
std::function<void(uint32_t)>&& aProgressCallback,
std::function<void(nsresult)>&& aCompleteCallback) {
QM_TRY_INSPECT(const auto& ioTarget,
MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<nsIEventTarget>,
MOZ_SELECT_OVERLOAD(do_GetService),
NS_STREAMTRANSPORTSERVICE_CONTRACTID));
struct CallbackClosure {
CallbackClosure(std::function<void(uint32_t)>&& aProgressCallback,
std::function<void(nsresult)>&& aCompleteCallback) {
@ -67,7 +63,7 @@ nsresult AsyncCopy(nsIInputStream* aSource, nsIOutputStream* aSink,
QM_TRY(
MOZ_TO_RESULT(NS_AsyncCopy(
aSource, aSink, ioTarget, aMode, kStreamCopyBlockSize,
aSource, aSink, aIOTarget, aMode, kStreamCopyBlockSize,
[](void* aClosure, nsresult aRv) {
auto* callbackClosure = static_cast<CallbackClosure*>(aClosure);
(*callbackClosure->mCompleteCallbackWrapper)(aRv);
@ -216,6 +212,12 @@ bool FileSystemSyncAccessHandle::IsOpen() const {
return mState == State::Open;
}
bool FileSystemSyncAccessHandle::IsClosing() const {
MOZ_ASSERT(mState != State::Initial);
return mState == State::Closing;
}
bool FileSystemSyncAccessHandle::IsClosed() const {
MOZ_ASSERT(mState != State::Initial);
@ -225,20 +227,42 @@ bool FileSystemSyncAccessHandle::IsClosed() const {
RefPtr<BoolPromise> FileSystemSyncAccessHandle::BeginClose() {
MOZ_ASSERT(IsOpen());
LOG(("%p: Closing", mStream.get()));
mState = State::Closing;
mState = State::Closed;
InvokeAsync(mIOTaskQueue, __func__,
[selfHolder = fs::TargetPtrHolder(this)]() {
LOG(("%p: Closing", selfHolder->mStream.get()));
mStream->OutputStream()->Close();
mStream = nullptr;
selfHolder->mStream->OutputStream()->Close();
selfHolder->mStream = nullptr;
if (mActor) {
mActor->SendClose();
}
return BoolPromise::CreateAndResolve(true, __func__);
})
->Then(GetCurrentSerialEventTarget(), __func__,
[self = RefPtr(this)](const BoolPromise::ResolveOrRejectValue&) {
return self->mIOTaskQueue->BeginShutdown();
})
->Then(
GetCurrentSerialEventTarget(), __func__,
[self = RefPtr(this)](const ShutdownPromise::ResolveOrRejectValue&) {
if (self->mActor) {
self->mActor->SendClose();
}
mWorkerRef = nullptr;
self->mWorkerRef = nullptr;
return BoolPromise::CreateAndResolve(true, __func__);
self->mState = State::Closed;
self->mClosePromiseHolder.ResolveIfExists(true, __func__);
});
return OnClose();
}
RefPtr<BoolPromise> FileSystemSyncAccessHandle::OnClose() {
MOZ_ASSERT(mState == State::Closing);
return mClosePromiseHolder.Ensure(__func__);
}
// WebIDL Boilerplate
@ -319,7 +343,7 @@ void FileSystemSyncAccessHandle::Flush(ErrorResult& aError) {
}
void FileSystemSyncAccessHandle::Close() {
if (!IsOpen()) {
if (!(IsOpen() || IsClosing())) {
return;
}
@ -336,7 +360,10 @@ void FileSystemSyncAccessHandle::Close() {
MOZ_ASSERT(syncLoopTarget);
InvokeAsync(syncLoopTarget, __func__, [self = RefPtr(this)]() {
return self->BeginClose();
if (self->IsOpen()) {
return self->BeginClose();
}
return self->OnClose();
})->Then(syncLoopTarget, __func__, [&workerRef, &syncLoopTarget]() {
workerRef->Private()->AssertIsOnWorkerThread();
@ -422,7 +449,7 @@ uint64_t FileSystemSyncAccessHandle::ReadOrWrite(
uint64_t totalCount = 0;
QM_TRY(MOZ_TO_RESULT(AsyncCopy(
inputStream, outputStream,
inputStream, outputStream, mIOTaskQueue,
aRead ? NS_ASYNCCOPY_VIA_WRITESEGMENTS
: NS_ASYNCCOPY_VIA_READSEGMENTS,
/* aCloseSource */ !aRead, /* aCloseSink */ aRead,

View File

@ -32,7 +32,7 @@ class StrongWorkerRef;
class FileSystemSyncAccessHandle final : public nsISupports,
public nsWrapperCache {
public:
enum struct State : uint8_t { Initial = 0, Open, Closed };
enum struct State : uint8_t { Initial = 0, Open, Closing, Closed };
static Result<RefPtr<FileSystemSyncAccessHandle>, nsresult> Create(
nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager,
@ -49,10 +49,14 @@ class FileSystemSyncAccessHandle final : public nsISupports,
bool IsOpen() const;
bool IsClosing() const;
bool IsClosed() const;
[[nodiscard]] RefPtr<BoolPromise> BeginClose();
[[nodiscard]] RefPtr<BoolPromise> OnClose();
// WebIDL Boilerplate
nsIGlobalObject* GetParentObject() const;
@ -103,6 +107,8 @@ class FileSystemSyncAccessHandle final : public nsISupports,
RefPtr<StrongWorkerRef> mWorkerRef;
MozPromiseHolder<BoolPromise> mClosePromiseHolder;
const fs::FileSystemEntryMetadata mMetadata;
State mState;

View File

@ -68,6 +68,8 @@ FileSystemManagerChild::AllocPFileSystemWritableFileStreamChild() {
if (handle->IsOpen()) {
promises.AppendElement(handle->BeginClose());
} else if (handle->IsClosing()) {
promises.AppendElement(handle->OnClose());
}
}