#include "common/errno.h"
#include "journal/Journaler.h"
#include "librbd/ImageCtx.h"
+#include "librbd/ObjectMap.h"
#include "librbd/Utils.h"
#include "librbd/journal/Types.h"
#include "tools/rbd_mirror/image_sync/ImageCopyRequest.h"
return;
}
+ send_copy_object_map();
+}
+
+template <typename I>
+void ImageSync<I>::send_copy_object_map() {
+ m_local_image_ctx->snap_lock.get_read();
+ if (!m_local_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP,
+ m_local_image_ctx->snap_lock)) {
+ m_local_image_ctx->snap_lock.put_read();
+ send_prune_sync_points();
+ return;
+ }
+
+ assert(m_local_image_ctx->object_map != nullptr);
+
+ assert(!m_client_meta->sync_points.empty());
+ librbd::journal::MirrorPeerSyncPoint &sync_point =
+ m_client_meta->sync_points.front();
+ auto snap_id_it = m_local_image_ctx->snap_ids.find(sync_point.snap_name);
+ assert(snap_id_it != m_local_image_ctx->snap_ids.end());
+ librados::snap_t snap_id = snap_id_it->second;
+
+ CephContext *cct = m_local_image_ctx->cct;
+ ldout(cct, 20) << ": snap_id=" << snap_id << ", "
+ << "snap_name=" << sync_point.snap_name << dendl;
+
+ // rollback the object map (copy snapshot object map to HEAD)
+ RWLock::WLocker object_map_locker(m_local_image_ctx->object_map_lock);
+ Context *ctx = create_context_callback<
+ ImageSync<I>, &ImageSync<I>::handle_copy_object_map>(this);
+ m_local_image_ctx->object_map->rollback(snap_id, ctx);
+ m_local_image_ctx->snap_lock.put_read();
+}
+
+template <typename I>
+void ImageSync<I>::handle_copy_object_map(int r) {
+ CephContext *cct = m_local_image_ctx->cct;
+ ldout(cct, 20) << dendl;
+
+ assert(r == 0);
+ send_refresh_object_map();
+}
+
+template <typename I>
+void ImageSync<I>::send_refresh_object_map() {
+ CephContext *cct = m_local_image_ctx->cct;
+ ldout(cct, 20) << dendl;
+
+ Context *ctx = create_context_callback<
+ ImageSync<I>, &ImageSync<I>::handle_refresh_object_map>(this);
+ m_object_map = m_local_image_ctx->create_object_map(CEPH_NOSNAP);
+ m_object_map->open(ctx);
+}
+
+template <typename I>
+void ImageSync<I>::handle_refresh_object_map(int r) {
+ CephContext *cct = m_local_image_ctx->cct;
+ ldout(cct, 20) << dendl;
+
+ assert(r == 0);
+ {
+ RWLock::WLocker snap_locker(m_local_image_ctx->snap_lock);
+ std::swap(m_local_image_ctx->object_map, m_object_map);
+ }
+ delete m_object_map;
+
send_prune_sync_points();
}
#define RBD_MIRROR_IMAGE_SYNC_H
#include "include/int_types.h"
+#include "librbd/ImageCtx.h"
#include "librbd/Journal.h"
#include "common/Mutex.h"
#include <map>
class Mutex;
class SafeTimer;
namespace journal { class Journaler; }
-namespace librbd { class ImageCtx; }
namespace librbd { namespace journal { struct MirrorPeerClientMeta; } }
namespace rbd {
* COPY_SNAPSHOTS
* |
* v
- * COPY_IMAGE . . . . . .
- * | .
- * v .
- * PRUNE_SYNC_POINTS . (image sync canceled)
- * | .
- * v .
- * <finish> < . . . . . .
+ * COPY_IMAGE . . . . . . . . . . . . . .
+ * | .
+ * v .
+ * COPY_OBJECT_MAP (skip if object .
+ * | map disabled) .
+ * v .
+ * REFRESH_OBJECT_MAP (skip if object .
+ * | map disabled) .
+ * v
+ * PRUNE_SYNC_POINTS . (image sync canceled)
+ * | .
+ * v .
+ * <finish> < . . . . . . . . . . . . . .
*
* @endverbatim
*/
bool m_canceled = false;
image_sync::ImageCopyRequest<ImageCtxT> *m_image_copy_request;
+ decltype(ImageCtxT::object_map) m_object_map = nullptr;
void send_prune_catch_up_sync_point();
void handle_prune_catch_up_sync_point(int r);
void send_copy_image();
void handle_copy_image(int r);
+ void send_copy_object_map();
+ void handle_copy_object_map(int r);
+
+ void send_refresh_object_map();
+ void handle_refresh_object_map(int r);
+
void send_prune_sync_points();
void handle_prune_sync_points(int r);
#include "ObjectCopyRequest.h"
#include "librados/snap_set_diff.h"
+#include "librbd/ObjectMap.h"
#include "librbd/Utils.h"
#include "common/errno.h"
namespace mirror {
namespace image_sync {
+using librbd::util::create_context_callback;
using librbd::util::create_rados_ack_callback;
using librbd::util::create_rados_safe_callback;
return;
}
- finish(r);
+ send_update_object_map();
+}
+
+template <typename I>
+void ObjectCopyRequest<I>::send_update_object_map() {
+ m_local_image_ctx->snap_lock.get_read();
+ if (!m_local_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP,
+ m_local_image_ctx->snap_lock) ||
+ m_snap_object_states.empty()) {
+ m_local_image_ctx->snap_lock.put_read();
+ finish(0);
+ return;
+ }
+
+ assert(m_local_image_ctx->object_map != nullptr);
+
+ auto snap_object_state = *m_snap_object_states.begin();
+ m_snap_object_states.erase(m_snap_object_states.begin());
+
+ CephContext *cct = m_local_image_ctx->cct;
+ ldout(cct, 20) << ": "
+ << "snap_id=" << snap_object_state.first << ", "
+ << "object_state=" << static_cast<uint32_t>(
+ snap_object_state.second)
+ << dendl;
+
+ RWLock::WLocker object_map_locker(m_local_image_ctx->object_map_lock);
+ Context *ctx = create_context_callback<
+ ObjectCopyRequest<I>, &ObjectCopyRequest<I>::handle_update_object_map>(
+ this);
+ m_local_image_ctx->object_map->aio_update(snap_object_state.first,
+ m_object_number,
+ m_object_number + 1,
+ snap_object_state.second,
+ boost::none, ctx);
+ m_local_image_ctx->snap_lock.put_read();
+}
+
+template <typename I>
+void ObjectCopyRequest<I>::handle_update_object_map(int r) {
+ CephContext *cct = m_local_image_ctx->cct;
+ ldout(cct, 20) << ": r=" << r << dendl;
+
+ assert(r == 0);
+ if (!m_snap_object_states.empty()) {
+ send_update_object_map();
+ return;
+ }
+ finish(0);
}
template <typename I>
ldout(cct, 20) << ": clearing truncate diff: " << trunc << dendl;
}
+ // prepare the object map state
+ {
+ RWLock::RLocker snap_locker(m_local_image_ctx->snap_lock);
+ uint8_t object_state = OBJECT_EXISTS;
+ if (m_local_image_ctx->test_features(RBD_FEATURE_FAST_DIFF,
+ m_local_image_ctx->snap_lock) &&
+ diff.empty() && end_size == prev_end_size) {
+ object_state = OBJECT_EXISTS_CLEAN;
+ }
+ m_snap_object_states[end_snap_id] = object_state;
+ }
+
// object write/zero, or truncate
for (auto it = diff.begin(); it != diff.end(); ++it) {
ldout(cct, 20) << ": read/write op: " << it.get_start() << "~"
m_snap_sync_ops[start_snap_id].emplace_back(SYNC_OP_TYPE_TRUNC,
end_size, 0U, bufferlist());
}
- } else if (prev_exists) {
- // object remove
- ldout(cct, 20) << ": remove op" << dendl;
- m_snap_sync_ops[start_snap_id].emplace_back(SYNC_OP_TYPE_REMOVE, 0U, 0U,
- bufferlist());
+ } else {
+ m_snap_object_states[end_snap_id] = OBJECT_NONEXISTENT;
+ if (prev_exists) {
+ // object remove
+ ldout(cct, 20) << ": remove op" << dendl;
+ m_snap_sync_ops[start_snap_id].emplace_back(SYNC_OP_TYPE_REMOVE, 0U, 0U,
+ bufferlist());
+ }
}
prev_end_size = end_size;
* LIST_SNAPS
* |
* v
- * READ_OBJECT <----\
- * | | (repeat for each snapshot)
- * v |
- * WRITE_OBJECT ----/
+ * READ_OBJECT <--------\
+ * | | (repeat for each snapshot)
+ * v |
+ * WRITE_OBJECT --------/
+ * |
+ * | /-----------\
+ * | | | (repeat for each snapshot)
+ * v v |
+ * UPDATE_OBJECT_MAP ---/ (skip if object
+ * | map disabled)
* |
* v
* <finish>
typedef std::tuple<SyncOpType, uint64_t, uint64_t, bufferlist> SyncOp;
typedef std::list<SyncOp> SyncOps;
typedef std::map<librados::snap_t, SyncOps> SnapSyncOps;
+ typedef std::map<librados::snap_t, uint8_t> SnapObjectStates;
ImageCtxT *m_local_image_ctx;
ImageCtxT *m_remote_image_ctx;
int m_snap_ret;
SnapSyncOps m_snap_sync_ops;
+ SnapObjectStates m_snap_object_states;
void send_list_snaps();
void handle_list_snaps(int r);
void send_write_object();
void handle_write_object(int r);
+ void send_update_object_map();
+ void handle_update_object_map(int r);
+
void compute_diffs();
void finish(int r);