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>;