protected:
int prepare(RGWRados *store, string *oid_rand);
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);
public:
}
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)
{
complete_writing_data();
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)
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()
{
RGWPutObjProcessor *processor = NULL;
}
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,
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);
/* 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);
}
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,
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,
uint64_t olh_epoch;
string version_id;
+ time_t delete_at;
+
public:
RGWPutObj() {
ret = 0;
mtime = 0;
user_manifest_parts_hash = NULL;
olh_epoch = 0;
+ delete_at = 0;
}
virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) {
string content_type;
RGWAccessControlPolicy policy;
map<string, bufferlist> 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);
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) {
string version_id;
uint64_t olh_epoch;
+ time_t delete_at;
int init_common();
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);
}
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)
{
- 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;
}
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_nomatch) {
int r = complete_writing_data();
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) {
}
}
+ 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);
processor->set_extra_data_len(len);
}
- int complete(string& etag, time_t *mtime, time_t set_mtime, map<string, bufferlist>& attrs) {
- return processor->complete(etag, mtime, set_mtime, 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, delete_at);
}
};
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,
map<string, bufferlist>& attrs,
RGWObjCategory category,
uint64_t olh_epoch,
+ time_t delete_at,
string *version_id,
string *ptag,
string *petag,
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;
}
map<string, bufferlist>& attrs,
RGWObjCategory category,
uint64_t olh_epoch,
+ time_t delete_at,
string *version_id,
string *ptag,
string *petag,
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<string, bufferlist> src_attrs;
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);
}
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) {
map<string, bufferlist>& attrs,
RGWObjCategory category,
uint64_t olh_epoch,
+ time_t delete_at,
string *version_id,
string *ptag,
string *petag,
}
}
- ret = processor.complete(etag, mtime, set_mtime, attrs);
+ ret = processor.complete(etag, mtime, set_mtime, attrs, delete_at);
return ret;
}
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;
+ }
}
}
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) {}
map<string, bufferlist>& attrs,
RGWObjCategory category,
uint64_t olh_epoch,
+ time_t delete_at,
string *version_id,
string *ptag,
string *petag,
map<std::string, bufferlist>& attrs,
RGWObjCategory category,
uint64_t olh_epoch,
+ time_t delete_at,
string *version_id,
string *ptag,
string *petag,
map<string, bufferlist>& attrs,
RGWObjCategory category,
uint64_t olh_epoch,
+ time_t delete_at,
string *version_id,
string *ptag,
string *petag,
RGWBucketInfo bucket_info;
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;
public:
assert(0);
}
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);
CephContext *ctx();
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<string, bufferlist>& attrs,
+ map<string, bufferlist>& attrs, time_t delete_at,
const char *if_match = NULL, const char *if_nomatch = NULL);
int prepare_next_part(off_t ofs);
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)
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();
}
}
/* 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", "");
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;
}