group_snap_create "${primary_cluster}" "${pool}/${group}" "${snap}"
check_group_snap_exists "${primary_cluster}" "${pool}/${group}" "${snap}"
local group_snap_id
- get_newest_group_snapshot_id "${primary_cluster}" "${pool}/${group}" group_snap_id
+ get_newest_created_group_snapshot_id "${primary_cluster}" "${pool}/${group}" group_snap_id
mirror_group_enable "${primary_cluster}" "${pool}/${group}"
wait_for_group_present "${secondary_cluster}" "${pool}" "${group}" "${group_image_count}"
wait_for_group_status_in_pool_dir "${primary_cluster}" "${pool}"/"${group}" 'down+unknown' 0
fi
+ wait_for_group_synced "${primary_cluster}" "${pool}/${group}" "${secondary_cluster}" "${pool}/${group}"
check_group_snap_exists "${secondary_cluster}" "${pool}/${group}" "${snap}"
- wait_for_group_snap_sync_complete "${secondary_cluster}" "${pool}/${group}" "${group_snap_id}"
- wait_for_group_synced "${primary_cluster}" "${pool}/${group}" "${secondary_cluster}" "${pool}/${group}"
mirror_group_snapshot_and_wait_for_sync_complete "${secondary_cluster}" "${primary_cluster}" "${pool}"/"${group}"
group_snap_remove "${primary_cluster}" "${pool}/${group}" "${snap}"
wait_for_group_synced "${primary_cluster}" "${pool}"/"${group}" "${secondary_cluster}" "${pool}"/"${group}"
local primary_group_snap_id
- get_newest_group_snapshot_id "${primary_cluster}" "${pool}"/"${group}" primary_group_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${primary_cluster}" "${pool}"/"${group}" primary_group_snap_id
local secondary_group_snap_id
- get_newest_group_snapshot_id "${secondary_cluster}" "${pool}"/"${group}" secondary_group_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${secondary_cluster}" "${pool}"/"${group}" secondary_group_snap_id
test "${primary_group_snap_id}" = "${secondary_group_snap_id}" || { fail "mismatched ids"; return 1; }
# Add image to synced group (whilst daemon is stopped)
wait_for_group_present "${secondary_cluster}" "${pool}" "${group}" "${group_image_count}"
fi
- get_newest_group_snapshot_id "${primary_cluster}" "${pool}"/"${group}" primary_group_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${primary_cluster}" "${pool}"/"${group}" primary_group_snap_id
test "${primary_group_snap_id}" != "${secondary_group_snap_id}" || { fail "matched ids"; return 1; }
echo "starting daemon"
wait_for_group_status_in_pool_dir "${secondary_cluster}" "${pool}"/"${group}" 'up+replaying' $(("${group_image_count}"+1))
wait_for_group_synced "${primary_cluster}" "${pool}"/"${group}" "${secondary_cluster}" "${pool}"/"${group}"
- get_newest_group_snapshot_id "${secondary_cluster}" "${pool}"/"${group}" secondary_group_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${secondary_cluster}" "${pool}"/"${group}" secondary_group_snap_id
test "${primary_group_snap_id}" = "${secondary_group_snap_id}" || { fail "mismatched ids"; return 1; }
# removed image from synced group (whilst daemon is stopped)
mirror_group_enable "${primary_cluster}" "${pool}/${group}"
fi
- get_newest_group_snapshot_id "${primary_cluster}" "${pool}"/"${group}" primary_group_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${primary_cluster}" "${pool}"/"${group}" primary_group_snap_id
test "${primary_group_snap_id}" != "${secondary_group_snap_id}" || { fail "matched ids"; return 1; }
echo "starting daemon"
wait_for_group_status_in_pool_dir "${secondary_cluster}" "${pool}"/"${group}" 'up+replaying' "${group_image_count}"
wait_for_group_synced "${primary_cluster}" "${pool}"/"${group}" "${secondary_cluster}" "${pool}"/"${group}"
- get_newest_group_snapshot_id "${secondary_cluster}" "${pool}"/"${group}" secondary_group_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${secondary_cluster}" "${pool}"/"${group}" secondary_group_snap_id
test "${primary_group_snap_id}" = "${secondary_group_snap_id}" || { fail "mismatched ids"; return 1; }
# TODO When dynamic groups are support this test could be extended with more actions whilst daemon is stopped.
fi
local group_snap_id
- get_newest_group_snapshot_id "${primary_cluster}" "${pool}/${group0}" group_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${primary_cluster}" "${pool}/${group0}" group_snap_id
echo "id = ${group_snap_id}"
wait_for_test_group_snap_present "${secondary_cluster}" "${pool}/${group0}" "${group_snap_id}" 1
mirror_group_enable "${primary_cluster}" "${pool}/${group0}"
wait_for_group_present "${secondary_cluster}" "${pool}" "${group0}" "${image_count}"
local group_snap_id
- get_newest_group_snapshot_id "${primary_cluster}" "${pool}/${group0}" group_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${primary_cluster}" "${pool}/${group0}" group_snap_id
wait_for_test_group_snap_present "${secondary_cluster}" "${pool}/${group0}" "${group_snap_id}" 1
# stop the daemon to prevent further syncing of snapshots
# failback to original primary (cluster2)
local group_snap_id_a group_snap_id_b
- get_newest_group_snapshot_id "${secondary_cluster}" "${pool}"/"${group0}" group_snap_id_a
- get_newest_group_snapshot_id "${primary_cluster}" "${pool}"/"${group0}" group_snap_id_b
+ get_newest_complete_mirror_group_snapshot_id "${secondary_cluster}" "${pool}"/"${group0}" group_snap_id_a
+ get_newest_complete_mirror_group_snapshot_id "${primary_cluster}" "${pool}"/"${group0}" group_snap_id_b
test "${group_snap_id_a}" = "${group_snap_id_b}" || fail "group not synced"
# demote - neither site is primary
# confirm that a new snapshot was taken by the demote operation
local group_snap_id_c
- get_newest_group_snapshot_id "${secondary_cluster}" "${pool}"/"${group0}" group_snap_id_c
+ get_newest_complete_mirror_group_snapshot_id "${secondary_cluster}" "${pool}"/"${group0}" group_snap_id_c
test "${group_snap_id_a}" != "${group_snap_id_c}" || fail "new snap not taken by demote"
local group_id_before group_id_after
wait_for_group_synced "${secondary_cluster}" "${pool}"/"${group0}" "${primary_cluster}" "${pool}/${group0}"
local group_snap_id_e group_snap_id_f
- get_newest_group_snapshot_id "${secondary_cluster}" "${pool}"/"${group0}" group_snap_id_e
- get_newest_group_snapshot_id "${primary_cluster}" "${pool}"/"${group0}" group_snap_id_f
+ get_newest_complete_mirror_group_snapshot_id "${secondary_cluster}" "${pool}"/"${group0}" group_snap_id_e
+ get_newest_complete_mirror_group_snapshot_id "${primary_cluster}" "${pool}"/"${group0}" group_snap_id_f
test "${group_snap_id_c}" = "${group_snap_id_e}" || fail "new snap on original secondary"
test "${group_snap_id_c}" = "${group_snap_id_f}" || fail "group not synced"
compare_image_with_snapshot "${secondary_cluster}" "${pool}/${image_prefix}0" "${primary_cluster}" "${pool}/${image_prefix}0@${snap0}"
local group_snap_id secondary_group_snap_id primary_group_snap_id
- get_newest_group_snapshot_id "${primary_cluster}" "${pool}/${group0}" primary_group_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${primary_cluster}" "${pool}/${group0}" primary_group_snap_id
echo "id = ${primary_group_snap_id}"
# stop the daemon to prevent further syncing of snapshots
stop_mirrors "${secondary_cluster}"
wait_for_group_status_in_pool_dir "${secondary_cluster}" "${pool}"/"${group0}" 'down+stopped'
local group_snap_id
- get_newest_group_snapshot_id "${primary_cluster}" "${pool}/${group0}" group_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${primary_cluster}" "${pool}/${group0}" group_snap_id
mirror_group_demote "${primary_cluster}" "${pool}/${group0}"
local primary_demote_snap_id
- get_newest_group_snapshot_id "${primary_cluster}" "${pool}/${group0}" primary_demote_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${primary_cluster}" "${pool}/${group0}" primary_demote_snap_id
test "${group_snap_id}" != "${primary_demote_snap_id}" || { fail "no new snapshot after demote"; return 1; }
wait_for_group_status_in_pool_dir "${primary_cluster}" "${pool}/${group0}" 'up+unknown'
local secondary_snap_id
- get_newest_group_snapshot_id "${secondary_cluster}" "${pool}/${group0}" secondary_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${secondary_cluster}" "${pool}/${group0}" secondary_snap_id
test "${primary_demote_snap_id}" = "${secondary_snap_id}" || { fail "demote snapshot ${primary_demote_snap_id} not synced"; return 1; }
write_image "${primary_cluster}" "${pool}" "${image_prefix}1" 256 4194304
mirror_group_demote "${primary_cluster}" "${pool}/${group0}"
local group_snap_id
- get_newest_group_snapshot_id "${primary_cluster}" "${pool}/${group0}" group_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${primary_cluster}" "${pool}/${group0}" group_snap_id
wait_for_test_group_snap_present "${secondary_cluster}" "${pool}/${group0}" "${group_snap_id}" 1
stop_mirrors "${secondary_cluster}" '-9'
local secondary_group_spec=$4
local group_snap_id
- get_newest_group_snapshot_id "${cluster}" "${group_spec}" group_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${cluster}" "${group_spec}" group_snap_id
wait_for_group_snap_present "${secondary_cluster}" "${secondary_group_spec}" "${group_snap_id}"
wait_for_group_snap_sync_complete "${secondary_cluster}" "${secondary_group_spec}" "${group_snap_id}"
}
local group_snap_id=$3
local expected_state=$4
- run_cmd "rbd --cluster ${cluster} group snap list ${group_spec} --format xml --pretty-format"
+ run_cmd "rbd --cluster ${cluster} group snap list ${group_spec} --format xml --pretty-format"
+
+ # Get <state> and <snaps_synced> for the given group snapshot ID
+ local state snaps_synced
+ state=$(xmlstarlet sel -t -v "//group_snaps/group_snap[id='${group_snap_id}']/state" < "$CMD_STDOUT")
+ snaps_synced=$(xmlstarlet sel -t -v "//group_snaps/group_snap[id='${group_snap_id}']/namespace/complete" < "$CMD_STDOUT")
- test "${expected_state}" = "$(xmlstarlet sel -t -v "//group_snaps/group_snap[id='${group_snap_id}']/state" < "$CMD_STDOUT")" || { fail; return 1; }
+ if [ "$expected_state" = "complete" ]; then
+ # Test if state is created and snaps_synced is 'true'
+ test "$state" = "created" || { fail; return 1; }
+ test "$snaps_synced" = "true" || { fail; return 1; }
+ elif [ "$expected_state" = "incomplete" ]; then
+ # Test if snaps_synced is 'false'
+ test "$snaps_synced" = "false" || { fail; return 1; }
+ fi
}
test_group_snap_sync_complete()
wait_for_group_replay_state "${cluster}" "${group_spec}" 'stopped' "${image_count}" 'false'
}
-get_newest_group_snapshot_id()
+get_newest_created_group_snapshot_id()
{
local cluster=$1
local group_spec=$2
local -n _group_snap_id=$3
- run_cmd "rbd --cluster ${cluster} group snap list ${group_spec} --format xml --pretty-format"
- _group_snap_id=$(xmlstarlet sel -t -v "(//group_snaps/group_snap[state='complete']/id)[last()]" "$CMD_STDOUT" ) && return 0
+ run_cmd "rbd --cluster ${cluster} group snap list ${group_spec} --format xml --pretty-format"
+ _group_snap_id=$(xmlstarlet sel -t -v "(//group_snaps/group_snap[state='created']/id)[last()]" "$CMD_STDOUT" ) && return 0
+
+ fail "Failed to get snapshot id"
+ return 1
+}
+
+get_newest_complete_mirror_group_snapshot_id()
+{
+ local cluster=$1
+ local group_spec=$2
+ local -n _group_snap_id=$3
+
+ run_cmd "rbd --cluster ${cluster} group snap list ${group_spec} --format xml --pretty-format"
+ _group_snap_id=$(xmlstarlet sel -t -v "(//group_snaps/group_snap[namespace/complete='true']/id)[last()]" "$CMD_STDOUT" ) && return 0
fail "Failed to get snapshot id"
return 1
local expected_synced_image_count=$3
local group_snap_id
- get_newest_group_snapshot_id "${cluster}" "${group_spec}" group_snap_id
+ get_newest_complete_mirror_group_snapshot_id "${cluster}" "${group_spec}" group_snap_id
test_group_synced_image_status "${cluster}" "${group_spec}" "${group_snap_id}" "${expected_synced_image_count}"
}
}
std::string key = group::snap_key(group_snap.id);
- if (group_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE) {
+ if (group_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_CREATING) {
bufferlist snap_bl;
r = cls_cxx_map_get_val(hctx, key, &snap_bl);
if (r < 0 && r != -ENOENT) {
CLS_ERR("error decoding snapshot: %s", group_snap_id.c_str());
return -EIO;
}
- if (group_snap.state != cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
- CLS_LOG(20, "snap %s not complete", group_snap_id.c_str());
+ if (group_snap.state != cls::rbd::GROUP_SNAPSHOT_STATE_CREATED) {
+ CLS_LOG(20, "snap %s is not created", group_snap_id.c_str());
return -ENOENT;
}
return os;
}
+std::ostream& operator<<(std::ostream& os, MirrorGroupSnapshotCompleteState state) {
+ switch (state) {
+ case MIRROR_GROUP_SNAPSHOT_COMPLETE_IF_CREATED:
+ os << "complete_if_created";
+ break;
+ case MIRROR_GROUP_SNAPSHOT_INCOMPLETE:
+ os << "incomplete";
+ break;
+ case MIRROR_GROUP_SNAPSHOT_COMPLETE:
+ os << "complete";
+ break;
+ default:
+ os << "unknown (" << static_cast<uint32_t>(state) << ")";
+ break;
+ }
+ return os;
+}
+
void GroupSnapshotNamespaceMirror::encode(bufferlist& bl) const {
using ceph::encode;
encode(state, bl);
void GroupSnapshotNamespaceMirror::dump(Formatter *f) const {
f->dump_stream("state") << state;
- f->dump_bool("complete", complete);
+ f->dump_stream("complete") << complete;
f->open_array_section("mirror_peer_uuids");
for (auto &peer : mirror_peer_uuids) {
f->dump_string("mirror_peer_uuid", peer);
o.push_back(new GroupSnapshotNamespace(GroupSnapshotNamespaceUser()));
o.push_back(new GroupSnapshotNamespace(GroupSnapshotNamespaceMirror(
MIRROR_SNAPSHOT_STATE_PRIMARY,
- {"peer uuid"}, "", "")));
+ {"peer uuid"}, "", "",
+ MIRROR_GROUP_SNAPSHOT_COMPLETE)));
}
std::ostream& operator<<(std::ostream& os, const GroupSnapshotNamespaceType& type) {
std::ostream& operator<<(std::ostream& os, GroupSnapshotState state) {
switch (state) {
- case GROUP_SNAPSHOT_STATE_INCOMPLETE:
- os << "incomplete";
+ case GROUP_SNAPSHOT_STATE_CREATING:
+ os << "creating";
break;
- case GROUP_SNAPSHOT_STATE_COMPLETE:
- os << "complete";
+ case GROUP_SNAPSHOT_STATE_CREATED:
+ os << "created";
break;
default:
os << "unknown (" << static_cast<uint32_t>(state) << ")";
void GroupSnapshot::generate_test_instances(std::list<GroupSnapshot *> &o) {
o.push_back(new GroupSnapshot("10152ae8944a", GroupSnapshotNamespaceUser{},
"groupsnapshot1",
- GROUP_SNAPSHOT_STATE_INCOMPLETE));
+ GROUP_SNAPSHOT_STATE_CREATING));
o.push_back(new GroupSnapshot("1018643c9869",
GroupSnapshotNamespaceMirror{
MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {},
- "uuid", "id"},
+ "uuid", "id", MIRROR_GROUP_SNAPSHOT_COMPLETE},
"groupsnapshot2",
- GROUP_SNAPSHOT_STATE_COMPLETE));
+ GROUP_SNAPSHOT_STATE_CREATED));
}
void TrashImageSpec::encode(bufferlist& bl) const {
entity_inst->addr.set_type(entity_addr_t::TYPE_ANY);
}
+bool is_mirror_group_snapshot_complete(
+ const cls::rbd::GroupSnapshotState &group_snap_state,
+ const cls::rbd::MirrorGroupSnapshotCompleteState &complete) {
+ // complete -- mirror_ns->complete is used
+ if (complete == cls::rbd::MIRROR_GROUP_SNAPSHOT_COMPLETE) {
+ ceph_assert(group_snap_state == cls::rbd::GROUP_SNAPSHOT_STATE_CREATED);
+ return true;
+ }
+
+ // complete -- mirror_ns->complete is not used (backwards compatibility)
+ if (complete == cls::rbd::MIRROR_GROUP_SNAPSHOT_COMPLETE_IF_CREATED &&
+ group_snap_state == cls::rbd::GROUP_SNAPSHOT_STATE_CREATED) {
+ return true;
+ }
+
+ return false;
+}
+
+cls::rbd::MirrorGroupSnapshotCompleteState
+get_mirror_group_snapshot_complete_initial(int8_t require_osd_release) {
+ if (require_osd_release >= CEPH_RELEASE_TENTACLE) {
+ // a new-style mirror group snapshot (i.e. first
+ // MIRROR_GROUP_SNAPSHOT_INCOMPLETE, later transitions to
+ // MIRROR_GROUP_SNAPSHOT_COMPLETE)
+ return cls::rbd::MIRROR_GROUP_SNAPSHOT_INCOMPLETE;
+ } else {
+ // an old-style mirror group snapshot (i.e. stays in
+ // MIRROR_GROUP_SNAPSHOT_COMPLETE_IF_CREATED)
+ return cls::rbd::MIRROR_GROUP_SNAPSHOT_COMPLETE_IF_CREATED;
+ }
+}
+
+void set_mirror_group_snapshot_complete(cls::rbd::GroupSnapshot& group_snap) {
+ auto& mirror_ns = std::get<cls::rbd::GroupSnapshotNamespaceMirror>(
+ group_snap.snapshot_namespace);
+ if (mirror_ns.complete != cls::rbd::MIRROR_GROUP_SNAPSHOT_COMPLETE_IF_CREATED) {
+ ceph_assert(group_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_CREATED);
+ mirror_ns.complete = cls::rbd::MIRROR_GROUP_SNAPSHOT_COMPLETE;
+ }
+}
+
} // namespace rbd
} // namespace cls
}
};
+enum MirrorGroupSnapshotCompleteState {
+ MIRROR_GROUP_SNAPSHOT_COMPLETE_IF_CREATED = 0,
+ MIRROR_GROUP_SNAPSHOT_INCOMPLETE = 1,
+ MIRROR_GROUP_SNAPSHOT_COMPLETE = 2,
+};
+
+inline void encode(const MirrorGroupSnapshotCompleteState& state, ceph::buffer::list& bl)
+{
+ using ceph::encode;
+ encode(static_cast<uint8_t>(state), bl);
+}
+
+inline void decode(MirrorGroupSnapshotCompleteState& state,
+ ceph::buffer::list::const_iterator& it)
+{
+ uint8_t int_state;
+ using ceph::decode;
+ decode(int_state, it);
+ state = static_cast<MirrorGroupSnapshotCompleteState>(int_state);
+}
+
+std::ostream& operator<<(std::ostream& os, MirrorGroupSnapshotCompleteState state);
+
struct GroupSnapshotNamespaceMirror {
static const GroupSnapshotNamespaceType GROUP_SNAPSHOT_NAMESPACE_TYPE =
GROUP_SNAPSHOT_NAMESPACE_TYPE_MIRROR;
MirrorSnapshotState state = MIRROR_SNAPSHOT_STATE_NON_PRIMARY;
- bool complete = false; // TODO: modify methods to handle this field
+ MirrorGroupSnapshotCompleteState complete = MIRROR_GROUP_SNAPSHOT_INCOMPLETE;
std::set<std::string> mirror_peer_uuids;
std::string primary_mirror_uuid;
GroupSnapshotNamespaceMirror(MirrorSnapshotState state,
const std::set<std::string> &mirror_peer_uuids,
const std::string &primary_mirror_uuid,
- const std::string &primary_snap_id)
- : state(state), mirror_peer_uuids(mirror_peer_uuids),
+ const std::string &primary_snap_id,
+ MirrorGroupSnapshotCompleteState complete)
+ : state(state), complete(complete), mirror_peer_uuids(mirror_peer_uuids),
primary_mirror_uuid(primary_mirror_uuid),
primary_snap_id(primary_snap_id) {
}
const GroupSnapshotNamespace& snapshot_namespace);
enum GroupSnapshotState {
- GROUP_SNAPSHOT_STATE_INCOMPLETE = 0,
- GROUP_SNAPSHOT_STATE_COMPLETE = 1,
+ GROUP_SNAPSHOT_STATE_CREATING = 0,
+ GROUP_SNAPSHOT_STATE_CREATED = 1,
};
inline void encode(const GroupSnapshotState &state, ceph::buffer::list& bl, uint64_t features=0)
GroupSnapshotNamespace snapshot_namespace = {GroupSnapshotNamespaceUser{}};
std::string name;
- GroupSnapshotState state = GROUP_SNAPSHOT_STATE_INCOMPLETE;
+ GroupSnapshotState state = GROUP_SNAPSHOT_STATE_CREATING;
std::vector<ImageSnapshotSpec> snaps;
GroupSnapshot() {}
void sanitize_entity_inst(entity_inst_t* entity_inst);
+bool is_mirror_group_snapshot_complete(
+ const cls::rbd::GroupSnapshotState &group_snap_state,
+ const cls::rbd::MirrorGroupSnapshotCompleteState &complete);
+
+cls::rbd::MirrorGroupSnapshotCompleteState
+get_mirror_group_snapshot_complete_initial(int8_t require_osd_release);
+
+void set_mirror_group_snapshot_complete(cls::rbd::GroupSnapshot& group_snap);
+
} // namespace rbd
} // namespace cls
} rbd_group_spec_t;
typedef enum {
- RBD_GROUP_SNAP_STATE_INCOMPLETE,
- RBD_GROUP_SNAP_STATE_COMPLETE
+ RBD_GROUP_SNAP_STATE_INCOMPLETE = 0, /* deprecated */
+ RBD_GROUP_SNAP_STATE_COMPLETE = 1, /* deprecated */
+
+ RBD_GROUP_SNAP_STATE_CREATING = 0,
+ RBD_GROUP_SNAP_STATE_CREATED = 1
} rbd_group_snap_state_t;
typedef enum {
class GetGroupMirrorVisitor {
public:
group_snap_mirror_namespace_t *mirror_snap;
+ cls::rbd::GroupSnapshotState group_snap_state;
- explicit GetGroupMirrorVisitor(group_snap_mirror_namespace_t *mirror_snap)
- : mirror_snap(mirror_snap) {}
+ explicit GetGroupMirrorVisitor(group_snap_mirror_namespace_t *mirror_snap,
+ cls::rbd::GroupSnapshotState group_snap_state)
+ : mirror_snap(mirror_snap), group_snap_state(group_snap_state) {}
template <typename T>
inline int operator()(const T&) const {
inline int operator()(
const cls::rbd::GroupSnapshotNamespaceMirror& snap_namespace) {
mirror_snap->state = static_cast<snap_mirror_state_t>(snap_namespace.state);
- mirror_snap->complete = snap_namespace.complete;
+ mirror_snap->complete = is_mirror_group_snapshot_complete(group_snap_state,
+ snap_namespace.complete);
mirror_snap->mirror_peer_uuids = snap_namespace.mirror_peer_uuids;
mirror_snap->primary_mirror_uuid = snap_namespace.primary_mirror_uuid;
mirror_snap->primary_snap_id = snap_namespace.primary_snap_id;
group_snap.id = librbd::util::generate_image_id(group_ioctx);
group_snap.name = string(snap_name);
- group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE;
+ group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_CREATING;
group_snap.snaps = image_snaps;
cls::rbd::ImageSnapshotNamespaceGroup ne{group_ioctx.get_id(), group_id,
}
group_snap.snaps = image_snaps;
- group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE;
+ group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_CREATED;
r = cls_client::group_snap_set(&group_ioctx, group_header_oid, group_snap);
if (r < 0) {
return -ENOENT;
}
- if (group_snap->state != cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
- lderr(cct) << "group snapshot is not complete" << dendl;
+ if (group_snap->state != cls::rbd::GROUP_SNAPSHOT_STATE_CREATED) {
+ lderr(cct) << "group snapshot is not created" << dendl;
return -EINVAL;
}
return r;
}
- GetGroupMirrorVisitor visitor(mirror_namespace);
+ GetGroupMirrorVisitor visitor(mirror_namespace, group_snap.state);
r = group_snap.snapshot_namespace.visit(visitor);
if (r < 0) {
return r;
int get_last_mirror_snapshot_state(librados::IoCtx &group_ioctx,
const std::string &group_id,
+ cls::rbd::GroupSnapshotState *group_snap_state,
cls::rbd::MirrorSnapshotState *state,
- cls::rbd::GroupSnapshotState *sync) {
+ cls::rbd::MirrorGroupSnapshotCompleteState *sync) {
std::vector<cls::rbd::GroupSnapshot> snaps;
C_SaferCond cond;
&it->snapshot_namespace);
if (ns != nullptr) {
// XXXMG: check primary_mirror_uuid matches?
+ *group_snap_state = it->state;
*state = ns->state;
- if (sync != nullptr) {
- *sync = it->state;
- }
+ *sync = ns->complete;
return 0;
}
}
}
}
- group_snap->snapshot_namespace = cls::rbd::GroupSnapshotNamespaceMirror{
- snap_state, *mirror_peer_uuids, {}, {}};
+ librados::Rados rados(group_ioctx);
+ int8_t require_osd_release;
+ r = rados.get_min_compatible_osd(&require_osd_release);
+ if (r < 0) {
+ lderr(cct) << "failed to retrieve min OSD release: " << cpp_strerror(r)
+ << dendl;
+ return r;
+ }
+ auto complete = cls::rbd::get_mirror_group_snapshot_complete_initial(require_osd_release);
+ group_snap->snapshot_namespace = cls::rbd::GroupSnapshotNamespaceMirror{
+ snap_state, *mirror_peer_uuids, {}, {},
+ complete};
for (auto image_ctx: *image_ctxs) {
group_snap->snaps.emplace_back(image_ctx->md_ctx.get_id(), image_ctx->id,
CEPH_NOSNAP);
<< ", group_snap_id=" << group_snap_id
<< dendl;
+ librados::Rados rados(group_ioctx);
+ int8_t require_osd_release;
+ int r = rados.get_min_compatible_osd(&require_osd_release);
+ if (r < 0) {
+ lderr(cct) << "failed to retrieve min OSD release: " << cpp_strerror(r)
+ << dendl;
+ return r;
+ }
+
+ auto complete = cls::rbd::get_mirror_group_snapshot_complete_initial(require_osd_release);
+ auto mirror_namespace = cls::rbd::GroupSnapshotNamespaceMirror(
+ cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, {}, {},
+ complete);
+
cls::rbd::GroupSnapshot group_snap{
- group_snap_id,
- cls::rbd::GroupSnapshotNamespaceMirror{
- cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, {} , {}},
+ group_snap_id, mirror_namespace,
prepare_non_primary_mirror_snap_name(cct, global_group_id, group_snap_id),
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
std::string group_header_oid = librbd::util::group_header_name(group_id);
- int r = cls_client::group_snap_set(&group_ioctx,
- group_header_oid, group_snap);
+ r = cls_client::group_snap_set(&group_ioctx,
+ group_header_oid, group_snap);
if (r < 0) {
lderr(cct) << "failed to create group snapshot: " << cpp_strerror(r)
<< dendl;
return r;
}
- group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE;
+ group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_CREATED;
+ cls::rbd::set_mirror_group_snapshot_complete(group_snap);
+
r = cls_client::group_snap_set(&group_ioctx, group_header_oid, group_snap);
if (r < 0) {
lderr(cct) << "failed to mark snapshot complete: " << cpp_strerror(r)
}
cls::rbd::MirrorSnapshotState state;
- cls::rbd::GroupSnapshotState sync;
- r = get_last_mirror_snapshot_state(group_ioctx, group_id, &state, &sync);
+ cls::rbd::MirrorGroupSnapshotCompleteState sync;
+ cls::rbd::GroupSnapshotState group_snap_state;
+ r = get_last_mirror_snapshot_state(group_ioctx, group_id, &group_snap_state, &state, &sync);
if (r == -ENOENT) {
- sync = cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE;
+ group_snap_state = cls::rbd::GROUP_SNAPSHOT_STATE_CREATING;
+ sync = cls::rbd::MIRROR_GROUP_SNAPSHOT_INCOMPLETE;
state = cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED; // XXXMG?
r = 0;
}
lderr(cct) << "group " << group_name << " is already primary" << dendl;
return -EINVAL;
} else if (!force && (state == cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY ||
- sync != cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE)) {
+ !is_mirror_group_snapshot_complete(group_snap_state, sync))) {
lderr(cct) << "group " << group_name
<< " is primary within a remote cluster or demotion is not propagated yet"
<< dendl;
if (mirror_ns == nullptr || mirror_ns->is_orphan()) {
continue;
}
-
- if (snap->state != cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
+ if (!is_mirror_group_snapshot_complete(snap->state, mirror_ns->complete)) {
need_rollback = true;
continue;
}
cls::rbd::GroupSnapshotNamespaceMirror{},
prepare_primary_mirror_snap_name(cct, mirror_group.global_group_id,
group_snap_id),
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
std::vector<I *> image_ctxs;
std::vector<uint64_t> quiesce_requests;
ldout(cct, 20) << "undoing group promote: " << ret_code << dendl;
remove_group_snap(group_ioctx, group_id, &group_snap, &image_ctxs);
} else if (!ret_code) {
- group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE;
+ group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_CREATED;
+ cls::rbd::set_mirror_group_snapshot_complete(group_snap);
+
r = cls_client::group_snap_set(&group_ioctx, group_header_oid, group_snap);
if (r < 0) {
lderr(cct) << "failed to update group snapshot metadata: "
cls::rbd::GroupSnapshotNamespaceMirror{},
prepare_primary_mirror_snap_name(cct, mirror_group.global_group_id,
group_snap_id),
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
std::vector<uint64_t> quiesce_requests;
std::vector<I *> image_ctxs;
std::string group_header_oid = librbd::util::group_header_name(group_id);
if (!ret_code) {
- group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE;
+ group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_CREATED;
+ cls::rbd::set_mirror_group_snapshot_complete(group_snap);
+
r = cls_client::group_snap_set(&group_ioctx, group_header_oid, group_snap);
if (r < 0) {
lderr(cct) << "failed to update group snapshot metadata: "
+ "." + m_group_snap.id;
m_group_snap.name = snap_name;
- cls::rbd::MirrorSnapshotState state = cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY;
+ librados::Rados rados(m_group_ioctx);
+ int8_t require_osd_release;
+ int r = rados.get_min_compatible_osd(&require_osd_release);
+ if (r < 0) {
+ lderr(m_cct) << "failed to retrieve min OSD release: " << cpp_strerror(r)
+ << dendl;
+ m_ret_val = r;
+ disable_mirror_group();
+ return;
+ }
- // Create incomplete group snap
+ auto complete = cls::rbd::get_mirror_group_snapshot_complete_initial(require_osd_release);
m_group_snap.snapshot_namespace = cls::rbd::GroupSnapshotNamespaceMirror{
- state, m_mirror_peer_uuids, {}, {}};
+ cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, m_mirror_peer_uuids, {}, {},
+ complete};
for (auto image_ctx: m_image_ctxs) {
m_group_snap.snaps.emplace_back(image_ctx->md_ctx.get_id(), image_ctx->id,
auto aio_comp = create_rados_callback<
GroupEnableRequest<I>,
&GroupEnableRequest<I>::handle_create_primary_group_snapshot>(this);
- int r = m_group_ioctx.aio_operate(librbd::util::group_header_name(m_group_id),
- aio_comp, &op);
+ r = m_group_ioctx.aio_operate(librbd::util::group_header_name(m_group_id),
+ aio_comp, &op);
ceph_assert(r == 0);
aio_comp->release();
}
m_group_snap.snaps[i].snap_id = m_snap_ids[i];
}
- m_group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE;
+ m_group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_CREATED;
+ cls::rbd::set_mirror_group_snapshot_complete(m_group_snap);
+
librados::ObjectWriteOperation op;
cls_client::group_snap_set(&op, m_group_snap);
// XXXMG: check primary_mirror_uuid matches?
switch (ns->state) {
case cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY:
- if (it->state == cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE) {
+ if (!is_mirror_group_snapshot_complete(it->state, ns->complete)) {
continue;
}
*m_promotion_state = PROMOTION_STATE_PRIMARY;
*m_promotion_state = PROMOTION_STATE_NON_PRIMARY;
break;
case cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED:
- if (it->state == cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE) {
+ if (!is_mirror_group_snapshot_complete(it->state, ns->complete)) {
continue;
}
*m_promotion_state = PROMOTION_STATE_ORPHAN;
break;
case cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED:
- if (it->state == cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
+ if (is_mirror_group_snapshot_complete(it->state, ns->complete)) {
*m_promotion_state = PROMOTION_STATE_ORPHAN;
} else {
*m_promotion_state = PROMOTION_STATE_NON_PRIMARY;
// TODO: Fix this to handle primary demoted snaps
cls::rbd::MirrorSnapshotState state = cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY;
- // Create incomplete group snap
+ librados::Rados rados(m_group_ioctx);
+ int8_t require_osd_release;
+ int r = rados.get_min_compatible_osd(&require_osd_release);
+ if (r < 0) {
+ lderr(m_cct) << "failed to retrieve min OSD release: " << cpp_strerror(r)
+ << dendl;
+ m_ret_code = r;
+ close_images();
+ return;
+ }
+
+ auto complete = cls::rbd::get_mirror_group_snapshot_complete_initial(require_osd_release);
m_group_snap.snapshot_namespace = cls::rbd::GroupSnapshotNamespaceMirror{
- state, m_mirror_peer_uuids, {}, {}};
+ state, m_mirror_peer_uuids, {}, {}, complete};
for (auto image_ctx: m_image_ctxs) {
m_group_snap.snaps.emplace_back(image_ctx->md_ctx.get_id(), image_ctx->id,
lderr(m_cct) << "failed to set group snapshot metadata: " << cpp_strerror(r)
<< dendl;
m_ret_code = r;
- if (m_group_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
+ if (m_group_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_CREATED) {
remove_incomplete_group_snap();
} else {
close_images();
return;
}
- if (m_group_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
+ if (m_group_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_CREATED) {
release_image_exclusive_locks();
} else {
notify_quiesce();
remove_incomplete_group_snap();
return;
} else {
- m_group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE;
+ m_group_snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_CREATED;
+ cls::rbd::set_mirror_group_snapshot_complete(m_group_snap);
+
*m_snap_id = m_group_snap.id;
set_snap_metadata();
if (ns->mirror_peer_uuids.empty() ||
(ns->mirror_peer_uuids.count(peer) != 0 &&
ns->is_primary() &&
- it->state == cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE)){
+ !is_mirror_group_snapshot_complete(it->state, ns->complete))) {
process_snapshot(*it, peer);
return;
}
const auto& ns = std::get<cls::rbd::GroupSnapshotNamespaceMirror>(
group_snap.snapshot_namespace);
if (ns.mirror_peer_uuids.empty() ||
- group_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE) {
+ !is_mirror_group_snapshot_complete(group_snap.state, ns.complete)) {
remove_group_snapshot(group_snap);
} else {
- // Note: avoid calling remove_peer_uuid() for INCOMPLETE snapshots as
+ // Note: avoid calling remove_peer_uuid() for CREATING snapshots as
// group_snap_set() returns EEXIST error
remove_peer_uuid(group_snap, mirror_peer_uuid);
}
m_group_snap_id = group_snap.id;
C_Gather *gather_ctx = new C_Gather(m_cct, ctx);
- if (group_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE) {
+ if (group_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_CREATING) {
for (size_t i = 0; i < m_image_ctxs->size(); ++i) {
ImageCtx *ictx = (*m_image_ctxs)[i];
for (auto it = ictx->snap_info.rbegin();
rbd_group_image_state_t state
ctypedef enum rbd_group_snap_state_t:
- _RBD_GROUP_SNAP_STATE_INCOMPLETE "RBD_GROUP_SNAP_STATE_INCOMPLETE"
- _RBD_GROUP_SNAP_STATE_COMPLETE "RBD_GROUP_SNAP_STATE_COMPLETE"
+ _RBD_GROUP_SNAP_STATE_CREATING "RBD_GROUP_SNAP_STATE_CREATING"
+ _RBD_GROUP_SNAP_STATE_CREATED "RBD_GROUP_SNAP_STATE_CREATED"
ctypedef enum rbd_group_snap_namespace_type_t:
_RBD_GROUP_SNAP_NAMESPACE_TYPE_USER "RBD_GROUP_SNAP_NAMESPACE_TYPE_USER"
rbd_snap_mirror_state_t state;
size_t mirror_peer_uuids_count;
char* mirror_peer_uuids;
- bint complete
+ bint complete;
char* primary_mirror_uuid;
char* primary_snap_id;
rbd_group_image_state_t state
ctypedef enum rbd_group_snap_state_t:
- _RBD_GROUP_SNAP_STATE_INCOMPLETE "RBD_GROUP_SNAP_STATE_INCOMPLETE"
- _RBD_GROUP_SNAP_STATE_COMPLETE "RBD_GROUP_SNAP_STATE_COMPLETE"
+ _RBD_GROUP_SNAP_STATE_CREATING "RBD_GROUP_SNAP_STATE_CREATING"
+ _RBD_GROUP_SNAP_STATE_CREATED "RBD_GROUP_SNAP_STATE_CREATED"
ctypedef enum rbd_group_snap_namespace_type_t:
_RBD_GROUP_SNAP_NAMESPACE_TYPE_USER "RBD_GROUP_SNAP_NAMESPACE_TYPE_USER"
rbd_snap_mirror_state_t state;
size_t mirror_peer_uuids_count;
char* mirror_peer_uuids;
- bint complete
+ bint complete;
char* primary_mirror_uuid;
char* primary_snap_id;
RBD_GROUP_IMAGE_STATE_ATTACHED = _RBD_GROUP_IMAGE_STATE_ATTACHED
RBD_GROUP_IMAGE_STATE_INCOMPLETE = _RBD_GROUP_IMAGE_STATE_INCOMPLETE
-RBD_GROUP_SNAP_STATE_INCOMPLETE = _RBD_GROUP_SNAP_STATE_INCOMPLETE
-RBD_GROUP_SNAP_STATE_COMPLETE = _RBD_GROUP_SNAP_STATE_COMPLETE
+RBD_GROUP_SNAP_STATE_CREATING = _RBD_GROUP_SNAP_STATE_CREATING
+RBD_GROUP_SNAP_STATE_CREATED = _RBD_GROUP_SNAP_STATE_CREATED
RBD_GROUP_SNAP_NAMESPACE_TYPE_USER = _RBD_GROUP_SNAP_NAMESPACE_TYPE_USER
string snap_id = "snap_id";
cls::rbd::GroupSnapshot snap = {snap_id,
cls::rbd::GroupSnapshotNamespaceUser{}, "",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(-EINVAL, group_snap_set(&ioctx, group_id, snap));
}
string snap_id = "snap_id";
cls::rbd::GroupSnapshot snap = {"", cls::rbd::GroupSnapshotNamespaceUser{},
"snap_name",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(-EINVAL, group_snap_set(&ioctx, group_id, snap));
}
cls::rbd::GroupSnapshot snap = {snap_id,
cls::rbd::GroupSnapshotNamespaceUser{},
"snap_name",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
cls::rbd::GroupSnapshot snap1 = {snap_id,
cls::rbd::GroupSnapshotNamespaceUser{},
"snap_name1",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(-EEXIST, group_snap_set(&ioctx, group_id, snap1));
}
cls::rbd::GroupSnapshot snap = {snap_id1,
cls::rbd::GroupSnapshotNamespaceUser{},
"snap_name",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
string snap_id2 = "snap_id2";
cls::rbd::GroupSnapshot snap1 = {snap_id2,
cls::rbd::GroupSnapshotNamespaceUser{},
"snap_name",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(-EEXIST, group_snap_set(&ioctx, group_id, snap1));
}
cls::rbd::GroupSnapshot snap = {snap_id,
cls::rbd::GroupSnapshotNamespaceUser{},
"test_snapshot",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
set<string> keys;
cls::rbd::GroupSnapshot snap1 = {snap_id1,
cls::rbd::GroupSnapshotNamespaceUser{},
"test_snapshot1",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap1));
string snap_id0 = "snap_id0";
cls::rbd::GroupSnapshot snap0 = {snap_id0,
cls::rbd::GroupSnapshotNamespaceUser{},
"test_snapshot0",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap0));
string snap_id2 = "snap_id2";
cls::rbd::GroupSnapshot snap2 = {snap_id2,
cls::rbd::GroupSnapshotNamespaceUser{},
"test_snapshot2",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap2));
std::vector<cls::rbd::GroupSnapshot> snapshots;
cls::rbd::GroupSnapshot snap4 = {snap_id4,
cls::rbd::GroupSnapshotNamespaceUser{},
"test_snapshot4",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap4));
ASSERT_EQ(0, group_snap_list_order(&ioctx, group_id, "", 10, &snap_orders));
cls::rbd::GroupSnapshot snap = {snap_id,
cls::rbd::GroupSnapshotNamespaceUser{},
"test_snapshot" + hexify(i),
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
}
cls::rbd::GroupSnapshot snap = {snap_id,
cls::rbd::GroupSnapshotNamespaceUser{},
"test_snapshot" + hexify(i),
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
}
cls::rbd::GroupSnapshot snap = {snap_id,
cls::rbd::GroupSnapshotNamespaceUser{},
"test_snapshot",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
set<string> keys;
cls::rbd::GroupSnapshot snap = {snap_id,
cls::rbd::GroupSnapshotNamespaceUser{},
"test_snapshot",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
// Simulate an older snapshot by removing the order key
cls::rbd::GroupSnapshot snap = {snap_id,
cls::rbd::GroupSnapshotNamespaceUser{},
"test_snapshot",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
ASSERT_EQ(-ENOENT, group_snap_unlink(&ioctx, group_id, snap_id, {}));
ASSERT_EQ(0, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap));
ASSERT_EQ(read_snap, snap);
- snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE;
+ snap.state = cls::rbd::GROUP_SNAPSHOT_STATE_CREATED;
ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
ASSERT_EQ(0, group_snap_unlink(&ioctx, group_id, snap_id, {}));
ASSERT_EQ(-ENOENT, group_snap_get_by_id(&ioctx, group_id, snap_id, &read_snap));
cls::rbd::GroupSnapshot snap = {snap_id,
cls::rbd::GroupSnapshotNamespaceUser{},
"test_snapshot",
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
cls::rbd::GroupSnapshot received_snap;
ASSERT_EQ(-ENOENT, group_snap_get_by_id(&ioctx, group_id, snap_id, &received_snap));
ASSERT_EQ(0, rbd_group_snap_get_info(ioctx2, gp_name, gp_snap_name,
&gp_snap_info));
ASSERT_STREQ(gp_snap_name, gp_snap_info.name);
- ASSERT_EQ(RBD_GROUP_SNAP_STATE_COMPLETE, gp_snap_info.state);
+ ASSERT_EQ(RBD_GROUP_SNAP_STATE_CREATED, gp_snap_info.state);
ASSERT_EQ(RBD_GROUP_SNAP_NAMESPACE_TYPE_USER, gp_snap_info.namespace_type);
ASSERT_STREQ("", gp_snap_info.image_snap_name);
ASSERT_EQ(0U, gp_snap_info.image_snaps_count);
ASSERT_EQ(0, rbd_group_snap_get_info(ioctx2, gp_name, gp_snap_name,
&gp_snap_info));
ASSERT_STREQ(gp_snap_name, gp_snap_info.name);
- ASSERT_EQ(RBD_GROUP_SNAP_STATE_COMPLETE, gp_snap_info.state);
+ ASSERT_EQ(RBD_GROUP_SNAP_STATE_CREATED, gp_snap_info.state);
ASSERT_EQ(RBD_GROUP_SNAP_NAMESPACE_TYPE_USER, gp_snap_info.namespace_type);
ASSERT_EQ(1U, gp_snap_info.image_snaps_count);
ASSERT_EQ(m_image_name, gp_snap_info.image_snaps[0].image_name);
ASSERT_EQ(0, m_rbd.group_snap_get_info(ioctx2, gp_name, gp_snap_name,
&gp_snap_info));
ASSERT_EQ(gp_snap_name, gp_snap_info.name);
- ASSERT_EQ(RBD_GROUP_SNAP_STATE_COMPLETE, gp_snap_info.state);
+ ASSERT_EQ(RBD_GROUP_SNAP_STATE_CREATED, gp_snap_info.state);
ASSERT_EQ(RBD_GROUP_SNAP_NAMESPACE_TYPE_USER, gp_snap_info.namespace_type);
ASSERT_EQ("", gp_snap_info.image_snap_name);
ASSERT_EQ(0U, gp_snap_info.image_snaps.size());
ASSERT_EQ(0, m_rbd.group_snap_get_info(ioctx2, gp_name, gp_snap_name,
&gp_snap_info));
ASSERT_EQ(gp_snap_name, gp_snap_info.name);
- ASSERT_EQ(RBD_GROUP_SNAP_STATE_COMPLETE, gp_snap_info.state);
+ ASSERT_EQ(RBD_GROUP_SNAP_STATE_CREATED, gp_snap_info.state);
ASSERT_EQ(RBD_GROUP_SNAP_NAMESPACE_TYPE_USER, gp_snap_info.namespace_type);
ASSERT_EQ(1U, gp_snap_info.image_snaps.size());
ASSERT_EQ(m_image_name, gp_snap_info.image_snaps[0].image_name);
ASSERT_EQ(4U, num_snaps);
for (int i = 0; i < 4; i++) {
- ASSERT_EQ(RBD_GROUP_SNAP_STATE_COMPLETE, gp_snaps[i].state);
+ ASSERT_EQ(RBD_GROUP_SNAP_STATE_CREATED, gp_snaps[i].state);
ASSERT_EQ(RBD_GROUP_SNAP_NAMESPACE_TYPE_USER, gp_snaps[i].namespace_type);
if (!strcmp(gp_snaps[i].name, gp_snap_names[0])) {
ASSERT_EQ(0U, gp_snaps[i].image_snaps_count);
ASSERT_EQ(4U, gp_snaps.size());
for (const auto& gp_snap : gp_snaps) {
- ASSERT_EQ(RBD_GROUP_SNAP_STATE_COMPLETE, gp_snap.state);
+ ASSERT_EQ(RBD_GROUP_SNAP_STATE_CREATED, gp_snap.state);
ASSERT_EQ(RBD_GROUP_SNAP_NAMESPACE_TYPE_USER, gp_snap.namespace_type);
if (gp_snap.name == gp_snap_names[0]) {
ASSERT_EQ(0U, gp_snap.image_snaps.size());
RBD_SNAP_CREATE_IGNORE_QUIESCE_ERROR,
RBD_WRITE_ZEROES_FLAG_THICK_PROVISION,
RBD_ENCRYPTION_FORMAT_LUKS1, RBD_ENCRYPTION_FORMAT_LUKS2,
- RBD_ENCRYPTION_FORMAT_LUKS, RBD_GROUP_SNAP_STATE_COMPLETE,
+ RBD_ENCRYPTION_FORMAT_LUKS, RBD_GROUP_SNAP_STATE_CREATED,
RBD_GROUP_SNAP_NAMESPACE_TYPE_USER)
rados = None
image_names = []
assert sorted(snap_info_dict.keys()) == self.gp_snap_keys
assert snap_info_dict['name'] == snap_name
- assert snap_info_dict['state'] == RBD_GROUP_SNAP_STATE_COMPLETE
+ assert snap_info_dict['state'] == RBD_GROUP_SNAP_STATE_CREATED
assert snap_info_dict['namespace_type'] == RBD_GROUP_SNAP_NAMESPACE_TYPE_USER
for image_snap in snap_info_dict['image_snaps']:
assert sorted(image_snap.keys()) == self.img_snap_keys
snap_info_dict = self.group.get_snap_info(snap_name)
assert sorted(snap_info_dict.keys()) == self.gp_snap_keys
assert snap_info_dict['name'] == snap_name
- assert snap_info_dict['state'] == RBD_GROUP_SNAP_STATE_COMPLETE
+ assert snap_info_dict['state'] == RBD_GROUP_SNAP_STATE_CREATED
assert snap_info_dict['namespace_type'] == RBD_GROUP_SNAP_NAMESPACE_TYPE_USER
assert snap_info_dict['image_snap_name'] == ""
assert snap_info_dict['image_snaps'] == []
return id;
}
+std::string group_snap_state(librbd::group_snap_state_t state) {
+ switch (state) {
+ case RBD_GROUP_SNAP_STATE_CREATING:
+ return "creating";
+ case RBD_GROUP_SNAP_STATE_CREATED:
+ return "created";
+ default:
+ return "unknown (" + stringify(state) + ")";
+ }
+}
+
std::string mirror_image_mode(librbd::mirror_image_mode_t mode) {
switch (mode) {
case RBD_MIRROR_IMAGE_MODE_JOURNAL:
std::string image_id(librbd::Image& image);
+std::string group_snap_state(
+ librbd::group_snap_state_t state);
std::string mirror_image_mode(
librbd::mirror_image_mode_t mirror_image_mode);
std::string mirror_image_state(
}
}
-std::string get_group_snap_state_name(rbd_group_snap_state_t state)
-{
- switch (state) {
- case RBD_GROUP_SNAP_STATE_INCOMPLETE:
- return "incomplete";
- case RBD_GROUP_SNAP_STATE_COMPLETE:
- return "complete";
- default:
- return "unknown (" + stringify(state) + ")";
- }
-}
-
std::string get_group_snap_namespace_name(
librbd::group_snap_namespace_type_t type)
{
}
for (const auto& snap : snaps) {
- auto state_string = get_group_snap_state_name(snap.state);
+ auto state_string = utils::group_snap_state(snap.state);
auto type_string = get_group_snap_namespace_name(snap.namespace_type);
-
int get_mirror_res = -ENOENT;
librbd::group_snap_mirror_namespace_t mirror_snap;
std::string mirror_snap_state = "unknown";
f->dump_string("peer_uuid", uuid);
}
f->close_section();
+ f->dump_bool("complete", mirror_snap.complete);
if (mirror_snap.state == RBD_SNAP_MIRROR_STATE_NON_PRIMARY ||
mirror_snap.state == RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED) {
f->dump_string("primary_mirror_uuid",
if (mirror_snap.state == RBD_SNAP_MIRROR_STATE_NON_PRIMARY ||
mirror_snap.state == RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED) {
oss << " " << mirror_snap.primary_mirror_uuid << ":"
- << mirror_snap.primary_snap_id;
+ << mirror_snap.primary_snap_id << " ";
+ if (!mirror_snap.complete) {
+ oss << "not ";
+ }
+ oss << "copied";
}
oss << ")";
}
return r;
}
- auto state_string = get_group_snap_state_name(group_snap.state);
+ auto state_string = utils::group_snap_state(group_snap.state);
if (f) {
f->open_object_section("group_snapshot");
f->dump_string("id", group_snap.id);
if (!snaps.empty()) {
formatter->open_array_section("snapshots");
for (auto &snap : snaps) {
- std::string state_string;
- if (snap.state == RBD_GROUP_SNAP_STATE_INCOMPLETE) {
- state_string = "incomplete";
- } else {
- state_string = "ok";
- }
+ auto state_string = utils::group_snap_state(snap.state);
formatter->open_object_section("snapshot");
formatter->dump_string("name", snap.name);
formatter->dump_string("state", state_string);
const cls::rbd::GroupSnapshot* get_latest_complete_mirror_group_snapshot(
const std::vector<cls::rbd::GroupSnapshot>& gp_snaps) {
for (auto it = gp_snaps.rbegin(); it != gp_snaps.rend(); ++it) {
- if (it->state == cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE &&
- (cls::rbd::get_group_snap_namespace_type(it->snapshot_namespace) ==
- cls::rbd::GROUP_SNAPSHOT_NAMESPACE_TYPE_MIRROR)) {
- return &*it;
+ auto gp_snap_ns = std::get_if<cls::rbd::GroupSnapshotNamespaceMirror>(
+ &it->snapshot_namespace);
+ if (gp_snap_ns != nullptr) {
+ if (is_mirror_group_snapshot_complete(it->state, gp_snap_ns->complete)) {
+ return &*it;
+ }
}
}
return nullptr;
// process snapshots requiring validation
for (auto &local_snap : m_local_group_snaps) {
// skip validation for already complete snapshots
- if (local_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
- continue;
+ auto ns = std::get_if<cls::rbd::GroupSnapshotNamespaceMirror>(
+ &local_snap.snapshot_namespace);
+ if (local_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_CREATED) {
+ if (ns == nullptr) {
+ // user group snapshot
+ continue;
+ }
+ if (is_mirror_group_snapshot_complete(local_snap.state, ns->complete)) {
+ continue;
+ }
}
// skip validation for primary snapshots
- auto ns = std::get_if<cls::rbd::GroupSnapshotNamespaceMirror>(
- &local_snap.snapshot_namespace);
if (ns != nullptr && ns->is_primary()) {
continue;
}
handle_replay_complete(&locker, 0, "orphan (force promoting)");
return;
}
- if (last_local_snap->state == cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE) {
+ if (!is_mirror_group_snapshot_complete(last_local_snap->state, ns.complete)) {
m_retry_validate_snap = true;
}
} else { // primary snapshot
- if (last_local_snap->state == cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
+ if (is_mirror_group_snapshot_complete(last_local_snap->state, ns.complete)) {
handle_replay_complete(&locker, 0, "local group is primary");
return;
}
if (!prev_snap_id.empty()) {
snap = std::next(remote_snap); // attempt to sync next remote snapshot
}
- if (snap != m_remote_group_snaps.end() &&
- snap->state == cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
+ if (snap != m_remote_group_snaps.end()) {
auto next_remote_snap_ns = std::get_if<cls::rbd::GroupSnapshotNamespaceMirror>(
&snap->snapshot_namespace);
if (next_remote_snap_ns == nullptr) {
- dout(10) << "found remote user group snapshot: "
- << snap->id << dendl;
- create_group_snapshot(*snap, locker);
- continue;
+ if (snap->state == cls::rbd::GROUP_SNAPSHOT_STATE_CREATED) {
+ dout(10) << "found remote user group snapshot: "
+ << snap->id << dendl;
+ create_group_snapshot(*snap, locker);
+ continue;
+ }
} else if (next_remote_snap_ns->is_primary()) {
- dout(10) << "found primary remote mirror group snapshot: "
- << snap->id << dendl;
- create_group_snapshot(*snap, locker);
- return;
+ if (is_mirror_group_snapshot_complete(snap->state,
+ next_remote_snap_ns->complete)) {
+ dout(10) << "found primary remote mirror group snapshot: "
+ << snap->id << dendl;
+ create_group_snapshot(*snap, locker);
+ return;
+ }
} else {
dout(10) << "skipping non-primary remote group snapshot: "
<< snap->id << dendl;
// check if we have a valid mirror snapshot to proceed
bool can_proceed = false;
for (; next_remote_snap != m_remote_group_snaps.end(); ++next_remote_snap) {
- auto next_snap_type = cls::rbd::get_group_snap_namespace_type(
- next_remote_snap->snapshot_namespace);
+ auto next_remote_snap_ns = std::get_if<cls::rbd::GroupSnapshotNamespaceMirror>(
+ &next_remote_snap->snapshot_namespace);
- if (next_snap_type == cls::rbd::GROUP_SNAPSHOT_NAMESPACE_TYPE_USER) {
+ if (next_remote_snap_ns == nullptr) {
continue; // skip user snapshots
- } else if (next_remote_snap->state == cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE) {
+ } else if (!is_mirror_group_snapshot_complete(next_remote_snap->state,
+ next_remote_snap_ns->complete)) {
dout(10) << "next mirror snapshot is incomplete, waiting: "
<< next_remote_snap->id << dendl;
return; // wait and try later
return s.id == group_snap_id;
});
- if (itl != m_local_group_snaps.end() &&
- itl->state == cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
+ if (itl != m_local_group_snaps.end()) {
dout(20) << "group snapshot: " << group_snap_id << " already exists"
<< dendl;
on_finish->complete(0);
}
}
+ librados::Rados rados(m_local_io_ctx);
+ int8_t require_osd_release;
+ r = rados.get_min_compatible_osd(&require_osd_release);
+ if (r < 0) {
+ derr << "failed to retrieve min OSD release: " << cpp_strerror(r)
+ << dendl;
+ on_finish->complete(r);
+ return;
+ }
+
+ auto complete = cls::rbd::get_mirror_group_snapshot_complete_initial(require_osd_release);
+ auto mirror_namespace = cls::rbd::GroupSnapshotNamespaceMirror(snap_state,
+ mirror_peer_uuids, m_remote_mirror_uuid, group_snap_id,
+ complete);
+
cls::rbd::GroupSnapshot local_snap =
- {group_snap_id,
- cls::rbd::GroupSnapshotNamespaceMirror{
- snap_state, mirror_peer_uuids, m_remote_mirror_uuid, group_snap_id},
- {}, cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ {group_snap_id, mirror_namespace,
+ {}, cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
+
local_snap.name = prepare_non_primary_mirror_snap_name(m_global_group_id,
group_snap_id);
cls::rbd::GroupSnapshot remote_snap = *itr;
locker.unlock();
+ if (local_snap.state == cls::rbd::GROUP_SNAPSHOT_STATE_CREATED) {
+ check_mirror_snapshot_sync_complete(group_snap_id, local_snap, on_finish);
+ return;
+ }
+
bufferlist* out_bl = new bufferlist();
std::vector<cls::rbd::GroupImageStatus>* local_images =
new std::vector<cls::rbd::GroupImageStatus>();
const std::vector<cls::rbd::GroupImageStatus>& local_images,
Context *on_finish) {
dout(10) << group_snap_id << dendl;
- post_mirror_snapshot_complete(group_snap_id, local_snap, remote_snap,
- local_images, on_finish);
+ post_mirror_snapshot_created(group_snap_id, local_snap, remote_snap,
+ local_images, on_finish);
}
template <typename I>
-void Replayer<I>::post_mirror_snapshot_complete(
+void Replayer<I>::post_mirror_snapshot_created(
const std::string &group_snap_id,
const cls::rbd::GroupSnapshot &local_snap,
const cls::rbd::GroupSnapshot &remote_snap,
local_image_snap_specs.reserve(remote_snap.snaps.size());
for (auto& image : local_images) {
- bool image_snap_complete = false;
+ bool image_snap_created = false;
std::string image_header_oid = librbd::util::header_name(image.spec.image_id);
::SnapContext snapc;
int r = librbd::cls_client::get_snapcontext(&m_local_io_ctx, image_header_oid, &snapc);
continue;
}
- // make sure the image snapshot is COMPLETE
- if (mirror_ns->group_snap_id == group_snap_id && mirror_ns->complete) {
- image_snap_complete = true;
+ if (mirror_ns->group_snap_id == group_snap_id) {
+ image_snap_created = true;
cls::rbd::ImageSnapshotSpec snap_spec;
snap_spec.pool = image.spec.pool_id;
snap_spec.image_id = image.spec.image_id;
snap_spec.snap_id = snap_info.id;
-
- // check if this spec already exists in local snaps
- auto it = std::find_if(local_snap.snaps.begin(), local_snap.snaps.end(),
- [&snap_spec](const cls::rbd::ImageSnapshotSpec &s) {
- return snap_spec.pool == s.pool &&
- snap_spec.image_id == s.image_id;
- });
- if (it == local_snap.snaps.end()) {
- local_image_snap_specs.push_back(snap_spec);
- }
+ local_image_snap_specs.push_back(snap_spec);
break;
} else {
dout(20) << "expecting remote group snap id: " << group_snap_id
}
}
- if (!image_snap_complete) {
+ if (!image_snap_created) {
set_image_replayer_limits(image.spec.image_id, &remote_snap, &locker);
}
}
}
}
- // User snap is added and not yet turned complete, wait for it.
+ // User snap is added and not yet turned created, wait for it.
for (auto local_snap = m_local_group_snaps.begin();
local_snap != m_local_group_snaps.end(); ++local_snap) {
if (local_snap->id == group_snap_id) {
break;
- } else if (local_snap->state == cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE) {
+ } else if (local_snap->state == cls::rbd::GROUP_SNAPSHOT_STATE_CREATING) {
locker.unlock();
- // there is a user group snap waiting sync, so lets wait for it to moved to complete
+ // there is a user group snap waiting sync, so lets wait for it to moved to created
on_finish->complete(-EAGAIN);
return;
}
if (remote_snap.snaps.size() == local_image_snap_specs.size()) {
cls::rbd::GroupSnapshot local_snap_copy = local_snap;
local_snap_copy.snaps = local_image_snap_specs;
- local_snap_copy.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE;
+ const auto &mirror_namespace = std::get<cls::rbd::GroupSnapshotNamespaceMirror>(
+ local_snap_copy.snapshot_namespace);
+ if (mirror_namespace.complete ==
+ cls::rbd::MIRROR_GROUP_SNAPSHOT_COMPLETE_IF_CREATED) {
+ dout(10) << "local group snap info: "
+ << "id: " << local_snap_copy.id
+ << ", name: " << local_snap_copy.name
+ << ", state: " << local_snap_copy.state
+ << ", snaps.size: " << local_snap_copy.snaps.size()
+ << dendl;
+ locker.unlock();
+ check_mirror_snapshot_sync_complete(group_snap_id, local_snap_copy, on_finish);
+ return;
+ }
+ local_snap_copy.state = cls::rbd::GROUP_SNAPSHOT_STATE_CREATED;
librados::ObjectWriteOperation op;
librbd::cls_client::group_snap_set(&op, local_snap_copy);
auto comp = create_rados_callback(
- new LambdaContext([this, group_snap_id, on_finish](int r) {
- handle_post_mirror_snapshot_complete(r, group_snap_id, on_finish);
+ new LambdaContext([this, group_snap_id, local_snap_copy, on_finish](int r) {
+ handle_post_mirror_snapshot_created(r, group_snap_id, local_snap_copy,
+ on_finish);
}));
int r = m_local_io_ctx.aio_operate(
librbd::util::group_header_name(m_local_group_id), comp, &op);
}
template <typename I>
-void Replayer<I>::handle_post_mirror_snapshot_complete(
+void Replayer<I>::handle_post_mirror_snapshot_created(
+ int r, const std::string &group_snap_id,
+ const cls::rbd::GroupSnapshot &local_snap,
+ Context *on_finish) {
+ dout(10) << group_snap_id << ", r=" << r << dendl;
+
+ if (r < 0) {
+ derr << "failed to set snap state to created for group snap id: "
+ << group_snap_id << ", : " << cpp_strerror(r) << dendl;
+ on_finish->complete(r);
+ return;
+ }
+
+ check_mirror_snapshot_sync_complete(group_snap_id, local_snap, on_finish);
+}
+
+template <typename I>
+void Replayer<I>::check_mirror_snapshot_sync_complete(
+ const std::string &group_snap_id,
+ const cls::rbd::GroupSnapshot &local_snap,
+ Context *on_finish) {
+ std::unique_lock locker{m_lock};
+ dout(10) << group_snap_id << dendl;
+
+ uint64_t num_images_sync_pending = 0;
+ for (const auto& snap_spec : local_snap.snaps) {
+ std::string image_header_oid = librbd::util::header_name(snap_spec.image_id);
+ cls::rbd::SnapshotInfo snap_info;
+ int r = librbd::cls_client::snapshot_get(&m_local_io_ctx, image_header_oid,
+ snap_spec.snap_id, &snap_info);
+ if (r < 0) {
+ derr << "failed getting snap info for snap id: " << snap_spec.snap_id
+ << ", : " << cpp_strerror(r) << dendl;
+ locker.unlock();
+ on_finish->complete(r);
+ return;
+ }
+ const auto& mirror_ns = std::get<cls::rbd::MirrorSnapshotNamespace>(
+ snap_info.snapshot_namespace);
+ if (!mirror_ns.complete) {
+ num_images_sync_pending++;
+ }
+ }
+
+ if (num_images_sync_pending == 0) {
+ // snapshot has been fully synced
+ set_mirror_snapshot_complete(group_snap_id, local_snap, on_finish);
+ } else {
+ locker.unlock();
+ on_finish->complete(0);
+ return;
+ }
+}
+
+template <typename I>
+void Replayer<I>::set_mirror_snapshot_complete(
+ const std::string &group_snap_id,
+ const cls::rbd::GroupSnapshot &local_snap,
+ Context *on_finish) {
+ dout(10) << group_snap_id << dendl;
+ ceph_assert(ceph_mutex_is_locked_by_me(m_lock));
+
+ cls::rbd::GroupSnapshot local_snap_copy = local_snap;
+ auto &mirror_namespace = std::get<cls::rbd::GroupSnapshotNamespaceMirror>(
+ local_snap_copy.snapshot_namespace);
+ if (mirror_namespace.complete == cls::rbd::MIRROR_GROUP_SNAPSHOT_COMPLETE_IF_CREATED) {
+ local_snap_copy.state = cls::rbd::GROUP_SNAPSHOT_STATE_CREATED;
+ } else {
+ ceph_assert(local_snap_copy.state == cls::rbd::GROUP_SNAPSHOT_STATE_CREATED);
+ mirror_namespace.complete = cls::rbd::MIRROR_GROUP_SNAPSHOT_COMPLETE;
+ }
+ librados::ObjectWriteOperation op;
+ librbd::cls_client::group_snap_set(&op, local_snap_copy);
+
+ auto comp = create_rados_callback(
+ new LambdaContext([this, group_snap_id, on_finish](int r) {
+ handle_set_mirror_snapshot_complete(r, group_snap_id, on_finish);
+ }));
+ int r = m_local_io_ctx.aio_operate(
+ librbd::util::group_header_name(m_local_group_id), comp, &op);
+ ceph_assert(r == 0);
+ comp->release();
+}
+
+template <typename I>
+void Replayer<I>::handle_set_mirror_snapshot_complete(
int r, const std::string &group_snap_id, Context *on_finish) {
dout(10) << group_snap_id << ", r=" << r << dendl;
if (r < 0) {
+ derr << "failed to set mirror snapshot complete field for group snap id: "
+ << group_snap_id << ", : " << cpp_strerror(r) << dendl;
on_finish->complete(r);
return;
}
return s.id == group_snap_id;
});
- if (itl != m_local_group_snaps.end() &&
- itl->state == cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
+ if (itl != m_local_group_snaps.end()) {
dout(20) << "group snapshot: " << group_snap_id << " already exists"
<< dendl;
on_finish->complete(0);
group_snap_id, // keeping it same as remote group snap id
cls::rbd::GroupSnapshotNamespaceUser{},
snap->name,
- cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
+ cls::rbd::GROUP_SNAPSHOT_STATE_CREATING};
librbd::cls_client::group_snap_set(&op, group_snap);
const std::vector<cls::rbd::GroupImageStatus>& local_images,
Context *on_finish) {
dout(10) << group_snap_id << dendl;
- post_user_snapshot_complete(group_snap_id, local_snap, remote_snap,
- local_images, on_finish);
+ post_user_snapshot_created(group_snap_id, local_snap, remote_snap,
+ local_images, on_finish);
}
template <typename I>
-void Replayer<I>::post_user_snapshot_complete(
+void Replayer<I>::post_user_snapshot_created(
const std::string &group_snap_id,
const cls::rbd::GroupSnapshot &local_snap,
const cls::rbd::GroupSnapshot &remote_snap,
if (remote_snap.snaps.size() == local_image_snap_specs.size()) {
cls::rbd::GroupSnapshot local_snap_copy = local_snap;
local_snap_copy.snaps = local_image_snap_specs;
- local_snap_copy.state = cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE;
+ local_snap_copy.state = cls::rbd::GROUP_SNAPSHOT_STATE_CREATED;
librados::ObjectWriteOperation op;
librbd::cls_client::group_snap_set(&op, local_snap_copy);
auto comp = create_rados_callback(
new LambdaContext([this, group_snap_id, on_finish](int r) {
- handle_post_user_snapshot_complete(r, group_snap_id, on_finish);
+ handle_post_user_snapshot_created(r, group_snap_id, on_finish);
}));
int r = m_local_io_ctx.aio_operate(
librbd::util::group_header_name(m_local_group_id), comp, &op);
}
template <typename I>
-void Replayer<I>::handle_post_user_snapshot_complete(
+void Replayer<I>::handle_post_user_snapshot_created(
int r, const std::string &group_snap_id, Context *on_finish) {
dout(10) << group_snap_id << ", r=" << r << dendl;
auto last_local_snap_id = m_local_group_snaps.rbegin()->id;
for (auto local_snap = m_local_group_snaps.begin();
local_snap != m_local_group_snaps.end(); ++local_snap) {
- if (local_snap->state != cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
- break;
+ auto local_snap_ns = std::get_if<cls::rbd::GroupSnapshotNamespaceMirror>(
+ &local_snap->snapshot_namespace);
+ if (local_snap_ns == nullptr) {
+ if (local_snap->state != cls::rbd::GROUP_SNAPSHOT_STATE_CREATED) {
+ break;
+ }
+ } else if (!is_mirror_group_snapshot_complete(local_snap->state,
+ local_snap_ns->complete)) {
+ break;
}
-
auto snap_type = cls::rbd::get_group_snap_namespace_type(
local_snap->snapshot_namespace);
if (snap_type != cls::rbd::GROUP_SNAPSHOT_NAMESPACE_TYPE_MIRROR) {
if (next_local_snap == m_local_group_snaps.end()) {
break; // no next snap.
}
- auto next_snap_type = cls::rbd::get_group_snap_namespace_type(
- next_local_snap->snapshot_namespace);
- if (next_snap_type != cls::rbd::GROUP_SNAPSHOT_NAMESPACE_TYPE_MIRROR) {
+ auto next_local_snap_ns = std::get_if<cls::rbd::GroupSnapshotNamespaceMirror>(
+ &next_local_snap->snapshot_namespace);
+ if (next_local_snap_ns == nullptr) {
continue; // next snap is user snap again.
- } else if (next_local_snap->state != cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE) {
+ } else if (
+ !is_mirror_group_snapshot_complete(next_local_snap->state,
+ next_local_snap_ns->complete)) {
break; // next snap is not complete yet.
}
}
auto next_local_snap = std::next(local_snap);
// If next local snap is end, or if it is the syncing in-progress snap,
// then we still need this group snapshot.
- if (next_local_snap == m_local_group_snaps.end() ||
- (next_local_snap->id == last_local_snap_id &&
- next_local_snap->state != cls::rbd::GROUP_SNAPSHOT_STATE_COMPLETE)) {
+ if (next_local_snap == m_local_group_snaps.end()) {
break;
+ } else if (next_local_snap->id == last_local_snap_id) {
+ auto next_local_snap_ns = std::get_if<cls::rbd::GroupSnapshotNamespaceMirror>(
+ &next_local_snap->snapshot_namespace);
+ if (next_local_snap_ns == nullptr) {
+ if (next_local_snap->state != cls::rbd::GROUP_SNAPSHOT_STATE_CREATED) {
+ break;
+ }
+ } else if (!is_mirror_group_snapshot_complete(next_local_snap->state,
+ next_local_snap_ns->complete)) {
+ break;
+ }
} else {
auto next_snap_type = cls::rbd::get_group_snap_namespace_type(
next_local_snap->snapshot_namespace);
const cls::rbd::GroupSnapshot &remote_snap,
const std::vector<cls::rbd::GroupImageStatus>& local_images,
Context *on_finish);
- void post_mirror_snapshot_complete(
+ void post_mirror_snapshot_created(
const std::string &group_snap_id,
const cls::rbd::GroupSnapshot &local_snap,
const cls::rbd::GroupSnapshot &remote_snap,
const std::vector<cls::rbd::GroupImageStatus>& local_images,
Context *on_finish);
- void handle_post_mirror_snapshot_complete(
+ void handle_post_mirror_snapshot_created(
+ int r, const std::string &group_snap_id,
+ const cls::rbd::GroupSnapshot &local_snap,
+ Context *on_finish);
+ void check_mirror_snapshot_sync_complete(
+ const std::string &group_snap_id,
+ const cls::rbd::GroupSnapshot &local_snap,
+ Context *on_finish);
+ void set_mirror_snapshot_complete(
+ const std::string &group_snap_id,
+ const cls::rbd::GroupSnapshot &local_snap,
+ Context *on_finish);
+ void handle_set_mirror_snapshot_complete(
int r, const std::string &group_snap_id, Context *on_finish);
void create_user_snapshot(
const cls::rbd::GroupSnapshot &remote_snap,
const std::vector<cls::rbd::GroupImageStatus>& local_images,
Context *on_finish);
- void post_user_snapshot_complete(
+ void post_user_snapshot_created(
const std::string &group_snap_id,
const cls::rbd::GroupSnapshot &local_snap,
const cls::rbd::GroupSnapshot &remote_snap,
const std::vector<cls::rbd::GroupImageStatus>& local_images,
Context *on_finish);
- void handle_post_user_snapshot_complete(
+ void handle_post_user_snapshot_created(
int r, const std::string &group_snap_id, Context *on_finish);
void mirror_group_snapshot_unlink_peer(const std::string &snap_id);