diff --git a/lix/libstore/s3-binary-cache-store.cc b/lix/libstore/s3-binary-cache-store.cc index 90f0b5ce3..1e52c08ff 100644 --- a/lix/libstore/s3-binary-cache-store.cc +++ b/lix/libstore/s3-binary-cache-store.cc @@ -1,3 +1,4 @@ +#include #if ENABLE_S3 #include "lix/libstore/s3.hh" @@ -13,6 +14,7 @@ #include "lix/libutil/strings.hh" #include +#include #include #include @@ -46,6 +48,36 @@ struct S3Error : public Error : Error(args...), err(err) { }; }; +namespace { +template +struct FulfillerWrapper +{ + kj::Own> wrapped; + + explicit FulfillerWrapper(kj::Own> fulfiller) + : wrapped(std::move(fulfiller)) + { + } + + ~FulfillerWrapper() noexcept + { + wrapped->reject(KJ_EXCEPTION(FAILED, "async job finished without notification")); + } + + template + void fulfill(Args &&... args) const + { + wrapped->fulfill(std::forward(args)...); + } +}; + +template +std::shared_ptr> wrap(kj::Own> fulfiller) +{ + return std::make_shared>(std::move(fulfiller)); +} +} + /* Helper: given an Outcome, return R in case of success, or throw an exception in case of an error. */ template @@ -177,11 +209,12 @@ try { auto pfp = kj::newPromiseAndCrossThreadFulfiller(); client->GetObjectAsync( request, - [&](const Aws::S3::S3Client *, - const Aws::S3::Model::GetObjectRequest &, - Aws::S3::Model::GetObjectOutcome res, - const std::shared_ptr &) { - pfp.fulfiller->fulfill(std::move(res)); + [fulfiller{wrap(std::move(pfp.fulfiller)) + }](const Aws::S3::S3Client *, + const Aws::S3::Model::GetObjectRequest &, + Aws::S3::Model::GetObjectOutcome res, + const std::shared_ptr &) { + fulfiller->fulfill(std::move(res)); } ); auto result = checkAws(fmt("AWS error fetching '%s'", key), co_await pfp.promise); @@ -350,11 +383,12 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore auto pfp = kj::newPromiseAndCrossThreadFulfiller(); s3Helper.client->HeadObjectAsync( Aws::S3::Model::HeadObjectRequest().WithBucket(bucketName).WithKey(path), - [&](const Aws::S3::S3Client *, - const Aws::S3::Model::HeadObjectRequest &, - const Aws::S3::Model::HeadObjectOutcome & res, - const std::shared_ptr &) { - pfp.fulfiller->fulfill(auto(res)); + [fulfiller{wrap(std::move(pfp.fulfiller)) + }](const Aws::S3::S3Client *, + const Aws::S3::Model::HeadObjectRequest &, + const Aws::S3::Model::HeadObjectOutcome & res, + const std::shared_ptr &) { + fulfiller->fulfill(auto(res)); } ); auto res = co_await pfp.promise; @@ -395,9 +429,9 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore struct TransferContext : Aws::Client::AsyncCallerContext { - kj::CrossThreadPromiseFulfiller * signal; - explicit TransferContext(kj::CrossThreadPromiseFulfiller * signal) - : signal(signal) + FulfillerWrapper signal; + explicit TransferContext(kj::Own> signal) + : signal(std::move(signal)) { } }; @@ -425,9 +459,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore auto context = std::static_pointer_cast( transferHandle->GetContext() ); - if (context->signal) { - context->signal->fulfill(); - } + context->signal.fulfill(); } }; @@ -449,7 +481,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore path, mimeType, Aws::Map(), - std::make_shared(pfp.fulfiller.get()) /*, contentEncoding */ + std::make_shared(std::move(pfp.fulfiller)) /*, contentEncoding */ ); co_await pfp.promise; @@ -480,11 +512,12 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore auto pfp = kj::newPromiseAndCrossThreadFulfiller(); s3Helper.client->PutObjectAsync( request, - [&](const Aws::S3::S3Client *, - const Aws::S3::Model::PutObjectRequest &, - const Aws::S3::Model::PutObjectOutcome & res, - const std::shared_ptr &) { - pfp.fulfiller->fulfill(auto(res)); + [fulfiller{wrap(std::move(pfp.fulfiller)) + }](const Aws::S3::S3Client *, + const Aws::S3::Model::PutObjectRequest &, + const Aws::S3::Model::PutObjectOutcome & res, + const std::shared_ptr &) { + fulfiller->fulfill(auto(res)); } ); auto result = checkAws(fmt("AWS error uploading '%s'", path), co_await pfp.promise); @@ -579,11 +612,12 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore .WithBucket(bucketName) .WithDelimiter("/") .WithMarker(marker), - [&](const Aws::S3::S3Client *, - const Aws::S3::Model::ListObjectsRequest &, - const Aws::S3::Model::ListObjectsOutcome & res, - const std::shared_ptr &) { - pfp.fulfiller->fulfill(auto(res)); + [fulfiller{wrap(std::move(pfp.fulfiller)) + }](const Aws::S3::S3Client *, + const Aws::S3::Model::ListObjectsRequest &, + const Aws::S3::Model::ListObjectsOutcome & res, + const std::shared_ptr &) { + fulfiller->fulfill(auto(res)); } ); auto res =