]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/test/librbd/io/test_mock_ImageRequestWQ.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / test / librbd / io / test_mock_ImageRequestWQ.cc
index 7a731db23a821b7ea0ed61be9fd329b1ccabaeec..dd4f153a5fbc0fadd7c6b8ef73a273bf7eec51a2 100644 (file)
@@ -5,6 +5,7 @@
 #include "test/librbd/test_support.h"
 #include "test/librbd/mock/MockImageCtx.h"
 #include "test/librbd/mock/exclusive_lock/MockPolicy.h"
+#include "librbd/io/ImageDispatchSpec.h"
 #include "librbd/io/ImageRequestWQ.h"
 #include "librbd/io/ImageRequest.h"
 
@@ -23,33 +24,53 @@ namespace io {
 template <>
 struct ImageRequest<librbd::MockTestImageCtx> {
   static ImageRequest* s_instance;
-  AioCompletion *aio_comp;
-
-  static ImageRequest* create_write_request(librbd::MockTestImageCtx &image_ctx,
-                                            AioCompletion *aio_comp,
-                                            Extents &&image_extents,
-                                            bufferlist &&bl, int op_flags,
-                                            const ZTracer::Trace &parent_trace) {
-    assert(s_instance != nullptr);
-    s_instance->aio_comp = aio_comp;
-    return s_instance;
-  }
+  AioCompletion *aio_comp = nullptr;
+
   static void aio_write(librbd::MockTestImageCtx *ictx, AioCompletion *c,
                         Extents &&image_extents, bufferlist &&bl, int op_flags,
                         const ZTracer::Trace &parent_trace) {
   }
 
+  ImageRequest() {
+    s_instance = this;
+  }
+};
+
+template <>
+struct ImageDispatchSpec<librbd::MockTestImageCtx> {
+  static ImageDispatchSpec* s_instance;
+  AioCompletion *aio_comp = nullptr;
+
+  static ImageDispatchSpec* create_write_request(
+      librbd::MockTestImageCtx &image_ctx, AioCompletion *aio_comp,
+      Extents &&image_extents, bufferlist &&bl, int op_flags,
+      const ZTracer::Trace &parent_trace) {
+    ceph_assert(s_instance != nullptr);
+    s_instance->aio_comp = aio_comp;
+    return s_instance;
+  }
+
+  static ImageDispatchSpec* create_flush_request(
+      librbd::MockTestImageCtx &image_ctx, AioCompletion *aio_comp,
+      FlushSource flush_source, const ZTracer::Trace &parent_trace) {
+    ceph_assert(s_instance != nullptr);
+    s_instance->aio_comp = aio_comp;
+    return s_instance;
+  }
 
   MOCK_CONST_METHOD0(is_write_op, bool());
   MOCK_CONST_METHOD0(start_op, void());
   MOCK_CONST_METHOD0(send, void());
   MOCK_CONST_METHOD1(fail, void(int));
+  MOCK_CONST_METHOD1(was_throttled, bool(uint64_t));
+  MOCK_CONST_METHOD0(were_all_throttled, bool());
+  MOCK_CONST_METHOD1(set_throttled, void(uint64_t));
+  MOCK_CONST_METHOD1(tokens_requested, uint64_t(uint64_t));
 
-  ImageRequest() {
+  ImageDispatchSpec() {
     s_instance = this;
   }
 };
-
 } // namespace io
 
 namespace util {
@@ -63,8 +84,8 @@ inline ImageCtx *get_image_ctx(MockTestImageCtx *image_ctx) {
 } // namespace librbd
 
 template <>
-struct ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>> {
-  typedef librbd::io::ImageRequest<librbd::MockTestImageCtx> ImageRequest;
+struct ThreadPool::PointerWQ<librbd::io::ImageDispatchSpec<librbd::MockTestImageCtx>> {
+  typedef librbd::io::ImageDispatchSpec<librbd::MockTestImageCtx> ImageDispatchSpec;
   static PointerWQ* s_instance;
 
   Mutex m_lock;
@@ -78,14 +99,15 @@ struct ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>>
 
   MOCK_METHOD0(drain, void());
   MOCK_METHOD0(empty, bool());
+  MOCK_METHOD0(mock_empty, bool());
   MOCK_METHOD0(signal, void());
   MOCK_METHOD0(process_finish, void());
 
-  MOCK_METHOD0(front, ImageRequest*());
-  MOCK_METHOD1(requeue, void(ImageRequest*));
+  MOCK_METHOD0(front, ImageDispatchSpec*());
+  MOCK_METHOD1(requeue, void(ImageDispatchSpec*));
 
   MOCK_METHOD0(dequeue, void*());
-  MOCK_METHOD1(queue, void(ImageRequest*));
+  MOCK_METHOD1(queue, void(ImageDispatchSpec*));
 
   void register_work_queue() {
     // no-op
@@ -98,21 +120,26 @@ struct ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>>
     Mutex::Locker locker(m_lock);
     return _void_dequeue();
   }
-  void invoke_process(ImageRequest *image_request) {
+  void invoke_process(ImageDispatchSpec *image_request) {
     process(image_request);
   }
 
   virtual void *_void_dequeue() {
     return dequeue();
   }
-  virtual void process(ImageRequest *req) = 0;
+  virtual void process(ImageDispatchSpec *req) = 0;
+  virtual bool _empty() {
+    return mock_empty();
+  }
 
 };
 
-ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>>*
-  ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>>::s_instance = nullptr;
+ThreadPool::PointerWQ<librbd::io::ImageDispatchSpec<librbd::MockTestImageCtx>>*
+  ThreadPool::PointerWQ<librbd::io::ImageDispatchSpec<librbd::MockTestImageCtx>>::s_instance = nullptr;
 librbd::io::ImageRequest<librbd::MockTestImageCtx>*
   librbd::io::ImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+librbd::io::ImageDispatchSpec<librbd::MockTestImageCtx>*
+  librbd::io::ImageDispatchSpec<librbd::MockTestImageCtx>::s_instance = nullptr;
 
 #include "librbd/io/ImageRequestWQ.cc"
 
@@ -128,8 +155,10 @@ using ::testing::WithArg;
 struct TestMockIoImageRequestWQ : public TestMockFixture {
   typedef ImageRequestWQ<librbd::MockTestImageCtx> MockImageRequestWQ;
   typedef ImageRequest<librbd::MockTestImageCtx> MockImageRequest;
+  typedef ImageDispatchSpec<librbd::MockTestImageCtx> MockImageDispatchSpec;
 
-  void expect_is_write_op(MockImageRequest &image_request, bool write_op) {
+  void expect_is_write_op(MockImageDispatchSpec &image_request,
+                          bool write_op) {
     EXPECT_CALL(image_request, is_write_op()).WillOnce(Return(write_op));
   }
 
@@ -141,8 +170,12 @@ struct TestMockIoImageRequestWQ : public TestMockFixture {
     EXPECT_CALL(image_request_wq, queue(_));
   }
 
+  void expect_requeue(MockImageRequestWQ &image_request_wq) {
+    EXPECT_CALL(image_request_wq, requeue(_));
+  }
+
   void expect_front(MockImageRequestWQ &image_request_wq,
-                    MockImageRequest *image_request) {
+                    MockImageDispatchSpec *image_request) {
     EXPECT_CALL(image_request_wq, front()).WillOnce(Return(image_request));
   }
 
@@ -153,7 +186,7 @@ struct TestMockIoImageRequestWQ : public TestMockFixture {
   }
 
   void expect_dequeue(MockImageRequestWQ &image_request_wq,
-                      MockImageRequest *image_request) {
+                      MockImageDispatchSpec *image_request) {
     EXPECT_CALL(image_request_wq, dequeue()).WillOnce(Return(image_request));
   }
 
@@ -180,7 +213,7 @@ struct TestMockIoImageRequestWQ : public TestMockFixture {
     EXPECT_CALL(mock_image_request_wq, process_finish()).Times(1);
   }
 
-  void expect_fail(MockImageRequest &mock_image_request, int r) {
+  void expect_fail(MockImageDispatchSpec &mock_image_request, int r) {
     EXPECT_CALL(mock_image_request, fail(r))
       .WillOnce(Invoke([&mock_image_request](int r) {
                     mock_image_request.aio_comp->get();
@@ -194,6 +227,26 @@ struct TestMockIoImageRequestWQ : public TestMockFixture {
                     *on_finish = ctx;
                   }));
   }
+
+  void expect_set_throttled(MockImageDispatchSpec &mock_image_request) {
+    EXPECT_CALL(mock_image_request, set_throttled(_)).Times(6);
+  }
+
+  void expect_was_throttled(MockImageDispatchSpec &mock_image_request, bool value) {
+    EXPECT_CALL(mock_image_request, was_throttled(_)).Times(6).WillRepeatedly(Return(value));
+  }
+
+  void expect_tokens_requested(MockImageDispatchSpec &mock_image_request, uint64_t value) {
+    EXPECT_CALL(mock_image_request, tokens_requested(_)).WillOnce(Return(value));
+  }
+
+  void expect_all_throttled(MockImageDispatchSpec &mock_image_request, bool value) {
+    EXPECT_CALL(mock_image_request, were_all_throttled()).WillOnce(Return(value));
+  }
+
+  void expect_start_op(MockImageDispatchSpec &mock_image_request) {
+    EXPECT_CALL(mock_image_request, start_op()).Times(1);
+  }
 };
 
 TEST_F(TestMockIoImageRequestWQ, AcquireLockError) {
@@ -206,22 +259,25 @@ TEST_F(TestMockIoImageRequestWQ, AcquireLockError) {
   MockExclusiveLock mock_exclusive_lock;
   mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
 
+  auto mock_queued_image_request = new MockImageDispatchSpec();
+  expect_was_throttled(*mock_queued_image_request, false);
+  expect_set_throttled(*mock_queued_image_request);
+
   InSequence seq;
   MockImageRequestWQ mock_image_request_wq(&mock_image_ctx, "io", 60, nullptr);
   expect_signal(mock_image_request_wq);
   mock_image_request_wq.set_require_lock(DIRECTION_WRITE, true);
 
-  auto mock_image_request = new MockImageRequest();
-  expect_is_write_op(*mock_image_request, true);
+  expect_is_write_op(*mock_queued_image_request, true);
   expect_queue(mock_image_request_wq);
   auto *aio_comp = new librbd::io::AioCompletion();
   mock_image_request_wq.aio_write(aio_comp, 0, 0, {}, 0);
 
   librbd::exclusive_lock::MockPolicy mock_exclusive_lock_policy;
-  expect_front(mock_image_request_wq, mock_image_request);
+  expect_front(mock_image_request_wq, mock_queued_image_request);
   expect_is_refresh_request(mock_image_ctx, false);
-  expect_is_write_op(*mock_image_request, true);
-  expect_dequeue(mock_image_request_wq, mock_image_request);
+  expect_is_write_op(*mock_queued_image_request, true);
+  expect_dequeue(mock_image_request_wq, mock_queued_image_request);
   expect_get_exclusive_lock_policy(mock_image_ctx, mock_exclusive_lock_policy);
   expect_may_auto_request_lock(mock_exclusive_lock_policy, true);
   Context *on_acquire = nullptr;
@@ -230,8 +286,8 @@ TEST_F(TestMockIoImageRequestWQ, AcquireLockError) {
   ASSERT_TRUE(on_acquire != nullptr);
 
   expect_process_finish(mock_image_request_wq);
-  expect_fail(*mock_image_request, -EPERM);
-  expect_is_write_op(*mock_image_request, true);
+  expect_fail(*mock_queued_image_request, -EPERM);
+  expect_is_write_op(*mock_queued_image_request, true);
   expect_signal(mock_image_request_wq);
   on_acquire->complete(-EPERM);
 
@@ -250,30 +306,32 @@ TEST_F(TestMockIoImageRequestWQ, AcquireLockBlacklisted) {
   MockExclusiveLock mock_exclusive_lock;
   mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
 
+  auto mock_queued_image_request = new MockImageDispatchSpec();
+  expect_was_throttled(*mock_queued_image_request, false);
+  expect_set_throttled(*mock_queued_image_request);
+
   InSequence seq;
   MockImageRequestWQ mock_image_request_wq(&mock_image_ctx, "io", 60, nullptr);
   expect_signal(mock_image_request_wq);
   mock_image_request_wq.set_require_lock(DIRECTION_WRITE, true);
 
-  auto mock_image_request = new MockImageRequest();
-  expect_is_write_op(*mock_image_request, true);
+  expect_is_write_op(*mock_queued_image_request, true);
   expect_queue(mock_image_request_wq);
   auto *aio_comp = new librbd::io::AioCompletion();
   mock_image_request_wq.aio_write(aio_comp, 0, 0, {}, 0);
 
   librbd::exclusive_lock::MockPolicy mock_exclusive_lock_policy;
-  expect_front(mock_image_request_wq, mock_image_request);
+  expect_front(mock_image_request_wq, mock_queued_image_request);
   expect_is_refresh_request(mock_image_ctx, false);
-  expect_is_write_op(*mock_image_request, true);
-  expect_dequeue(mock_image_request_wq, mock_image_request);
+  expect_is_write_op(*mock_queued_image_request, true);
+  expect_dequeue(mock_image_request_wq, mock_queued_image_request);
   expect_get_exclusive_lock_policy(mock_image_ctx, mock_exclusive_lock_policy);
   expect_may_auto_request_lock(mock_exclusive_lock_policy, false);
   EXPECT_CALL(*mock_image_ctx.exclusive_lock, get_unlocked_op_error())
     .WillOnce(Return(-EBLACKLISTED));
-
   expect_process_finish(mock_image_request_wq);
-  expect_fail(*mock_image_request, -EBLACKLISTED);
-  expect_is_write_op(*mock_image_request, true);
+  expect_fail(*mock_queued_image_request, -EBLACKLISTED);
+  expect_is_write_op(*mock_queued_image_request, true);
   expect_signal(mock_image_request_wq);
   ASSERT_TRUE(mock_image_request_wq.invoke_dequeue() == nullptr);
 
@@ -288,27 +346,30 @@ TEST_F(TestMockIoImageRequestWQ, RefreshError) {
 
   MockTestImageCtx mock_image_ctx(*ictx);
 
+  auto mock_queued_image_request = new MockImageDispatchSpec();
+  expect_was_throttled(*mock_queued_image_request, false);
+  expect_set_throttled(*mock_queued_image_request);
+
   InSequence seq;
   MockImageRequestWQ mock_image_request_wq(&mock_image_ctx, "io", 60, nullptr);
 
-  auto mock_image_request = new MockImageRequest();
-  expect_is_write_op(*mock_image_request, true);
+  expect_is_write_op(*mock_queued_image_request, true);
   expect_queue(mock_image_request_wq);
   auto *aio_comp = new librbd::io::AioCompletion();
   mock_image_request_wq.aio_write(aio_comp, 0, 0, {}, 0);
 
-  expect_front(mock_image_request_wq, mock_image_request);
+  expect_front(mock_image_request_wq, mock_queued_image_request);
   expect_is_refresh_request(mock_image_ctx, true);
-  expect_is_write_op(*mock_image_request, true);
-  expect_dequeue(mock_image_request_wq, mock_image_request);
+  expect_is_write_op(*mock_queued_image_request, true);
+  expect_dequeue(mock_image_request_wq, mock_queued_image_request);
   Context *on_refresh = nullptr;
   expect_refresh(mock_image_ctx, &on_refresh);
   ASSERT_TRUE(mock_image_request_wq.invoke_dequeue() == nullptr);
   ASSERT_TRUE(on_refresh != nullptr);
 
   expect_process_finish(mock_image_request_wq);
-  expect_fail(*mock_image_request, -EPERM);
-  expect_is_write_op(*mock_image_request, true);
+  expect_fail(*mock_queued_image_request, -EPERM);
+  expect_is_write_op(*mock_queued_image_request, true);
   expect_signal(mock_image_request_wq);
   on_refresh->complete(-EPERM);
 
@@ -317,5 +378,76 @@ TEST_F(TestMockIoImageRequestWQ, RefreshError) {
   aio_comp->release();
 }
 
+TEST_F(TestMockIoImageRequestWQ, QosNoLimit) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockTestImageCtx mock_image_ctx(*ictx);
+
+  MockImageDispatchSpec mock_queued_image_request;
+  expect_was_throttled(mock_queued_image_request, false);
+  expect_set_throttled(mock_queued_image_request);
+
+  InSequence seq;
+  MockImageRequestWQ mock_image_request_wq(&mock_image_ctx, "io", 60, nullptr);
+
+  mock_image_request_wq.apply_qos_limit(RBD_QOS_BPS_THROTTLE, 0, 0);
+
+  expect_front(mock_image_request_wq, &mock_queued_image_request);
+  expect_is_refresh_request(mock_image_ctx, false);
+  expect_is_write_op(mock_queued_image_request, true);
+  expect_dequeue(mock_image_request_wq, &mock_queued_image_request);
+  expect_start_op(mock_queued_image_request);
+  ASSERT_TRUE(mock_image_request_wq.invoke_dequeue() == &mock_queued_image_request);
+}
+
+TEST_F(TestMockIoImageRequestWQ, BPSQosNoBurst) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockTestImageCtx mock_image_ctx(*ictx);
+
+  MockImageDispatchSpec mock_queued_image_request;
+  expect_was_throttled(mock_queued_image_request, false);
+  expect_set_throttled(mock_queued_image_request);
+
+  InSequence seq;
+  MockImageRequestWQ mock_image_request_wq(&mock_image_ctx, "io", 60, nullptr);
+
+  mock_image_request_wq.apply_qos_limit(RBD_QOS_BPS_THROTTLE, 1, 0);
+
+  expect_front(mock_image_request_wq, &mock_queued_image_request);
+  expect_tokens_requested(mock_queued_image_request, 2);
+  expect_dequeue(mock_image_request_wq, &mock_queued_image_request);
+  expect_all_throttled(mock_queued_image_request, true);
+  expect_requeue(mock_image_request_wq);
+  expect_signal(mock_image_request_wq);
+  ASSERT_TRUE(mock_image_request_wq.invoke_dequeue() == nullptr);
+}
+
+TEST_F(TestMockIoImageRequestWQ, BPSQosWithBurst) {
+  librbd::ImageCtx *ictx;
+  ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+  MockTestImageCtx mock_image_ctx(*ictx);
+
+  MockImageDispatchSpec mock_queued_image_request;
+  expect_was_throttled(mock_queued_image_request, false);
+  expect_set_throttled(mock_queued_image_request);
+
+  InSequence seq;
+  MockImageRequestWQ mock_image_request_wq(&mock_image_ctx, "io", 60, nullptr);
+
+  mock_image_request_wq.apply_qos_limit(RBD_QOS_BPS_THROTTLE, 1, 1);
+
+  expect_front(mock_image_request_wq, &mock_queued_image_request);
+  expect_tokens_requested(mock_queued_image_request, 2);
+  expect_dequeue(mock_image_request_wq, &mock_queued_image_request);
+  expect_all_throttled(mock_queued_image_request, true);
+  expect_requeue(mock_image_request_wq);
+  expect_signal(mock_image_request_wq);
+  ASSERT_TRUE(mock_image_request_wq.invoke_dequeue() == nullptr);
+}
+
 } // namespace io
 } // namespace librbd