1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2    	// vim: ts=8 sw=2 smarttab
3    	
4    	#include "EventPreprocessor.h"
5    	#include "common/debug.h"
6    	#include "common/dout.h"
7    	#include "common/errno.h"
8    	#include "common/WorkQueue.h"
9    	#include "journal/Journaler.h"
10   	#include "librbd/ImageCtx.h"
11   	#include "librbd/ImageState.h"
12   	#include "librbd/Utils.h"
13   	#include "librbd/journal/Types.h"
14   	#include <boost/variant.hpp>
15   	
16   	#define dout_context g_ceph_context
17   	#define dout_subsys ceph_subsys_rbd_mirror
18   	
19   	#undef dout_prefix
20   	#define dout_prefix *_dout << "rbd::mirror::image_replayer::EventPreprocessor: " \
21   	                           << this << " " << __func__
22   	
23   	namespace rbd {
24   	namespace mirror {
25   	namespace image_replayer {
26   	
27   	using librbd::util::create_context_callback;
28   	
29   	template <typename I>
30   	EventPreprocessor<I>::EventPreprocessor(I &local_image_ctx,
31   	                                        Journaler &remote_journaler,
32   	                                        const std::string &local_mirror_uuid,
33   	                                        MirrorPeerClientMeta *client_meta,
34   	                                        ContextWQ *work_queue)
35   	  : m_local_image_ctx(local_image_ctx), m_remote_journaler(remote_journaler),
36   	    m_local_mirror_uuid(local_mirror_uuid), m_client_meta(client_meta),
37   	    m_work_queue(work_queue) {
38   	}
39   	
40   	template <typename I>
(1) Event exn_spec_violation: An exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE" is thrown but the throw list "throw()" doesn't allow it to be thrown. This will cause a call to unexpected() which usually calls terminate().
Also see events: [fun_call_w_exception]
41   	EventPreprocessor<I>::~EventPreprocessor() {
(2) Event fun_call_w_exception: Called function throws an exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE". [details]
Also see events: [exn_spec_violation]
42   	  ceph_assert(!m_in_progress);
43   	}
44   	
45   	template <typename I>
46   	bool EventPreprocessor<I>::is_required(const EventEntry &event_entry) {
47   	  SnapSeqs snap_seqs(m_client_meta->snap_seqs);
48   	  return (prune_snap_map(&snap_seqs) ||
49   	          event_entry.get_event_type() ==
50   	            librbd::journal::EVENT_TYPE_SNAP_RENAME);
51   	}
52   	
53   	template <typename I>
54   	void EventPreprocessor<I>::preprocess(EventEntry *event_entry,
55   	                                      Context *on_finish) {
56   	  ceph_assert(!m_in_progress);
57   	  m_in_progress = true;
58   	  m_event_entry = event_entry;
59   	  m_on_finish = on_finish;
60   	
61   	  refresh_image();
62   	}
63   	
64   	template <typename I>
65   	void EventPreprocessor<I>::refresh_image() {
66   	  dout(20) << dendl;
67   	
68   	  Context *ctx = create_context_callback<
69   	    EventPreprocessor<I>, &EventPreprocessor<I>::handle_refresh_image>(this);
70   	  m_local_image_ctx.state->refresh(ctx);
71   	}
72   	
73   	template <typename I>
74   	void EventPreprocessor<I>::handle_refresh_image(int r) {
75   	  dout(20) << ": r=" << r << dendl;
76   	
77   	  if (r < 0) {
78   	    derr << "error encountered during image refresh: " << cpp_strerror(r)
79   	         << dendl;
80   	    finish(r);
81   	    return;
82   	  }
83   	
84   	  preprocess_event();
85   	}
86   	
87   	template <typename I>
88   	void EventPreprocessor<I>::preprocess_event() {
89   	  dout(20) << dendl;
90   	
91   	  m_snap_seqs = m_client_meta->snap_seqs;
92   	  m_snap_seqs_updated = prune_snap_map(&m_snap_seqs);
93   	
94   	  int r = boost::apply_visitor(PreprocessEventVisitor(this),
95   	                               m_event_entry->event);
96   	  if (r < 0) {
97   	    finish(r);
98   	    return;
99   	  }
100  	
101  	  update_client();
102  	}
103  	
104  	template <typename I>
105  	int EventPreprocessor<I>::preprocess_snap_rename(
106  	    librbd::journal::SnapRenameEvent &event) {
107  	  dout(20) << ": "
108  	           << "remote_snap_id=" << event.snap_id << ", "
109  	           << "src_snap_name=" << event.src_snap_name << ", "
110  	           << "dest_snap_name=" << event.dst_snap_name << dendl;
111  	
112  	  auto snap_seq_it = m_snap_seqs.find(event.snap_id);
113  	  if (snap_seq_it != m_snap_seqs.end()) {
114  	    dout(20) << ": remapping remote snap id " << snap_seq_it->first << " "
115  	             << "to local snap id " << snap_seq_it->second << dendl;
116  	    event.snap_id = snap_seq_it->second;
117  	    return 0;
118  	  }
119  	
120  	  auto snap_id_it = m_local_image_ctx.snap_ids.find({cls::rbd::UserSnapshotNamespace(),
121  							     event.src_snap_name});
122  	  if (snap_id_it == m_local_image_ctx.snap_ids.end()) {
123  	    dout(20) << ": cannot map remote snapshot '" << event.src_snap_name << "' "
124  	             << "to local snapshot" << dendl;
125  	    event.snap_id = CEPH_NOSNAP;
126  	    return -ENOENT;
127  	  }
128  	
129  	  dout(20) << ": mapping remote snap id " << event.snap_id << " "
130  	           << "to local snap id " << snap_id_it->second << dendl;
131  	  m_snap_seqs_updated = true;
132  	  m_snap_seqs[event.snap_id] = snap_id_it->second;
133  	  event.snap_id = snap_id_it->second;
134  	  return 0;
135  	}
136  	
137  	template <typename I>
138  	void EventPreprocessor<I>::update_client() {
139  	  if (!m_snap_seqs_updated) {
140  	    finish(0);
141  	    return;
142  	  }
143  	
144  	  dout(20) << dendl;
145  	  librbd::journal::MirrorPeerClientMeta client_meta(*m_client_meta);
146  	  client_meta.snap_seqs = m_snap_seqs;
147  	
148  	  librbd::journal::ClientData client_data(client_meta);
149  	  bufferlist data_bl;
150  	  encode(client_data, data_bl);
151  	
152  	  Context *ctx = create_context_callback<
153  	    EventPreprocessor<I>, &EventPreprocessor<I>::handle_update_client>(
154  	      this);
155  	  m_remote_journaler.update_client(data_bl, ctx);
156  	}
157  	
158  	template <typename I>
159  	void EventPreprocessor<I>::handle_update_client(int r) {
160  	  dout(20) << ": r=" << r << dendl;
161  	
162  	  if (r < 0) {
163  	    derr << "failed to update mirror peer journal client: "
164  	         << cpp_strerror(r) << dendl;
165  	    finish(r);
166  	    return;
167  	  }
168  	
169  	  m_client_meta->snap_seqs = m_snap_seqs;
170  	  finish(0);
171  	}
172  	
173  	template <typename I>
174  	bool EventPreprocessor<I>::prune_snap_map(SnapSeqs *snap_seqs) {
175  	  bool pruned = false;
176  	
177  	  std::shared_lock image_locker{m_local_image_ctx.image_lock};
178  	  for (auto it = snap_seqs->begin(); it != snap_seqs->end(); ) {
179  	    auto current_it(it++);
180  	    if (m_local_image_ctx.snap_info.count(current_it->second) == 0) {
181  	      snap_seqs->erase(current_it);
182  	      pruned = true;
183  	    }
184  	  }
185  	  return pruned;
186  	}
187  	
188  	template <typename I>
189  	void EventPreprocessor<I>::finish(int r) {
190  	  dout(20) << ": r=" << r << dendl;
191  	
192  	  Context *on_finish = m_on_finish;
193  	  m_on_finish = nullptr;
194  	  m_event_entry = nullptr;
195  	  m_in_progress = false;
196  	  m_snap_seqs_updated = false;
197  	  m_work_queue->queue(on_finish, r);
198  	}
199  	
200  	} // namespace image_replayer
201  	} // namespace mirror
202  	} // namespace rbd
203  	
204  	template class rbd::mirror::image_replayer::EventPreprocessor<librbd::ImageCtx>;
205