]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
cls/user: implement reset user stats
authorAbhishek Lekshmanan <abhishek@suse.com>
Mon, 12 Mar 2018 19:17:36 +0000 (20:17 +0100)
committerAbhishek Lekshmanan <abhishek@suse.com>
Mon, 23 Apr 2018 16:51:30 +0000 (18:51 +0200)
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 <abhishek@suse.com>
(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
src/cls/user/cls_user_client.cc
src/cls/user/cls_user_client.h
src/cls/user/cls_user_ops.h

index d168e7cb8a84df86721083a2a222f8dd3a70901a..3d96c4a590b33c8b953d510a35f319fa61c14c50 100644 (file)
@@ -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<string, bufferlist> 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;
 }
 
index b2b4cbb64846081b4a6eb155ba99c1b4e1bc9e1b..e1fd34b03c1c8cde57a2abf2474734569162d7f3 100644 (file)
@@ -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;
index 5a1d9441200ab4a36a486a439413cd8a50fb5dcf..5c5a0fe8a0fc72ab4d920658a805cb99102ad0da 100644 (file)
@@ -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
index 0e90b22d13ac72a681dffce81b5bf073f95c86c8..5e580e689b5b45f410017b6f45f17aec0ff53b02 100644 (file)
@@ -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<cls_user_reset_stats_op*>& ls);
+};
+WRITE_CLASS_ENCODER(cls_user_reset_stats_op);
+
 struct cls_user_get_header_ret {
   cls_user_header header;