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
rgw: add the remove-x-delete feature to cancel swift object expiration #13621
Conversation
f6d6c6c
to
25ad980
Compare
Hi, @rzarzynski |
src/rgw/rgw_op.h
Outdated
{ | ||
if (real_clock::is_zero(delete_at)) { |
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.
It looks we started treating0
in delete_at
as special value saying "expiration hint revoked". Does the expirer
part is OK with that?
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.
Yeah. @rzarzynski : In this change, if we want to set the object expiration time. The var set_delete_at
will be true and the delete_at
updated relatively.
In int RGWObjectExpirer::garbage_single_object(objexp_hint_entry& hint)
it will call delete_obj()
In int RGWRados::Object::Delete::delete_obj()
, you will find these code:
if (!real_clock::is_zero(params.expiration_time)) {
bufferlist bl;
real_time delete_at;
if (state->get_attr(RGW_ATTR_DELETE_AT, bl)) {
try {
bufferlist::iterator iter = bl.begin();
::decode(delete_at, iter);
} catch (buffer::error& err) {
ldout(store->ctx(), 0) << "ERROR: couldn't decode RGW_ATTR_DELETE_AT" << dendl;
return -EIO;
}
if (params.expiration_time != delete_at) {
return -ERR_PRECONDITION_FAILED;
}
}
}
In if (params.expiration_time != delete_at) {
:
if the expiration time of object is updated, the delete_at
is the current expiration time in bufferlist and the params,expiration_time is the non-current expiration time in the list of cls_timeindex_entry
.
So, that means if the two expriation time is not consistent, the object will not be deleted.
If we intend to cancel the object expiration time, the delete_at
will be 0
and the object will never be deleted because of if (!real_clock::is_zero(params.expiration_time)) {
in upper code.
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.
Thanks for the very detailed explanation! Conceptually everything looks good.
src/rgw/rgw_op.h
Outdated
{ | ||
if (real_clock::is_zero(delete_at)) { | ||
map<string, bufferlist>::iterator iter = attrs.find(RGW_ATTR_DELETE_AT); | ||
if (!set_delete_at && iter != attrs.end()) { |
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.
@rzarzynski in this change, the delete_at
will be encoded only in two situations:
- the object was upload in first time
- the object expiration time was updated(including remove the expiration time)
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.
What do you think about switching to boost::optional<ceph::real_time>
instead of introducing theset_delete_at
flag? Optional seems to be intended for handling cases exactly like this one.
25ad980
to
8c6753e
Compare
@rzarzynski Hi, thanks for your suggestion! I've updated them with |
8c6753e
to
2a9da73
Compare
src/rgw/rgw_file.cc
Outdated
@@ -1145,7 +1145,7 @@ namespace rgw { | |||
emplace_attr(RGW_ATTR_SLO_UINDICATOR, std::move(slo_userindicator_bl)); | |||
} | |||
|
|||
op_ret = processor->complete(s->obj_size, etag, &mtime, real_time(), attrs, delete_at, | |||
op_ret = processor->complete(s->obj_size, etag, &mtime, real_time(), attrs, *delete_at, |
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.
It looks we might be dereferencing an empty boost::optional
here. If that's true, following check should help:
delete_at ? *delete_at : 0
src/rgw/rgw_op.cc
Outdated
@@ -3343,7 +3343,7 @@ void RGWPostObj::execute() | |||
emplace_attr(RGW_ATTR_COMPRESSION, std::move(tmp)); | |||
} | |||
|
|||
op_ret = processor.complete(s->obj_size, etag, NULL, real_time(), attrs, delete_at); | |||
op_ret = processor.complete(s->obj_size, etag, NULL, real_time(), attrs, *delete_at); |
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 same here.
src/rgw/rgw_op.h
Outdated
if (real_clock::is_zero(delete_at)) { | ||
return; | ||
map<string, bufferlist>::iterator iter = attrs.find(RGW_ATTR_DELETE_AT); | ||
if (delete_at == boost::none) { |
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.
This is much more readable now. Thanks!
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.
Hmm, I wonder whether we really need to have the RGW_ATTR_DELETE_AT
set for all objects (including those created through the S3 API). Maybe the check solely for boost::none
would be enough? What do you think?
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.
@rzarzynski ,I've updated them. I considered the http://tracker.ceph.com/issues/19074, so I set RGW_ATTR_DELETE_AT
to all objects before. But now there is another solution instead which is described below.
1347007
to
e0ade73
Compare
In openstack swift, it also support the feature to cancel the object expiration, which could be found at last point in https://docs.openstack.org/user-guide/cli-swift-set-object-expiration.html. we can remove the object expiration by set 'X-Remove-Delete-At:'. This patch also could fix the bug that when we set the object expiration and then upload the same object to the container again. The previous object expiration also works, which is not compatible with the openstack swift. Fixes: http://tracker.ceph.com/issues/19074 Signed-off-by: Jing Wenjun <jingwenjun@cmss.chinamobile.com>
e0ade73
to
230429e
Compare
@@ -8328,6 +8328,8 @@ int RGWRados::Object::Delete::delete_obj() | |||
if (params.expiration_time != delete_at) { | |||
return -ERR_PRECONDITION_FAILED; | |||
} | |||
} else { |
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.
Hi, @rzarzynski ,this change will fix http://tracker.ceph.com/issues/19074 .
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.
OK, RGWRados::delete_obj
takes expiration_time
which is by default ceph::real_time()
:
/** Delete an object.*/
int delete_obj(RGWObjectCtx& obj_ctx,
const RGWBucketInfo& bucket_owner,
const rgw_obj& src_obj,
int versioning_status,
uint16_t bilog_flags = 0,
const ceph::real_time& expiration_time = ceph::real_time());
passed teuthology: http://pulpito.ceph.com/cbodley-2017-03-23_12:12:34-rgw-wip-cbodley-testing---basic-mira (waiting on @rzarzynski review) |
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.
Looks good. Thanks, @Jing-Scott!
op_ret = processor->complete(s->obj_size, etag, &mtime, real_time(), attrs, delete_at, | ||
if_match, if_nomatch); | ||
op_ret = processor->complete(s->obj_size, etag, &mtime, real_time(), attrs, | ||
(delete_at ? *delete_at : real_time()), if_match, if_nomatch); |
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 delete_at
is empty, then we supply an instance of real_time
. ceph::real_time
is an alias over std::chrono::time_point<ceph::time_detail::real_clock>
. Its default-constructed instance represents logical zero --real_clock::is_zero(ceph::real_time()) == true
. OK.
@@ -8328,6 +8328,8 @@ int RGWRados::Object::Delete::delete_obj() | |||
if (params.expiration_time != delete_at) { | |||
return -ERR_PRECONDITION_FAILED; | |||
} | |||
} else { |
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.
OK, RGWRados::delete_obj
takes expiration_time
which is by default ceph::real_time()
:
/** Delete an object.*/
int delete_obj(RGWObjectCtx& obj_ctx,
const RGWBucketInfo& bucket_owner,
const rgw_obj& src_obj,
int versioning_status,
uint16_t bilog_flags = 0,
const ceph::real_time& expiration_time = ceph::real_time());
In openstack swift, it also support the feature to cancel the object expiration, which could be found at last point in https://docs.openstack.org/user-guide/cli-swift-set-object-expiration.html. we can remove the object expiration by set 'X-Remove-Delete-At:'.
This patch also could fix the bug that when we set the object expiration and then upload the same object to the container again. The previous object expiration also works, which is not compatible with the openstack swift.
Fixes: http://tracker.ceph.com/issues/19074
Signed-off-by: Jing Wenjun jingwenjun@cmss.chinamobile.com