|
30 | 30 | #include <aws/s3/S3Client.h> |
31 | 31 | #include <aws/sts/STSClient.h> |
32 | 32 | #include <bvar/reducer.h> |
| 33 | +#include <cpp/s3_rate_limiter.h> |
33 | 34 | #include <util/string_util.h> |
34 | 35 |
|
35 | 36 | #include <atomic> |
| 37 | + |
36 | 38 | #ifdef USE_AZURE |
37 | 39 | #include <azure/core/diagnostics/logger.hpp> |
38 | 40 | #include <azure/storage/blobs/blob_container_client.hpp> |
@@ -131,11 +133,66 @@ bvar::Adder<int64_t> get_rate_limit_exceed_req_num("get_rate_limit_exceed_req_nu |
131 | 133 | bvar::Adder<int64_t> put_rate_limit_ns("put_rate_limit_ns"); |
132 | 134 | bvar::Adder<int64_t> put_rate_limit_exceed_req_num("put_rate_limit_exceed_req_num"); |
133 | 135 |
|
| 136 | +static std::atomic<int64_t> last_s3_get_token_bucket_tokens {0}; |
| 137 | +static std::atomic<int64_t> last_s3_get_token_limit {0}; |
| 138 | +static std::atomic<int64_t> last_s3_get_token_per_second {0}; |
| 139 | +static std::atomic<int64_t> last_s3_put_token_per_second {0}; |
| 140 | +static std::atomic<int64_t> last_s3_put_token_bucket_tokens {0}; |
| 141 | +static std::atomic<int64_t> last_s3_put_token_limit {0}; |
| 142 | + |
| 143 | +static std::atomic<bool> updating_get_limiter {false}; |
| 144 | +static std::atomic<bool> updating_put_limiter {false}; |
| 145 | + |
134 | 146 | S3RateLimiterHolder* S3ClientFactory::rate_limiter(S3RateLimitType type) { |
135 | 147 | CHECK(type == S3RateLimitType::GET || type == S3RateLimitType::PUT) << to_string(type); |
136 | 148 | return _rate_limiters[static_cast<size_t>(type)].get(); |
137 | 149 | } |
138 | 150 |
|
| 151 | +template <S3RateLimitType LimiterType> |
| 152 | +void update_rate_limiter_if_changed(int64_t current_tps, int64_t current_bucket, |
| 153 | + int64_t current_limit, std::atomic<int64_t>& last_tps, |
| 154 | + std::atomic<int64_t>& last_bucket, |
| 155 | + std::atomic<int64_t>& last_limit, |
| 156 | + std::atomic<bool>& updating_flag, const char* limiter_name) { |
| 157 | + if (last_tps.load(std::memory_order_relaxed) != current_tps || |
| 158 | + last_bucket.load(std::memory_order_relaxed) != current_bucket || |
| 159 | + last_limit.load(std::memory_order_relaxed) != current_limit) { |
| 160 | + bool expected = false; |
| 161 | + if (!updating_flag.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) { |
| 162 | + return; |
| 163 | + } |
| 164 | + if (last_tps.load(std::memory_order_acquire) != current_tps || |
| 165 | + last_bucket.load(std::memory_order_acquire) != current_bucket || |
| 166 | + last_limit.load(std::memory_order_acquire) != current_limit) { |
| 167 | + int ret = |
| 168 | + reset_s3_rate_limiter(LimiterType, current_tps, current_bucket, current_limit); |
| 169 | + |
| 170 | + if (ret == 0) { |
| 171 | + last_tps.store(current_tps, std::memory_order_release); |
| 172 | + last_bucket.store(current_bucket, std::memory_order_release); |
| 173 | + last_limit.store(current_limit, std::memory_order_release); |
| 174 | + } else { |
| 175 | + LOG(WARNING) << "Failed to reset S3 " << limiter_name |
| 176 | + << " rate limiter, error code: " << ret; |
| 177 | + } |
| 178 | + } |
| 179 | + |
| 180 | + updating_flag.store(false, std::memory_order_release); |
| 181 | + } |
| 182 | +} |
| 183 | + |
| 184 | +void check_s3_rate_limiter_config_changed() { |
| 185 | + update_rate_limiter_if_changed<S3RateLimitType::GET>( |
| 186 | + config::s3_get_token_per_second, config::s3_get_bucket_tokens, |
| 187 | + config::s3_get_token_limit, last_s3_get_token_per_second, |
| 188 | + last_s3_get_token_bucket_tokens, last_s3_get_token_limit, updating_get_limiter, "GET"); |
| 189 | + |
| 190 | + update_rate_limiter_if_changed<S3RateLimitType::PUT>( |
| 191 | + config::s3_put_token_per_second, config::s3_put_bucket_tokens, |
| 192 | + config::s3_put_token_limit, last_s3_put_token_per_second, |
| 193 | + last_s3_put_token_bucket_tokens, last_s3_put_token_limit, updating_put_limiter, "PUT"); |
| 194 | +} |
| 195 | + |
139 | 196 | int reset_s3_rate_limiter(S3RateLimitType type, size_t max_speed, size_t max_burst, size_t limit) { |
140 | 197 | if (type == S3RateLimitType::UNKNOWN) { |
141 | 198 | return -1; |
@@ -204,6 +261,8 @@ std::shared_ptr<io::ObjStorageClient> S3ClientFactory::create(const S3ClientConf |
204 | 261 | return nullptr; |
205 | 262 | } |
206 | 263 |
|
| 264 | + check_s3_rate_limiter_config_changed(); |
| 265 | + |
207 | 266 | #ifdef BE_TEST |
208 | 267 | { |
209 | 268 | std::lock_guard l(_lock); |
|
0 commit comments