diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 3078e419790..74c77f761eb 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -1581,7 +1581,7 @@ class RGWPutObjProcessor_Multipart : public RGWPutObjProcessor_Atomic protected: int prepare(RGWRados *store, string *oid_rand); int do_complete(string& etag, time_t *mtime, time_t set_mtime, - map& attrs, + map& attrs, time_t delete_at, const char *if_match = NULL, const char *if_nomatch = NULL); 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, - map& attrs, + map& attrs, time_t delete_at, const char *if_match, const char *if_nomatch) { 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.mtime = mtime; 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); if (r < 0) @@ -1788,6 +1789,17 @@ static int get_system_versioning_params(req_state *s, uint64_t *olh_epoch, strin return 0; } +static void encode_delete_at_attr(time_t delete_at, map& attrs) +{ + if (delete_at == 0) { + return; + } + + bufferlist delatbl; + ::encode(utime_t(delete_at, 0), delatbl); + attrs[RGW_ATTR_DELETE_AT] = delatbl; +} + void RGWPutObj::execute() { RGWPutObjProcessor *processor = NULL; @@ -1985,8 +1997,10 @@ void RGWPutObj::execute() } 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: dispose_processor(processor); perfcounter->tinc(l_rgw_put_lat, @@ -2105,7 +2119,7 @@ void RGWPostObj::execute() attrs[RGW_ATTR_CONTENT_TYPE] = ct_bl; } - ret = processor->complete(etag, NULL, 0, attrs); + ret = processor->complete(etag, NULL, 0, attrs, delete_at); done: dispose_processor(processor); @@ -2372,12 +2386,7 @@ void RGWPutMetadataObject::execute() /* Filter currently existing attributes. */ prepare_add_del_attrs(orig_attrs, attrs, rmattrs); populate_with_generic_attrs(s, attrs); - - if (!delete_at.is_zero()) { - bufferlist delatbl; - ::encode(delete_at, delatbl); - attrs[RGW_ATTR_DELETE_AT] = delatbl; - } + encode_delete_at_attr(delete_at, attrs); 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(dst_obj); + encode_delete_at_attr(delete_at, attrs); + ret = store->copy_obj(obj_ctx, s->user.user_id, client_id, @@ -2631,6 +2642,7 @@ void RGWCopyObj::execute() attrs_mod, attrs, RGW_OBJ_CATEGORY_MAIN, olh_epoch, + delete_at, (version_id.empty() ? NULL : &version_id), &s->req_id, /* use req_id as tag */ &etag, diff --git a/src/rgw/rgw_op.h b/src/rgw/rgw_op.h index 8781faeff46..7a196a3d6ce 100644 --- a/src/rgw/rgw_op.h +++ b/src/rgw/rgw_op.h @@ -436,6 +436,8 @@ protected: uint64_t olh_epoch; string version_id; + time_t delete_at; + public: RGWPutObj() { ret = 0; @@ -449,6 +451,7 @@ public: mtime = 0; user_manifest_parts_hash = NULL; olh_epoch = 0; + delete_at = 0; } virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { @@ -489,11 +492,12 @@ protected: string content_type; RGWAccessControlPolicy policy; map attrs; + time_t delete_at; public: RGWPostObj() : min_len(0), max_len(LLONG_MAX), ret(0), len(0), ofs(0), 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) { RGWOp::init(store, s, h); @@ -579,11 +583,11 @@ protected: int ret; RGWAccessControlPolicy policy; string placement_rule; - utime_t delete_at; + time_t delete_at; public: RGWPutMetadataObject() - : ret(0) + : ret(0), delete_at(0) {} virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) { @@ -658,6 +662,7 @@ protected: string version_id; uint64_t olh_epoch; + time_t delete_at; int init_common(); @@ -680,6 +685,7 @@ public: attrs_mod = RGWRados::ATTRSMOD_NONE; last_ofs = 0; olh_epoch = 0; + delete_at = 0; } static bool parse_copy_location(const string& src, string& bucket_name, rgw_obj_key& object); diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index bde1cd7249f..a682cd422d1 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -892,10 +892,10 @@ void RGWObjVersionTracker::generate_new_write_ver(CephContext *cct) } int RGWPutObjProcessor::complete(string& etag, time_t *mtime, time_t set_mtime, - map& attrs, + map& attrs, time_t delete_at, 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) 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, - map& attrs, + map& attrs, time_t delete_at, const char *if_match, const char *if_nomatch) { 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.flags = PUT_OBJ_CREATE; obj_op.meta.olh_epoch = olh_epoch; + obj_op.meta.delete_at = delete_at; r = obj_op.write_meta(obj_len, attrs); 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 */ 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); } - int complete(string& etag, time_t *mtime, time_t set_mtime, map& attrs) { - return processor->complete(etag, mtime, set_mtime, attrs); + int complete(string& etag, time_t *mtime, time_t set_mtime, map& attrs, time_t delete_at) { + 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 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, @@ -3948,6 +3960,7 @@ int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx, map& attrs, RGWObjCategory category, uint64_t olh_epoch, + time_t delete_at, string *version_id, string *ptag, string *petag, @@ -4047,7 +4060,7 @@ int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx, 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) { goto set_err_state; } @@ -4128,6 +4141,7 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx, map& attrs, RGWObjCategory category, uint64_t olh_epoch, + time_t delete_at, string *version_id, string *ptag, 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, 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, - 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 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 */ 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); } @@ -4330,6 +4344,7 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx, write_op.meta.flags = PUT_OBJ_CREATE; write_op.meta.category = category; write_op.meta.olh_epoch = olh_epoch; + write_op.meta.delete_at = delete_at; ret = write_op.write_meta(end + 1, attrs); if (ret < 0) { @@ -4373,6 +4388,7 @@ int RGWRados::copy_obj_data(RGWObjectCtx& obj_ctx, map& attrs, RGWObjCategory category, uint64_t olh_epoch, + time_t delete_at, string *version_id, string *ptag, 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; } @@ -5503,12 +5519,16 @@ int RGWRados::set_attrs(void *ctx, rgw_obj& obj, if (name.compare(RGW_ATTR_DELETE_AT) == 0) { utime_t ts; - ::decode(ts, bl); + try { + ::decode(ts, bl); - rgw_obj_key obj_key; - obj.get_index_key(&obj_key); + rgw_obj_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; + } } } diff --git a/src/rgw/rgw_rados.h b/src/rgw/rgw_rados.h index 121bfa58c22..c533b51045e 100644 --- a/src/rgw/rgw_rados.h +++ b/src/rgw/rgw_rados.h @@ -1606,10 +1606,11 @@ public: const char *if_match; const char *if_nomatch; uint64_t olh_epoch; + time_t delete_at; MetaParams() : mtime(NULL), rmattrs(NULL), data(NULL), manifest(NULL), ptag(NULL), 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; Write(RGWRados::Object *_target) : target(_target) {} @@ -1808,6 +1809,7 @@ public: map& attrs, RGWObjCategory category, uint64_t olh_epoch, + time_t delete_at, string *version_id, string *ptag, string *petag, @@ -1855,6 +1857,7 @@ public: map& attrs, RGWObjCategory category, uint64_t olh_epoch, + time_t delete_at, string *version_id, string *ptag, string *petag, @@ -1873,6 +1876,7 @@ public: map& attrs, RGWObjCategory category, uint64_t olh_epoch, + time_t delete_at, string *version_id, string *ptag, string *petag, @@ -2377,7 +2381,7 @@ protected: RGWBucketInfo bucket_info; virtual int do_complete(string& etag, time_t *mtime, time_t set_mtime, - map& attrs, + map& attrs, time_t delete_at, const char *if_match = NULL, const char *if_nomatch = NULL) = 0; public: @@ -2393,7 +2397,7 @@ public: assert(0); } virtual int complete(string& etag, time_t *mtime, time_t set_mtime, - map& attrs, + map& attrs, time_t delete_at, const char *if_match = NULL, const char *if_nomatch = NULL); CephContext *ctx(); @@ -2464,7 +2468,7 @@ protected: 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, - map& attrs, + map& attrs, time_t delete_at, const char *if_match = NULL, const char *if_nomatch = NULL); int prepare_next_part(off_t ofs); diff --git a/src/rgw/rgw_rest_swift.cc b/src/rgw/rgw_rest_swift.cc index 7dea41012f7..02a0cd17f0c 100644 --- a/src/rgw/rgw_rest_swift.cc +++ b/src/rgw/rgw_rest_swift.cc @@ -481,6 +481,40 @@ void RGWDeleteBucket_ObjStore_SWIFT::send_response() 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() { 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"); + 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(); } @@ -621,31 +661,10 @@ int RGWPutMetadataObject_ObjStore_SWIFT::get_params() } /* 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()) { - 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; + 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; } 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; } + 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; }