Skip to content

Commit 7ba63ac

Browse files
committed
common/not_before_queue_t: tolerate non-monotonic cut-off values
as the system monotonic clock is used when the container is used in Scrub implementation, and on some kernels there are rare cases where the monotonic clock can go backwards, we need to tolerate such events. Fixes: https://tracker.ceph.com/issues/70055 Signed-off-by: Ronen Friedman <[email protected]>
1 parent 6c9e390 commit 7ba63ac

File tree

2 files changed

+25
-11
lines changed

2 files changed

+25
-11
lines changed

src/common/not_before_queue.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,21 @@ class not_before_queue_t {
210210
/**
211211
* advance_time
212212
*
213-
* Advances the eligibility cutoff, argument must be non-decreasing in
214-
* successive calls.
213+
* Advances the eligibility cutoff.
214+
* Argument should be non-decreasing in successive calls.
215+
*
216+
* As for the scrub queue the cutoff is a time value, and as we have
217+
* encountered rare cases of clock resets (even the monotonic clock
218+
* can be slightly adjusted backwards on some kernels), "backward"
219+
* updates will be tolerated - ignored and not assert.
220+
*
221+
* \retval: true if the cutoff was advanced. False if we
222+
* had to ignore the update.
215223
*/
216-
void advance_time(T next_time) {
217-
assert(next_time >= current_time);
224+
bool advance_time(T next_time) {
225+
if (next_time < current_time) {
226+
return false;
227+
}
218228
current_time = next_time;
219229
while (true) {
220230
if (ineligible_queue.empty()) {
@@ -233,6 +243,7 @@ class not_before_queue_t {
233243
ineligible_queue.erase(typename ineligible_queue_t::const_iterator(iter));
234244
eligible_queue.insert(item);
235245
}
246+
return true;
236247
}
237248

238249
/**

src/test/test_not_before_queue.cc

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@ TEST_F(NotBeforeTest, NotBefore) {
111111
ASSERT_EQ(queue.dequeue(), std::make_optional(e5));
112112
ASSERT_EQ(queue.dequeue(), std::nullopt);
113113

114-
queue.advance_time(1);
114+
EXPECT_TRUE(queue.advance_time(1U));
115+
// a 2'nd call using earlier time - should fail
116+
EXPECT_FALSE(queue.advance_time(0U));
115117

116118
EXPECT_EQ(queue.dequeue(), std::make_optional(e1));
117119
EXPECT_EQ(queue.dequeue(), std::make_optional(e2));
@@ -237,17 +239,17 @@ TEST_F(NotBeforeTest, RemoveIfByClass_with_cond) {
237239
// rm from both eligible and non-eligible
238240
EXPECT_EQ(
239241
queue.remove_if_by_class(
240-
57, [](const tv_t &v) { return v.ordering_value == 43; }),
242+
57U, [](const tv_t &v) { return v.ordering_value == 43; }),
241243
3);
242244
EXPECT_EQ(
243245
queue.remove_if_by_class(
244-
53, [](const tv_t &v) { return v.ordering_value == 44; }),
246+
53U, [](const tv_t &v) { return v.ordering_value == 44; }),
245247
2);
246248

247-
ASSERT_EQ(queue.total_count(), 17);
249+
ASSERT_EQ(queue.total_count(), 17U);
248250
EXPECT_EQ(
249251
queue.remove_if_by_class(
250-
57, [](const tv_t &v) { return v.ordering_value > 10; }, 20),
252+
57U, [](const tv_t &v) { return v.ordering_value > 10; }, 20),
251253
5);
252254
}
253255

@@ -294,14 +296,15 @@ TEST_F(NotBeforeTest, accumulate_1) {
294296
EXPECT_EQ(res_all, "abcdefgh");
295297

296298
// set time to 20: the order changes: 2, 4, 1, 3
297-
queue.advance_time(20);
299+
EXPECT_TRUE(queue.advance_time(20));
300+
EXPECT_FALSE(queue.advance_time(18));
298301
acc_just_elig = acc_just_elig_templ;
299302
res = queue.accumulate<std::string, decltype(acc_just_elig)>(
300303
std::move(acc_just_elig));
301304
EXPECT_EQ(res, "jpor");
302305

303306
// at 35: 2, 4, 1, 7, 8, 3
304-
queue.advance_time(35);
307+
EXPECT_TRUE(queue.advance_time(35));
305308
acc_just_elig = acc_just_elig_templ;
306309
res = queue.accumulate<std::string, decltype(acc_just_elig)>(
307310
std::move(acc_just_elig));

0 commit comments

Comments
 (0)