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/debug.h"
6 #include "common/errno.h"
7 #include "journal/Journaler.h"
8 #include "librbd/ImageCtx.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/Operations.h"
11 #include "librbd/Utils.h"
14 #define dout_context g_ceph_context
15 #define dout_subsys ceph_subsys_rbd_mirror
17 #define dout_prefix *_dout << "rbd::mirror::image_sync::SyncPointPruneRequest: " \
18 << this << " " << __func__
21 namespace image_sync
{
23 using librbd::util::create_context_callback
;
26 SyncPointPruneRequest
<I
>::SyncPointPruneRequest(I
*remote_image_ctx
,
29 MirrorPeerClientMeta
*client_meta
,
31 : m_remote_image_ctx(remote_image_ctx
), m_sync_complete(sync_complete
),
32 m_journaler(journaler
), m_client_meta(client_meta
), m_on_finish(on_finish
),
33 m_client_meta_copy(*client_meta
) {
37 void SyncPointPruneRequest
<I
>::send() {
38 if (m_client_meta
->sync_points
.empty()) {
43 if (m_sync_complete
) {
44 // if sync is complete, we can remove the master sync point
45 auto it
= m_client_meta_copy
.sync_points
.begin();
46 MirrorPeerSyncPoint
&sync_point
= *it
;
49 if (it
== m_client_meta_copy
.sync_points
.end() ||
50 it
->from_snap_name
!= sync_point
.snap_name
) {
51 m_snap_names
.push_back(sync_point
.snap_name
);
54 if (!sync_point
.from_snap_name
.empty()) {
55 m_snap_names
.push_back(sync_point
.from_snap_name
);
58 // if we have more than one sync point or invalid sync points,
60 RWLock::RLocker
snap_locker(m_remote_image_ctx
->snap_lock
);
61 std::set
<std::string
> snap_names
;
62 for (auto it
= m_client_meta_copy
.sync_points
.rbegin();
63 it
!= m_client_meta_copy
.sync_points
.rend(); ++it
) {
64 MirrorPeerSyncPoint
&sync_point
= *it
;
65 if (&sync_point
== &m_client_meta_copy
.sync_points
.front()) {
66 if (m_remote_image_ctx
->get_snap_id(
67 cls::rbd::UserSnapshotNamespace(), sync_point
.snap_name
) ==
69 derr
<< ": failed to locate sync point snapshot: "
70 << sync_point
.snap_name
<< dendl
;
71 } else if (!sync_point
.from_snap_name
.empty()) {
72 derr
<< ": unexpected from_snap_name in primary sync point: "
73 << sync_point
.from_snap_name
<< dendl
;
75 // first sync point is OK -- keep it
78 m_invalid_master_sync_point
= true;
81 if (snap_names
.count(sync_point
.snap_name
) == 0) {
82 snap_names
.insert(sync_point
.snap_name
);
83 m_snap_names
.push_back(sync_point
.snap_name
);
86 MirrorPeerSyncPoint
&front_sync_point
=
87 m_client_meta_copy
.sync_points
.front();
88 if (!sync_point
.from_snap_name
.empty() &&
89 snap_names
.count(sync_point
.from_snap_name
) == 0 &&
90 sync_point
.from_snap_name
!= front_sync_point
.snap_name
) {
91 snap_names
.insert(sync_point
.from_snap_name
);
92 m_snap_names
.push_back(sync_point
.from_snap_name
);
100 template <typename I
>
101 void SyncPointPruneRequest
<I
>::send_remove_snap() {
102 if (m_snap_names
.empty()) {
103 send_refresh_image();
107 const std::string
&snap_name
= m_snap_names
.front();
109 dout(20) << ": snap_name=" << snap_name
<< dendl
;
111 Context
*ctx
= create_context_callback
<
112 SyncPointPruneRequest
<I
>, &SyncPointPruneRequest
<I
>::handle_remove_snap
>(
114 m_remote_image_ctx
->operations
->snap_remove(cls::rbd::UserSnapshotNamespace(),
119 template <typename I
>
120 void SyncPointPruneRequest
<I
>::handle_remove_snap(int r
) {
121 dout(20) << ": r=" << r
<< dendl
;
123 ceph_assert(!m_snap_names
.empty());
124 std::string snap_name
= m_snap_names
.front();
125 m_snap_names
.pop_front();
131 derr
<< ": failed to remove snapshot '" << snap_name
<< "': "
132 << cpp_strerror(r
) << dendl
;
140 template <typename I
>
141 void SyncPointPruneRequest
<I
>::send_refresh_image() {
144 Context
*ctx
= create_context_callback
<
145 SyncPointPruneRequest
<I
>, &SyncPointPruneRequest
<I
>::handle_refresh_image
>(
147 m_remote_image_ctx
->state
->refresh(ctx
);
150 template <typename I
>
151 void SyncPointPruneRequest
<I
>::handle_refresh_image(int r
) {
152 dout(20) << ": r=" << r
<< dendl
;
155 derr
<< ": remote image refresh failed: " << cpp_strerror(r
) << dendl
;
160 send_update_client();
163 template <typename I
>
164 void SyncPointPruneRequest
<I
>::send_update_client() {
167 if (m_sync_complete
) {
168 m_client_meta_copy
.sync_points
.pop_front();
169 if (m_client_meta_copy
.sync_points
.empty()) {
170 m_client_meta_copy
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
173 while (m_client_meta_copy
.sync_points
.size() > 1) {
174 m_client_meta_copy
.sync_points
.pop_back();
176 if (m_invalid_master_sync_point
) {
177 // all subsequent sync points would have been pruned
178 m_client_meta_copy
.sync_points
.clear();
182 bufferlist client_data_bl
;
183 librbd::journal::ClientData
client_data(m_client_meta_copy
);
184 encode(client_data
, client_data_bl
);
186 Context
*ctx
= create_context_callback
<
187 SyncPointPruneRequest
<I
>, &SyncPointPruneRequest
<I
>::handle_update_client
>(
189 m_journaler
->update_client(client_data_bl
, ctx
);
192 template <typename I
>
193 void SyncPointPruneRequest
<I
>::handle_update_client(int r
) {
194 dout(20) << ": r=" << r
<< dendl
;
197 derr
<< ": failed to update client data: " << cpp_strerror(r
)
203 // update provided meta structure to reflect reality
204 *m_client_meta
= m_client_meta_copy
;
208 template <typename I
>
209 void SyncPointPruneRequest
<I
>::finish(int r
) {
210 dout(20) << ": r=" << r
<< dendl
;
212 m_on_finish
->complete(r
);
216 } // namespace image_sync
217 } // namespace mirror
220 template class rbd::mirror::image_sync::SyncPointPruneRequest
<librbd::ImageCtx
>;