}
if (existed && !real_clock::is_zero(op.unmod_since)) {
- if (obj.mtime() >= op.unmod_since) {
+ struct timespec mtime = ceph::real_clock::to_timespec(obj.mtime);
+ struct timespec unmod = ceph::real_clock::to_timespec(op.unmod_since);
+ if (!op.high_precision_time) {
+ mtime.tv_nsec = 0;
+ unmod.tv_nsec = 0;
+ }
+ if (mtime >= unmod) {
return 0; /* no need to set error, we just return 0 and avoid writing to the bi log */
}
}
ceph_timespec obj_ts = ceph::real_clock::to_ceph_timespec(obj_ut);
ceph_timespec op_ts = ceph::real_clock::to_ceph_timespec(op.mtime);
+ if (!op.high_precision_time) {
+ obj_ts.tv_nsec = 0;
+ op_ts.tv_nsec = 0;
+ }
+
CLS_LOG(10, "%s: obj_ut=%lld.%06lld op.mtime=%lld.%06lld", __func__,
(long long)obj_ts.tv_sec, (long long)obj_ts.tv_nsec,
(long long)op_ts.tv_sec, (long long)op_ts.tv_nsec);
switch (op.type) {
case CLS_RGW_CHECK_TIME_MTIME_EQ:
- check = (obj_ut == op.mtime);
+ check = (obj_ts == op_ts);
break;
case CLS_RGW_CHECK_TIME_MTIME_LT:
- check = (obj_ut < op.mtime);
+ check = (obj_ts < op_ts);
break;
case CLS_RGW_CHECK_TIME_MTIME_LE:
- check = (obj_ut <= op.mtime);
+ check = (obj_ts <= op_ts);
break;
case CLS_RGW_CHECK_TIME_MTIME_GT:
- check = (obj_ut > op.mtime);
+ check = (obj_ts > op_ts);
break;
case CLS_RGW_CHECK_TIME_MTIME_GE:
- check = (obj_ut >= op.mtime);
+ check = (obj_ts >= op_ts);
break;
default:
return -EINVAL;
o.exec("rgw", "obj_check_attrs_prefix", in);
}
-void cls_rgw_obj_check_mtime(librados::ObjectOperation& o, const real_time& mtime, RGWCheckMTimeType type)
+void cls_rgw_obj_check_mtime(librados::ObjectOperation& o, const real_time& mtime, bool high_precision_time, RGWCheckMTimeType type)
{
bufferlist in;
struct rgw_cls_obj_check_mtime call;
call.mtime = mtime;
+ call.high_precision_time = high_precision_time;
call.type = type;
::encode(call, in);
o.exec("rgw", "obj_check_mtime", in);
int cls_rgw_bucket_link_olh(librados::IoCtx& io_ctx, const string& oid, const cls_rgw_obj_key& key, bufferlist& olh_tag,
bool delete_marker, const string& op_tag, struct rgw_bucket_dir_entry_meta *meta,
- uint64_t olh_epoch, ceph::real_time unmod_since, bool log_op)
+ uint64_t olh_epoch, ceph::real_time unmod_since, bool high_precision_time, bool log_op)
{
bufferlist in, out;
struct rgw_cls_link_olh_op call;
call.olh_epoch = olh_epoch;
call.log_op = log_op;
call.unmod_since = unmod_since;
+ call.high_precision_time = high_precision_time;
::encode(call, in);
int r = io_ctx.exec(oid, "rgw", "bucket_link_olh", in, out);
if (r < 0)
void cls_rgw_remove_obj(librados::ObjectWriteOperation& o, list<string>& keep_attr_prefixes);
void cls_rgw_obj_store_pg_ver(librados::ObjectWriteOperation& o, const string& attr);
void cls_rgw_obj_check_attrs_prefix(librados::ObjectOperation& o, const string& prefix, bool fail_if_exist);
-void cls_rgw_obj_check_mtime(librados::ObjectOperation& o, const ceph::real_time& mtime, RGWCheckMTimeType type);
+void cls_rgw_obj_check_mtime(librados::ObjectOperation& o, const ceph::real_time& mtime, bool high_precision_time, RGWCheckMTimeType type);
int cls_rgw_bi_get(librados::IoCtx& io_ctx, const string oid,
BIIndexType index_type, cls_rgw_obj_key& key,
int cls_rgw_bucket_link_olh(librados::IoCtx& io_ctx, const string& oid, const cls_rgw_obj_key& key, bufferlist& olh_tag,
bool delete_marker, const string& op_tag, struct rgw_bucket_dir_entry_meta *meta,
- uint64_t olh_epoch, ceph::real_time unmod_since, bool log_op);
+ uint64_t olh_epoch, ceph::real_time unmod_since, bool high_precision_time, bool log_op);
int cls_rgw_bucket_unlink_instance(librados::IoCtx& io_ctx, const string& oid, const cls_rgw_obj_key& key, const string& op_tag,
uint64_t olh_epoch, bool log_op);
int cls_rgw_get_olh_log(librados::IoCtx& io_ctx, string& oid, librados::ObjectReadOperation& op, const cls_rgw_obj_key& olh, uint64_t ver_marker,
::encode_json("bilog_flags", (uint32_t)bilog_flags, f);
utime_t ut(unmod_since);
::encode_json("unmod_since", ut, f);
+ ::encode_json("high_precision_time", high_precision_time, f);
}
void rgw_cls_unlink_instance_op::generate_test_instances(list<rgw_cls_unlink_instance_op*>& o)
bool log_op;
uint16_t bilog_flags;
real_time unmod_since; /* only create delete marker if newer then this */
+ bool high_precision_time;
- rgw_cls_link_olh_op() : delete_marker(false), olh_epoch(0), log_op(false), bilog_flags(0) {}
+ rgw_cls_link_olh_op() : delete_marker(false), olh_epoch(0), log_op(false), bilog_flags(0), high_precision_time(false) {}
void encode(bufferlist& bl) const {
- ENCODE_START(3, 1, bl);
+ ENCODE_START(4, 1, bl);
::encode(key, bl);
::encode(olh_tag, bl);
::encode(delete_marker, bl);
time_t t = ceph::real_clock::to_time_t(unmod_since);
::encode(t, bl);
::encode(unmod_since, bl);
+ ::encode(high_precision_time, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator& bl) {
- DECODE_START(3, bl);
+ DECODE_START(4, bl);
::decode(key, bl);
::decode(olh_tag, bl);
::decode(delete_marker, bl);
if (struct_v >= 3) {
::decode(unmod_since, bl);
}
+ if (struct_v >= 4) {
+ ::decode(high_precision_time, bl);
+ }
DECODE_FINISH(bl);
}
struct rgw_cls_obj_check_mtime {
ceph::real_time mtime;
RGWCheckMTimeType type;
+ bool high_precision_time;
- rgw_cls_obj_check_mtime() : type(CLS_RGW_CHECK_TIME_MTIME_EQ) {}
+ rgw_cls_obj_check_mtime() : type(CLS_RGW_CHECK_TIME_MTIME_EQ), high_precision_time(false) {}
void encode(bufferlist& bl) const {
- ENCODE_START(1, 1, bl);
+ ENCODE_START(2, 1, bl);
::encode(mtime, bl);
::encode((uint8_t)type, bl);
+ ::encode(high_precision_time, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator& bl) {
- DECODE_START(1, bl);
+ DECODE_START(2, bl);
::decode(mtime, bl);
uint8_t c;
::decode(c, bl);
type = (RGWCheckMTimeType)c;
+ if (struct_v >= 2) {
+ ::decode(high_precision_time, bl);
+ }
DECODE_FINISH(bl);
}
};
NULL, /* real_time* mtime, */
NULL, /* const real_time* mod_ptr, */
NULL, /* const real_time* unmod_ptr, */
+ false, /* high precision time */
NULL, /* const char *if_match, */
NULL, /* const char *if_nomatch, */
RGWRados::ATTRSMOD_NONE,
del_op.params.obj_owner.set_id(owner);
del_op.params.obj_owner.set_name(owner_display_name);
del_op.params.mtime = timestamp;
+ del_op.params.high_precision_time = true;
ret = del_op.delete_obj();
if (ret < 0) {
read_op.conds.mod_ptr = mod_ptr;
read_op.conds.unmod_ptr = unmod_ptr;
+ read_op.conds.high_precision_time = s->system_request; /* system request need to use high precision time */
read_op.conds.mod_zone_id = mod_zone_id;
read_op.conds.mod_pg_ver = mod_pg_ver;
read_op.conds.if_match = if_match;
del_op.params.versioning_status = s->bucket_info.versioning_status();
del_op.params.obj_owner = s->owner;
del_op.params.unmod_since = unmod_since;
+ del_op.params.high_precision_time = s->system_request; /* system request uses high precision time */
op_ret = del_op.delete_obj();
if (op_ret >= 0) {
encode_delete_at_attr(delete_at, attrs);
+ bool high_precision_time = (s->system_request);
+
op_ret = store->copy_obj(obj_ctx,
s->user->user_id,
client_id,
&mtime,
mod_ptr,
unmod_ptr,
+ high_precision_time,
if_match,
if_nomatch,
attrs_mod,
NULL, /* time_t *mtime */
NULL, /* const time_t *mod_ptr */
NULL, /* const time_t *unmod_ptr */
+ false, /* bool high_precision_time */
NULL, /* const char *if_match */
NULL, /* const char *if_nomatch */
RGWRados::ATTRSMOD_NONE,
state = NULL;
if (versioned_op) {
- r = store->set_olh(target->get_ctx(), target->get_bucket_info(), obj, false, NULL, meta.olh_epoch, real_time());
+ r = store->set_olh(target->get_ctx(), target->get_bucket_info(), obj, false, NULL, meta.olh_epoch, real_time(), false);
if (r < 0) {
return r;
}
real_time mtime;
uint32_t zone_short_id;
uint64_t pg_ver;
+ bool high_precision;
- obj_time_weight() : zone_short_id(0), pg_ver(0) {}
+ obj_time_weight() : zone_short_id(0), pg_ver(0), high_precision(false) {}
+
+ bool compare_low_precision(const obj_time_weight& rhs) {
+ struct timespec l = ceph::real_clock::to_timespec(mtime);
+ struct timespec r = ceph::real_clock::to_timespec(rhs.mtime);
+ l.tv_nsec = 0;
+ r.tv_nsec = 0;
+ if (l > r) {
+ return false;
+ }
+ if (l < r) {
+ return true;
+ }
+ if (zone_short_id != rhs.zone_short_id) {
+ return (zone_short_id < rhs.zone_short_id);
+ }
+ return (pg_ver < rhs.pg_ver);
+
+ }
bool operator<(const obj_time_weight& rhs) {
+ if (!high_precision || !rhs.high_precision) {
+ return compare_low_precision(rhs);
+ }
if (mtime > rhs.mtime) {
return false;
}
real_time *mtime,
const real_time *mod_ptr,
const real_time *unmod_ptr,
+ bool high_precision_time,
const char *if_match,
const char *if_nomatch,
AttrsMod attrs_mod,
int i;
append_rand_alpha(cct, tag, tag, 32);
obj_time_weight set_mtime_weight;
+ set_mtime_weight.high_precision = high_precision_time;
RGWPutObjProcessor_Atomic processor(obj_ctx,
dest_bucket_info, dest_obj.bucket, dest_obj.get_orig_obj(),
goto set_err_state;
}
dest_mtime_weight.init(dest_state);
+ dest_mtime_weight.high_precision = high_precision_time;
if (!dest_state->exists ||
dest_mtime_weight < set_mtime_weight) {
ldout(cct, 20) << "retrying writing object mtime=" << set_mtime << " dest_state->mtime=" << dest_state->mtime << " dest_state->exists=" << dest_state->exists << dendl;
real_time *mtime,
const real_time *mod_ptr,
const real_time *unmod_ptr,
+ bool high_precision_time,
const char *if_match,
const char *if_nomatch,
AttrsMod attrs_mod,
if (remote_src || !source_zone.empty()) {
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, copy_if_newer, attrs, category,
+ unmod_ptr, high_precision_time,
+ if_match, if_nomatch, attrs_mod, copy_if_newer, attrs, category,
olh_epoch, delete_at, version_id, ptag, petag, err, progress_cb, progress_data);
}
read_op.conds.mod_ptr = mod_ptr;
read_op.conds.unmod_ptr = unmod_ptr;
+ read_op.conds.high_precision_time = high_precision_time;
read_op.conds.if_match = if_match;
read_op.conds.if_nomatch = if_nomatch;
read_op.params.attrs = &src_attrs;
cls_rgw_obj_check_attrs_prefix(op, prefix, fail_if_exist);
}
-void RGWRados::cls_obj_check_mtime(ObjectOperation& op, const real_time& mtime, RGWCheckMTimeType type)
+void RGWRados::cls_obj_check_mtime(ObjectOperation& op, const real_time& mtime, bool high_precision_time, RGWCheckMTimeType type)
{
- cls_rgw_obj_check_mtime(op, mtime, type);
+ cls_rgw_obj_check_mtime(op, mtime, high_precision_time, type);
}
meta.mtime = params.mtime;
}
- int r = store->set_olh(target->get_ctx(), target->get_bucket_info(), marker, true, &meta, params.olh_epoch, params.unmod_since);
+ int r = store->set_olh(target->get_ctx(), target->get_bucket_info(), marker, true, &meta, params.olh_epoch, params.unmod_since, params.high_precision_time);
if (r < 0) {
return r;
}
ObjectWriteOperation op;
if (!real_clock::is_zero(params.unmod_since)) {
- real_time ctime = state->mtime;
+ struct timespec ctime = ceph::real_clock::to_timespec(state->mtime);
+ struct timespec unmod = ceph::real_clock::to_timespec(params.unmod_since);
+ if (!params.high_precision_time) {
+ ctime.tv_nsec = 0;
+ unmod.tv_nsec = 0;
+ }
ldout(store->ctx(), 10) << "If-UnModified-Since: " << params.unmod_since << " Last-Modified: " << ctime << dendl;
- if (ctime > params.unmod_since) {
+ if (ctime > unmod) {
return -ERR_PRECONDITION_FAILED;
}
/* only delete object if mtime is less than or equal to params.unmod_since */
- store->cls_obj_check_mtime(op, params.unmod_since, CLS_RGW_CHECK_TIME_MTIME_LE);
+ store->cls_obj_check_mtime(op, params.unmod_since, params.high_precision_time, CLS_RGW_CHECK_TIME_MTIME_LE);
}
uint64_t obj_size = state->size;
if (conds.mod_ptr || conds.unmod_ptr) {
obj_time_weight src_weight;
src_weight.init(astate);
+ src_weight.high_precision = conds.high_precision_time;
obj_time_weight dest_weight;
+ dest_weight.high_precision = conds.high_precision_time;
if (conds.mod_ptr) {
dest_weight.init(*conds.mod_ptr, conds.mod_zone_id, conds.mod_pg_ver);
const string& op_tag,
struct rgw_bucket_dir_entry_meta *meta,
uint64_t olh_epoch,
- real_time unmod_since)
+ real_time unmod_since, bool high_precision_time)
{
rgw_rados_ref ref;
rgw_bucket bucket;
cls_rgw_obj_key key(obj_instance.get_index_key_name(), obj_instance.get_instance());
ret = cls_rgw_bucket_link_olh(bs.index_ctx, bs.bucket_obj, key, olh_state.olh_tag, delete_marker, op_tag, meta, olh_epoch,
- unmod_since,
+ unmod_since, high_precision_time,
get_zone().log_data);
if (ret < 0) {
return ret;
}
int RGWRados::set_olh(RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, rgw_obj& target_obj, bool delete_marker, rgw_bucket_dir_entry_meta *meta,
- uint64_t olh_epoch, real_time unmod_since)
+ uint64_t olh_epoch, real_time unmod_since, bool high_precision_time)
{
string op_tag;
}
return ret;
}
- ret = bucket_index_link_olh(*state, target_obj, delete_marker, op_tag, meta, olh_epoch, unmod_since);
+ ret = bucket_index_link_olh(*state, target_obj, delete_marker, op_tag, meta, olh_epoch, unmod_since, high_precision_time);
if (ret < 0) {
ldout(cct, 20) << "bucket_index_link_olh() target_obj=" << target_obj << " delete_marker=" << (int)delete_marker << " returned " << ret << dendl;
if (ret == -ECANCELED) {
void remove_rgw_head_obj(librados::ObjectWriteOperation& op);
void cls_obj_check_prefix_exist(librados::ObjectOperation& op, const string& prefix, bool fail_if_exist);
- void cls_obj_check_mtime(librados::ObjectOperation& op, const real_time& mtime, RGWCheckMTimeType type);
+ void cls_obj_check_mtime(librados::ObjectOperation& op, const real_time& mtime, bool high_precision_time, RGWCheckMTimeType type);
protected:
CephContext *cct;
struct ConditionParams {
const ceph::real_time *mod_ptr;
const ceph::real_time *unmod_ptr;
+ bool high_precision_time;
uint32_t mod_zone_id;
uint64_t mod_pg_ver;
const char *if_match;
const char *if_nomatch;
ConditionParams() :
- mod_ptr(NULL), unmod_ptr(NULL), mod_zone_id(0), mod_pg_ver(0),
+ mod_ptr(NULL), unmod_ptr(NULL), high_precision_time(false), mod_zone_id(0), mod_pg_ver(0),
if_match(NULL), if_nomatch(NULL) {}
} conds;
ceph::real_time expiration_time;
ceph::real_time unmod_since;
ceph::real_time mtime; /* for setting delete marker mtime */
+ bool high_precision_time;
- DeleteParams() : versioning_status(0), olh_epoch(0), bilog_flags(0), remove_objs(NULL) {}
+ DeleteParams() : versioning_status(0), olh_epoch(0), bilog_flags(0), remove_objs(NULL), high_precision_time(false) {}
} params;
struct DeleteResult {
ceph::real_time *mtime,
const ceph::real_time *mod_ptr,
const ceph::real_time *unmod_ptr,
+ bool high_precision_time,
const char *if_match,
const char *if_nomatch,
AttrsMod attrs_mod,
ceph::real_time *mtime,
const ceph::real_time *mod_ptr,
const ceph::real_time *unmod_ptr,
+ bool high_precision_time,
const char *if_match,
const char *if_nomatch,
AttrsMod attrs_mod,
int bucket_index_link_olh(RGWObjState& olh_state, rgw_obj& obj_instance, bool delete_marker,
const string& op_tag, struct rgw_bucket_dir_entry_meta *meta,
uint64_t olh_epoch,
- ceph::real_time unmod_since);
+ ceph::real_time unmod_since, bool high_precision_time);
int bucket_index_unlink_instance(rgw_obj& obj_instance, const string& op_tag, uint64_t olh_epoch);
int bucket_index_read_olh_log(RGWObjState& state, rgw_obj& obj_instance, uint64_t ver_marker,
map<uint64_t, vector<rgw_bucket_olh_log_entry> > *log, bool *is_truncated);
uint64_t *plast_ver);
int update_olh(RGWObjectCtx& obj_ctx, RGWObjState *state, RGWBucketInfo& bucket_info, rgw_obj& obj);
int set_olh(RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, rgw_obj& target_obj, bool delete_marker, rgw_bucket_dir_entry_meta *meta,
- uint64_t olh_epoch, ceph::real_time unmod_since);
+ uint64_t olh_epoch, ceph::real_time unmod_since, bool high_precision_time);
int unlink_obj_instance(RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, rgw_obj& target_obj,
uint64_t olh_epoch);