YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/net/rate_limiter-test.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#include <chrono>
15
#include <random>
16
17
#include "yb/util/net/rate_limiter.h"
18
#include "yb/util/random_util.h"
19
#include "yb/util/size_literals.h"
20
#include "yb/util/status.h"
21
#include "yb/util/test_macros.h"
22
23
#include <gtest/gtest.h>
24
25
DECLARE_uint64(rate_limiter_min_rate);
26
27
namespace yb {
28
29
using namespace std::chrono_literals;
30
31
constexpr uint64_t kRate = 1_KB;
32
33
namespace {
34
8
uint64_t GetDifference(uint64_t n1, uint64_t n2) {
35
5
  return n1 > n2 ? n1 - n2 : n2 - n1;
36
8
}
37
}
38
39
1
TEST(RateLimiter, TestRate) {
40
8
  for (uint64_t rate : {1_KB, 512ul, 1ul, 0ul, 48ul, 4_KB, 1_MB, 1_GB}) {
41
8
    RateLimiter rate_limiter([rate]() { return rate; });
42
8
    auto min_rate = std::max(rate, static_cast<uint64_t>(FLAGS_rate_limiter_min_rate));
43
8
    ASSERT_EQ(rate_limiter.GetMaxSizeForNextTransmission(),
44
8
              min_rate * rate_limiter.time_slot_ms() / MonoTime::kMillisecondsPerSecond);
45
8
  }
46
1
}
47
48
1
TEST(RateLimiter, TestUpdateDataSize) {
49
1
  MonoDelta local_sleep_time(3s);
50
1
  RateLimiter rate_limiter([]() { return kRate; });
51
1
  rate_limiter.Init();
52
1
  SleepFor(local_sleep_time);
53
1
  auto start = MonoTime::Now();
54
  // This method should sleep about 1 second to make the rate equivalent to 1024 bytes/sec.
55
1
  rate_limiter.UpdateDataSizeAndMaybeSleep(4 * kRate);
56
1
  auto elapsed = MonoTime::Now().GetDeltaSince(start);
57
1
  auto time_diff_ms = GetDifference(elapsed.ToMilliseconds(), MonoTime::kMillisecondsPerSecond);
58
1
#if defined(OS_MACOSX)
59
  // MacOS tests are much slower, and the timing check usually fails. So use the time slept by the
60
  // rate limiter instead.
61
1
  if (time_diff_ms > 100) {
62
0
    time_diff_ms = GetDifference(rate_limiter.total_time_slept().ToMilliseconds(),
63
0
                                 MonoTime::kMillisecondsPerSecond);
64
0
  }
65
1
#endif
66
1
  ASSERT_LE(time_diff_ms, 100);
67
1
  auto max_allowed_rate_diff = kRate * 5 / 100;
68
1
  auto diff = GetDifference(rate_limiter.GetRate(), kRate);
69
1
#if defined(OS_MACOSX)
70
1
  if (diff > max_allowed_rate_diff) {
71
    // We add the 3s that we slept in this test.
72
0
    diff = GetDifference(rate_limiter.MacOSRate(local_sleep_time), kRate);
73
74
    // For MacOS allow a 10% difference.
75
0
    max_allowed_rate_diff = kRate * 10 / 100;
76
0
  }
77
1
#endif
78
1
  ASSERT_LE(diff, max_allowed_rate_diff);
79
1
}
80
81
1
TEST(RateLimiter, TestSendRequest) {
82
1
  MonoDelta local_sleep_time(3s);
83
1
  RateLimiter rate_limiter([]() { return kRate; });
84
1
  auto start = MonoTime::Now();
85
1
  auto status = rate_limiter.SendOrReceiveData(
86
      // Send or receive function.
87
1
      [local_sleep_time]() {
88
1
        SleepFor(local_sleep_time);
89
1
        return Status::OK();
90
1
      },
91
      // Returns the total amount of data sent or received.
92
1
      []() { return 4 * kRate; });
93
1
  ASSERT_OK(status);
94
1
  auto elapsed = MonoTime::Now().GetDeltaSince(start);
95
  // The elapsed time should be ~4s (4 * kRate bytes transmitted at kRate bytes/sec).
96
1
  auto time_diff_ms = GetDifference(elapsed.ToMilliseconds(), 4 * MonoTime::kMillisecondsPerSecond);
97
98
  // Allow a 5% difference (200 ms in this case).
99
1
  auto max_allowed_time_diff_ms = 4 * MonoTime::kMillisecondsPerSecond * 5 / 100;
100
1
#if defined(OS_MACOSX)
101
  // MacOS tests are much slower, and the timing check usually fails. So use the time slept by the
102
  // rate limiter instead.
103
1
  if (time_diff_ms > max_allowed_time_diff_ms) {
104
0
    time_diff_ms = GetDifference(
105
0
        rate_limiter.total_time_slept().ToMilliseconds() + local_sleep_time.ToMilliseconds(),
106
0
        4 * MonoTime::kMillisecondsPerSecond);
107
108
    // For MacOS allow a 10% time difference.
109
0
    max_allowed_time_diff_ms = 4 * MonoTime::kMillisecondsPerSecond * 10 / 100;
110
0
  }
111
1
#endif
112
1
  ASSERT_LE(time_diff_ms, max_allowed_time_diff_ms);
113
  // Check that diff in rate is not more than 5%.
114
1
  auto max_allowed_rate_diff = kRate * 5 / 100;
115
1
  auto diff = GetDifference(rate_limiter.GetRate(), kRate);
116
1
#if defined(OS_MACOSX)
117
1
  if (diff > max_allowed_rate_diff) {
118
    // We add the 3s that we slept in this test.
119
0
    diff = GetDifference(rate_limiter.MacOSRate(local_sleep_time), kRate);
120
121
    // Allow 10% difference for MacOS.
122
0
    max_allowed_rate_diff = kRate * 10 / 100;
123
0
  }
124
1
#endif
125
1
  ASSERT_LE(diff, max_allowed_rate_diff);
126
1
}
127
128
1
TEST(RateLimiter, TestSendRequestWithMultipleRates) {
129
1
  vector<uint64_t> rates;
130
1
  uint64_t rates_sum = 0;
131
132
100
  RateLimiter rate_limiter([&rates, &rates_sum]() {
133
    // This is the rate updater function.
134
100
    auto nconnections = RandomUniformInt(1, 20);
135
100
    auto rate = kRate * 1_KB / nconnections;
136
100
    rates.push_back(rate);
137
100
    rates_sum += rate;
138
100
    return rate;
139
100
  });
140
141
1
  constexpr int kIterations = 100;
142
1
  constexpr int kIterationsPerSecond = 10;
143
1
  auto start = MonoTime::Now();
144
101
  for (int i = 0; i < kIterations; i++) {
145
100
    auto status = rate_limiter.SendOrReceiveData(
146
        // Send or receive function.
147
100
        []() {
148
          // Sleep for 100ms.
149
100
          SleepFor(
150
100
              MonoDelta::FromMilliseconds(MonoTime::kMillisecondsPerSecond / kIterationsPerSecond));
151
100
          return Status::OK();
152
100
        },
153
        // Returns the total amount of data sent or received.
154
100
        [&rates]() {
155
          // The number of bytes sent or received is always equal to the rate / 10, which means that
156
          // it should take 100ms to send or receive the data. But since our function sleeps for
157
          // 100ms, the rate_limiter object should not sleep.
158
100
          return rates.back() / kIterationsPerSecond;
159
100
        });
160
100
    ASSERT_OK(status);
161
100
  }
162
163
1
  auto end = MonoTime::Now();
164
1
  auto elapsed = end.GetDeltaSince(start);
165
166
  // The total time should be ~10s
167
  // ((kIterations * MonoTime::kMillisecondsPerSecond / 10) milliseconds because each call to the
168
  // send/receive function slept for (MonoTime::kMillisecondsPerSecond / 10) ms) since rate limiter
169
  // should have never had additional sleeps. The only sleeps that should have happened are the ones
170
  // in our send/receive function.
171
1
  auto expected_time_ms = kIterations * MonoTime::kMillisecondsPerSecond / 10;
172
1
  auto time_diff_ms = GetDifference(elapsed.ToMilliseconds(), expected_time_ms);
173
1
  auto max_allowed_time_diff_ms = expected_time_ms * 5 / 100;
174
1
#if defined(OS_MACOSX)
175
  // MacOS tests are much slower, and the timing check usually fails. So use the time slept by the
176
  // rate limiter instead.
177
  // Since we don't expect the rate limiter to sleep, RateLimiter::total_time_slept() should be
178
  // close to zero.
179
1
  if (time_diff_ms > expected_time_ms * 5 / 100) {
180
0
    time_diff_ms = rate_limiter.total_time_slept().ToMilliseconds();
181
    // For MacOS allow a 10% difference.
182
0
    max_allowed_time_diff_ms = expected_time_ms * 10 / 100;
183
0
  }
184
1
#endif
185
1
  ASSERT_LE(time_diff_ms, max_allowed_time_diff_ms);
186
187
1
  auto expected_avg_rate = rates_sum / rates.size();
188
  // Check that diff in rate is not more than 5%.
189
1
  auto max_allowed_rate_diff = expected_avg_rate * 5 / 100;
190
191
1
  LOG(INFO) << "Expected average rate: " << expected_avg_rate;
192
1
  LOG(INFO) << "Rate limiter rate: " << rate_limiter.GetRate();
193
1
  auto diff = GetDifference(rate_limiter.GetRate(), expected_avg_rate);
194
1
#if defined(OS_MACOSX)
195
1
  if (diff > max_allowed_rate_diff) {
196
    // We add the time our send/receive function spent sleeping.
197
0
    diff = GetDifference(rate_limiter.MacOSRate(MonoDelta::FromMilliseconds(expected_time_ms)),
198
0
                         expected_avg_rate);
199
    // For MacOS allow a 10% difference.
200
0
    max_allowed_rate_diff = expected_avg_rate * 10 / 100;
201
0
  }
202
1
#endif
203
1
  ASSERT_LE(diff, max_allowed_rate_diff);
204
1
}
205
206
1
TEST(RateLimiter, TestFastSendRequestWithMultipleRates) {
207
1
  vector<uint64_t> rates;
208
1
  uint64_t rates_sum = 0;
209
210
100
  RateLimiter rate_limiter([&rates, &rates_sum]() {
211
100
    auto nconnections = RandomUniformInt(1, 20);
212
100
    auto rate = kRate * 1_KB / nconnections;
213
100
    rates.push_back(rate);
214
100
    rates_sum += rate;
215
100
    return rate;
216
100
  });
217
218
1
  constexpr int kIterations = 100;
219
1
  constexpr int kIterationsPerSecond = 10;
220
1
  auto start = MonoTime::Now();
221
101
  for (int i = 0; i < kIterations; i++) {
222
100
    auto status = rate_limiter.SendOrReceiveData(
223
        // Send or receive function. This time there is no sleep, so the sleep will be called by
224
        // the RateLimiter object.
225
100
        []() {
226
100
          return Status::OK();
227
100
        },
228
        // The number of bytes sent or received is always equal to the rate / 10, which means that
229
        // the rate limiter object should sleep for 100ms.
230
100
        [&rates]() {
231
100
          return rates.back() / kIterationsPerSecond;
232
100
        });
233
100
    ASSERT_OK(status);
234
100
  }
235
1
  auto end = MonoTime::Now();
236
1
  auto elapsed = end.GetDeltaSince(start);
237
238
  // The total time should be ~10s
239
  // ((kIterations * MonoTime::kMillisecondsPerSecond / 10) milliseconds) since the RateLimiter
240
  // object should have slept for 100ms for every call to SendOrReceiveData.
241
1
  auto expected_time_ms = kIterations * MonoTime::kMillisecondsPerSecond / 10;
242
1
  auto time_diff_ms = GetDifference(elapsed.ToMilliseconds(), expected_time_ms);
243
1
  auto max_allowed_time_diff_ms = expected_time_ms * 5 / 100;
244
1
#if defined(OS_MACOSX)
245
  // MacOS tests are much slower, and the timing check usually fails. So use the time slept by the
246
  // rate limiter instead.
247
1
  if (time_diff_ms > max_allowed_time_diff_ms) {
248
0
    time_diff_ms = GetDifference(rate_limiter.total_time_slept().ToMilliseconds(),
249
0
                                 expected_time_ms);
250
    // For MacOS allow a 10% difference.
251
0
    max_allowed_time_diff_ms = expected_time_ms * 10 / 100;
252
0
  }
253
1
#endif
254
  // Verify that the difference in elapsed time is within 5% (or 10% for MacOS in some cases) of the
255
  // expected time.
256
1
  ASSERT_LE(time_diff_ms, max_allowed_time_diff_ms);
257
258
1
  auto expected_avg_rate = rates_sum / rates.size();
259
  // Check that diff in rate is not more than 5%.
260
1
  auto max_allowed_rate_diff = expected_avg_rate * 5 / 100;
261
262
1
  LOG(INFO) << "Expected average rate: " << expected_avg_rate;
263
1
  LOG(INFO) << "Rate limiter rate: " << rate_limiter.GetRate();
264
1
  auto rate_diff = GetDifference(rate_limiter.GetRate(), expected_avg_rate);
265
1
#if defined(OS_MACOSX)
266
1
  if (rate_diff > max_allowed_rate_diff) {
267
0
    rate_diff = GetDifference(rate_limiter.MacOSRate(), expected_avg_rate);
268
269
    // For MacOS allow a 10% rate difference.
270
0
    max_allowed_rate_diff = expected_avg_rate * 10 / 100;
271
0
  }
272
1
#endif
273
1
  LOG(INFO) << "diff: " << rate_diff;
274
1
  ASSERT_LE(rate_diff, max_allowed_rate_diff);
275
1
}
276
277
1
TEST(RateLimiter, TestInactiveRateLimiter) {
278
10
  RateLimiter active_rate_limiter([]() { return kRate; });
279
1
  RateLimiter inactive_rate_limiter;
280
1
  ASSERT_TRUE(active_rate_limiter.active());
281
1
  ASSERT_FALSE(inactive_rate_limiter.active());
282
283
1
  vector<MonoDelta> elapsed_times;
284
2
  for (auto* rate_limiter : {&active_rate_limiter, &inactive_rate_limiter}) {
285
2
    auto start = MonoTime::Now();
286
22
    for (int i = 0; i < 10; i++) {
287
20
      auto status = rate_limiter->SendOrReceiveData([]() { return Status::OK(); },
288
20
                                                    []() { return kRate * 11 / 10; });
289
20
    }
290
2
    auto end = MonoTime::Now();
291
2
    elapsed_times.emplace_back(end.GetDeltaSince(start));
292
2
    LOG(INFO) << "Elapsed time is: " << elapsed_times.back().ToMilliseconds();
293
2
  }
294
1
  ASSERT_LT(elapsed_times[1].ToMilliseconds(), elapsed_times[0].ToMilliseconds() / 100);
295
1
}
296
297
} // namespace yb