rgw: delete-at and delete-after also on obj put / copy

And potentially later we could use also the S3 api, so it
could work with multipart upload, and POST obj.

Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
This commit is contained in:
Yehuda Sadeh 2015-08-27 16:02:44 -07:00
parent 9db8122680
commit fa347d8f69
5 changed files with 123 additions and 56 deletions

View File

@ -1581,7 +1581,7 @@ class RGWPutObjProcessor_Multipart : public RGWPutObjProcessor_Atomic
protected: protected:
int prepare(RGWRados *store, string *oid_rand); int prepare(RGWRados *store, string *oid_rand);
int do_complete(string& etag, time_t *mtime, time_t set_mtime, int do_complete(string& etag, time_t *mtime, time_t set_mtime,
map<string, bufferlist>& attrs, map<string, bufferlist>& attrs, time_t delete_at,
const char *if_match = NULL, const char *if_nomatch = NULL); const char *if_match = NULL, const char *if_nomatch = NULL);
public: public:
@ -1655,7 +1655,7 @@ static bool is_v2_upload_id(const string& upload_id)
} }
int RGWPutObjProcessor_Multipart::do_complete(string& etag, time_t *mtime, time_t set_mtime, int RGWPutObjProcessor_Multipart::do_complete(string& etag, time_t *mtime, time_t set_mtime,
map<string, bufferlist>& attrs, map<string, bufferlist>& attrs, time_t delete_at,
const char *if_match, const char *if_nomatch) const char *if_match, const char *if_nomatch)
{ {
complete_writing_data(); complete_writing_data();
@ -1666,6 +1666,7 @@ int RGWPutObjProcessor_Multipart::do_complete(string& etag, time_t *mtime, time_
head_obj_op.meta.set_mtime = set_mtime; head_obj_op.meta.set_mtime = set_mtime;
head_obj_op.meta.mtime = mtime; head_obj_op.meta.mtime = mtime;
head_obj_op.meta.owner = s->owner.get_id(); head_obj_op.meta.owner = s->owner.get_id();
head_obj_op.meta.delete_at = delete_at;
int r = head_obj_op.write_meta(s->obj_size, attrs); int r = head_obj_op.write_meta(s->obj_size, attrs);
if (r < 0) if (r < 0)
@ -1788,6 +1789,17 @@ static int get_system_versioning_params(req_state *s, uint64_t *olh_epoch, strin
return 0; return 0;
} }
static void encode_delete_at_attr(time_t delete_at, map<string, bufferlist>& attrs)
{
if (delete_at == 0) {
return;
}
bufferlist delatbl;
::encode(utime_t(delete_at, 0), delatbl);
attrs[RGW_ATTR_DELETE_AT] = delatbl;
}
void RGWPutObj::execute() void RGWPutObj::execute()
{ {
RGWPutObjProcessor *processor = NULL; RGWPutObjProcessor *processor = NULL;
@ -1985,8 +1997,10 @@ void RGWPutObj::execute()
} }
rgw_get_request_metadata(s->cct, s->info, attrs); rgw_get_request_metadata(s->cct, s->info, attrs);
encode_delete_at_attr(delete_at, attrs);
ret = processor->complete(etag, &mtime, 0, attrs, delete_at, if_match, if_nomatch);
ret = processor->complete(etag, &mtime, 0, attrs, if_match, if_nomatch);
done: done:
dispose_processor(processor); dispose_processor(processor);
perfcounter->tinc(l_rgw_put_lat, perfcounter->tinc(l_rgw_put_lat,
@ -2105,7 +2119,7 @@ void RGWPostObj::execute()
attrs[RGW_ATTR_CONTENT_TYPE] = ct_bl; attrs[RGW_ATTR_CONTENT_TYPE] = ct_bl;
} }
ret = processor->complete(etag, NULL, 0, attrs); ret = processor->complete(etag, NULL, 0, attrs, delete_at);
done: done:
dispose_processor(processor); dispose_processor(processor);
@ -2372,12 +2386,7 @@ void RGWPutMetadataObject::execute()
/* Filter currently existing attributes. */ /* Filter currently existing attributes. */
prepare_add_del_attrs(orig_attrs, attrs, rmattrs); prepare_add_del_attrs(orig_attrs, attrs, rmattrs);
populate_with_generic_attrs(s, attrs); populate_with_generic_attrs(s, attrs);
encode_delete_at_attr(delete_at, attrs);
if (!delete_at.is_zero()) {
bufferlist delatbl;
::encode(delete_at, delatbl);
attrs[RGW_ATTR_DELETE_AT] = delatbl;
}
ret = store->set_attrs(s->obj_ctx, obj, attrs, &rmattrs, NULL); ret = store->set_attrs(s->obj_ctx, obj, attrs, &rmattrs, NULL);
} }
@ -2612,6 +2621,8 @@ void RGWCopyObj::execute()
obj_ctx.set_atomic(src_obj); obj_ctx.set_atomic(src_obj);
obj_ctx.set_atomic(dst_obj); obj_ctx.set_atomic(dst_obj);
encode_delete_at_attr(delete_at, attrs);
ret = store->copy_obj(obj_ctx, ret = store->copy_obj(obj_ctx,
s->user.user_id, s->user.user_id,
client_id, client_id,
@ -2631,6 +2642,7 @@ void RGWCopyObj::execute()
attrs_mod, attrs_mod,
attrs, RGW_OBJ_CATEGORY_MAIN, attrs, RGW_OBJ_CATEGORY_MAIN,
olh_epoch, olh_epoch,
delete_at,
(version_id.empty() ? NULL : &version_id), (version_id.empty() ? NULL : &version_id),
&s->req_id, /* use req_id as tag */ &s->req_id, /* use req_id as tag */
&etag, &etag,

View File

@ -436,6 +436,8 @@ protected:
uint64_t olh_epoch; uint64_t olh_epoch;
string version_id; string version_id;
time_t delete_at;
public: public:
RGWPutObj() { RGWPutObj() {
ret = 0; ret = 0;
@ -449,6 +451,7 @@ public:
mtime = 0; mtime = 0;
user_manifest_parts_hash = NULL; user_manifest_parts_hash = NULL;
olh_epoch = 0; olh_epoch = 0;
delete_at = 0;
} }
virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) {
@ -489,11 +492,12 @@ protected:
string content_type; string content_type;
RGWAccessControlPolicy policy; RGWAccessControlPolicy policy;
map<string, bufferlist> attrs; map<string, bufferlist> attrs;
time_t delete_at;
public: public:
RGWPostObj() : min_len(0), max_len(LLONG_MAX), ret(0), len(0), ofs(0), RGWPostObj() : min_len(0), max_len(LLONG_MAX), ret(0), len(0), ofs(0),
supplied_md5_b64(NULL), supplied_etag(NULL), supplied_md5_b64(NULL), supplied_etag(NULL),
data_pending(false) {} data_pending(false), delete_at(0) {}
virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) {
RGWOp::init(store, s, h); RGWOp::init(store, s, h);
@ -579,11 +583,11 @@ protected:
int ret; int ret;
RGWAccessControlPolicy policy; RGWAccessControlPolicy policy;
string placement_rule; string placement_rule;
utime_t delete_at; time_t delete_at;
public: public:
RGWPutMetadataObject() RGWPutMetadataObject()
: ret(0) : ret(0), delete_at(0)
{} {}
virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) {
@ -658,6 +662,7 @@ protected:
string version_id; string version_id;
uint64_t olh_epoch; uint64_t olh_epoch;
time_t delete_at;
int init_common(); int init_common();
@ -680,6 +685,7 @@ public:
attrs_mod = RGWRados::ATTRSMOD_NONE; attrs_mod = RGWRados::ATTRSMOD_NONE;
last_ofs = 0; last_ofs = 0;
olh_epoch = 0; olh_epoch = 0;
delete_at = 0;
} }
static bool parse_copy_location(const string& src, string& bucket_name, rgw_obj_key& object); static bool parse_copy_location(const string& src, string& bucket_name, rgw_obj_key& object);

View File

@ -892,10 +892,10 @@ void RGWObjVersionTracker::generate_new_write_ver(CephContext *cct)
} }
int RGWPutObjProcessor::complete(string& etag, time_t *mtime, time_t set_mtime, int RGWPutObjProcessor::complete(string& etag, time_t *mtime, time_t set_mtime,
map<string, bufferlist>& attrs, map<string, bufferlist>& attrs, time_t delete_at,
const char *if_match, const char * if_nomatch) const char *if_match, const char * if_nomatch)
{ {
int r = do_complete(etag, mtime, set_mtime, attrs, if_match, if_nomatch); int r = do_complete(etag, mtime, set_mtime, attrs, delete_at, if_match, if_nomatch);
if (r < 0) if (r < 0)
return r; return r;
@ -1209,7 +1209,7 @@ int RGWPutObjProcessor_Atomic::complete_writing_data()
} }
int RGWPutObjProcessor_Atomic::do_complete(string& etag, time_t *mtime, time_t set_mtime, int RGWPutObjProcessor_Atomic::do_complete(string& etag, time_t *mtime, time_t set_mtime,
map<string, bufferlist>& attrs, map<string, bufferlist>& attrs, time_t delete_at,
const char *if_match, const char *if_match,
const char *if_nomatch) { const char *if_nomatch) {
int r = complete_writing_data(); int r = complete_writing_data();
@ -1235,6 +1235,7 @@ int RGWPutObjProcessor_Atomic::do_complete(string& etag, time_t *mtime, time_t s
obj_op.meta.owner = bucket_info.owner; obj_op.meta.owner = bucket_info.owner;
obj_op.meta.flags = PUT_OBJ_CREATE; obj_op.meta.flags = PUT_OBJ_CREATE;
obj_op.meta.olh_epoch = olh_epoch; obj_op.meta.olh_epoch = olh_epoch;
obj_op.meta.delete_at = delete_at;
r = obj_op.write_meta(obj_len, attrs); r = obj_op.write_meta(obj_len, attrs);
if (r < 0) { if (r < 0) {
@ -3624,6 +3625,17 @@ int RGWRados::Object::Write::write_meta(uint64_t size,
} }
} }
if (meta.delete_at > 0) {
rgw_obj_key obj_key;
obj.get_index_key(&obj_key);
r = store->objexp_hint_add(utime_t(meta.delete_at, 0), bucket.name, bucket.bucket_id, obj_key);
if (r < 0) {
ldout(store->ctx(), 0) << "ERROR: objexp_hint_add() returned r=" << r << ", object will not get removed" << dendl;
/* ignoring error, nothing we can do at this point */
}
}
/* update quota cache */ /* update quota cache */
store->quota_handler->update_stats(meta.owner, bucket, (orig_exists ? 0 : 1), size, orig_size); store->quota_handler->update_stats(meta.owner, bucket, (orig_exists ? 0 : 1), size, orig_size);
@ -3861,8 +3873,8 @@ public:
processor->set_extra_data_len(len); processor->set_extra_data_len(len);
} }
int complete(string& etag, time_t *mtime, time_t set_mtime, map<string, bufferlist>& attrs) { int complete(string& etag, time_t *mtime, time_t set_mtime, map<string, bufferlist>& attrs, time_t delete_at) {
return processor->complete(etag, mtime, set_mtime, attrs); return processor->complete(etag, mtime, set_mtime, attrs, delete_at);
} }
}; };
@ -3925,7 +3937,7 @@ int RGWRados::rewrite_obj(RGWBucketInfo& dest_bucket_info, rgw_obj& obj)
return ret; return ret;
} }
return copy_obj_data(rctx, dest_bucket_info, read_op, end, obj, obj, max_chunk_size, NULL, mtime, attrset, RGW_OBJ_CATEGORY_MAIN, 0, NULL, NULL, NULL, NULL); return copy_obj_data(rctx, dest_bucket_info, read_op, end, obj, obj, max_chunk_size, NULL, mtime, attrset, RGW_OBJ_CATEGORY_MAIN, 0, 0, NULL, NULL, NULL, NULL);
} }
int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx, int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx,
@ -3948,6 +3960,7 @@ int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx,
map<string, bufferlist>& attrs, map<string, bufferlist>& attrs,
RGWObjCategory category, RGWObjCategory category,
uint64_t olh_epoch, uint64_t olh_epoch,
time_t delete_at,
string *version_id, string *version_id,
string *ptag, string *ptag,
string *petag, string *petag,
@ -4047,7 +4060,7 @@ int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx,
set_copy_attrs(src_attrs, attrs, attrs_mod); set_copy_attrs(src_attrs, attrs, attrs_mod);
} }
ret = cb.complete(etag, mtime, set_mtime, attrs); ret = cb.complete(etag, mtime, set_mtime, attrs, delete_at);
if (ret < 0) { if (ret < 0) {
goto set_err_state; goto set_err_state;
} }
@ -4128,6 +4141,7 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx,
map<string, bufferlist>& attrs, map<string, bufferlist>& attrs,
RGWObjCategory category, RGWObjCategory category,
uint64_t olh_epoch, uint64_t olh_epoch,
time_t delete_at,
string *version_id, string *version_id,
string *ptag, string *ptag,
string *petag, string *petag,
@ -4160,7 +4174,7 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx,
return fetch_remote_obj(obj_ctx, user_id, client_id, op_id, info, source_zone, return fetch_remote_obj(obj_ctx, user_id, client_id, op_id, info, source_zone,
dest_obj, src_obj, dest_bucket_info, src_bucket_info, src_mtime, mtime, mod_ptr, dest_obj, src_obj, dest_bucket_info, src_bucket_info, src_mtime, mtime, mod_ptr,
unmod_ptr, if_match, if_nomatch, attrs_mod, attrs, category, unmod_ptr, if_match, if_nomatch, attrs_mod, attrs, category,
olh_epoch, version_id, ptag, petag, err, progress_cb, progress_data); olh_epoch, delete_at, version_id, ptag, petag, err, progress_cb, progress_data);
} }
map<string, bufferlist> src_attrs; map<string, bufferlist> src_attrs;
@ -4238,7 +4252,7 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx,
if (copy_data) { /* refcounting tail wouldn't work here, just copy the data */ if (copy_data) { /* refcounting tail wouldn't work here, just copy the data */
return copy_obj_data(obj_ctx, dest_bucket_info, read_op, end, dest_obj, src_obj, return copy_obj_data(obj_ctx, dest_bucket_info, read_op, end, dest_obj, src_obj,
max_chunk_size, mtime, 0, attrs, category, olh_epoch, max_chunk_size, mtime, 0, attrs, category, olh_epoch, delete_at,
version_id, ptag, petag, err); version_id, ptag, petag, err);
} }
@ -4330,6 +4344,7 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx,
write_op.meta.flags = PUT_OBJ_CREATE; write_op.meta.flags = PUT_OBJ_CREATE;
write_op.meta.category = category; write_op.meta.category = category;
write_op.meta.olh_epoch = olh_epoch; write_op.meta.olh_epoch = olh_epoch;
write_op.meta.delete_at = delete_at;
ret = write_op.write_meta(end + 1, attrs); ret = write_op.write_meta(end + 1, attrs);
if (ret < 0) { if (ret < 0) {
@ -4373,6 +4388,7 @@ int RGWRados::copy_obj_data(RGWObjectCtx& obj_ctx,
map<string, bufferlist>& attrs, map<string, bufferlist>& attrs,
RGWObjCategory category, RGWObjCategory category,
uint64_t olh_epoch, uint64_t olh_epoch,
time_t delete_at,
string *version_id, string *version_id,
string *ptag, string *ptag,
string *petag, string *petag,
@ -4429,7 +4445,7 @@ int RGWRados::copy_obj_data(RGWObjectCtx& obj_ctx,
} }
} }
ret = processor.complete(etag, mtime, set_mtime, attrs); ret = processor.complete(etag, mtime, set_mtime, attrs, delete_at);
return ret; return ret;
} }
@ -5503,12 +5519,16 @@ int RGWRados::set_attrs(void *ctx, rgw_obj& obj,
if (name.compare(RGW_ATTR_DELETE_AT) == 0) { if (name.compare(RGW_ATTR_DELETE_AT) == 0) {
utime_t ts; utime_t ts;
::decode(ts, bl); try {
::decode(ts, bl);
rgw_obj_key obj_key; rgw_obj_key obj_key;
obj.get_index_key(&obj_key); obj.get_index_key(&obj_key);
objexp_hint_add(ts, bucket.name, bucket.bucket_id, obj_key); objexp_hint_add(ts, bucket.name, bucket.bucket_id, obj_key);
} catch (buffer::error& err) {
ldout(cct, 0) << "ERROR: failed to decode " RGW_ATTR_DELETE_AT << " attr" << dendl;
}
} }
} }

View File

@ -1606,10 +1606,11 @@ public:
const char *if_match; const char *if_match;
const char *if_nomatch; const char *if_nomatch;
uint64_t olh_epoch; uint64_t olh_epoch;
time_t delete_at;
MetaParams() : mtime(NULL), rmattrs(NULL), data(NULL), manifest(NULL), ptag(NULL), MetaParams() : mtime(NULL), rmattrs(NULL), data(NULL), manifest(NULL), ptag(NULL),
remove_objs(NULL), set_mtime(0), category(RGW_OBJ_CATEGORY_MAIN), flags(0), remove_objs(NULL), set_mtime(0), category(RGW_OBJ_CATEGORY_MAIN), flags(0),
if_match(NULL), if_nomatch(NULL), olh_epoch(0) {} if_match(NULL), if_nomatch(NULL), olh_epoch(0), delete_at(0) {}
} meta; } meta;
Write(RGWRados::Object *_target) : target(_target) {} Write(RGWRados::Object *_target) : target(_target) {}
@ -1808,6 +1809,7 @@ public:
map<string, bufferlist>& attrs, map<string, bufferlist>& attrs,
RGWObjCategory category, RGWObjCategory category,
uint64_t olh_epoch, uint64_t olh_epoch,
time_t delete_at,
string *version_id, string *version_id,
string *ptag, string *ptag,
string *petag, string *petag,
@ -1855,6 +1857,7 @@ public:
map<std::string, bufferlist>& attrs, map<std::string, bufferlist>& attrs,
RGWObjCategory category, RGWObjCategory category,
uint64_t olh_epoch, uint64_t olh_epoch,
time_t delete_at,
string *version_id, string *version_id,
string *ptag, string *ptag,
string *petag, string *petag,
@ -1873,6 +1876,7 @@ public:
map<string, bufferlist>& attrs, map<string, bufferlist>& attrs,
RGWObjCategory category, RGWObjCategory category,
uint64_t olh_epoch, uint64_t olh_epoch,
time_t delete_at,
string *version_id, string *version_id,
string *ptag, string *ptag,
string *petag, string *petag,
@ -2377,7 +2381,7 @@ protected:
RGWBucketInfo bucket_info; RGWBucketInfo bucket_info;
virtual int do_complete(string& etag, time_t *mtime, time_t set_mtime, virtual int do_complete(string& etag, time_t *mtime, time_t set_mtime,
map<string, bufferlist>& attrs, map<string, bufferlist>& attrs, time_t delete_at,
const char *if_match = NULL, const char *if_nomatch = NULL) = 0; const char *if_match = NULL, const char *if_nomatch = NULL) = 0;
public: public:
@ -2393,7 +2397,7 @@ public:
assert(0); assert(0);
} }
virtual int complete(string& etag, time_t *mtime, time_t set_mtime, virtual int complete(string& etag, time_t *mtime, time_t set_mtime,
map<string, bufferlist>& attrs, map<string, bufferlist>& attrs, time_t delete_at,
const char *if_match = NULL, const char *if_nomatch = NULL); const char *if_match = NULL, const char *if_nomatch = NULL);
CephContext *ctx(); CephContext *ctx();
@ -2464,7 +2468,7 @@ protected:
int write_data(bufferlist& bl, off_t ofs, void **phandle, bool exclusive); int write_data(bufferlist& bl, off_t ofs, void **phandle, bool exclusive);
virtual int do_complete(string& etag, time_t *mtime, time_t set_mtime, virtual int do_complete(string& etag, time_t *mtime, time_t set_mtime,
map<string, bufferlist>& attrs, map<string, bufferlist>& attrs, time_t delete_at,
const char *if_match = NULL, const char *if_nomatch = NULL); const char *if_match = NULL, const char *if_nomatch = NULL);
int prepare_next_part(off_t ofs); int prepare_next_part(off_t ofs);

View File

@ -481,6 +481,40 @@ void RGWDeleteBucket_ObjStore_SWIFT::send_response()
rgw_flush_formatter_and_reset(s, s->formatter); rgw_flush_formatter_and_reset(s, s->formatter);
} }
static int get_delete_at_param(req_state *s, time_t *delete_at)
{
/* Handle Swift object expiration. */
utime_t delat_proposal;
string x_delete = s->info.env->get("HTTP_X_DELETE_AFTER", "");
if (x_delete.empty()) {
x_delete = s->info.env->get("HTTP_X_DELETE_AT", "");
} else {
/* X-Delete-After HTTP is present. It means we need add its value
* to the current time. */
delat_proposal = ceph_clock_now(g_ceph_context);
}
if (x_delete.empty()) {
return 0;
}
string err;
long ts = strict_strtoll(x_delete.c_str(), 10, &err);
if (!err.empty()) {
return -EINVAL;
}
delat_proposal += utime_t(ts, 0);
if (delat_proposal < ceph_clock_now(g_ceph_context)) {
return -EINVAL;
}
*delete_at = delat_proposal.sec();
return 0;
}
int RGWPutObj_ObjStore_SWIFT::get_params() int RGWPutObj_ObjStore_SWIFT::get_params()
{ {
if (s->has_bad_meta) if (s->has_bad_meta)
@ -515,6 +549,12 @@ int RGWPutObj_ObjStore_SWIFT::get_params()
obj_manifest = s->info.env->get("HTTP_X_OBJECT_MANIFEST"); obj_manifest = s->info.env->get("HTTP_X_OBJECT_MANIFEST");
int r = get_delete_at_param(s, &delete_at);
if (r < 0) {
ldout(s->cct, 5) << "ERROR: failed to get Delete-At param" << dendl;
return r;
}
return RGWPutObj_ObjStore::get_params(); return RGWPutObj_ObjStore::get_params();
} }
@ -621,31 +661,10 @@ int RGWPutMetadataObject_ObjStore_SWIFT::get_params()
} }
/* Handle Swift object expiration. */ /* Handle Swift object expiration. */
utime_t delat_proposal; int r = get_delete_at_param(s, &delete_at);
string x_delete = s->info.env->get("HTTP_X_DELETE_AFTER", ""); if (r < 0) {
ldout(s->cct, 5) << "ERROR: failed to get Delete-At param" << dendl;
if (x_delete.empty()) { return r;
x_delete = s->info.env->get("HTTP_X_DELETE_AT", "");
} else {
/* X-Delete-After HTTP is present. It means we need add its value
* to the current time. */
delat_proposal = ceph_clock_now(g_ceph_context);
}
if (!x_delete.empty()) {
string err;
long ts = strict_strtoll(x_delete.c_str(), 10, &err);
if (!err.empty()) {
return -EINVAL;
}
delat_proposal += utime_t(ts, 0);
if (delat_proposal < ceph_clock_now(g_ceph_context)) {
return -EINVAL;
}
delete_at = delat_proposal;
} }
placement_rule = s->info.env->get("HTTP_X_STORAGE_POLICY", ""); placement_rule = s->info.env->get("HTTP_X_STORAGE_POLICY", "");
@ -750,6 +769,12 @@ int RGWCopyObj_ObjStore_SWIFT::get_params()
attrs_mod = RGWRados::ATTRSMOD_MERGE; attrs_mod = RGWRados::ATTRSMOD_MERGE;
} }
int r = get_delete_at_param(s, &delete_at);
if (r < 0) {
ldout(s->cct, 5) << "ERROR: failed to get Delete-At param" << dendl;
return r;
}
return 0; return 0;
} }