71
71
#include " io/fs/s3_common.h"
72
72
#include " util/bvar_helper.h"
73
73
74
+ namespace {
75
+ inline ::Aws::Client::AWSError<::Aws::S3::S3Errors> s3_error_factory () {
76
+ return {::Aws::S3::S3Errors::INTERNAL_FAILURE, " exceeds limit" , " exceeds limit" , false };
77
+ }
78
+
79
+ template <typename Func>
80
+ auto s3_rate_limit (doris::S3RateLimitType op, Func callback) -> decltype(callback()) {
81
+ using T = decltype (callback ());
82
+ if (!doris::config::enable_s3_rate_limiter) {
83
+ return callback ();
84
+ }
85
+ auto sleep_duration = doris::S3ClientFactory::instance ().rate_limiter (op)->add (1 );
86
+ if (sleep_duration < 0 ) {
87
+ return T (s3_error_factory ());
88
+ }
89
+ return callback ();
90
+ }
91
+
92
+ template <typename Func>
93
+ auto s3_get_rate_limit (Func callback) -> decltype(callback()) {
94
+ return s3_rate_limit (doris::S3RateLimitType::GET, std::move (callback));
95
+ }
96
+
97
+ template <typename Func>
98
+ auto s3_put_rate_limit (Func callback) -> decltype(callback()) {
99
+ return s3_rate_limit (doris::S3RateLimitType::PUT, std::move (callback));
100
+ }
101
+ } // namespace
102
+
74
103
namespace Aws ::S3::Model {
75
104
class DeleteObjectRequest ;
76
105
} // namespace Aws::S3::Model
@@ -92,9 +121,9 @@ ObjectStorageUploadResponse S3ObjStorageClient::create_multipart_upload(
92
121
create_request.SetContentType (" application/octet-stream" );
93
122
94
123
SCOPED_BVAR_LATENCY (s3_bvar::s3_multi_part_upload_latency);
95
- auto outcome = SYNC_POINT_HOOK_RETURN_VALUE (_client-> CreateMultipartUpload (create_request),
96
- " s3_file_writer::create_multi_part_upload " ,
97
- std::cref (create_request).get ());
124
+ auto outcome = SYNC_POINT_HOOK_RETURN_VALUE (
125
+ s3_put_rate_limit ([&]() { return _client-> CreateMultipartUpload (create_request); }) ,
126
+ " s3_file_writer::create_multi_part_upload " , std::cref (create_request).get ());
98
127
SYNC_POINT_CALLBACK (" s3_file_writer::_open" , &outcome);
99
128
100
129
if (outcome.IsSuccess ()) {
@@ -122,9 +151,9 @@ ObjectStorageResponse S3ObjStorageClient::put_object(const ObjectStoragePathOpti
122
151
request.SetContentLength (stream.size ());
123
152
request.SetContentType (" application/octet-stream" );
124
153
SCOPED_BVAR_LATENCY (s3_bvar::s3_put_latency);
125
- auto response =
126
- SYNC_POINT_HOOK_RETURN_VALUE ( _client->PutObject (request), " s3_file_writer::put_object " ,
127
- std::cref (request).get (), &stream);
154
+ auto response = SYNC_POINT_HOOK_RETURN_VALUE (
155
+ s3_put_rate_limit ([&]() { return _client->PutObject (request); }) ,
156
+ " s3_file_writer::put_object " , std::cref (request).get (), &stream);
128
157
if (!response.IsSuccess ()) {
129
158
auto st = s3fs_error (response.GetError (),
130
159
fmt::format (" failed to put object {}" , opts.path .native ()));
@@ -157,8 +186,8 @@ ObjectStorageUploadResponse S3ObjStorageClient::upload_part(const ObjectStorageP
157
186
{
158
187
SCOPED_BVAR_LATENCY (s3_bvar::s3_multi_part_upload_latency);
159
188
upload_part_outcome = SYNC_POINT_HOOK_RETURN_VALUE (
160
- _client->UploadPart (upload_request), " s3_file_writer::upload_part " ,
161
- std::cref (upload_request).get (), &stream);
189
+ s3_put_rate_limit ([&]() { return _client->UploadPart (upload_request); }) ,
190
+ " s3_file_writer::upload_part " , std::cref (upload_request).get (), &stream);
162
191
}
163
192
TEST_SYNC_POINT_CALLBACK (" S3FileWriter::_upload_one_part" , &upload_part_outcome);
164
193
if (!upload_part_outcome.IsSuccess ()) {
@@ -199,7 +228,7 @@ ObjectStorageResponse S3ObjStorageClient::complete_multipart_upload(
199
228
TEST_SYNC_POINT_RETURN_WITH_VALUE (" S3FileWriter::_complete:3" , ObjectStorageResponse (), this );
200
229
SCOPED_BVAR_LATENCY (s3_bvar::s3_multi_part_upload_latency);
201
230
auto complete_outcome = SYNC_POINT_HOOK_RETURN_VALUE (
202
- _client->CompleteMultipartUpload (complete_request),
231
+ s3_put_rate_limit ([&]() { return _client->CompleteMultipartUpload (complete_request); } ),
203
232
" s3_file_writer::complete_multi_part" , std::cref (complete_request).get ());
204
233
205
234
if (!complete_outcome.IsSuccess ()) {
@@ -220,7 +249,8 @@ ObjectStorageHeadResponse S3ObjStorageClient::head_object(const ObjectStoragePat
220
249
221
250
SCOPED_BVAR_LATENCY (s3_bvar::s3_head_latency);
222
251
auto outcome = SYNC_POINT_HOOK_RETURN_VALUE (
223
- _client->HeadObject (request), " s3_file_system::head_object" , std::ref (request).get ());
252
+ s3_get_rate_limit ([&]() { return _client->HeadObject (request); }),
253
+ " s3_file_system::head_object" , std::ref (request).get ());
224
254
if (outcome.IsSuccess ()) {
225
255
return {.resp = {convert_to_obj_response (Status::OK ())},
226
256
.file_size = outcome.GetResult ().GetContentLength ()};
@@ -247,7 +277,7 @@ ObjectStorageResponse S3ObjStorageClient::get_object(const ObjectStoragePathOpti
247
277
request.SetResponseStreamFactory (AwsWriteableStreamFactory (buffer, bytes_read));
248
278
249
279
SCOPED_BVAR_LATENCY (s3_bvar::s3_get_latency);
250
- auto outcome = _client->GetObject (request);
280
+ auto outcome = s3_get_rate_limit ([&]() { return _client->GetObject (request); } );
251
281
if (!outcome.IsSuccess ()) {
252
282
return {convert_to_obj_response (
253
283
s3fs_error (outcome.GetError (),
@@ -273,7 +303,7 @@ ObjectStorageResponse S3ObjStorageClient::list_objects(const ObjectStoragePathOp
273
303
Aws::S3::Model::ListObjectsV2Outcome outcome;
274
304
{
275
305
SCOPED_BVAR_LATENCY (s3_bvar::s3_list_latency);
276
- outcome = _client->ListObjectsV2 (request);
306
+ outcome = s3_get_rate_limit ([&]() { return _client->ListObjectsV2 (request); } );
277
307
}
278
308
if (!outcome.IsSuccess ()) {
279
309
files->clear ();
@@ -310,8 +340,9 @@ ObjectStorageResponse S3ObjStorageClient::delete_objects(const ObjectStoragePath
310
340
});
311
341
del.WithObjects (std::move (objects)).SetQuiet (true );
312
342
delete_request.SetDelete (std::move (del));
313
- SCOPED_BVAR_LATENCY (s3_bvar::s3_delete_latency);
314
- auto delete_outcome = _client->DeleteObjects (delete_request);
343
+ SCOPED_BVAR_LATENCY (s3_bvar::s3_delete_objects_latency);
344
+ auto delete_outcome =
345
+ s3_put_rate_limit ([&]() { return _client->DeleteObjects (delete_request); });
315
346
if (!delete_outcome.IsSuccess ()) {
316
347
return {convert_to_obj_response (
317
348
s3fs_error (delete_outcome.GetError (),
@@ -331,8 +362,8 @@ ObjectStorageResponse S3ObjStorageClient::delete_object(const ObjectStoragePathO
331
362
Aws::S3::Model::DeleteObjectRequest request;
332
363
request.WithBucket (opts.bucket ).WithKey (opts.key );
333
364
334
- SCOPED_BVAR_LATENCY (s3_bvar::s3_delete_latency );
335
- auto outcome = _client->DeleteObject (request);
365
+ SCOPED_BVAR_LATENCY (s3_bvar::s3_delete_object_latency );
366
+ auto outcome = s3_put_rate_limit ([&]() { return _client->DeleteObject (request); } );
336
367
if (outcome.IsSuccess () ||
337
368
outcome.GetError ().GetResponseCode () == Aws::Http::HttpResponseCode::NOT_FOUND) {
338
369
return ObjectStorageResponse::OK ();
@@ -354,7 +385,7 @@ ObjectStorageResponse S3ObjStorageClient::delete_objects_recursively(
354
385
Aws::S3::Model::ListObjectsV2Outcome outcome;
355
386
{
356
387
SCOPED_BVAR_LATENCY (s3_bvar::s3_list_latency);
357
- outcome = _client->ListObjectsV2 (request);
388
+ outcome = s3_get_rate_limit ([&]() { return _client->ListObjectsV2 (request); } );
358
389
}
359
390
if (!outcome.IsSuccess ()) {
360
391
return {convert_to_obj_response (s3fs_error (
@@ -373,8 +404,9 @@ ObjectStorageResponse S3ObjStorageClient::delete_objects_recursively(
373
404
Aws::S3::Model::Delete del;
374
405
del.WithObjects (std::move (objects)).SetQuiet (true );
375
406
delete_request.SetDelete (std::move (del));
376
- SCOPED_BVAR_LATENCY (s3_bvar::s3_delete_latency);
377
- auto delete_outcome = _client->DeleteObjects (delete_request);
407
+ SCOPED_BVAR_LATENCY (s3_bvar::s3_delete_objects_latency);
408
+ auto delete_outcome =
409
+ s3_put_rate_limit ([&]() { return _client->DeleteObjects (delete_request); });
378
410
if (!delete_outcome.IsSuccess ()) {
379
411
return {convert_to_obj_response (
380
412
s3fs_error (delete_outcome.GetError (),
0 commit comments