From 809c5430c2929ea1b33d3d1ab7c0023fbb2ce7a5 Mon Sep 17 00:00:00 2001 From: Julien Collet Date: Tue, 20 Feb 2018 10:14:00 +0100 Subject: [PATCH] librbd: add image access/last modified timestamps Add access and modify timestamps and associated tests to RBD images. Access (resp. modify) timestamps are updated on read (resp. write) operations. A configurable throttling mechanism is implemented (default to 60s). Signed-off-by: Julien Collet --- src/cls/rbd/cls_rbd.cc | 156 +++++++++++++++++- src/cls/rbd/cls_rbd_client.cc | 92 +++++++++++ src/cls/rbd/cls_rbd_client.h | 19 +++ src/common/options.cc | 10 ++ src/include/rbd/librbd.h | 4 + src/include/rbd/librbd.hpp | 2 + src/librbd/ImageCtx.cc | 27 +++ src/librbd/ImageCtx.h | 12 +- src/librbd/image/OpenRequest.cc | 44 +++++ src/librbd/image/OpenRequest.h | 6 + src/librbd/io/ImageRequest.cc | 86 +++++++++- src/librbd/librbd.cc | 64 +++++++ src/pybind/rbd/rbd.pyx | 26 +++ .../cli-integration/rbd/formatted-output.t | 48 ++++++ src/test/cls_rbd/test_cls_rbd.cc | 28 ++++ src/test/librbd/io/test_mock_ImageRequest.cc | 114 +++++++++++++ src/test/librbd/mock/MockImageCtx.h | 16 +- src/test/librbd/test_librbd.cc | 54 +++++- src/test/pybind/test_rbd.py | 10 ++ src/tools/rbd/action/Info.cc | 49 +++++- src/tracing/librbd.tp | 45 +++++ 21 files changed, 894 insertions(+), 18 deletions(-) diff --git a/src/cls/rbd/cls_rbd.cc b/src/cls/rbd/cls_rbd.cc index b3579579694..ed2163dbf4c 100644 --- a/src/cls/rbd/cls_rbd.cc +++ b/src/cls/rbd/cls_rbd.cc @@ -520,15 +520,15 @@ int create(cls_method_context_t hctx, bufferlist *in, bufferlist *out) bufferlist featuresbl; bufferlist object_prefixbl; bufferlist snap_seqbl; - bufferlist create_timestampbl; + bufferlist timestampbl; uint64_t snap_seq = 0; - utime_t create_timestamp = ceph_clock_now(); + utime_t timestamp = ceph_clock_now(); encode(size, sizebl); encode(order, orderbl); encode(features, featuresbl); encode(object_prefix, object_prefixbl); encode(snap_seq, snap_seqbl); - encode(create_timestamp, create_timestampbl); + encode(timestamp, timestampbl); map omap_vals; omap_vals["size"] = sizebl; @@ -536,7 +536,9 @@ int create(cls_method_context_t hctx, bufferlist *in, bufferlist *out) omap_vals["features"] = featuresbl; omap_vals["object_prefix"] = object_prefixbl; omap_vals["snap_seq"] = snap_seqbl; - omap_vals["create_timestamp"] = create_timestampbl; + omap_vals["create_timestamp"] = timestampbl; + omap_vals["access_timestamp"] = timestampbl; + omap_vals["modify_timestamp"] = timestampbl; if ((features & RBD_FEATURE_OPERATIONS) != 0ULL) { CLS_ERR("Attempting to set internal feature: operations"); @@ -1093,6 +1095,81 @@ int get_create_timestamp(cls_method_context_t hctx, bufferlist *in, bufferlist * return 0; } +/** + * get the image access timestamp + * + * Input: + * @param none + * + * Output: + * @param timestamp the image access timestamp + * + * @returns 0 on success, negative error code upon failure + */ +int get_access_timestamp(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + CLS_LOG(20, "get_access_timestamp"); + + utime_t timestamp; + bufferlist bl; + int r = cls_cxx_map_get_val(hctx, "access_timestamp", &bl); + if (r < 0) { + if (r != -ENOENT) { + CLS_ERR("error reading access_timestamp: %s", cpp_strerror(r).c_str()); + return r; + } + } else { + try { + auto it = bl.cbegin(); + decode(timestamp, it); + } catch (const buffer::error &err) { + CLS_ERR("could not decode access_timestamp"); + return -EIO; + } + } + + encode(timestamp, *out); + return 0; +} + +/** + * get the image modify timestamp + * + * Input: + * @param none + * + * Output: + * @param timestamp the image modify timestamp + * + * @returns 0 on success, negative error code upon failure + */ +int get_modify_timestamp(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + CLS_LOG(20, "get_modify_timestamp"); + + utime_t timestamp; + bufferlist bl; + int r = cls_cxx_map_get_val(hctx, "modify_timestamp", &bl); + if (r < 0) { + if (r != -ENOENT) { + CLS_ERR("error reading modify_timestamp: %s", cpp_strerror(r).c_str()); + return r; + } + } else { + try { + auto it = bl.cbegin(); + decode(timestamp, it); + } catch (const buffer::error &err) { + CLS_ERR("could not decode modify_timestamp"); + return -EIO; + } + } + + encode(timestamp, *out); + return 0; +} + + /** * get the image flags * @@ -2393,6 +2470,59 @@ int set_id(cls_method_context_t hctx, bufferlist *in, bufferlist *out) return cls_cxx_write(hctx, 0, write_bl.length(), &write_bl); } +/** + * Update the access timestamp of an image + * + * Input: + * @param none + * + * Output: + * @returns 0 on success, negative error code on other error + */ +int set_access_timestamp(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + int r = check_exists(hctx); + if(r < 0) + return r; + + utime_t timestamp = ceph_clock_now(); + r = write_key(hctx, "access_timestamp", timestamp); + if(r < 0) { + CLS_ERR("error setting access_timestamp"); + return r; + } + + return 0; +} + +/** + * Update the modify timestamp of an image + * + * Input: + * @param none + * + * Output: + * @returns 0 on success, negative error code on other error + */ + +int set_modify_timestamp(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + int r = check_exists(hctx); + if(r < 0) + return r; + + utime_t timestamp = ceph_clock_now(); + r = write_key(hctx, "modify_timestamp", timestamp); + if(r < 0) { + CLS_ERR("error setting modify_timestamp"); + return r; + } + + return 0; +} + + + /*********************** methods for rbd_directory ***********************/ static const string dir_key_for_id(const string &id) @@ -6651,6 +6781,8 @@ CLS_INIT(rbd) cls_method_handle_t h_get_stripe_unit_count; cls_method_handle_t h_set_stripe_unit_count; cls_method_handle_t h_get_create_timestamp; + cls_method_handle_t h_get_access_timestamp; + cls_method_handle_t h_get_modify_timestamp; cls_method_handle_t h_get_flags; cls_method_handle_t h_set_flags; cls_method_handle_t h_op_features_get; @@ -6673,6 +6805,8 @@ CLS_INIT(rbd) cls_method_handle_t h_copyup; cls_method_handle_t h_get_id; cls_method_handle_t h_set_id; + cls_method_handle_t h_set_modify_timestamp; + cls_method_handle_t h_set_access_timestamp; cls_method_handle_t h_dir_get_id; cls_method_handle_t h_dir_get_name; cls_method_handle_t h_dir_list; @@ -6828,6 +6962,12 @@ CLS_INIT(rbd) cls_register_cxx_method(h_class, "get_create_timestamp", CLS_METHOD_RD, get_create_timestamp, &h_get_create_timestamp); + cls_register_cxx_method(h_class, "get_access_timestamp", + CLS_METHOD_RD, + get_access_timestamp, &h_get_access_timestamp); + cls_register_cxx_method(h_class, "get_modify_timestamp", + CLS_METHOD_RD, + get_modify_timestamp, &h_get_modify_timestamp); cls_register_cxx_method(h_class, "get_flags", CLS_METHOD_RD, get_flags, &h_get_flags); @@ -6883,6 +7023,14 @@ CLS_INIT(rbd) assert_snapc_seq, &h_assert_snapc_seq); + cls_register_cxx_method(h_class, "set_modify_timestamp", + CLS_METHOD_RD | CLS_METHOD_WR, + set_modify_timestamp, &h_set_modify_timestamp); + + cls_register_cxx_method(h_class, "set_access_timestamp", + CLS_METHOD_RD | CLS_METHOD_WR, + set_access_timestamp, &h_set_access_timestamp); + /* methods for the rbd_children object */ cls_register_cxx_method(h_class, "add_child", CLS_METHOD_RD | CLS_METHOD_WR, diff --git a/src/cls/rbd/cls_rbd_client.cc b/src/cls/rbd/cls_rbd_client.cc index 087ed597b23..88317f893bc 100644 --- a/src/cls/rbd/cls_rbd_client.cc +++ b/src/cls/rbd/cls_rbd_client.cc @@ -1065,6 +1065,32 @@ namespace librbd { return ioctx->operate(oid, &op); } + void set_modify_timestamp(librados::ObjectWriteOperation *op) + { + bufferlist empty_bl; + op->exec("rbd","set_modify_timestamp",empty_bl); + } + + int set_modify_timestamp(librados::IoCtx *ioctx, const std::string &oid) + { + librados::ObjectWriteOperation op; + set_modify_timestamp(&op); + return ioctx->operate(oid, &op); + } + + void set_access_timestamp(librados::ObjectWriteOperation *op) + { + bufferlist empty_bl; + op->exec("rbd","set_access_timestamp",empty_bl); + } + + int set_access_timestamp(librados::IoCtx *ioctx, const std::string &oid) + { + librados::ObjectWriteOperation op; + set_access_timestamp(&op); + return ioctx->operate(oid, &op); + } + void get_create_timestamp_start(librados::ObjectReadOperation *op) { bufferlist empty_bl; op->exec("rbd", "get_create_timestamp", empty_bl); @@ -1098,6 +1124,72 @@ namespace librbd { return get_create_timestamp_finish(&it, timestamp); } + void get_access_timestamp_start(librados::ObjectReadOperation *op) { + bufferlist empty_bl; + op->exec("rbd", "get_access_timestamp", empty_bl); + } + + int get_access_timestamp_finish(bufferlist::const_iterator *it, + utime_t *timestamp) { + assert(timestamp); + + try { + decode(*timestamp, *it); + } catch (const buffer::error &err) { + return -EBADMSG; + } + return 0; + } + + int get_access_timestamp(librados::IoCtx *ioctx, const std::string &oid, + utime_t *timestamp) + { + librados::ObjectReadOperation op; + get_access_timestamp_start(&op); + + bufferlist out_bl; + int r = ioctx->operate(oid, &op, &out_bl); + if (r < 0) { + return r; + } + + auto it = out_bl.cbegin(); + return get_access_timestamp_finish(&it, timestamp); + } + + void get_modify_timestamp_start(librados::ObjectReadOperation *op) { + bufferlist empty_bl; + op->exec("rbd", "get_modify_timestamp", empty_bl); + } + + int get_modify_timestamp_finish(bufferlist::const_iterator *it, + utime_t *timestamp) { + assert(timestamp); + + try { + decode(*timestamp, *it); + } catch (const buffer::error &err) { + return -EBADMSG; + } + return 0; + } + + int get_modify_timestamp(librados::IoCtx *ioctx, const std::string &oid, + utime_t *timestamp) + { + librados::ObjectReadOperation op; + get_modify_timestamp_start(&op); + + bufferlist out_bl; + int r = ioctx->operate(oid, &op, &out_bl); + if (r < 0) { + return r; + } + + auto it = out_bl.cbegin(); + return get_modify_timestamp_finish(&it, timestamp); + } + /************************ rbd_id object methods ************************/ void get_id_start(librados::ObjectReadOperation *op) { diff --git a/src/cls/rbd/cls_rbd_client.h b/src/cls/rbd/cls_rbd_client.h index 2acc5be4743..c9c362bb536 100644 --- a/src/cls/rbd/cls_rbd_client.h +++ b/src/cls/rbd/cls_rbd_client.h @@ -222,6 +222,25 @@ namespace librbd { utime_t *timestamp); int get_create_timestamp(librados::IoCtx *ioctx, const std::string &oid, utime_t *timestamp); + + void get_access_timestamp_start(librados::ObjectReadOperation *op); + int get_access_timestamp_finish(bufferlist::const_iterator *it, + utime_t *timestamp); + int get_access_timestamp(librados::IoCtx *ioctx, const std::string &oid, + utime_t *timestamp); + + void get_modify_timestamp_start(librados::ObjectReadOperation *op); + int get_modify_timestamp_finish(bufferlist::const_iterator *it, + utime_t *timestamp); + int get_modify_timestamp(librados::IoCtx *ioctx, const std::string &oid, + utime_t *timestamp); + + void set_modify_timestamp(librados::ObjectWriteOperation *op); + int set_modify_timestamp(librados::IoCtx *ioctx, const std::string &oid); + + void set_access_timestamp(librados::ObjectWriteOperation *op); + int set_access_timestamp(librados::IoCtx *ioctx, const std::string &oid); + int metadata_list(librados::IoCtx *ioctx, const std::string &oid, const std::string &start, uint64_t max_return, map *pairs); diff --git a/src/common/options.cc b/src/common/options.cc index 7d52edd0a47..ef57318c92b 100644 --- a/src/common/options.cc +++ b/src/common/options.cc @@ -6632,6 +6632,16 @@ static std::vector