Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / AsyncObjectThrottle.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 #include "librbd/AsyncObjectThrottle.h"
4 #include "common/RWLock.h"
5 #include "common/WorkQueue.h"
6 #include "librbd/AsyncRequest.h"
7 #include "librbd/ImageCtx.h"
8 #include "librbd/Utils.h"
9
10 namespace librbd
11 {
12
13 template <typename T>
14 AsyncObjectThrottle<T>::AsyncObjectThrottle(
15     const AsyncRequest<T>* async_request, T &image_ctx,
16     const ContextFactory& context_factory, Context *ctx,
17     ProgressContext *prog_ctx, uint64_t object_no, uint64_t end_object_no)
18   : m_lock(util::unique_lock_name("librbd::AsyncThrottle::m_lock", this)),
19     m_async_request(async_request), m_image_ctx(image_ctx),
20     m_context_factory(context_factory), m_ctx(ctx), m_prog_ctx(prog_ctx),
21     m_object_no(object_no), m_end_object_no(end_object_no), m_current_ops(0),
22     m_ret(0)
23 {
24 }
25
26 template <typename T>
27 void AsyncObjectThrottle<T>::start_ops(uint64_t max_concurrent) {
28   assert(m_image_ctx.owner_lock.is_locked());
29   bool complete;
30   {
31     Mutex::Locker l(m_lock);
32     for (uint64_t i = 0; i < max_concurrent; ++i) {
33       start_next_op();
34       if (m_ret < 0 && m_current_ops == 0) {
35         break;
36       }
37     }
38     complete = (m_current_ops == 0);
39   }
40   if (complete) {
41     // avoid re-entrant callback
42     m_image_ctx.op_work_queue->queue(m_ctx, m_ret);
43     delete this;
44   }
45 }
46
47 template <typename T>
48 void AsyncObjectThrottle<T>::finish_op(int r) {
49   bool complete;
50   {
51     RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
52     Mutex::Locker locker(m_lock);
53     --m_current_ops;
54     if (r < 0 && r != -ENOENT && m_ret == 0) {
55       m_ret = r;
56     }
57
58     start_next_op();
59     complete = (m_current_ops == 0);
60   }
61   if (complete) {
62     m_ctx->complete(m_ret);
63     delete this;
64   }
65 }
66
67 template <typename T>
68 void AsyncObjectThrottle<T>::start_next_op() {
69   bool done = false;
70   while (!done) {
71     if (m_async_request != NULL && m_async_request->is_canceled() &&
72         m_ret == 0) {
73       // allow in-flight ops to complete, but don't start new ops
74       m_ret = -ERESTART;
75       return;
76     } else if (m_ret != 0 || m_object_no >= m_end_object_no) {
77       return;
78     }
79
80     uint64_t ono = m_object_no++;
81     C_AsyncObjectThrottle<T> *ctx = m_context_factory(*this, ono);
82
83     int r = ctx->send();
84     if (r < 0) {
85       m_ret = r;
86       delete ctx;
87       return;
88     } else if (r > 0) {
89       // op completed immediately
90       delete ctx;
91     } else {
92       ++m_current_ops;
93       done = true;
94     }
95     if (m_prog_ctx != NULL) {
96       m_prog_ctx->update_progress(ono, m_end_object_no);
97     }
98   }
99 }
100
101 } // namespace librbd
102
103 #ifndef TEST_F
104 template class librbd::AsyncObjectThrottle<librbd::ImageCtx>;
105 #endif