]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: a tool to fix buckets with leaked multipart references
authorYehuda Sadeh <yehuda@inktank.com>
Tue, 5 Feb 2013 22:50:54 +0000 (14:50 -0800)
committerYehuda Sadeh <yehuda@inktank.com>
Tue, 5 Feb 2013 23:52:41 +0000 (15:52 -0800)
Checks specified bucket for the #4011 symptoms, optionally fix
the issue.

sytax:
  radosgw-admin bucket check --bucket=<bucket> [--fix]

Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
src/rgw/rgw_admin.cc
src/rgw/rgw_rados.cc
src/rgw/rgw_rados.h

index f0781504efc2a12eea4f1c9a0e4c2a25261f3356..86194e6ceb54b08d10bf38a5e8f5a0e407b24174 100644 (file)
@@ -125,6 +125,7 @@ enum {
   OPT_BUCKET_LINK,
   OPT_BUCKET_UNLINK,
   OPT_BUCKET_STATS,
+  OPT_BUCKET_CHECK,
   OPT_OBJECT_UNLINK,
   OPT_POLICY,
   OPT_POOL_ADD,
@@ -256,6 +257,8 @@ static int get_cmd(const char *cmd, const char *prev_cmd, bool *need_more)
       return OPT_BUCKET_UNLINK;
     if (strcmp(cmd, "stats") == 0)
       return OPT_BUCKET_STATS;
+    if (strcmp(cmd, "check") == 0)
+      return OPT_BUCKET_CHECK;
   } else if (strcmp(prev_cmd, "object") == 0) {
     if (strcmp(cmd, "unlink") == 0)
       return OPT_OBJECT_UNLINK;
@@ -522,6 +525,88 @@ enum ObjectKeyType {
   KEY_TYPE_S3,
 };
 
+void check_bad_index_multipart(rgw_bucket& bucket, bool fix)
+{
+  int max = 1000;
+  string prefix;
+  string marker;
+  string delim;
+
+  map<string, bool> common_prefixes;
+  string ns = "multipart";
+
+  bool is_truncated;
+  list<string> objs_to_unlink;
+  map<string, bool> meta_objs;
+  map<string, string> all_objs;
+
+  do {
+    vector<RGWObjEnt> result;
+    int r = rgwstore->list_objects(bucket, max, prefix, delim, marker,
+                                result, common_prefixes, false, ns,
+                                &is_truncated, NULL);
+
+    if (r < 0) {
+      cerr << "failed to list objects in bucket=" << bucket << " err=" << cpp_strerror(-r) << std::endl;
+      return;
+    }
+
+    vector<RGWObjEnt>::iterator iter;
+    for (iter = result.begin(); iter != result.end(); ++iter) {
+      RGWObjEnt& ent = *iter;
+
+      rgw_obj obj(bucket, ent.name);
+      obj.set_ns(ns);
+
+      string& oid = obj.object;
+      marker = oid;
+
+      int pos = oid.find_last_of('.');
+      if (pos < 0)
+       continue;
+
+      string name = oid.substr(0, pos);
+      string suffix = oid.substr(pos + 1);
+
+      if (suffix.compare("meta") == 0) {
+       meta_objs[name] = true;
+      } else {
+       all_objs[oid] = name;
+      }
+    }
+
+  } while (is_truncated);
+
+  map<string, string>::iterator aiter;
+  for (aiter = all_objs.begin(); aiter != all_objs.end(); ++aiter) {
+    string& name = aiter->second;
+
+    if (meta_objs.find(name) == meta_objs.end()) {
+      objs_to_unlink.push_back(aiter->first);
+    }
+  }
+
+  if (objs_to_unlink.empty())
+    return;
+
+  if (!fix) {
+    cout << "Need to unlink the following objects from bucket=" << bucket << std::endl;
+  } else {
+    cout << "Unlinking the following objects from bucket=" << bucket << std::endl;
+  }
+  for (list<string>::iterator oiter = objs_to_unlink.begin(); oiter != objs_to_unlink.end(); ++oiter) {
+    cout << *oiter << std::endl;
+  }
+
+  if (fix) {
+    int r = rgwstore->remove_objs_from_index(bucket, objs_to_unlink);
+    if (r < 0) {
+      cerr << "ERROR: remove_obj_from_index() returned error: " << cpp_strerror(-r) << std::endl;
+    }
+  }
+
+}
+
 static void parse_date(string& date, uint64_t *epoch, string *out_date = NULL, string *out_time = NULL)
 {
   struct tm tm;
@@ -594,6 +679,7 @@ int main(int argc, char **argv)
   int purge_keys = false;
   int yes_i_really_mean_it = false;
   int max_buckets = -1;
+  int fix = false;
 
   std::string val;
   std::ostringstream errs;
@@ -678,6 +764,8 @@ int main(int argc, char **argv)
       // do nothing
     } else if (ceph_argparse_binary_flag(args, i, &yes_i_really_mean_it, NULL, "--yes-i-really-mean-it", (char*)NULL)) {
       // do nothing
+    } else if (ceph_argparse_binary_flag(args, i, &fix, NULL, "--fix", (char*)NULL)) {
+      // do nothing
     } else {
       ++i;
     }
@@ -1503,12 +1591,18 @@ next:
   }
 
   if (opt_cmd == OPT_OBJECT_UNLINK) {
-    int ret = rgwstore->remove_obj_from_index(bucket, object);
+    list<string> oid_list;
+    oid_list.push_back(object);
+    int ret = rgwstore->remove_objs_from_index(bucket, oid_list);
     if (ret < 0) {
       cerr << "ERROR: remove_obj_from_index() returned error: " << cpp_strerror(-ret) << std::endl;
       return 1;
     }
   }
 
+  if (opt_cmd == OPT_BUCKET_CHECK) {
+    check_bad_index_multipart(bucket, fix);
+  }
+
   return 0;
 }
index a5655a9038e50035f65f660eb50289943024e444..cb396bfadbcd4b6c971ba8132e1aca82077d7e91 100644 (file)
@@ -2751,7 +2751,7 @@ int RGWRados::cls_obj_usage_log_trim(string& oid, string& user, uint64_t start_e
   return r;
 }
 
-int RGWRados::remove_obj_from_index(rgw_bucket& bucket, const string& oid)
+int RGWRados::remove_objs_from_index(rgw_bucket& bucket, list<string>& oid_list)
 {
   librados::IoCtx io_ctx;
 
@@ -2762,13 +2762,19 @@ int RGWRados::remove_obj_from_index(rgw_bucket& bucket, const string& oid)
   string dir_oid = dir_oid_prefix;
   dir_oid.append(bucket.marker);
 
-  rgw_bucket_dir_entry entry;
-  entry.epoch = (uint64_t)-1; // ULLONG_MAX, needed to that objclass doesn't skip out request
-  entry.name = oid;
-
   bufferlist updates;
-  updates.append(CEPH_RGW_REMOVE);
-  ::encode(entry, updates);
+
+  list<string>::iterator iter;
+
+  for (iter = oid_list.begin(); iter != oid_list.end(); ++iter) {
+    string& oid = *iter;
+    dout(2) << "RGWRados::remove_objs_from_index bucket=" << bucket << " oid=" << oid << dendl;
+    rgw_bucket_dir_entry entry;
+    entry.epoch = (uint64_t)-1; // ULLONG_MAX, needed to that objclass doesn't skip out request
+    entry.name = oid;
+    updates.append(CEPH_RGW_REMOVE);
+    ::encode(entry, updates);
+  }
 
   bufferlist out;
 
index 7d681c9e74b73b63e21be5c9295333e76c5a62d8..7e4e840da991384d5b5aaee3c812d676fa0fd466 100644 (file)
@@ -583,7 +583,7 @@ public:
   /// clean up/process any temporary objects older than given date[/time]
   int remove_temp_objects(string date, string time);
 
-  int remove_obj_from_index(rgw_bucket& bucket, const string& oid);
+  int remove_objs_from_index(rgw_bucket& bucket, list<string>& oid_list);
 
  private:
   int process_intent_log(rgw_bucket& bucket, string& oid,