]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: propagate low time precision for user operations 8108/head
authorYehuda Sadeh <yehuda@redhat.com>
Tue, 15 Mar 2016 21:22:06 +0000 (14:22 -0700)
committerYehuda Sadeh <yehuda@redhat.com>
Tue, 15 Mar 2016 21:22:06 +0000 (14:22 -0700)
When user set a conditional timestamp to compare (e.g. if-modified-since),
it uses a low precision time resolution. Need to adjust checks for that.

Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
src/cls/rgw/cls_rgw.cc
src/cls/rgw/cls_rgw_client.cc
src/cls/rgw/cls_rgw_client.h
src/cls/rgw/cls_rgw_ops.cc
src/cls/rgw/cls_rgw_ops.h
src/rgw/rgw_cr_rados.cc
src/rgw/rgw_op.cc
src/rgw/rgw_rados.cc
src/rgw/rgw_rados.h

index 431c2b49744e216e477c7d3565d768af3b8e1d19..ba92b846844a2739da5d926c6b5fbb747405eedf 100644 (file)
@@ -1391,7 +1391,13 @@ static int rgw_bucket_link_olh(cls_method_context_t hctx, bufferlist *in, buffer
   }
 
   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 */
     }
   }
@@ -2104,6 +2110,11 @@ static int rgw_obj_check_mtime(cls_method_context_t hctx, bufferlist *in, buffer
   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);
@@ -2112,19 +2123,19 @@ static int rgw_obj_check_mtime(cls_method_context_t hctx, bufferlist *in, buffer
 
   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;
index 275595d2d4c306e734a9f15c2afdcb0fa43d26db..40041aa484f6264f7a3d4f01e28a8ea8177f80d4 100644 (file)
@@ -227,11 +227,12 @@ void cls_rgw_obj_check_attrs_prefix(librados::ObjectOperation& o, const string&
   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);
@@ -306,7 +307,7 @@ int cls_rgw_bi_list(librados::IoCtx& io_ctx, const string oid,
 
 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;
@@ -320,6 +321,7 @@ int cls_rgw_bucket_link_olh(librados::IoCtx& io_ctx, const string& oid, const cl
   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)
index c2cad2a37309d7b103008cad9b119a8540564742..130a009f5fff02db148cdde33261eb224478564d 100644 (file)
@@ -318,7 +318,7 @@ void cls_rgw_bucket_complete_op(librados::ObjectWriteOperation& o, RGWModifyOp o
 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,
@@ -331,7 +331,7 @@ int cls_rgw_bi_list(librados::IoCtx& io_ctx, const string oid,
 
 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,
index b9cf68fdcc9e732f044237f815a5c499a9cc3fe0..2cf361993e8385f877c8cbf30642be28e09b8398 100644 (file)
@@ -178,6 +178,7 @@ void rgw_cls_link_olh_op::dump(Formatter *f) const
   ::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)
index 8312fe46bca30725d32e7b88ee09bf81f56887bb..3f2c8d9798e4f5f1852b81a5f68e71d1b9be9af0 100644 (file)
@@ -166,11 +166,12 @@ struct rgw_cls_link_olh_op {
   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);
@@ -182,11 +183,12 @@ struct rgw_cls_link_olh_op {
     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);
@@ -203,6 +205,9 @@ struct rgw_cls_link_olh_op {
     if (struct_v >= 3) {
       ::decode(unmod_since, bl);
     }
+    if (struct_v >= 4) {
+      ::decode(high_precision_time, bl);
+    }
     DECODE_FINISH(bl);
   }
 
@@ -492,22 +497,27 @@ WRITE_CLASS_ENCODER(rgw_cls_obj_check_attrs_prefix)
 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);
   }
 };
index b4c782519d958dfc55bc4612e394734394d01102..2e7fe0b9dc2000b96b4ff5fc597195af0da1e39e 100644 (file)
@@ -470,6 +470,7 @@ int RGWAsyncFetchRemoteObj::_send_request()
                        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,
@@ -547,6 +548,7 @@ int RGWAsyncRemoveObj::_send_request()
   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) {
index e6afc45e2a853c2708706010ad8377ccf028e1e0..c81c61a2892e2b46a27f0212ead8fbd1f1e42e2b 100644 (file)
@@ -1203,6 +1203,7 @@ void RGWGetObj::execute()
 
   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;
@@ -2996,6 +2997,7 @@ void RGWDeleteObj::execute()
     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) {
@@ -3227,6 +3229,8 @@ void RGWCopyObj::execute()
 
   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,
@@ -3241,6 +3245,7 @@ void RGWCopyObj::execute()
                           &mtime,
                           mod_ptr,
                           unmod_ptr,
+                           high_precision_time,
                           if_match,
                           if_nomatch,
                           attrs_mod,
index 7e4c3749fd044f3d442bd48965f0325671c0ec34..a8d74649813dd932e0b406445437c3f248186fe3 100644 (file)
@@ -5713,6 +5713,7 @@ int RGWRados::swift_versioning_copy(RGWBucketInfo& bucket_info, RGWRados::Object
                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,
@@ -5908,7 +5909,7 @@ int RGWRados::Object::Write::write_meta(uint64_t size,
   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;
     }
@@ -6272,10 +6273,32 @@ struct obj_time_weight {
   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;
     }
@@ -6325,6 +6348,7 @@ int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx,
                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,
@@ -6348,6 +6372,7 @@ int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx,
   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(),
@@ -6504,6 +6529,7 @@ int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx,
         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;
@@ -6598,6 +6624,7 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx,
                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,
@@ -6637,7 +6664,8 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx,
   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);
   }
 
@@ -6649,6 +6677,7 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx,
 
   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;
@@ -7308,9 +7337,9 @@ void RGWRados::cls_obj_check_prefix_exist(ObjectOperation& op, const string& pre
   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);
 }
 
 
@@ -7359,7 +7388,7 @@ int RGWRados::Object::Delete::delete_obj()
         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;
       }
@@ -7409,15 +7438,20 @@ int RGWRados::Object::Delete::delete_obj()
   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;
 
@@ -8307,8 +8341,10 @@ int RGWRados::Object::Read::prepare(int64_t *pofs, int64_t *pend)
   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);
@@ -9327,7 +9363,7 @@ int RGWRados::bucket_index_link_olh(RGWObjState& olh_state, rgw_obj& obj_instanc
                                     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;
@@ -9345,7 +9381,7 @@ int RGWRados::bucket_index_link_olh(RGWObjState& olh_state, rgw_obj& obj_instanc
 
   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;
@@ -9627,7 +9663,7 @@ int RGWRados::update_olh(RGWObjectCtx& obj_ctx, RGWObjState *state, RGWBucketInf
 }
 
 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;
 
@@ -9658,7 +9694,7 @@ int RGWRados::set_olh(RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, rgw_obj
       }
       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) {
index f06cd62340c2969bfec9847a6690c116479d7866..8a2db376d29bd7ce24d90314927cca1b6b3e52b2 100644 (file)
@@ -1786,7 +1786,7 @@ class RGWRados
 
   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;
 
@@ -2177,13 +2177,14 @@ public:
       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;
 
@@ -2250,8 +2251,9 @@ public:
         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 {
@@ -2435,6 +2437,7 @@ public:
                        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,
@@ -2486,6 +2489,7 @@ public:
                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,
@@ -2638,7 +2642,7 @@ public:
   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);
@@ -2649,7 +2653,7 @@ public:
                     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);