]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: Add archive zone metadata support
authorJavier M. Mellid <jmunhoz@igalia.com>
Mon, 1 Oct 2018 18:44:42 +0000 (20:44 +0200)
committerYehuda Sadeh <yehuda@redhat.com>
Thu, 24 Jan 2019 04:19:02 +0000 (20:19 -0800)
Signed-off-by: Javier M. Mellid <jmunhoz@igalia.com>
src/rgw/rgw_bucket.cc
src/rgw/rgw_data_sync.cc
src/rgw/rgw_metadata.cc
src/rgw/rgw_metadata.h

index 3ff965ec510d8638d16041a5f85fa44a8ec56c5c..dd28a479d54f15c9a626332a8263638343f3f0bf 100644 (file)
@@ -2481,6 +2481,174 @@ public:
   }
 };
 
+void get_md5_digest(const RGWBucketEntryPoint *be, string& md5_digest) {
+
+   char md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1];
+   unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE];
+   bufferlist bl;
+
+   Formatter *f = new JSONFormatter(false);
+   be->dump(f);
+   f->flush(bl);
+
+   MD5 hash;
+   hash.Update((const unsigned char *)bl.c_str(), bl.length());
+   hash.Final(m);
+
+   buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, md5);
+
+   delete f;
+
+   md5_digest = md5;
+}
+
+class RGWArchiveBucketMetadataHandler : public RGWBucketMetadataHandler {
+
+public:
+
+  int remove_by_metakey(RGWRados *store, string& metadata_key) override {
+
+    ldout(store->ctx(), 0) << "SKIP: bucket removal is not allowed on archive zone: " << metadata_key << " ... proceeding to rename" << dendl;
+
+    string type;
+    string entry;
+    store->meta_mgr->parse_metadata_key(metadata_key, type, entry);
+
+    RGWMetadataObject *obj;
+    int ret = get(store, entry, &obj);
+    if (ret < 0) {
+        return ret;
+    }
+
+    RGWBucketEntryPoint be;
+    RGWObjectCtx obj_ctx(store);
+    RGWObjVersionTracker objv_tracker;
+    objv_tracker.read_version = obj->get_version();
+
+    delete obj;
+
+    string tenant_name, bucket_name;
+    parse_bucket(entry, &tenant_name, &bucket_name);
+
+    real_time mtime;
+
+    ret = store->get_bucket_entrypoint_info(obj_ctx, tenant_name, bucket_name, be, &objv_tracker, &mtime, NULL);
+    if (ret < 0) {
+        return ret;
+    }
+
+    string md5_digest;
+    get_md5_digest(&be, md5_digest);
+
+    string archive_zone_suffix = "-deleted-" + md5_digest;
+    be.bucket.name = be.bucket.name + archive_zone_suffix;
+
+    RGWBucketEntryMetadataObject *be_mdo = new RGWBucketEntryMetadataObject(be, objv_tracker.read_version, mtime);
+
+    JSONFormatter f(false);
+    f.open_object_section("metadata_info");
+    encode_json("key", metadata_key + archive_zone_suffix, &f);
+    encode_json("ver", be_mdo->get_version(), &f);
+    mtime = be_mdo->get_mtime();
+    if (!real_clock::is_zero(mtime)) {
+       utime_t ut(mtime);
+       encode_json("mtime", ut, &f);
+    }
+    encode_json("data", *be_mdo, &f);
+    f.close_section();
+
+    delete be_mdo;
+
+    ret = rgw_unlink_bucket(store, be.owner, tenant_name, bucket_name, false);
+    if (ret < 0) {
+        lderr(store->ctx()) << "could not unlink bucket=" << entry << " owner=" << be.owner << dendl;
+    }
+
+    // if (ret == -ECANCELED) it means that there was a race here, and someone
+    // wrote to the bucket entrypoint just before we removed it. The question is
+    // whether it was a newly created bucket entrypoint ...  in which case we
+    // should ignore the error and move forward, or whether it is a higher version
+    // of the same bucket instance ... in which we should retry
+    ret = rgw_bucket_delete_bucket_obj(store, tenant_name, bucket_name, objv_tracker);
+    if (ret < 0) {
+        lderr(store->ctx()) << "could not delete bucket=" << entry << dendl;
+    }
+
+    string new_entry, new_bucket_name;
+    new_entry = entry + archive_zone_suffix;
+    parse_bucket(new_entry, &tenant_name, &new_bucket_name);
+
+    bufferlist bl;
+    f.flush(bl);
+
+    JSONParser parser;
+    if (!parser.parse(bl.c_str(), bl.length())) {
+        return -EINVAL;
+    }
+
+    JSONObj *jo = parser.find_obj("data");
+    if (!jo) {
+        return -EINVAL;
+    }
+
+    try {
+        decode_json_obj(be, jo);
+    } catch (JSONDecoder::err& e) {
+        return -EINVAL;
+    }
+
+    RGWBucketEntryPoint ep;
+    ep.linked = be.linked;
+    ep.owner = be.owner;
+    ep.bucket = be.bucket;
+
+    RGWObjVersionTracker ot;
+    ot.generate_new_write_ver(store->ctx());
+
+    map<string, bufferlist> attrs;
+
+    ret = store->put_bucket_entrypoint_info(tenant_name, new_bucket_name, ep, false, ot, mtime, &attrs);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = rgw_link_bucket(store, be.owner, be.bucket, be.creation_time, false);
+    if (ret < 0) {
+        return ret;
+    }
+
+    // .bucket.meta.my-bucket-1:c0f7ef8c-2309-4ebb-a1d0-1b0a61dc5a78.4226.1
+    string meta_name = bucket_name + ":" + be.bucket.marker;
+
+    map<string, bufferlist> attrs_m;
+    RGWBucketInfo bi_m;
+
+    ret = store->get_bucket_instance_info(obj_ctx, meta_name, bi_m, NULL, &attrs_m);
+    if (ret < 0) {
+        return ret;
+    }
+
+    string new_meta_name = RGW_BUCKET_INSTANCE_MD_PREFIX + new_bucket_name + ":" + be.bucket.marker;
+
+    bi_m.bucket.name = new_bucket_name;
+
+    bufferlist bl_m;
+    using ceph::encode;
+    encode(bi_m, bl_m);
+
+    ret = rgw_put_system_obj(store, store->get_zone_params().domain_root, new_meta_name, bl_m, false, NULL, real_time(), NULL);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = rgw_delete_system_obj(store, store->get_zone_params().domain_root, RGW_BUCKET_INSTANCE_MD_PREFIX + meta_name, NULL);
+
+    /* idempotent */
+    return 0;
+  }
+
+};
+
 class RGWBucketInstanceMetadataHandler : public RGWMetadataHandler {
 
 public:
@@ -2700,10 +2868,26 @@ public:
   }
 };
 
+class RGWArchiveBucketInstanceMetadataHandler : public RGWBucketInstanceMetadataHandler {
+
+public:
+
+   int remove_by_metakey(RGWRados *store, string& metadata_key) override {
+       ldout(store->ctx(), 0) << "SKIP: bucket instance removal is not allowed on archive zone: " << metadata_key << dendl;
+          return 0;
+   }
+
+};
+
 void rgw_bucket_init(RGWMetadataManager *mm)
 {
-  bucket_meta_handler = new RGWBucketMetadataHandler;
+  if (mm->get_store()->get_zone().tier_type == "archive") {
+      bucket_meta_handler = new RGWArchiveBucketMetadataHandler;
+      bucket_instance_meta_handler = new RGWArchiveBucketInstanceMetadataHandler;
+  } else {
+      bucket_meta_handler = new RGWBucketMetadataHandler;
+      bucket_instance_meta_handler = new RGWBucketInstanceMetadataHandler;
+  }
   mm->register_handler(bucket_meta_handler);
-  bucket_instance_meta_handler = new RGWBucketInstanceMetadataHandler;
   mm->register_handler(bucket_instance_meta_handler);
 }
index 4c53f2faa5419cb4b00b6898a332fb3745837e76..1ad06149bc24658808f1d4cc19a4d914533572cf 100644 (file)
@@ -1718,8 +1718,7 @@ RGWCoroutine *RGWArchiveDataSyncModule::sync_object(RGWDataSyncEnv *sync_env, RG
   if (!bucket_info.versioned() ||
      (bucket_info.flags & BUCKET_VERSIONS_SUSPENDED)) {
       ldout(sync_env->cct, 0) << "SYNC_ARCHIVE: sync_object: enabling object versioning for archive bucket" << dendl;
-      bucket_info.flags |= BUCKET_VERSIONED;
-      bucket_info.flags &= ~BUCKET_VERSIONS_SUSPENDED;
+      bucket_info.flags = (bucket_info.flags & ~BUCKET_VERSIONS_SUSPENDED) | BUCKET_VERSIONED;
       int op_ret = sync_env->store->put_bucket_instance_info(bucket_info, false, real_time(), NULL);
       if (op_ret < 0) {
          ldout(sync_env->cct, 0) << "SYNC_ARCHIVE: sync_object: error versioning archive bucket" << dendl;
index bb6657ee0f8996fcccd6174353e4bdc5fbc45bd5..1d36ce7c2ee719731f16d63d2b69513b1cccc95f 100644 (file)
@@ -275,6 +275,23 @@ obj_version& RGWMetadataObject::get_version()
   return objv;
 }
 
+int RGWMetadataHandler::remove_by_metakey(RGWRados *store, string& metadata_key) {
+    string entry;
+    string type;
+    store->meta_mgr->parse_metadata_key(metadata_key, type, entry);
+
+    RGWMetadataObject *obj;
+    int ret = get(store, entry, &obj);
+    if (ret < 0) {
+        return ret;
+    }
+    RGWObjVersionTracker objv_tracker;
+    objv_tracker.read_version = obj->get_version();
+    delete obj;
+
+    return remove(store, entry, objv_tracker);
+}
+
 class RGWMetadataTopHandler : public RGWMetadataHandler {
   struct iter_data {
     set<string> sections;
@@ -293,6 +310,7 @@ public:
   virtual void get_pool_and_oid(RGWRados *store, const string& key, rgw_pool& pool, string& oid) override {}
 
   int remove(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker) override { return -ENOTSUP; }
+  int remove_by_metakey(RGWRados *store, string& metadata_key) override { return -ENOTSUP; }
 
   int list_keys_init(RGWRados *store, const string& marker, void **phandle) override {
     iter_data *data = new iter_data;
@@ -760,8 +778,19 @@ int RGWMetadataManager::put(string& metadata_key, bufferlist& bl,
   string entry;
 
   int ret = find_handler(metadata_key, &handler, entry);
-  if (ret < 0)
+  if (ret < 0) {
     return ret;
+  }
+
+  // archive existing bucket if needed
+  if (store->get_zone().tier_type == "archive") {
+      if (handler->get_type() == "bucket") {
+          size_t found = metadata_key.find("-deleted-");
+          if(found != string::npos) {
+             remove(metadata_key);
+          }
+      }
+  }
 
   JSONParser parser;
   if (!parser.parse(bl.c_str(), bl.length())) {
@@ -832,23 +861,11 @@ int RGWMetadataManager::remove(string& metadata_key)
   string entry;
 
   int ret = find_handler(metadata_key, &handler, entry);
-  if (ret < 0)
-    return ret;
-
-  RGWMetadataObject *obj;
-
-  ret = handler->get(store, entry, &obj);
   if (ret < 0) {
     return ret;
   }
 
-  RGWObjVersionTracker objv_tracker;
-
-  objv_tracker.read_version = obj->get_version();
-
-  delete obj;
-
-  return handler->remove(store, entry, objv_tracker);
+  return handler->remove_by_metakey(store, metadata_key);
 }
 
 int RGWMetadataManager::lock_exclusive(string& metadata_key, timespan duration, string& owner_id) {
@@ -1133,8 +1150,9 @@ int RGWMetadataManager::remove_entry(RGWMetadataHandler *handler,
   string section;
   RGWMetadataLogData log_data;
   int ret = pre_modify(handler, section, key, log_data, objv_tracker, MDLOG_STATUS_REMOVE);
-  if (ret < 0)
-    return ret;
+  if (ret < 0) {
+      return ret;
+  }
 
   string oid;
   rgw_pool pool;
@@ -1151,8 +1169,9 @@ int RGWMetadataManager::remove_entry(RGWMetadataHandler *handler,
   /* cascading ret into post_modify() */
 
   ret = post_modify(handler, section, key, log_data, objv_tracker, ret);
-  if (ret < 0)
-    return ret;
+  if (ret < 0) {
+      return ret;
+  }
 
   return 0;
 }
index 9ceef74c4509c2d8d2243dee59cd612095e4fe28..2c8d61db5baf653adb372b0cd037bc4dae8a2fad 100644 (file)
@@ -72,6 +72,7 @@ public:
       return false;
     return true;
   }
+
   virtual ~RGWMetadataHandler() {}
   virtual string get_type() = 0;
 
@@ -79,6 +80,7 @@ public:
   virtual int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker,
                   real_time mtime, JSONObj *obj, sync_type_t type) = 0;
   virtual int remove(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker) = 0;
+  virtual int remove_by_metakey(RGWRados *store, string& metadata_key);
 
   virtual int list_keys_init(RGWRados *store, const string& marker, void **phandle) = 0;
   virtual int list_keys_next(void *handle, int max, list<string>& keys, bool *truncated) = 0;
@@ -300,8 +302,6 @@ class RGWMetadataManager {
   // use the current period's log for mutating operations
   RGWMetadataLog* current_log = nullptr;
 
-  void parse_metadata_key(const string& metadata_key, string& type, string& entry);
-
   int find_handler(const string& metadata_key, RGWMetadataHandler **handler, string& entry);
   int pre_modify(RGWMetadataHandler *handler, string& section, const string& key,
                  RGWMetadataLogData& log_data, RGWObjVersionTracker *objv_tracker,
@@ -323,6 +323,8 @@ public:
   RGWMetadataManager(CephContext *_cct, RGWRados *_store);
   ~RGWMetadataManager();
 
+  RGWRados* get_store() { return store; }
+
   int init(const std::string& current_period);
 
   /// initialize the oldest log period if it doesn't exist, and attach it to
@@ -382,6 +384,8 @@ public:
   int unlock(string& metadata_key, string& owner_id);
 
   int get_log_shard_id(const string& section, const string& key, int *shard_id);
+
+  void parse_metadata_key(const string& metadata_key, string& type, string& entry);
 };
 
 template <typename F>