From: Casey Bodley Date: Mon, 19 Jul 2021 22:07:47 +0000 (-0400) Subject: test/rgw: fix use of poll() with timers in unittest_rgw_dmclock_scheduler X-Git-Tag: v15.2.16~77^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=5ddf3d48e8a4f629078260faa3ada1a291d21265;p=ceph.git test/rgw: fix use of poll() with timers in unittest_rgw_dmclock_scheduler the AsyncScheduler uses an asio timer to dispatch work to its executor with an optional delay. when no delay is requested, it waits on the timer with an expiration time in the past (crimson::dmclock::TimeZero) tests are failing here because poll() is returning without executing the handlers of those expired timers asio implements these timers with timerfd and epoll. debugging with strace, i see that these timers armed with timerfd_settime() are not always immediately ready according to epoll_wait(): eventfd2(0, EFD_CLOEXEC|EFD_NONBLOCK) = 3 epoll_create1(EPOLL_CLOEXEC) = 4 timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC) = 5 epoll_ctl(4, EPOLL_CTL_ADD, 3, {events=EPOLLIN|EPOLLERR|EPOLLET, data={u32=14164052, u64=14164052}}) = 0 epoll_ctl(4, EPOLL_CTL_ADD, 5, {events=EPOLLIN|EPOLLERR, data={u32=14164064, u64=14164064}}) = 0 timerfd_settime(5, TFD_TIMER_ABSTIME, {it_interval={tv_sec=0, tv_nsec=0}, it_value={tv_sec=0, tv_nsec=1}}, {it_interval={tv_sec=0, tv_nsec=0}, it_value={tv_sec=0, tv_nsec=0}}) = 0 epoll_wait(4, [{events=EPOLLIN, data={u32=14164052, u64=14164052}}], 128, 0) = 1 epoll_wait(4, [], 128, 0) = 0 epoll_wait(4, [], 128, 0) = 0 epoll_wait(4, [], 128, 0) = 0 epoll_wait(4, [], 128, 0) = 0 epoll_wait(4, [{events=EPOLLIN, data={u32=14164064, u64=14164064}}], 128, 0) = 1 in this example, it took 6 calls to context.poll() before it was ready to execute the timer's handler to work around this, replace calls to context.poll() with calls to context.run_for() with a very short duration Fixes: https://tracker.ceph.com/issues/42788 Signed-off-by: Casey Bodley (cherry picked from commit 21baed999e31c5e69c75f0cbb8757ef91585d917) --- diff --git a/src/test/rgw/test_rgw_dmclock_scheduler.cc b/src/test/rgw/test_rgw_dmclock_scheduler.cc index b7e9b0eabf7c..d6eddff322f2 100644 --- a/src/test/rgw/test_rgw_dmclock_scheduler.cc +++ b/src/test/rgw/test_rgw_dmclock_scheduler.cc @@ -108,7 +108,7 @@ TEST(Queue, RateLimit) EXPECT_EQ(1u, counters(client_id::admin)->get(queue_counters::l_qlen)); EXPECT_EQ(1u, counters(client_id::auth)->get(queue_counters::l_qlen)); - context.poll(); + context.run_for(std::chrono::milliseconds(1)); EXPECT_TRUE(context.stopped()); ASSERT_TRUE(ec1); @@ -166,7 +166,7 @@ TEST(Queue, AsyncRequest) EXPECT_EQ(1u, counters(client_id::admin)->get(queue_counters::l_qlen)); EXPECT_EQ(1u, counters(client_id::auth)->get(queue_counters::l_qlen)); - context.poll(); + context.run_for(std::chrono::milliseconds(1)); EXPECT_TRUE(context.stopped()); ASSERT_TRUE(ec1); @@ -220,7 +220,7 @@ TEST(Queue, Cancel) EXPECT_FALSE(ec1); EXPECT_FALSE(ec2); - context.poll(); + context.run_for(std::chrono::milliseconds(1)); EXPECT_TRUE(context.stopped()); ASSERT_TRUE(ec1); @@ -268,7 +268,7 @@ TEST(Queue, CancelClient) EXPECT_FALSE(ec1); EXPECT_FALSE(ec2); - context.poll(); + context.run_for(std::chrono::milliseconds(1)); EXPECT_TRUE(context.stopped()); ASSERT_TRUE(ec1); @@ -318,7 +318,7 @@ TEST(Queue, CancelOnDestructor) EXPECT_FALSE(ec1); EXPECT_FALSE(ec2); - context.poll(); + context.run_for(std::chrono::milliseconds(1)); EXPECT_TRUE(context.stopped()); ASSERT_TRUE(ec1); @@ -372,20 +372,20 @@ TEST(Queue, CrossExecutorRequest) EXPECT_EQ(1u, counters(client_id::admin)->get(queue_counters::l_qlen)); EXPECT_EQ(1u, counters(client_id::auth)->get(queue_counters::l_qlen)); - callback_context.poll(); + callback_context.run_for(std::chrono::milliseconds(1)); // maintains work on callback executor while in queue EXPECT_FALSE(callback_context.stopped()); EXPECT_FALSE(ec1); EXPECT_FALSE(ec2); - queue_context.poll(); + queue_context.run_for(std::chrono::milliseconds(1)); EXPECT_TRUE(queue_context.stopped()); EXPECT_FALSE(ec1); // no callbacks until callback executor runs EXPECT_FALSE(ec2); - callback_context.poll(); + callback_context.run_for(std::chrono::milliseconds(1)); EXPECT_TRUE(callback_context.stopped()); ASSERT_TRUE(ec1); @@ -424,7 +424,7 @@ TEST(Queue, SpawnAsyncRequest) EXPECT_EQ(PhaseType::priority, p2); }); - context.poll(); + context.run_for(std::chrono::milliseconds(1)); EXPECT_TRUE(context.stopped()); }