]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
rbd-mirror: sync snapshots between remote-local images during bootstrap
authorJason Dillaman <dillaman@redhat.com>
Mon, 7 Mar 2016 22:33:49 +0000 (17:33 -0500)
committerJason Dillaman <dillaman@redhat.com>
Sun, 13 Mar 2016 03:40:15 +0000 (22:40 -0500)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/tools/Makefile-client.am
src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc [new file with mode: 0644]
src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.h [new file with mode: 0644]

index ed6da4e560f4481dfdfb6b4e812f67caec38261c..dbd3cf05199cc198184b6d34cab668cd6cf3a62d 100644 (file)
@@ -88,7 +88,8 @@ librbd_mirror_internal_la_SOURCES = \
        tools/rbd_mirror/Replayer.cc \
        tools/rbd_mirror/Threads.cc \
        tools/rbd_mirror/types.cc \
-       tools/rbd_mirror/image_sync/ObjectCopyRequest.cc
+       tools/rbd_mirror/image_sync/ObjectCopyRequest.cc \
+       tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc
 noinst_LTLIBRARIES += librbd_mirror_internal.la
 noinst_HEADERS += \
        tools/rbd_mirror/ClusterWatcher.h \
@@ -98,7 +99,8 @@ noinst_HEADERS += \
        tools/rbd_mirror/Replayer.h \
        tools/rbd_mirror/Threads.h \
        tools/rbd_mirror/types.h \
-       tools/rbd_mirror/image_sync/ObjectCopyRequest.h
+       tools/rbd_mirror/image_sync/ObjectCopyRequest.h \
+       tools/rbd_mirror/image_sync/SnapshotCopyRequest.h
 
 rbd_mirror_SOURCES = \
        tools/rbd_mirror/main.cc
diff --git a/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc b/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc
new file mode 100644 (file)
index 0000000..b53c0e1
--- /dev/null
@@ -0,0 +1,239 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "SnapshotCopyRequest.h"
+#include "common/errno.h"
+#include "journal/Journaler.h"
+#include "librbd/Operations.h"
+#include "librbd/Utils.h"
+#include "librbd/journal/Types.h"
+
+#define dout_subsys ceph_subsys_rbd_mirror
+#undef dout_prefix
+#define dout_prefix *_dout << "rbd::mirror::image_sync::SnapshotCopyRequest: " \
+                           << this << " " << __func__
+
+namespace rbd {
+namespace mirror {
+namespace image_sync {
+
+namespace {
+
+template <typename I>
+const std::string &get_snapshot_name(I *image_ctx, librados::snap_t snap_id) {
+  auto snap_it = std::find_if(image_ctx->snap_ids.begin(),
+                              image_ctx->snap_ids.end(),
+                              [snap_id](
+      const std::pair<std::string, librados::snap_t> &pair) {
+    return pair.second == snap_id;
+  });
+  assert(snap_it != image_ctx->snap_ids.end());
+  return snap_it->first;
+}
+
+} // anonymous namespace
+
+using librbd::util::create_context_callback;
+
+
+
+template <typename I>
+SnapshotCopyRequest<I>::SnapshotCopyRequest(I *local_image_ctx,
+                                            I *remote_image_ctx,
+                                            SnapMap *snap_map,
+                                            Journaler *journaler,
+                                            librbd::journal::MirrorPeerClientMeta *meta,
+                                            Context *on_finish)
+  : m_local_image_ctx(local_image_ctx), m_remote_image_ctx(remote_image_ctx),
+    m_snap_map(snap_map), m_journaler(journaler), m_client_meta(meta),
+    m_on_finish(on_finish), m_snap_seqs(meta->snap_seqs) {
+  m_snap_map->clear();
+
+  // snap ids ordered from oldest to newest
+  m_remote_snap_ids.insert(remote_image_ctx->snaps.begin(),
+                           remote_image_ctx->snaps.end());
+  m_local_snap_ids.insert(local_image_ctx->snaps.begin(),
+                          local_image_ctx->snaps.end());
+}
+
+template <typename I>
+void SnapshotCopyRequest<I>::send() {
+  send_snap_remove();
+}
+
+template <typename I>
+void SnapshotCopyRequest<I>::send_snap_remove() {
+  librados::snap_t local_snap_id = CEPH_NOSNAP;
+  while (local_snap_id == CEPH_NOSNAP && !m_local_snap_ids.empty()) {
+    librados::snap_t snap_id = *m_local_snap_ids.begin();
+
+    // if local snapshot id isn't in our mapping table, delete it
+    // we match by id since snapshots can be renamed
+    if (std::find_if(m_snap_seqs.begin(), m_snap_seqs.end(),
+                     [snap_id](const SnapSeqs::value_type& pair) {
+        return pair.second == snap_id; }) == m_snap_seqs.end()) {
+      local_snap_id = snap_id;
+      m_local_snap_ids.erase(m_local_snap_ids.begin());
+    }
+  }
+
+  if (local_snap_id == CEPH_NOSNAP && m_local_snap_ids.empty()) {
+    // no local snapshots to delete
+    send_snap_create();
+    return;
+  }
+
+  m_snap_name = get_snapshot_name(m_local_image_ctx, local_snap_id);
+
+  CephContext *cct = m_local_image_ctx->cct;
+  ldout(cct, 20) << ": "
+                 << "snap_name=" << m_snap_name << ", "
+                 << "snap_id=" << local_snap_id << dendl;
+
+  Context *ctx = create_context_callback<
+    SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::handle_snap_remove>(
+      this);
+  RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
+  m_local_image_ctx->operations->snap_remove(m_snap_name.c_str(), ctx);
+}
+
+template <typename I>
+void SnapshotCopyRequest<I>::handle_snap_remove(int r) {
+  CephContext *cct = m_local_image_ctx->cct;
+  ldout(cct, 20) << ": r=" << r << dendl;
+
+  if (r < 0) {
+    lderr(cct) << "failed to remove snapshot '" << m_snap_name << "': "
+               << cpp_strerror(r) << dendl;
+    finish(r);
+    return;
+  }
+
+  send_snap_remove();
+}
+
+template <typename I>
+void SnapshotCopyRequest<I>::send_snap_create() {
+  librados::snap_t remote_snap_id = CEPH_NOSNAP;
+  while (remote_snap_id == CEPH_NOSNAP && !m_remote_snap_ids.empty()) {
+    librados::snap_t snap_id = *m_remote_snap_ids.begin();
+    if (m_snap_seqs.find(snap_id) == m_snap_seqs.end()) {
+      // missing remote -> local mapping
+      remote_snap_id = snap_id;
+    } else {
+      // already have remote -> local mapping
+      m_remote_snap_ids.erase(m_remote_snap_ids.begin());
+    }
+  }
+
+  if (remote_snap_id == CEPH_NOSNAP && m_remote_snap_ids.empty()) {
+    // no local snapshots to create
+    send_update_client();
+    return;
+  }
+
+  m_snap_name = get_snapshot_name(m_remote_image_ctx, remote_snap_id);
+
+  CephContext *cct = m_local_image_ctx->cct;
+  ldout(cct, 20) << ": "
+                 << "snap_name=" << m_snap_name << ", "
+                 << "snap_id=" << remote_snap_id << dendl;
+
+  Context *ctx = create_context_callback<
+    SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::handle_snap_create>(
+      this);
+  RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock);
+  m_local_image_ctx->operations->snap_create(m_snap_name.c_str(), ctx, 0U);
+}
+
+template <typename I>
+void SnapshotCopyRequest<I>::handle_snap_create(int r) {
+  CephContext *cct = m_local_image_ctx->cct;
+  ldout(cct, 20) << ": r=" << r << dendl;
+
+  if (r < 0) {
+    lderr(cct) << "failed to create snapshot '" << m_snap_name << "': "
+               << cpp_strerror(r) << dendl;
+    finish(r);
+    return;
+  }
+
+  assert(!m_remote_snap_ids.empty());
+  librados::snap_t remote_snap_id = *m_remote_snap_ids.begin();
+  m_remote_snap_ids.erase(m_remote_snap_ids.begin());
+
+  auto snap_it = m_local_image_ctx->snap_ids.find(m_snap_name);
+  assert(snap_it != m_local_image_ctx->snap_ids.end());
+  librados::snap_t local_snap_id = snap_it->second;
+
+  ldout(cct, 20) << ": mapping remote snap id " << remote_snap_id << " to "
+                 << local_snap_id << dendl;
+  m_snap_seqs[remote_snap_id] = local_snap_id;
+
+  send_snap_create();
+}
+
+template <typename I>
+void SnapshotCopyRequest<I>::send_update_client() {
+  CephContext *cct = m_local_image_ctx->cct;
+  ldout(cct, 20) << dendl;
+
+  compute_snap_map();
+
+  librbd::journal::MirrorPeerClientMeta client_meta(*m_client_meta);
+  client_meta.snap_seqs = m_snap_seqs;
+
+  librbd::journal::ClientData client_data(client_meta);
+  bufferlist data_bl;
+  ::encode(client_data, data_bl);
+
+  Context *ctx = create_context_callback<
+    SnapshotCopyRequest<I>, &SnapshotCopyRequest<I>::handle_update_client>(
+      this);
+  m_journaler->update_client(data_bl, ctx);
+}
+
+template <typename I>
+void SnapshotCopyRequest<I>::handle_update_client(int r) {
+  CephContext *cct = m_local_image_ctx->cct;
+  ldout(cct, 20) << ": r=" << r << dendl;
+
+  if (r < 0) {
+    lderr(cct) << "failed to update client data: " << cpp_strerror(r) << dendl;
+    finish(r);
+    return;
+  }
+
+  m_client_meta->snap_seqs = m_snap_seqs;
+
+  finish(0);
+}
+
+template <typename I>
+void SnapshotCopyRequest<I>::finish(int r) {
+  CephContext *cct = m_local_image_ctx->cct;
+  ldout(cct, 20) << ": r=" << r << dendl;
+
+  if (r >= 0) {
+    m_client_meta->snap_seqs = m_snap_seqs;
+  }
+
+  m_on_finish->complete(r);
+  delete this;
+}
+
+template <typename I>
+void SnapshotCopyRequest<I>::compute_snap_map() {
+  SnapIds local_snap_ids;
+  for (auto &pair : m_snap_seqs) {
+    local_snap_ids.reserve(1 + local_snap_ids.size());
+    local_snap_ids.insert(local_snap_ids.begin(), pair.second);
+    m_snap_map->insert(std::make_pair(pair.first, local_snap_ids));
+  }
+}
+
+} // namespace image_sync
+} // namespace mirror
+} // namespace rbd
+
+template class rbd::mirror::image_sync::SnapshotCopyRequest<librbd::ImageCtx>;
diff --git a/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.h b/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.h
new file mode 100644 (file)
index 0000000..44368f2
--- /dev/null
@@ -0,0 +1,112 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef RBD_MIRROR_IMAGE_SYNC_SNAPSHOT_COPY_REQUEST_H
+#define RBD_MIRROR_IMAGE_SYNC_SNAPSHOT_COPY_REQUEST_H
+
+#include "include/int_types.h"
+#include "include/rados/librados.hpp"
+#include "common/snap_types.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/Journal.h"
+#include <map>
+#include <set>
+#include <string>
+#include <tuple>
+
+class Context;
+namespace journal { class Journaler; }
+namespace librbd { namespace journal { struct MirrorPeerClientMeta; } }
+
+namespace rbd {
+namespace mirror {
+namespace image_sync {
+
+template <typename ImageCtxT = librbd::ImageCtx>
+class SnapshotCopyRequest {
+public:
+  typedef librbd::journal::TypeTraits<ImageCtxT> TypeTraits;
+  typedef typename TypeTraits::Journaler Journaler;
+
+  typedef std::vector<librados::snap_t> SnapIds;
+  typedef std::map<librados::snap_t, SnapIds> SnapMap;
+
+  static SnapshotCopyRequest* create(ImageCtxT *local_image_ctx,
+                                     ImageCtxT *remote_image_ctx,
+                                     SnapMap *snap_map, Journaler *journaler,
+                                     librbd::journal::MirrorPeerClientMeta *client_meta,
+                                     Context *on_finish) {
+    return new SnapshotCopyRequest(local_image_ctx, remote_image_ctx,
+                                   snap_map, journaler, client_meta, on_finish);
+  }
+
+  SnapshotCopyRequest(ImageCtxT *local_image_ctx, ImageCtxT *remote_image_ctx,
+                      SnapMap *snap_map, Journaler *journaler,
+                      librbd::journal::MirrorPeerClientMeta *client_meta,
+                      Context *on_finish);
+
+  void send();
+
+private:
+  /**
+   * @verbatim
+   *
+   * <start>
+   *    |
+   *    |   /-------\
+   *    |   |       |
+   *    v   v       | (repeat as needed)
+   * REMOVE_SNAP <--/
+   *    |
+   *    |   /-------\
+   *    |   |       |
+   *    v   v       | (repeat as needed)
+   * CREATE_SNAP <--/
+   *    |
+   *    v
+   * UPDATE_CLIENT
+   *    |
+   *    v
+   * <finish>
+   *
+   * @endverbatim
+   */
+
+  typedef std::set<librados::snap_t> SnapIdSet;
+  typedef std::map<librados::snap_t, librados::snap_t> SnapSeqs;
+
+  ImageCtxT *m_local_image_ctx;
+  ImageCtxT *m_remote_image_ctx;
+  SnapMap *m_snap_map;
+  Journaler *m_journaler;
+  librbd::journal::MirrorPeerClientMeta *m_client_meta;
+  Context *m_on_finish;
+
+  SnapIdSet m_local_snap_ids;
+  SnapIdSet m_remote_snap_ids;
+  SnapSeqs m_snap_seqs;
+
+  std::string m_snap_name;
+
+  void send_snap_remove();
+  void handle_snap_remove(int r);
+
+  void send_snap_create();
+  void handle_snap_create(int r);
+
+  void send_update_client();
+  void handle_update_client(int r);
+
+  void finish(int r);
+
+  void compute_snap_map();
+
+};
+
+} // namespace image_sync
+} // namespace mirror
+} // namespace rbd
+
+extern template class rbd::mirror::image_sync::SnapshotCopyRequest<librbd::ImageCtx>;
+
+#endif // RBD_MIRROR_IMAGE_SYNC_SNAPSHOT_COPY_REQUEST_H