From df477bb65198e626a23aaeb566b8cabf940b30af 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. Fixes: http://tracker.ceph.com/issues/23335 Signed-off-by: Abhishek Lekshmanan (cherry picked from commit 63f9127dd685890d938a612739320c942a96f910) * conflicts: cls_user.cc: jewel only cls fixes, truncated is not a part of omap get vals, so iterating over the range by checking the output of omap_get_vals and continuing. cls_user_ops.h: explicit ::encode/::decode --- src/cls/user/cls_user.cc | 51 ++++++++++++++++++++++++++++++++- 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, 81 insertions(+), 1 deletion(-) diff --git a/src/cls/user/cls_user.cc b/src/cls/user/cls_user.cc index d168e7cb8a84d..3d96c4a590b33 100644 --- a/src/cls/user/cls_user.cc +++ b/src/cls/user/cls_user.cc @@ -23,6 +23,7 @@ cls_method_handle_t h_user_complete_stats_sync; 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; static int write_entry(cls_method_context_t hctx, const string& key, const cls_user_bucket_entry& entry) { @@ -370,6 +371,54 @@ 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; + string from_index, prefix; +#define MAX_ENTRIES 1000 + int rc; + map keys; + do { + rc = cls_cxx_map_get_vals(hctx, from_index, prefix, MAX_ENTRIES, &keys); + + 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; + } + from_index = kv.first; + add_header_stats(&header.stats, e); + } + } while (keys.size() == MAX_ENTRIES); + + bufferlist bl; + header.last_stats_update = op.time; + encode(header, bl); + + return cls_cxx_map_write_header(hctx, &bl); +} + void __cls_init() { CLS_LOG(1, "Loaded user class!"); @@ -384,7 +433,7 @@ void __cls_init() 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 b2b4cbb648460..e1fd34b03c1c8 100644 --- a/src/cls/user/cls_user_client.cc +++ b/src/cls/user/cls_user_client.cc @@ -134,6 +134,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 5a1d9441200ab..5c5a0fe8a0fc7 100644 --- a/src/cls/user/cls_user_client.h +++ b/src/cls/user/cls_user_client.h @@ -32,5 +32,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 0e90b22d13ac7..5e580e689b5b4 100644 --- a/src/cls/user/cls_user_ops.h +++ b/src/cls/user/cls_user_ops.h @@ -137,6 +137,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