diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/librbd/AsyncObjectThrottle.cc | |
parent | Initial commit. (diff) | |
download | ceph-upstream.tar.xz ceph-upstream.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/librbd/AsyncObjectThrottle.cc')
-rw-r--r-- | src/librbd/AsyncObjectThrottle.cc | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/src/librbd/AsyncObjectThrottle.cc b/src/librbd/AsyncObjectThrottle.cc new file mode 100644 index 00000000..b6dbcb26 --- /dev/null +++ b/src/librbd/AsyncObjectThrottle.cc @@ -0,0 +1,108 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +#include "librbd/AsyncObjectThrottle.h" +#include "common/RWLock.h" +#include "common/WorkQueue.h" +#include "librbd/AsyncRequest.h" +#include "librbd/ImageCtx.h" +#include "librbd/Utils.h" + +namespace librbd +{ + +template <typename T> +AsyncObjectThrottle<T>::AsyncObjectThrottle( + const AsyncRequest<T>* async_request, T &image_ctx, + const ContextFactory& context_factory, Context *ctx, + ProgressContext *prog_ctx, uint64_t object_no, uint64_t end_object_no) + : m_lock(util::unique_lock_name("librbd::AsyncThrottle::m_lock", this)), + m_async_request(async_request), m_image_ctx(image_ctx), + m_context_factory(context_factory), m_ctx(ctx), m_prog_ctx(prog_ctx), + m_object_no(object_no), m_end_object_no(end_object_no), m_current_ops(0), + m_ret(0) +{ +} + +template <typename T> +void AsyncObjectThrottle<T>::start_ops(uint64_t max_concurrent) { + ceph_assert(m_image_ctx.owner_lock.is_locked()); + bool complete; + { + Mutex::Locker l(m_lock); + for (uint64_t i = 0; i < max_concurrent; ++i) { + start_next_op(); + if (m_ret < 0 && m_current_ops == 0) { + break; + } + } + complete = (m_current_ops == 0); + } + if (complete) { + // avoid re-entrant callback + m_image_ctx.op_work_queue->queue(m_ctx, m_ret); + delete this; + } +} + +template <typename T> +void AsyncObjectThrottle<T>::finish_op(int r) { + bool complete; + { + RWLock::RLocker owner_locker(m_image_ctx.owner_lock); + Mutex::Locker locker(m_lock); + --m_current_ops; + if (r < 0 && r != -ENOENT && m_ret == 0) { + m_ret = r; + } + + start_next_op(); + complete = (m_current_ops == 0); + } + if (complete) { + m_ctx->complete(m_ret); + delete this; + } +} + +template <typename T> +void AsyncObjectThrottle<T>::start_next_op() { + bool done = false; + while (!done) { + if (m_async_request != NULL && m_async_request->is_canceled() && + m_ret == 0) { + // allow in-flight ops to complete, but don't start new ops + m_ret = -ERESTART; + return; + } else if (m_ret != 0 || m_object_no >= m_end_object_no) { + return; + } + + uint64_t ono = m_object_no++; + C_AsyncObjectThrottle<T> *ctx = m_context_factory(*this, ono); + + int r = ctx->send(); + if (r < 0) { + m_ret = r; + delete ctx; + return; + } else if (r > 0) { + // op completed immediately + delete ctx; + } else { + ++m_current_ops; + done = true; + } + if (m_prog_ctx != NULL) { + r = m_prog_ctx->update_progress(ono, m_end_object_no); + if (r < 0) { + m_ret = r; + } + } + } +} + +} // namespace librbd + +#ifndef TEST_F +template class librbd::AsyncObjectThrottle<librbd::ImageCtx>; +#endif |