New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
librbd: add support for snapshot namespaces #11160
librbd: add support for snapshot namespaces #11160
Conversation
e99bcfd
to
821794e
Compare
@@ -1488,6 +1489,34 @@ int get_snapshot_name(cls_method_context_t hctx, bufferlist *in, bufferlist *out | |||
return 0; | |||
} | |||
|
|||
int get_snapshot_namespace(cls_method_context_t hctx, bufferlist *in, bufferlist *out) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: add block comment describing expected in/out params
|
||
CLS_LOG(20, "get_snapshot_namespace snap_id=%llu", (unsigned long long)snap_id); | ||
|
||
if (snap_id == CEPH_NOSNAP) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: wrap in braces
string snapshot_key; | ||
key_from_snap_id(snap_id, &snapshot_key); | ||
int r = read_key(hctx, snapshot_key, &snap); | ||
if (r < 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: same here
return -EINVAL; | ||
} | ||
|
||
CLS_LOG(20, "get_snapshot_namespace snap_id=%llu", (unsigned long long)snap_id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: you can use PRIu64
to directly encode snap_id
::encode(snap_id, bl2); | ||
op->exec("rbd", "get_size", bl2); | ||
::encode(snap_id, bl2); | ||
op->exec("rbd", "get_snapshot_namespace", bl2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this cls method won't exist on older OSDs, unfortunately, until we get to the point of only supporting Kraken+, you need to retrieve the snapshot namespaces as part of an individual OSD op in case it errors out with -EOPNOTSUPP (which you could then ignore)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Too bad I didn't think about it.
|
||
std::ostream& operator<<(std::ostream& os, const GroupSnapshotNamespace& ns) { | ||
os << "[group]"; | ||
return os; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: dump fields?
string snapshot_id; | ||
|
||
void encode(bufferlist& bl) const { | ||
::encode(group_pool, bl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: move the implementation into the cc file
|
||
inline void encode(const SnapshotNamespace &c, bufferlist &bl, uint64_t features=0) | ||
{ | ||
ENCODE_DUMP_PRE(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is doing what you are expecting -- this for for creating the binary file dump records, which leads to the next comment ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand this comment. Are you talking about ENCODE_DUMP_PRE(); specifically? I see that WRITE_CLASS_ENCODER is used in order to create encode and decode functions for MirrorImageStatus. WRITE_CLASS_ENCODER adds ENCODE_DUMP_PRE and ENCODE_DUMP post inside encode function it generates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you look at the code for ENCODE_DUMP_PRE -- most of the time it's a no-op. The only time it actually does something is within the dencoder test where it writes the binary encoding format out to a file. I think you were looking for ENCODE_START/ENCODE_FINISH which add version control.
|
||
void encode(bufferlist& bl) const {} | ||
void decode(bufferlist::iterator& it) {} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the new types should have generate_test_instances
and dump
methods so that they can be registered with the dencoder test case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... might be either to create a new SnapshotNamespace struct that just inherits from boost::variant. That would allow you to create the necessary generate_test_instances
static member function for use with dencoder. Then you wouldn't need generate_test_instances
for each individual type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to implement it using inheritance and couldn't reconcile all types of constructors that are provided by boost::variant. It looks like the solution is to have a wrapper type like NotifyMessage wraps Payload and EventEntry wraps Event type. Those wrappers implement all the required methods.
09e2514
to
db5bf5d
Compare
not ready yet. will update when done with addressing comments |
82e4fe1
to
c32e3a5
Compare
... all internal plumbing changes, no doc updates required |
4ab1798
to
0b7f89f
Compare
@dillaman could you please take a look if you like this version at all. In the mean time I'll look into what happened to the tests. |
81ffdb0
to
142d4fc
Compare
@@ -316,5 +317,138 @@ bool GroupSpec::is_valid() const { | |||
return (!group_id.empty()) && (pool_id != -1); | |||
} | |||
|
|||
void GroupSnapshotNamespace::encode(bufferlist& bl) const { | |||
ENCODE_START(1, 1, bl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: probably no need to encode another version here since it's already wrapped in a versioned struct
} | ||
|
||
void SnapshotNamespaceEntry::generate_test_instances(std::list<SnapshotNamespaceEntry *> &o) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: append a UserSnapshotNamespace
and GroupSnapshotNamespace
example to the list
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should GroupSnapshotNamespace have any meaningful ids in it or any random values are enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Random but valid is fine -- it's to help ensure that the format isn't unintentionally broken by future changes.
|
||
}; | ||
|
||
WRITE_CLASS_ENCODER(UserSnapshotNamespace); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: since these will always be encoded via SnapshotNamespaceEntry
, no need to create encode/decode free functions for these types.
@@ -230,6 +231,8 @@ namespace librbd { | |||
const SnapInfo* get_snap_info(librados::snap_t in_snap_id) const; | |||
int get_snap_name(librados::snap_t in_snap_id, | |||
std::string *out_snap_name) const; | |||
int get_snap_namespace(librados::snap_t in_snap_id, | |||
cls::rbd::SnapshotNamespaceEntry *out_snap_namespace) const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: could directly use SnapshotNamespace
variant since SnapshotNamespaceEntry
is only used for encode/decode and requires an indirection. Perhaps rename SnapshotNamespaceEntry
to SnapshotNamespaceOnDisk
and hide its use outside of "cls/rbd"
@@ -135,9 +136,10 @@ struct SnapCreateEvent : public SnapEventBase { | |||
|
|||
SnapCreateEvent() { | |||
} | |||
SnapCreateEvent(uint64_t op_tid, const std::string &snap_name) | |||
: SnapEventBase(op_tid, snap_name) { | |||
SnapCreateEvent(uint64_t op_tid, const std::string &snap_name, const cls::rbd::SnapshotNamespaceEntry &_snap_namespace) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would there be a need to journal group snapshot create events? It seems like the group actions would be journaled via a group journal (eventually). If group snap create events are recorded with the image, they wouldn't be properly associated with a group and you wouldn't be able to remove them (perhaps). Therefore, perhaps this should wait until after group actions can be journaled and replayed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but then I don't have any info about snapshots namespace and in case of replay I can't recreate the snapshot with required namespace. So, far all it does - keeps this information. Nobody in the code creates namespaces other than UserSnapshotNamespace. If I remove this then all replayed snapshots should be in UserSnapshotNamespace by default.
ac014b1
to
f964026
Compare
@@ -140,6 +140,11 @@ Context *RefreshRequest<I>::handle_v1_get_snapshots(int *result) { | |||
return m_on_finish; | |||
} | |||
|
|||
int n = m_snap_names.size(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: could just use m_snap_namespaces = {m_snap_names.size(), cls::rbd::UserSnapshotNamespace()};
send_v2_get_mutable_metadata(); | ||
return nullptr; | ||
} else if (*result == -EOPNOTSUPP) { | ||
m_snap_namespaces.resize(m_snapc.snaps.size()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: default to cls::rbd::UserSnapshotNamespace
?
@@ -354,8 +368,23 @@ void SnapshotCopyRequest<I>::send_snap_protect() { | |||
librados::snap_t remote_snap_id = *snap_id_it; | |||
|
|||
m_remote_image_ctx->snap_lock.get_read(); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: I don't think you'll need this for the unprotect/protect states since only user snapshots should be protected -- but I think you need to skip over non-user snapshots in the remove state machine for now.
db1b6c0
to
c800c9c
Compare
@dillaman done. it looks like those test failures are unrelated. every time I push different tests sigfault. |
c800c9c
to
34d0e90
Compare
@@ -239,6 +240,26 @@ void SnapPayloadBase::dump(Formatter *f) const { | |||
f->dump_string("snap_name", snap_name); | |||
} | |||
|
|||
void SnapCreatePayload::encode(bufferlist &bl) const { | |||
::encode(cls::rbd::SnapshotNamespaceOnDisk(snap_namespace), bl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All additions need to be added to the end of the structure. Move the encode/decode of the namespace to the end of the function
34d0e90
to
6689573
Compare
@dillaman fixed. |
ok. looking into it. |
@@ -1678,7 +1678,8 @@ int snapshot_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out) | |||
(unsigned long long)snap_id.val); | |||
return -EIO; | |||
} | |||
if (snap_meta.name == old_meta.name || snap_meta.id == old_meta.id) { | |||
if ((snap_meta.name == old_meta.name || snap_meta.id == old_meta.id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The snap id should be unique regardless of the namespace -- so the check should be:
if (snap_meta.id == old_meta.id ||
(snap_meta.name == old_meta.name &&
snap_meta.snapshot_namespace == old_meta.snapshot_namespace)) {
e3dd0c7
to
ca82f88
Compare
done |
@@ -1678,7 +1678,9 @@ int snapshot_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out) | |||
(unsigned long long)snap_id.val); | |||
return -EIO; | |||
} | |||
if (snap_meta.name == old_meta.name || snap_meta.id == old_meta.id) { | |||
if ((snap_meta.name == old_meta.name | |||
&& snap_meta.snapshot_namespace == old_meta.snapshot_namespace) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: the conditionals should go at the end of the line and not the start of a new line:
if ((snap_meta.name == old_meta.name &&
snap_meta.snapshot_namespace == old_meta.snapshot_namespace) ||
snap_meta.id == old_meta.id) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops. sorry. too much haskell before this commit. fixed.
ccf117b
to
7d4350b
Compare
Signed-off-by: Victor Denisov <denisovenator@gmail.com>
Signed-off-by: Victor Denisov <denisovenator@gmail.com>
Signed-off-by: Victor Denisov <denisovenator@gmail.com>
Signed-off-by: Victor Denisov <denisovenator@gmail.com>
7d4350b
to
dfc6316
Compare
No description provided.