]>
git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd_mirror/image_replayer/ReplayStatusFormatter.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "ReplayStatusFormatter.h"
5 #include "common/debug.h"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "journal/Journaler.h"
9 #include "librbd/ImageCtx.h"
10 #include "librbd/Journal.h"
11 #include "librbd/Utils.h"
13 #define dout_context g_ceph_context
14 #define dout_subsys ceph_subsys_rbd_mirror
16 #define dout_prefix *_dout << "rbd::mirror::image_replayer::ReplayStatusFormatter: " \
17 << this << " " << __func__ << ": "
21 namespace image_replayer
{
23 using librbd::util::unique_lock_name
;
26 ReplayStatusFormatter
<I
>::ReplayStatusFormatter(Journaler
*journaler
,
27 const std::string
&mirror_uuid
)
28 : m_journaler(journaler
),
29 m_mirror_uuid(mirror_uuid
),
30 m_lock(unique_lock_name("ReplayStatusFormatter::m_lock", this)) {
34 bool ReplayStatusFormatter
<I
>::get_or_send_update(std::string
*description
,
38 bool in_progress
= false;
40 Mutex::Locker
locker(m_lock
);
44 m_on_finish
= on_finish
;
49 dout(10) << "previous request is still in progress, ignoring" << dendl
;
50 on_finish
->complete(-EAGAIN
);
54 m_master_position
= cls::journal::ObjectPosition();
55 m_mirror_position
= cls::journal::ObjectPosition();
57 cls::journal::Client master_client
, mirror_client
;
60 r
= m_journaler
->get_cached_client(librbd::Journal
<>::IMAGE_CLIENT_ID
,
63 derr
<< "error retrieving registered master client: "
64 << cpp_strerror(r
) << dendl
;
66 r
= m_journaler
->get_cached_client(m_mirror_uuid
, &mirror_client
);
68 derr
<< "error retrieving registered mirror client: "
69 << cpp_strerror(r
) << dendl
;
73 if (!master_client
.commit_position
.object_positions
.empty()) {
75 *(master_client
.commit_position
.object_positions
.begin());
78 if (!mirror_client
.commit_position
.object_positions
.empty()) {
80 *(mirror_client
.commit_position
.object_positions
.begin());
83 if (!calculate_behind_master_or_send_update()) {
84 dout(20) << "need to update tag cache" << dendl
;
91 Mutex::Locker
locker(m_lock
);
92 assert(m_on_finish
== on_finish
);
93 m_on_finish
= nullptr;
96 on_finish
->complete(-EEXIST
);
100 template <typename I
>
101 bool ReplayStatusFormatter
<I
>::calculate_behind_master_or_send_update() {
102 dout(20) << "m_master_position=" << m_master_position
103 << ", m_mirror_position=" << m_mirror_position
<< dendl
;
105 m_entries_behind_master
= 0;
107 if (m_master_position
== cls::journal::ObjectPosition() ||
108 m_master_position
.tag_tid
< m_mirror_position
.tag_tid
) {
112 cls::journal::ObjectPosition master
= m_master_position
;
113 uint64_t mirror_tag_tid
= m_mirror_position
.tag_tid
;
115 while (master
.tag_tid
!= mirror_tag_tid
) {
116 auto tag_it
= m_tag_cache
.find(master
.tag_tid
);
117 if (tag_it
== m_tag_cache
.end()) {
118 send_update_tag_cache(master
.tag_tid
, mirror_tag_tid
);
121 librbd::journal::TagData
&tag_data
= tag_it
->second
;
122 m_entries_behind_master
+= master
.entry_tid
;
123 master
= cls::journal::ObjectPosition(0, tag_data
.predecessor
.tag_tid
,
124 tag_data
.predecessor
.entry_tid
);
126 m_entries_behind_master
+= master
.entry_tid
- m_mirror_position
.entry_tid
;
128 dout(20) << "clearing tags not needed any more (below mirror position)"
131 uint64_t tag_tid
= mirror_tag_tid
;
132 size_t old_size
= m_tag_cache
.size();
133 while (tag_tid
!= 0) {
134 auto tag_it
= m_tag_cache
.find(tag_tid
);
135 if (tag_it
== m_tag_cache
.end()) {
138 librbd::journal::TagData
&tag_data
= tag_it
->second
;
140 dout(20) << "erasing tag " << tag_data
<< "for tag_tid " << tag_tid
143 tag_tid
= tag_data
.predecessor
.tag_tid
;
144 m_tag_cache
.erase(tag_it
);
147 dout(20) << old_size
- m_tag_cache
.size() << " entries cleared" << dendl
;
152 template <typename I
>
153 void ReplayStatusFormatter
<I
>::send_update_tag_cache(uint64_t master_tag_tid
,
154 uint64_t mirror_tag_tid
) {
156 dout(20) << "master_tag_tid=" << master_tag_tid
<< ", mirror_tag_tid="
157 << mirror_tag_tid
<< dendl
;
159 if (master_tag_tid
== mirror_tag_tid
) {
160 Context
*on_finish
= nullptr;
162 Mutex::Locker
locker(m_lock
);
163 std::swap(m_on_finish
, on_finish
);
167 on_finish
->complete(0);
171 FunctionContext
*ctx
= new FunctionContext(
172 [this, master_tag_tid
, mirror_tag_tid
](int r
) {
173 handle_update_tag_cache(master_tag_tid
, mirror_tag_tid
, r
);
175 m_journaler
->get_tag(master_tag_tid
, &m_tag
, ctx
);
178 template <typename I
>
179 void ReplayStatusFormatter
<I
>::handle_update_tag_cache(uint64_t master_tag_tid
,
180 uint64_t mirror_tag_tid
,
182 librbd::journal::TagData tag_data
;
185 derr
<< "error retrieving tag " << master_tag_tid
<< ": " << cpp_strerror(r
)
188 dout(20) << "retrieved tag " << master_tag_tid
<< ": " << m_tag
<< dendl
;
190 bufferlist::iterator it
= m_tag
.data
.begin();
192 ::decode(tag_data
, it
);
193 } catch (const buffer::error
&err
) {
194 derr
<< "error decoding tag " << master_tag_tid
<< ": " << err
.what()
199 if (tag_data
.predecessor
.mirror_uuid
!=
200 librbd::Journal
<>::LOCAL_MIRROR_UUID
&&
201 tag_data
.predecessor
.mirror_uuid
!=
202 librbd::Journal
<>::ORPHAN_MIRROR_UUID
) {
203 dout(20) << "hit remote image non-primary epoch" << dendl
;
204 tag_data
.predecessor
.tag_tid
= mirror_tag_tid
;
205 } else if (tag_data
.predecessor
.tag_tid
== 0) {
206 // We failed. Don't consider this fatal, just terminate retrieving.
207 dout(20) << "making fake tag" << dendl
;
208 tag_data
.predecessor
.tag_tid
= mirror_tag_tid
;
211 dout(20) << "decoded tag " << master_tag_tid
<< ": " << tag_data
<< dendl
;
213 m_tag_cache
.insert(std::make_pair(master_tag_tid
, tag_data
));
214 send_update_tag_cache(tag_data
.predecessor
.tag_tid
, mirror_tag_tid
);
217 template <typename I
>
218 void ReplayStatusFormatter
<I
>::format(std::string
*description
) {
220 dout(20) << "m_master_position=" << m_master_position
221 << ", m_mirror_position=" << m_mirror_position
222 << ", m_entries_behind_master=" << m_entries_behind_master
<< dendl
;
224 std::stringstream ss
;
225 ss
<< "master_position=";
226 if (m_master_position
== cls::journal::ObjectPosition()) {
229 ss
<< m_master_position
;
231 ss
<< ", mirror_position=";
232 if (m_mirror_position
== cls::journal::ObjectPosition()) {
235 ss
<< m_mirror_position
;
237 ss
<< ", entries_behind_master="
238 << (m_entries_behind_master
> 0 ? m_entries_behind_master
: 0);
240 *description
= ss
.str();
243 } // namespace image_replayer
244 } // namespace mirror
248 rbd::mirror::image_replayer::ReplayStatusFormatter
<librbd::ImageCtx
>;