@@ -54,20 +54,20 @@ GenericRateLimiter::GenericRateLimiter(
54
54
rate_bytes_per_sec_(auto_tuned ? rate_bytes_per_sec / 2
55
55
: rate_bytes_per_sec),
56
56
refill_bytes_per_period_(
57
- CalculateRefillBytesPerPeriod (rate_bytes_per_sec_)),
57
+ CalculateRefillBytesPerPeriodLocked (rate_bytes_per_sec_)),
58
58
clock_(clock),
59
59
stop_(false ),
60
60
exit_cv_(&request_mutex_),
61
61
requests_to_wait_(0 ),
62
62
available_bytes_(0 ),
63
- next_refill_us_(NowMicrosMonotonic ()),
63
+ next_refill_us_(NowMicrosMonotonicLocked ()),
64
64
fairness_(fairness > 100 ? 100 : fairness),
65
65
rnd_((uint32_t )time(nullptr )),
66
66
wait_until_refill_pending_(false ),
67
67
auto_tuned_(auto_tuned),
68
68
num_drains_(0 ),
69
69
max_bytes_per_sec_(rate_bytes_per_sec),
70
- tuned_time_(NowMicrosMonotonic ()) {
70
+ tuned_time_(NowMicrosMonotonicLocked ()) {
71
71
for (int i = Env::IO_LOW; i < Env::IO_TOTAL; ++i) {
72
72
total_requests_[i] = 0 ;
73
73
total_bytes_through_[i] = 0 ;
@@ -97,10 +97,15 @@ GenericRateLimiter::~GenericRateLimiter() {
97
97
98
98
// This API allows user to dynamically change rate limiter's bytes per second.
99
99
void GenericRateLimiter::SetBytesPerSecond (int64_t bytes_per_second) {
100
+ MutexLock g (&request_mutex_);
101
+ SetBytesPerSecondLocked (bytes_per_second);
102
+ }
103
+
104
+ void GenericRateLimiter::SetBytesPerSecondLocked (int64_t bytes_per_second) {
100
105
assert (bytes_per_second > 0 );
101
- rate_bytes_per_sec_ = bytes_per_second;
106
+ rate_bytes_per_sec_. store ( bytes_per_second, std::memory_order_relaxed) ;
102
107
refill_bytes_per_period_.store (
103
- CalculateRefillBytesPerPeriod (bytes_per_second),
108
+ CalculateRefillBytesPerPeriodLocked (bytes_per_second),
104
109
std::memory_order_relaxed);
105
110
}
106
111
@@ -115,10 +120,10 @@ void GenericRateLimiter::Request(int64_t bytes, const Env::IOPriority pri,
115
120
116
121
if (auto_tuned_) {
117
122
static const int kRefillsPerTune = 100 ;
118
- std::chrono::microseconds now (NowMicrosMonotonic ());
123
+ std::chrono::microseconds now (NowMicrosMonotonicLocked ());
119
124
if (now - tuned_time_ >=
120
125
kRefillsPerTune * std::chrono::microseconds (refill_period_us_)) {
121
- Status s = Tune ();
126
+ Status s = TuneLocked ();
122
127
s.PermitUncheckedError (); // **TODO: What to do on error?
123
128
}
124
129
}
@@ -152,7 +157,7 @@ void GenericRateLimiter::Request(int64_t bytes, const Env::IOPriority pri,
152
157
// (1) Waiting for the next refill time.
153
158
// (2) Refilling the bytes and granting requests.
154
159
do {
155
- int64_t time_until_refill_us = next_refill_us_ - NowMicrosMonotonic ();
160
+ int64_t time_until_refill_us = next_refill_us_ - NowMicrosMonotonicLocked ();
156
161
if (time_until_refill_us > 0 ) {
157
162
if (wait_until_refill_pending_) {
158
163
// Somebody is performing (1). Trust we'll be woken up when our request
@@ -173,7 +178,7 @@ void GenericRateLimiter::Request(int64_t bytes, const Env::IOPriority pri,
173
178
} else {
174
179
// Whichever thread reaches here first performs duty (2) as described
175
180
// above.
176
- RefillBytesAndGrantRequests ();
181
+ RefillBytesAndGrantRequestsLocked ();
177
182
if (r.granted ) {
178
183
// If there is any remaining requests, make sure there exists at least
179
184
// one candidate is awake for future duties by signaling a front request
@@ -215,20 +220,20 @@ void GenericRateLimiter::Request(int64_t bytes, const Env::IOPriority pri,
215
220
}
216
221
217
222
std::vector<Env::IOPriority>
218
- GenericRateLimiter::GeneratePriorityIterationOrder () {
223
+ GenericRateLimiter::GeneratePriorityIterationOrderLocked () {
219
224
std::vector<Env::IOPriority> pri_iteration_order (Env::IO_TOTAL /* 4 */ );
220
225
// We make Env::IO_USER a superior priority by always iterating its queue
221
226
// first
222
227
pri_iteration_order[0 ] = Env::IO_USER;
223
228
224
229
bool high_pri_iterated_after_mid_low_pri = rnd_.OneIn (fairness_);
225
230
TEST_SYNC_POINT_CALLBACK (
226
- " GenericRateLimiter::GeneratePriorityIterationOrder ::"
231
+ " GenericRateLimiter::GeneratePriorityIterationOrderLocked ::"
227
232
" PostRandomOneInFairnessForHighPri" ,
228
233
&high_pri_iterated_after_mid_low_pri);
229
234
bool mid_pri_itereated_after_low_pri = rnd_.OneIn (fairness_);
230
235
TEST_SYNC_POINT_CALLBACK (
231
- " GenericRateLimiter::GeneratePriorityIterationOrder ::"
236
+ " GenericRateLimiter::GeneratePriorityIterationOrderLocked ::"
232
237
" PostRandomOneInFairnessForMidPri" ,
233
238
&mid_pri_itereated_after_low_pri);
234
239
@@ -247,15 +252,16 @@ GenericRateLimiter::GeneratePriorityIterationOrder() {
247
252
}
248
253
249
254
TEST_SYNC_POINT_CALLBACK (
250
- " GenericRateLimiter::GeneratePriorityIterationOrder ::"
255
+ " GenericRateLimiter::GeneratePriorityIterationOrderLocked ::"
251
256
" PreReturnPriIterationOrder" ,
252
257
&pri_iteration_order);
253
258
return pri_iteration_order;
254
259
}
255
260
256
- void GenericRateLimiter::RefillBytesAndGrantRequests () {
257
- TEST_SYNC_POINT (" GenericRateLimiter::RefillBytesAndGrantRequests" );
258
- next_refill_us_ = NowMicrosMonotonic () + refill_period_us_;
261
+ void GenericRateLimiter::RefillBytesAndGrantRequestsLocked () {
262
+ TEST_SYNC_POINT_CALLBACK (
263
+ " GenericRateLimiter::RefillBytesAndGrantRequestsLocked" , &request_mutex_);
264
+ next_refill_us_ = NowMicrosMonotonicLocked () + refill_period_us_;
259
265
// Carry over the left over quota from the last period
260
266
auto refill_bytes_per_period =
261
267
refill_bytes_per_period_.load (std::memory_order_relaxed);
@@ -264,7 +270,7 @@ void GenericRateLimiter::RefillBytesAndGrantRequests() {
264
270
}
265
271
266
272
std::vector<Env::IOPriority> pri_iteration_order =
267
- GeneratePriorityIterationOrder ();
273
+ GeneratePriorityIterationOrderLocked ();
268
274
269
275
for (int i = Env::IO_LOW; i < Env::IO_TOTAL; ++i) {
270
276
assert (!pri_iteration_order.empty ());
@@ -293,7 +299,7 @@ void GenericRateLimiter::RefillBytesAndGrantRequests() {
293
299
}
294
300
}
295
301
296
- int64_t GenericRateLimiter::CalculateRefillBytesPerPeriod (
302
+ int64_t GenericRateLimiter::CalculateRefillBytesPerPeriodLocked (
297
303
int64_t rate_bytes_per_sec) {
298
304
if (std::numeric_limits<int64_t >::max () / rate_bytes_per_sec <
299
305
refill_period_us_) {
@@ -305,7 +311,7 @@ int64_t GenericRateLimiter::CalculateRefillBytesPerPeriod(
305
311
}
306
312
}
307
313
308
- Status GenericRateLimiter::Tune () {
314
+ Status GenericRateLimiter::TuneLocked () {
309
315
const int kLowWatermarkPct = 50 ;
310
316
const int kHighWatermarkPct = 90 ;
311
317
const int kAdjustFactorPct = 5 ;
@@ -314,7 +320,7 @@ Status GenericRateLimiter::Tune() {
314
320
const int kAllowedRangeFactor = 20 ;
315
321
316
322
std::chrono::microseconds prev_tuned_time = tuned_time_;
317
- tuned_time_ = std::chrono::microseconds (NowMicrosMonotonic ());
323
+ tuned_time_ = std::chrono::microseconds (NowMicrosMonotonicLocked ());
318
324
319
325
int64_t elapsed_intervals = (tuned_time_ - prev_tuned_time +
320
326
std::chrono::microseconds (refill_period_us_) -
@@ -349,7 +355,7 @@ Status GenericRateLimiter::Tune() {
349
355
new_bytes_per_sec = prev_bytes_per_sec;
350
356
}
351
357
if (new_bytes_per_sec != prev_bytes_per_sec) {
352
- SetBytesPerSecond (new_bytes_per_sec);
358
+ SetBytesPerSecondLocked (new_bytes_per_sec);
353
359
}
354
360
num_drains_ = 0 ;
355
361
return Status::OK ();
0 commit comments