]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
ceph-objectstore-tool: Add new remove-clone-metadata object op
authorDavid Zafman <dzafman@redhat.com>
Thu, 15 Oct 2015 03:34:28 +0000 (20:34 -0700)
committerDavid Zafman <dzafman@redhat.com>
Fri, 30 Oct 2015 20:01:50 +0000 (13:01 -0700)
Fixes: #12740
Signed-off-by: David Zafman <dzafman@redhat.com>
src/tools/ceph_objectstore_tool.cc

index 187a2578f7c90efd309a03de332bf80a0db448fc..d51bd205a37dfe437247cbda82067ae64b4607c9 100644 (file)
@@ -2075,6 +2075,102 @@ int clear_snapset(ObjectStore *store, coll_t coll, ghobject_t &ghobj,
   return 0;
 }
 
+vector<snapid_t>::iterator find(vector<snapid_t> &v, snapid_t clid)
+{
+  return std::find(v.begin(), v.end(), clid);
+}
+
+map<snapid_t, interval_set<uint64_t> >::iterator
+find(map<snapid_t, interval_set<uint64_t> > &m, snapid_t clid)
+{
+  return m.find(clid);
+}
+
+map<snapid_t, uint64_t>::iterator find(map<snapid_t, uint64_t> &m,
+                                      snapid_t clid)
+{
+  return m.find(clid);
+}
+
+template<class T>
+int remove_from(T &mv, string name, snapid_t cloneid, bool force)
+{
+  typename T::iterator i = find(mv, cloneid);
+  if (i != mv.end()) {
+    mv.erase(i);
+  } else {
+    cerr << "Clone " << cloneid << " doesn't exist in " << name;
+    if (force) {
+      cerr << " (ignored)" << std::endl;
+      return 0;
+    }
+    cerr << std::endl;
+    return -EINVAL;
+  }
+  return 0;
+}
+
+int remove_clone(ObjectStore *store, coll_t coll, ghobject_t &ghobj, snapid_t cloneid, bool force,
+                    ObjectStore::Sequencer &osr)
+{
+  // XXX: Don't allow this if in a cache tier or former cache tier
+  // bool allow_incomplete_clones() const {
+  //   return cache_mode != CACHEMODE_NONE || has_flag(FLAG_INCOMPLETE_CLONES);
+
+  SnapSet snapset;
+  int ret = get_snapset(store, coll, ghobj, snapset);
+  if (ret < 0)
+    return ret;
+
+  // Derived from trim_object()
+  // ...from snapset
+  vector<snapid_t>::iterator p;
+  for (p = snapset.clones.begin(); p != snapset.clones.end(); ++p)
+    if (*p == cloneid)
+      break;
+  if (p == snapset.clones.end()) {
+    cerr << "Clone " << cloneid << " not present";
+    return -ENOENT;
+  }
+  if (p != snapset.clones.begin()) {
+    // not the oldest... merge overlap into next older clone
+    vector<snapid_t>::iterator n = p - 1;
+    hobject_t prev_coid = ghobj.hobj;
+    prev_coid.snap = *n;
+    //bool adjust_prev_bytes = is_present_clone(prev_coid);
+
+    //if (adjust_prev_bytes)
+    //  ctx->delta_stats.num_bytes -= snapset.get_clone_bytes(*n);
+
+    snapset.clone_overlap[*n].intersection_of(
+       snapset.clone_overlap[*p]);
+
+    //if (adjust_prev_bytes)
+    //  ctx->delta_stats.num_bytes += snapset.get_clone_bytes(*n);
+  }
+
+  ret = remove_from(snapset.clones, "clones", cloneid, force);
+  if (ret) return ret;
+  ret = remove_from(snapset.clone_overlap, "clone_overlap", cloneid, force);
+  if (ret) return ret;
+  ret = remove_from(snapset.clone_size, "clone_size", cloneid, force);
+  if (ret) return ret;
+
+  bufferlist bl;
+  ::encode(snapset, bl);
+  ObjectStore::Transaction t;
+  t.setattr(coll, ghobj, SS_ATTR, bl);
+  int r = store->apply_transaction(&osr, t);
+  if (r < 0) {
+    cerr << "Error setting snapset on : " << make_pair(coll, ghobj) << ", "
+        << cpp_strerror(r) << std::endl;
+    return r;
+  }
+  cout << "Removal of clone " << cloneid << " complete" << std::endl;
+  cout << "Use pg repair after OSD restarted to correct stat information" << std::endl;
+  return 0;
+}
+
 void usage(po::options_description &desc)
 {
     cerr << std::endl;
@@ -2092,6 +2188,7 @@ void usage(po::options_description &desc)
     cerr << "ceph-objectstore-tool ... <object> remove" << std::endl;
     cerr << "ceph-objectstore-tool ... <object> dump" << std::endl;
     cerr << "ceph-objectstore-tool ... <object> set-size" << std::endl;
+    cerr << "ceph-objectstore-tool ... <object> remove-clone-metadata <cloneid>" << std::endl;
     cerr << std::endl;
     cerr << "<object> can be a JSON object description as displayed" << std::endl;
     cerr << "by --op list." << std::endl;
@@ -2452,6 +2549,9 @@ int main(int argc, char **argv)
     json_spirit::Value v;
     try {
       if (!json_spirit::read(object, v)) {
+        // Special: Need head/snapdir so set even if user didn't specify
+        if (vm.count("objcmd") && (objcmd == "remove-clone-metadata"))
+         head = true;
        lookup_ghobject lookup(object, head);
        if (action_on_all_objects(fs, lookup, debug)) {
          throw std::runtime_error("Internal error");
@@ -3034,6 +3134,26 @@ int main(int argc, char **argv)
        }
         ret = clear_snapset(fs, coll, ghobj, arg1, *osr);
         goto out;
+      } else if (objcmd == "remove-clone-metadata") {
+        // Extra arg
+       if (vm.count("arg1") == 0 || vm.count("arg2")) {
+         usage(desc);
+          ret = 1;
+          goto out;
+        }
+       if (!ghobj.hobj.has_snapset()) {
+         cerr << "'" << objcmd << "' requires a head or snapdir object" << std::endl;
+         ret = 1;
+         goto out;
+       }
+        if (arg1.length() == 0 || !isdigit(arg1.c_str()[0])) {
+         cerr << "Invalid cloneid '" << arg1 << "' specified" << std::endl;
+         ret = 1;
+         goto out;
+       }
+        snapid_t cloneid = atoi(arg1.c_str());
+       ret = remove_clone(fs, coll, ghobj, cloneid, force, *osr);
+       goto out;
       }
       cerr << "Unknown object command '" << objcmd << "'" << std::endl;
       usage(desc);