From 7bdd82ab5b0b2edc7a8c3061a631b95742e75f9d Mon Sep 17 00:00:00 2001 From: Abhishek Lekshmanan Date: Mon, 12 Mar 2018 20:17:36 +0100 Subject: [PATCH] cls/user: implement reset user stats This is an implementation of reset user stats, that recalculates the user stats purely based on the values of bucket entries in user.buckets object. This is helpful in cases when user stats has been improperly set in case of manual resharding etc. Luminous only additions: use global scope for encode in cls_user_ops Fixes: http://tracker.ceph.com/issues/23335 Signed-off-by: Abhishek Lekshmanan (cherry picked from commit 63f9127dd685890d938a612739320c942a96f910) --- src/cls/user/cls_user.cc | 49 ++++++++++++++++++++++++++++++++- src/cls/user/cls_user_client.cc | 9 ++++++ src/cls/user/cls_user_client.h | 1 + src/cls/user/cls_user_ops.h | 21 ++++++++++++++ 4 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/cls/user/cls_user.cc b/src/cls/user/cls_user.cc index 840470e9f4d9b..9a9c5bd9f7ebb 100644 --- a/src/cls/user/cls_user.cc +++ b/src/cls/user/cls_user.cc @@ -359,6 +359,52 @@ static int cls_user_get_header(cls_method_context_t hctx, bufferlist *in, buffer return 0; } +/// A method to reset the user.buckets header stats in accordance to the values +/// seen in the user.buckets omap keys. This will not be equivalent to --sync-stats +/// which requires comparing the values with actual bucket meta stats supplied +/// by RGW +static int cls_user_reset_stats(cls_method_context_t hctx, bufferlist *in, bufferlist *out /*ignore*/) +{ + cls_user_reset_stats_op op; + + try { + auto bliter = in->begin(); + ::decode(op, bliter); + } catch (buffer::error& err) { + CLS_LOG(0, "ERROR: cls_user_reset_op(): failed to decode op"); + return -EINVAL; + } + cls_user_header header; + bool truncated = false; + string from_index, prefix; + do { + map keys; + int rc = cls_cxx_map_get_vals(hctx, from_index, prefix, MAX_ENTRIES, &keys, &truncated); + + if (rc < 0) + return rc; + + for (const auto&kv : keys){ + cls_user_bucket_entry e; + try { + auto bl = kv.second; + auto bliter = bl.begin(); + decode(e, bliter); + } catch (buffer::error& err) { + CLS_LOG(0, "ERROR: failed to decode bucket entry for %s", kv.first.c_str()); + return -EIO; + } + add_header_stats(&header.stats, e); + } + } while (truncated); + + bufferlist bl; + header.last_stats_update = op.time; + ::encode(header, bl); + + return cls_cxx_map_write_header(hctx, &bl); +} + CLS_INIT(user) { CLS_LOG(1, "Loaded user class!"); @@ -369,6 +415,7 @@ CLS_INIT(user) cls_method_handle_t h_user_remove_bucket; cls_method_handle_t h_user_list_buckets; cls_method_handle_t h_user_get_header; + cls_method_handle_t h_user_reset_stats; cls_register("user", &h_class); @@ -380,7 +427,7 @@ CLS_INIT(user) cls_register_cxx_method(h_class, "remove_bucket", CLS_METHOD_RD | CLS_METHOD_WR, cls_user_remove_bucket, &h_user_remove_bucket); cls_register_cxx_method(h_class, "list_buckets", CLS_METHOD_RD, cls_user_list_buckets, &h_user_list_buckets); cls_register_cxx_method(h_class, "get_header", CLS_METHOD_RD, cls_user_get_header, &h_user_get_header); - + cls_register_cxx_method(h_class, "reset_user_stats", CLS_METHOD_RD | CLS_METHOD_WR, cls_user_reset_stats, &h_user_reset_stats); return; } diff --git a/src/cls/user/cls_user_client.cc b/src/cls/user/cls_user_client.cc index c77075dcb24a7..5e0d65a8dbd3e 100644 --- a/src/cls/user/cls_user_client.cc +++ b/src/cls/user/cls_user_client.cc @@ -132,6 +132,15 @@ void cls_user_get_header(librados::ObjectReadOperation& op, op.exec("user", "get_header", inbl, new ClsUserGetHeaderCtx(header, NULL, pret)); } +void cls_user_reset_stats(librados::ObjectWriteOperation &op) +{ + bufferlist inbl; + cls_user_reset_stats_op call; + call.time = real_clock::now(); + ::encode(call, inbl); + op.exec("user", "reset_user_stats", inbl); +} + int cls_user_get_header_async(IoCtx& io_ctx, string& oid, RGWGetUserHeader_CB *ctx) { bufferlist in, out; diff --git a/src/cls/user/cls_user_client.h b/src/cls/user/cls_user_client.h index 5e5d3063d011b..b398961e061e6 100644 --- a/src/cls/user/cls_user_client.h +++ b/src/cls/user/cls_user_client.h @@ -36,5 +36,6 @@ void cls_user_bucket_list(librados::ObjectReadOperation& op, int *pret); void cls_user_get_header(librados::ObjectReadOperation& op, cls_user_header *header, int *pret); int cls_user_get_header_async(librados::IoCtx& io_ctx, string& oid, RGWGetUserHeader_CB *ctx); +void cls_user_reset_stats(librados::ObjectWriteOperation& op); #endif diff --git a/src/cls/user/cls_user_ops.h b/src/cls/user/cls_user_ops.h index 2219a49596200..a79e03cc6cf7f 100644 --- a/src/cls/user/cls_user_ops.h +++ b/src/cls/user/cls_user_ops.h @@ -135,6 +135,27 @@ struct cls_user_get_header_op { }; WRITE_CLASS_ENCODER(cls_user_get_header_op) +struct cls_user_reset_stats_op { + real_time time; + cls_user_reset_stats_op() {} + + void encode(bufferlist& bl) const { + ENCODE_START(1, 1, bl); + ::encode(time, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::iterator& bl) { + DECODE_START(1, bl); + ::decode(time, bl); + DECODE_FINISH(bl); + } + + void dump(Formatter *f) const; + static void generate_test_instances(list& ls); +}; +WRITE_CLASS_ENCODER(cls_user_reset_stats_op); + struct cls_user_get_header_ret { cls_user_header header; -- 2.39.5