]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rados: add "list-inconsistent-obj" cmd
authorKefu Chai <kchai@redhat.com>
Sat, 30 Jan 2016 08:35:27 +0000 (16:35 +0800)
committerKefu Chai <kchai@redhat.com>
Thu, 25 Feb 2016 04:41:55 +0000 (12:41 +0800)
to list inconsistent objects of a given PG, this command exposes
get_inconsistent_objects() rados API to user.

Signed-off-by: Kefu Chai <kchai@redhat.com>
src/tools/rados/rados.cc

index d5848859d68301bc8ed31b20bf03214d8886cbf2..4d314ebe1f34709f438abbf1d4daaa80d39285a0 100644 (file)
@@ -145,6 +145,7 @@ void usage(ostream& out)
 "\n"
 "SCRUB AND REPAIR:\n"
 "   list-inconsistent-pg <pool>      list inconsistent PGs in given pool\n"
+"   list-inconsistent-obj <pgid>     list inconsistent objects in given pg\n"
 "\n"
 "CACHE POOLS: (for testing/development only)\n"
 "   cache-flush <obj-name>           flush cache pool object (blocking)\n"
@@ -1240,6 +1241,151 @@ static int do_get_inconsistent_pg_cmd(const std::vector<const char*> &nargs,
   return 0;
 }
 
+static void dump_shard(const shard_info_t& shard,
+                      const inconsistent_obj_t& inc,
+                      Formatter &f)
+{
+  f.dump_bool("missing", shard.has_shard_missing());
+  if (shard.has_shard_missing()) {
+    return;
+  }
+  f.dump_bool("read_error", shard.has_read_error());
+  f.dump_bool("data_digest_mismatch", shard.has_data_digest_mismatch());
+  f.dump_bool("omap_digest_mismatch", shard.has_omap_digest_mismatch());
+  f.dump_bool("size_mismatch", shard.has_size_mismatch());
+  if (!shard.has_read_error()) {
+    f.dump_bool("data_digest_mismatch_oi", shard.has_data_digest_mismatch_oi());
+    f.dump_bool("omap_digest_mismatch_oi", shard.has_omap_digest_mismatch_oi());
+    f.dump_bool("size_mismatch_oi", shard.has_size_mismatch_oi());
+  }
+  f.dump_unsigned("size", shard.size);
+  if (shard.omap_digest_present) {
+    f.dump_format("omap_digest", "0x%08x", shard.omap_digest);
+  }
+  if (shard.data_digest_present) {
+    f.dump_format("data_digest", "0x%08x", shard.data_digest);
+  }
+  if (inc.has_attr_mismatch()) {
+    f.open_object_section("attrs");
+    for (auto kv : shard.attrs) {
+      f.open_object_section("attr");
+      f.dump_string("name", kv.first);
+      bufferlist b64;
+      kv.second.encode_base64(b64);
+      string v(b64.c_str(), b64.length());
+      f.dump_string("value", v);
+      f.close_section();
+    }
+    f.close_section();
+  }
+}
+
+static void dump_object_id(const object_id_t& object,
+                       Formatter &f)
+{
+  f.dump_string("name", object.name);
+  f.dump_string("nspace", object.nspace);
+  f.dump_string("locator", object.locator);
+  switch (object.snap) {
+  case CEPH_NOSNAP:
+    f.dump_string("snap", "head");
+    break;
+  case CEPH_SNAPDIR:
+    f.dump_string("snap", "snapdir");
+    break;
+  default:
+    f.dump_format("snap", "0x%08x", object.snap);
+    break;
+  }
+}
+
+static void dump_inconsistent(const inconsistent_obj_t& inc,
+                             Formatter &f)
+{
+  f.open_object_section("object");
+  dump_object_id(inc.object, f);
+  f.close_section();
+  f.dump_bool("missing", inc.has_shard_missing());
+  f.dump_bool("stat_err", inc.has_stat_error());
+  f.dump_bool("read_err", inc.has_read_error());
+  f.dump_bool("data_digest_mismatch", inc.has_data_digest_mismatch());
+  f.dump_bool("omap_digest_mismatch", inc.has_omap_digest_mismatch());
+  f.dump_bool("size_mismatch", inc.has_size_mismatch());
+  f.dump_bool("attr_mismatch", inc.has_attr_mismatch());
+  f.open_array_section("shards");
+  for (auto osd_shard : inc.shards) {
+    f.open_object_section("shard");
+    f.dump_int("osd", osd_shard.first);
+    dump_shard(osd_shard.second, inc, f);
+    f.close_section();
+  }
+  f.close_section();
+  f.close_section();
+}
+
+// dispatch the call by type
+static int do_get_inconsistent(Rados& rados,
+                              const PlacementGroup& pg,
+                              const librados::object_id_t &start,
+                              unsigned max_return,
+                              AioCompletion *c,
+                              std::vector<inconsistent_obj_t>* objs,
+                              uint32_t* interval)
+{
+  return rados.get_inconsistent_objects(pg, start, max_return, c,
+                                       objs, interval);
+}
+
+template <typename T>
+static int do_get_inconsistent_cmd(const std::vector<const char*> &nargs,
+                                  Rados& rados,
+                                  Formatter& formatter)
+{
+  if (nargs.size() < 2) {
+    usage_exit();
+  }
+  PlacementGroup pg;
+  int ret = 0;
+  ret = pg.parse(nargs[1]);
+  if (!ret) {
+    cerr << "bad pg: " << nargs[1] << std::endl;
+    return ret;
+  }
+
+  uint32_t interval = 0;
+  const unsigned max_item_num = 32;
+  for (librados::object_id_t start;;) {
+    std::vector<T> items;
+    auto completion = librados::Rados::aio_create_completion();
+    ret = do_get_inconsistent(rados, pg, start, max_item_num, completion,
+                             &items, &interval);
+    completion->wait_for_safe();
+    ret = completion->get_return_value();
+    completion->release();
+    if (ret == -EAGAIN) {
+      cerr << "interval#" << interval << " expired." << std::endl;
+      break;
+    }
+    if (start.name.empty()) {
+      formatter.open_array_section("inconsistents");
+    }
+    for (auto& inc : items) {
+      formatter.open_object_section("inconsistent");
+      dump_inconsistent(inc, formatter);
+    }
+    if (items.size() < max_item_num) {
+      formatter.close_section();
+      break;
+    }
+    if (!items.empty()) {
+      start = items.back().object;
+    }
+    items.clear();
+  }
+  formatter.flush(cout);
+  return ret;
+}
+
 /**********************************************
 
 **********************************************/
@@ -2865,6 +3011,11 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts,
       formatter = new JSONFormatter(pretty_format);
     }
     ret = do_get_inconsistent_pg_cmd(nargs, rados, *formatter);
+  } else if (strcmp(nargs[0], "list-inconsistent-obj") == 0) {
+    if (!formatter) {
+      formatter = new JSONFormatter(pretty_format);
+    }
+    ret = do_get_inconsistent_cmd<inconsistent_obj_t>(nargs, rados, *formatter);
   } else if (strcmp(nargs[0], "cache-flush") == 0) {
     if (!pool_name || nargs.size() < 2)
       usage_exit();