1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "SyncPointPruneRequest.h"
5 #include "common/errno.h"
6 #include "journal/Journaler.h"
7 #include "librbd/ImageCtx.h"
8 #include "librbd/ImageState.h"
9 #include "librbd/Operations.h"
10 #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_sync::SyncPointPruneRequest: " \
17 << this << " " << __func__
20 namespace image_sync {
22 using librbd::util::create_context_callback;
25 SyncPointPruneRequest<I>::SyncPointPruneRequest(I *remote_image_ctx,
28 MirrorPeerClientMeta *client_meta,
30 : m_remote_image_ctx(remote_image_ctx), m_sync_complete(sync_complete),
31 m_journaler(journaler), m_client_meta(client_meta), m_on_finish(on_finish),
32 m_client_meta_copy(*client_meta) {
36 void SyncPointPruneRequest<I>::send() {
37 if (m_client_meta->sync_points.empty()) {
42 if (m_sync_complete) {
43 // if sync is complete, we can remove the master sync point
44 auto it = m_client_meta_copy.sync_points.begin();
45 MirrorPeerSyncPoint &sync_point = *it;
48 if (it == m_client_meta_copy.sync_points.end() ||
49 it->from_snap_name != sync_point.snap_name) {
50 m_snap_names.push_back(sync_point.snap_name);
53 if (!sync_point.from_snap_name.empty()) {
54 m_snap_names.push_back(sync_point.from_snap_name);
57 // if we have more than one sync point or invalid sync points,
59 RWLock::RLocker snap_locker(m_remote_image_ctx->snap_lock);
60 std::set<std::string> snap_names;
61 for (auto it = m_client_meta_copy.sync_points.rbegin();
62 it != m_client_meta_copy.sync_points.rend(); ++it) {
63 MirrorPeerSyncPoint &sync_point = *it;
64 if (&sync_point == &m_client_meta_copy.sync_points.front()) {
65 if (m_remote_image_ctx->get_snap_id(
66 cls::rbd::UserSnapshotNamespace(), sync_point.snap_name) ==
68 derr << ": failed to locate sync point snapshot: "
69 << sync_point.snap_name << dendl;
70 } else if (!sync_point.from_snap_name.empty()) {
71 derr << ": unexpected from_snap_name in primary sync point: "
72 << sync_point.from_snap_name << dendl;
74 // first sync point is OK -- keep it
77 m_invalid_master_sync_point = true;
80 if (snap_names.count(sync_point.snap_name) == 0) {
81 snap_names.insert(sync_point.snap_name);
82 m_snap_names.push_back(sync_point.snap_name);
85 MirrorPeerSyncPoint &front_sync_point =
86 m_client_meta_copy.sync_points.front();
87 if (!sync_point.from_snap_name.empty() &&
88 snap_names.count(sync_point.from_snap_name) == 0 &&
89 sync_point.from_snap_name != front_sync_point.snap_name) {
90 snap_names.insert(sync_point.from_snap_name);
91 m_snap_names.push_back(sync_point.from_snap_name);
100 void SyncPointPruneRequest<I>::send_remove_snap() {
101 if (m_snap_names.empty()) {
102 send_refresh_image();
106 const std::string &snap_name = m_snap_names.front();
108 dout(20) << ": snap_name=" << snap_name << dendl;
110 Context *ctx = create_context_callback<
111 SyncPointPruneRequest<I>, &SyncPointPruneRequest<I>::handle_remove_snap>(
113 m_remote_image_ctx->operations->snap_remove(cls::rbd::UserSnapshotNamespace(),
118 template <typename I>
119 void SyncPointPruneRequest<I>::handle_remove_snap(int r) {
120 dout(20) << ": r=" << r << dendl;
122 assert(!m_snap_names.empty());
123 std::string snap_name = m_snap_names.front();
124 m_snap_names.pop_front();
130 derr << ": failed to remove snapshot '" << snap_name << "': "
131 << cpp_strerror(r) << dendl;
139 template <typename I>
140 void SyncPointPruneRequest<I>::send_refresh_image() {
143 Context *ctx = create_context_callback<
144 SyncPointPruneRequest<I>, &SyncPointPruneRequest<I>::handle_refresh_image>(
146 m_remote_image_ctx->state->refresh(ctx);
149 template <typename I>
150 void SyncPointPruneRequest<I>::handle_refresh_image(int r) {
151 dout(20) << ": r=" << r << dendl;
154 derr << ": remote image refresh failed: " << cpp_strerror(r) << dendl;
159 send_update_client();
162 template <typename I>
163 void SyncPointPruneRequest<I>::send_update_client() {
166 if (m_sync_complete) {
167 m_client_meta_copy.sync_points.pop_front();
168 if (m_client_meta_copy.sync_points.empty()) {
169 m_client_meta_copy.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
172 while (m_client_meta_copy.sync_points.size() > 1) {
173 m_client_meta_copy.sync_points.pop_back();
175 if (m_invalid_master_sync_point) {
176 // all subsequent sync points would have been pruned
177 m_client_meta_copy.sync_points.clear();
181 bufferlist client_data_bl;
182 librbd::journal::ClientData client_data(m_client_meta_copy);
183 ::encode(client_data, client_data_bl);
185 Context *ctx = create_context_callback<
186 SyncPointPruneRequest<I>, &SyncPointPruneRequest<I>::handle_update_client>(
188 m_journaler->update_client(client_data_bl, ctx);
191 template <typename I>
192 void SyncPointPruneRequest<I>::handle_update_client(int r) {
193 dout(20) << ": r=" << r << dendl;
196 derr << ": failed to update client data: " << cpp_strerror(r)
202 // update provided meta structure to reflect reality
203 *m_client_meta = m_client_meta_copy;
207 template <typename I>
208 void SyncPointPruneRequest<I>::finish(int r) {
209 dout(20) << ": r=" << r << dendl;
211 m_on_finish->complete(r);
215 } // namespace image_sync
216 } // namespace mirror
219 template class rbd::mirror::image_sync::SyncPointPruneRequest<librbd::ImageCtx>;