11#include " openPMD/toolkit/Aws.hpp"
22
3+ #include < aws/s3/S3Client.h>
34#include < aws/s3/model/CreateBucketRequest.h>
45#include < aws/s3/model/GetObjectRequest.h>
56#include < aws/s3/model/PutObjectRequest.h>
67
78#include < iostream>
9+ #include < mutex>
810#include < stdexcept>
911
1012namespace
@@ -31,13 +33,44 @@ struct imemstream : std::iostream
3133
3234namespace openPMD ::internal
3335{
36+ void AwsAsyncHandler::wait ()
37+ {
38+ std::cerr << " Waiting for remaining tasks. Have " << completion_counter
39+ << " of " << request_counter << std::endl;
40+ size_t target = this ->request_counter ;
41+ std::unique_lock lk (this ->mutex );
42+ this ->event .wait (
43+ lk, [this , target]() { return this ->completion_counter >= target; });
44+ std::cerr << " Finished waiting for remaining tasks" << std::endl;
45+ }
46+
47+ void AwsAsyncHandler::add_task ()
48+ {
49+ this ->request_counter ++;
50+ }
51+
52+ void AwsAsyncHandler::add_and_notify_result ()
53+ {
54+ std::unique_lock lk (this ->mutex );
55+ this ->completion_counter ++;
56+ lk.unlock ();
57+ this ->event .notify_all ();
58+ }
59+
60+ AwsAsyncHandler::~AwsAsyncHandler ()
61+ {
62+ this ->wait ();
63+ }
64+
3465ExternalBlockStorageAws::ExternalBlockStorageAws (
3566 Aws::S3 ::S3Client client,
3667 std::string bucketName,
37- std::optional<std::string> endpoint)
68+ std::optional<std::string> endpoint,
69+ bool async)
3870 : m_client{std::move (client)}
3971 , m_bucketName(std::move(bucketName))
4072 , m_endpoint(std::move(endpoint))
73+ , m_async(async ? std::make_optional<AwsAsyncHandler>() : std::nullopt )
4174{
4275 Aws::S3 ::Model::CreateBucketRequest create_request;
4376 create_request.SetBucket (m_bucketName);
@@ -71,16 +104,49 @@ auto ExternalBlockStorageAws::put(
71104 put_request.SetBody (input_data);
72105 put_request.SetContentLength (static_cast <long long >(len));
73106
74- auto put_outcome = m_client.PutObject (put_request);
75-
76- if (put_outcome.IsSuccess ())
107+ if (!m_async.has_value ())
77108 {
78- std::cout << " File uploaded successfully to S3!" << std::endl;
109+ auto put_outcome = m_client.PutObject (put_request);
110+
111+ if (put_outcome.IsSuccess ())
112+ {
113+ std::cout << " File synchronously uploaded successfully to S3!"
114+ << std::endl;
115+ }
116+ else
117+ {
118+ std::cerr << " Synchronous upload failed: "
119+ << put_outcome.GetError ().GetMessage () << std::endl;
120+ }
79121 }
80122 else
81123 {
82- std::cerr << " Upload failed: " << put_outcome.GetError ().GetMessage ()
83- << std::endl;
124+ auto &async_handler = *m_async;
125+ auto responseReceivedHandler =
126+ [&async_handler](
127+ const Aws::S3 ::S3Client *,
128+ const Aws::S3 ::Model::PutObjectRequest &,
129+ const Aws::S3 ::Model::PutObjectOutcome &put_outcome,
130+ const std::shared_ptr<const Aws::Client::AsyncCallerContext>
131+ &) {
132+ if (put_outcome.IsSuccess ())
133+ {
134+ std::cout
135+ << " File asynchronously uploaded successfully to S3!"
136+ << std::endl;
137+ }
138+ else
139+ {
140+ std::cerr << " Asynchronous upload failed: "
141+ << put_outcome.GetError ().GetMessage ()
142+ << std::endl;
143+ }
144+ async_handler.add_and_notify_result ();
145+ };
146+ async_handler.add_task ();
147+ m_client.PutObjectAsync (put_request, responseReceivedHandler);
148+ // todo replace this
149+ async_handler.wait ();
84150 }
85151 return sanitized;
86152}
@@ -117,6 +183,15 @@ void ExternalBlockStorageAws::get(
117183 }
118184}
119185
186+ void ExternalBlockStorageAws::sync ()
187+ {
188+ if (!this ->m_async .has_value ())
189+ {
190+ return ;
191+ }
192+ this ->m_async ->wait ();
193+ }
194+
120195[[nodiscard]] auto ExternalBlockStorageAws::externalStorageLocation () const
121196 -> nlohmann::json
122197{
0 commit comments