From 272a73ac338ea8e84f3b7e2479c3a26a07fe2bdf Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Thu, 28 Mar 2019 09:22:40 -0700 Subject: [PATCH] rgw: meta put: revise Signed-off-by: Yehuda Sadeh --- src/rgw/rgw_bucket.cc | 335 ++++++++++++++++++++--------------- src/rgw/rgw_bucket.h | 8 +- src/rgw/rgw_metadata.cc | 67 +++++++ src/rgw/rgw_metadata.h | 43 +++++ src/rgw/rgw_service.h | 2 +- src/rgw/rgw_user.cc | 224 ++++++----------------- src/rgw/rgw_user.h | 44 ++++- src/rgw/services/svc_user.cc | 305 +++++++++++++++++++++++++++++-- src/rgw/services/svc_user.h | 19 +- 9 files changed, 719 insertions(+), 328 deletions(-) diff --git a/src/rgw/rgw_bucket.cc b/src/rgw/rgw_bucket.cc index 6434084386e..b6c307767ae 100644 --- a/src/rgw/rgw_bucket.cc +++ b/src/rgw/rgw_bucket.cc @@ -2562,7 +2562,8 @@ public: RGWBucketEntryPoint *be, RGWObjVersionTracker *objv_tracker, ceph::real_time *pmtime, - map *pattrs) { + map *pattrs, + optional_yield y) { bufferlist bl; RGWSI_MBSObj_GetParams params = { .pmtime = pmtime, @@ -2639,11 +2640,11 @@ public: real_time mtime; map attrs; - int ret = read_bucket_entrypoint_info(ctx, entry, &be, &ot, &mtime, &attrs); + int ret = read_bucket_entrypoint_info(ctx, entry, &be, &ot, &mtime, &attrs, null_yield); if (ret < 0) return ret; - RGWBucketEntryMetadataObject *mdo = new RGWBucketEntryMetadataObject(be, ot.read_version, mtime); + RGWBucketEntryMetadataObject *mdo = new RGWBucketEntryMetadataObject(be, ot.read_version, mtime, attrs); *obj = mdo; @@ -2651,49 +2652,9 @@ public: } int do_put(RGWSI_MetaBackend::Context *ctx, string& entry, - RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker, - RGWMDLogSyncType type) override { - RGWBucketEntryMetadataObject *obj = static_cast(_obj); - - auto& be = obj->get_be(); - - RGWBucketEntryPoint old_be; - try { - decode_json_obj(be, obj); - } catch (JSONDecoder::err& e) { - return -EINVAL; - } - - RGWObjVersionTracker old_ot; - - map attrs; - int ret = read_bucket_entrypoint_info(ctx, entry, &old_be, &old_ot, &orig_mtime, &attrs); - if (ret < 0 && ret != -ENOENT) - return ret; - - // are we actually going to perform this put, or is it too old? - bool exists = (ret != -ENOENT); - if (!check_versions(exists, old_ot.read_version, orig_mtime, - objv_tracker.write_version, obj->get_mtime(), sync_type)) { - return STATUS_NO_APPLY; - } - - objv_tracker.read_version = old_ot.read_version; /* maintain the obj version we just read */ - - ret = store_bucket_entrypoint_info(entry, be, false, objv_tracker, obj->get_mtime(), &attrs); - if (ret < 0) - return ret; - - /* link bucket */ - if (be.linked) { - ret = rgw_link_bucket(store, be.owner, be.bucket, be.creation_time, false); - } else { - ret = rgw_unlink_bucket(store, be.owner, be.bucket.tenant, - be.bucket.name, false); - } - - return ret; - } + RGWMetadataObject *obj, + RGWObjVersionTracker& objv_tracker, + RGWMDLogSyncType type) override; struct list_keys_info { RGWRados *store; @@ -2705,7 +2666,7 @@ public: real_time orig_mtime; - int ret = read_bucket_entrypoint_info(ctx, entry, be, &objv_tracker, &orig_mtime, nullptr); + int ret = read_bucket_entrypoint_info(ctx, entry, be, &objv_tracker, &orig_mtime, nullptr, null_yield); if (ret < 0) return ret; @@ -2787,6 +2748,64 @@ public: } }; +class RGWMetadataHandlerPut_Bucket : public RGWMetadataHanderPut_SObj +{ + RGWBucketMetadataHandler *handler; + RGWBucketEntryMetadataObject *obj; +public: + RGWMetadataHandlerPut_Bucket(RGWBucketMetadataHandler *_handler, + RGWSI_MetaBackend::Context *ctx, string& entry, + RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker, + RGWMDLogSyncType type) : RGWMetadataHanderPut_SObj(ctx, entry, obj, objv_tracker, type), + handler(_handler) { + obj = static_cast(_obj); + } + ~RGWMetadataHandlerPut_Bucket() {} + + int put_checked(RGWMetadataObject *_old_obj) override; + int put_post() override; +}; + +int RGWBucketMetadataHandler::do_put(RGWSI_MetaBackend::Context *ctx, string& entry, + RGWMetadataObject *obj, + RGWObjVersionTracker& objv_tracker, + RGWMDLogSyncType type) +{ + RGWMetadataHandlerPut_Bucket op(this, ctx, entry, obj, objv_tracker, type); + return do_put(&op); +} + +int RGWMetadataHandlerPut_Bucket::put_checked(RGWMetadataObject *_old_obj) +{ + RGWBucketEntryMetadataObject *old_obj = static_cast(_old_obj); + + auto& be = obj->get_be(); + + map *pattrs = (old_obj ? &old_obj->get_attrs() : nullptr); + + ret = handler->store_bucket_entrypoint_info(entry, be, false, objv_tracker, + obj->get_mtime(), &old_obj->get_attrs()); + if (ret < 0) + return ret; + + return 0; +} + +int RGWMetadataHandlerPut_Bucket::put_post() +{ + auto& be = obj->get_be(); + + /* link bucket */ + if (be.linked) { + ret = rgw_link_bucket(store, be.owner, be.bucket, be.creation_time, false); + } else { + ret = rgw_unlink_bucket(store, be.owner, be.bucket.tenant, + be.bucket.name, false); + } + + return ret; +} + void get_md5_digest(const RGWBucketEntryPoint *be, string& md5_digest) { char md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1]; @@ -2850,7 +2869,7 @@ WRITE_CLASS_ENCODER(archive_meta_info) class RGWArchiveBucketMetadataHandler : public RGWBucketMetadataHandler { public: - int remove(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker) override { + int do_remove(RGWMetaBackend::Context *ctx, string& entry, RGWObjVersionTracker& objv_tracker) override { ldout(store->ctx(), 5) << "SKIP: bucket removal is not allowed on archive zone: bucket:" << entry << " ... proceeding to rename" << dendl; string tenant_name, bucket_name; @@ -2861,9 +2880,8 @@ public: /* read original entrypoint */ RGWBucketEntryPoint be; - auto obj_ctx = store->svc.sysobj->init_obj_ctx(); map attrs; - int ret = store->get_bucket_entrypoint_info(obj_ctx, tenant_name, bucket_name, be, &objv_tracker, &mtime, &attrs); + int ret = read_bucket_entrypoint_info(ctx, entry, be, &objv_tracker, &mtime, &attrs, null_yield); if (ret < 0) { return ret; } @@ -2959,12 +2977,14 @@ public: return 0; } - int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker, - real_time mtime, JSONObj *obj, RGWMDLogSyncType sync_type) override { + int do_put(RGWSI_MetaBackend::Context *ctx, string& entry, + RGWMetadataObject *obj, + RGWObjVersionTracker& objv_tracker, + RGWMDLogSyncType type) override { if (entry.find("-deleted-") != string::npos) { RGWObjVersionTracker ot; RGWMetadataObject *robj; - int ret = get(store, entry, &robj); + int ret = do_get(ctx, entry, &robj); if (ret != -ENOENT) { if (ret < 0) { return ret; @@ -2972,15 +2992,15 @@ public: ot.read_version = robj->get_version(); delete robj; - ret = remove(store, entry, ot); + ret = do_remove(ctx, entry, ot); if (ret < 0) { return ret; } } } - return RGWBucketMetadataHandler::put(store, entry, objv_tracker, - mtime, obj, sync_type); + return RGWBucketMetadataHandler::do_put(ctx, entry, objv_tracker, + mtime, obj, sync_type); } }; @@ -3129,94 +3149,7 @@ public: int do_put(RGWSI_MetaBackend::Context *ctx, string& entry, RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker, - RGWMDLogSyncType type) override { - RGWBucketInstanceMetadataObject *obj = static_cast(_obj); - - auto& be = obj->get_bucket_info(); - - real_time orig_mtime; - - int ret = store->get_bucket_instance_info(obj_ctx, entry, old_bci.info, - &orig_mtime, &old_bci.attrs, null_yield); - bool exists = (ret != -ENOENT); - if (ret < 0 && exists) - return ret; - - if (!exists || old_bci.info.bucket.bucket_id != bci.info.bucket.bucket_id) { - /* a new bucket, we need to select a new bucket placement for it */ - auto key(entry); - rgw_bucket_instance_oid_to_key(key); - string tenant_name; - string bucket_name; - string bucket_instance; - parse_bucket(key, &tenant_name, &bucket_name, &bucket_instance); - - RGWZonePlacementInfo rule_info; - bci.info.bucket.name = bucket_name; - bci.info.bucket.bucket_id = bucket_instance; - bci.info.bucket.tenant = tenant_name; - ret = svc.zone->select_bucket_location_by_rule(bci.info.placement_rule, &rule_info); - if (ret < 0) { - ldout(cct, 0) << "ERROR: select_bucket_placement() returned " << ret << dendl; - return ret; - } - bci.info.index_type = rule_info.index_type; - } else { - /* existing bucket, keep its placement */ - bci.info.bucket.explicit_placement = old_bci.info.bucket.explicit_placement; - bci.info.placement_rule = old_bci.info.placement_rule; - } - - if (exists && old_bci.info.datasync_flag_enabled() != bci.info.datasync_flag_enabled()) { - int shards_num = bci.info.num_shards? bci.info.num_shards : 1; - int shard_id = bci.info.num_shards? 0 : -1; - - if (!bci.info.datasync_flag_enabled()) { - ret = store->stop_bi_log_entries(bci.info, -1); - if (ret < 0) { - lderr(store->ctx()) << "ERROR: failed writing bilog" << dendl; - return ret; - } - } else { - ret = store->resync_bi_log_entries(bci.info, -1); - if (ret < 0) { - lderr(store->ctx()) << "ERROR: failed writing bilog" << dendl; - return ret; - } - } - - for (int i = 0; i < shards_num; ++i, ++shard_id) { - ret = store->data_log->add_entry(bci.info.bucket, shard_id); - if (ret < 0) { - lderr(store->ctx()) << "ERROR: failed writing data log" << dendl; - return ret; - } - } - } - - // are we actually going to perform this put, or is it too old? - if (!check_versions(exist, old_bci.info.objv_tracker.read_version, orig_mtime, - objv_tracker.write_version, mtime, sync_type)) { - objv_tracker.read_version = old_bci.info.objv_tracker.read_version; - return STATUS_NO_APPLY; - } - - /* record the read version (if any), store the new version */ - bci.info.objv_tracker.read_version = old_bci.info.objv_tracker.read_version; - bci.info.objv_tracker.write_version = objv_tracker.write_version; - - ret = store_bucket_instance_entry(bci.info, false, mtime, &bci.attrs); - if (ret < 0) - return ret; - - objv_tracker = bci.info.objv_tracker; - - ret = store->init_bucket_index(bci.info, bci.info.num_shards); - if (ret < 0) - return ret; - - return STATUS_APPLIED; - } + RGWMetadataObject *_old_obj) override; struct list_keys_info { RGWRados *store; @@ -3296,6 +3229,120 @@ public: } }; +class RGWMetadataHandlerPut_BucketInstance : public RGWMetadataHanderPut_SObj +{ + RGWBucketInstanceMetadataHandler *handler; + RGWBucketInstanceMetadataObject *obj; +public: + RGWMetadataHandlerPut_BucketInstance(RGWBucketInstanceMetadataHandler *_handler, + RGWSI_MetaBackend::Context *ctx, string& entry, + RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker, + RGWMDLogSyncType type) : RGWMetadataHanderPut_SObj(ctx, entry, obj, objv_tracker, type), + handler(_handler) { + obj = static_cast(_obj); + } + + int put_pre() override; + int put_checked(RGWMetadataObject *_old_obj) override; + int put_post() override; +}; + +int RGWBucketInstanceMetadatHandler::do_put(RGWSI_MetaBackend::Context *ctx, string& entry, + RGWMetadataObject *obj, + RGWObjVersionTracker& objv_tracker, + RGWMDLogSyncType type) override +{ + RGWMetadataHandlerPut_BucketInstance put_op(this, ctx, entry, obj, + objv_tracker, type); + return do_put(&op); +} + +int RGWMetadataHandlerPut_BucketInstance::put_pre() +{ + RGWBucketInstanceMetadataObject *old_obj = static_cast(_old_obj); + + RGWBucketCompleteInfo *old_bci = (old_obj ? &old_obj->get_bci() : nullptr); + + bool exists = (!!old_obj); + + if (!exists || old_bci->info.bucket.bucket_id != bci->info.bucket.bucket_id) { + /* a new bucket, we need to select a new bucket placement for it */ + auto key(entry); + rgw_bucket_instance_oid_to_key(key); + string tenant_name; + string bucket_name; + string bucket_instance; + parse_bucket(key, &tenant_name, &bucket_name, &bucket_instance); + + RGWZonePlacementInfo rule_info; + bci.info.bucket.name = bucket_name; + bci.info.bucket.bucket_id = bucket_instance; + bci.info.bucket.tenant = tenant_name; + ret = svc.zone->select_bucket_location_by_rule(bci.info.placement_rule, &rule_info); + if (ret < 0) { + ldout(cct, 0) << "ERROR: select_bucket_placement() returned " << ret << dendl; + return ret; + } + bci.info.index_type = rule_info.index_type; + } else { + /* existing bucket, keep its placement */ + bci.info.bucket.explicit_placement = old_bci->info.bucket.explicit_placement; + bci.info.placement_rule = old_bci->info.placement_rule; + } + + if (exists && old_bci->info.datasync_flag_enabled() != bci.info.datasync_flag_enabled()) { + int shards_num = bci.info.num_shards? bci.info.num_shards : 1; + int shard_id = bci.info.num_shards? 0 : -1; + + if (!bci.info.datasync_flag_enabled()) { + ret = store->stop_bi_log_entries(bci.info, -1); + if (ret < 0) { + lderr(store->ctx()) << "ERROR: failed writing bilog" << dendl; + return ret; + } + } else { + ret = store->resync_bi_log_entries(bci.info, -1); + if (ret < 0) { + lderr(store->ctx()) << "ERROR: failed writing bilog" << dendl; + return ret; + } + } + + for (int i = 0; i < shards_num; ++i, ++shard_id) { + ret = store->data_log->add_entry(bci.info.bucket, shard_id); + if (ret < 0) { + lderr(store->ctx()) << "ERROR: failed writing data log" << dendl; + return ret; + } + } + } + + /* record the read version (if any), store the new version */ + bci.info.objv_tracker.read_version = objv_tracker.read_version; + bci.info.objv_tracker.write_version = objv_tracker.write_version; + + return 0; +} + +int RGWMetadataHandlerPut_BucketInstance::put_checked(RGWMetadataObject *_old_obj) { + ret = store_bucket_instance_entry(bci.info, false, mtime, &bci.attrs); + if (ret < 0) + return ret; + + return 0; +} + +int RGWMetadataHandlerPut_BucketInstance::put_post() +{ + objv_tracker = bci.info.objv_tracker; + + ret = store->init_bucket_index(bci.info, bci.info.num_shards); + if (ret < 0) + return ret; + + return STATUS_APPLIED; +} + class RGWArchiveBucketInstanceMetadataHandler : public RGWBucketInstanceMetadataHandler { public: diff --git a/src/rgw/rgw_bucket.h b/src/rgw/rgw_bucket.h index 77435d017ab..941b74f2b2c 100644 --- a/src/rgw/rgw_bucket.h +++ b/src/rgw/rgw_bucket.h @@ -66,8 +66,10 @@ struct RGWBucketCompleteInfo { class RGWBucketEntryMetadataObject : public RGWMetadataObject { RGWBucketEntryPoint ep; + map attrs; public: - RGWBucketEntryMetadataObject(RGWBucketEntryPoint& _ep, obj_version& v, real_time m) : ep(_ep) { + RGWBucketEntryMetadataObject(RGWBucketEntryPoint& _ep, obj_version& v, real_time m, map&& _attrs) : + ep(_ep), attrs(std::move(_attrs)) { objv = v; mtime = m; } @@ -79,6 +81,10 @@ public: RGWBucketEntryPoint& get_ep() { return ep; } + + RGWBucketEntryPoint& get_attrs() { + return ep; + } }; class RGWBucketInstanceMetadataObject : public RGWMetadataObject { diff --git a/src/rgw/rgw_metadata.cc b/src/rgw/rgw_metadata.cc index 3ed1d9942fa..990a7fb4608 100644 --- a/src/rgw/rgw_metadata.cc +++ b/src/rgw/rgw_metadata.cc @@ -389,6 +389,73 @@ int RGWMetadataHandler::init(RGWMetadataManager *manager) return manager->register_handler(this, &meta_be, &be_handle); } +int RGWMetadataHandlerPut_SObj::put(RGWSI_MetaBackend::Context *ctx, string& entry, + RGWMetadataObject *obj, + RGWObjVersionTracker& objv_tracker, + RGWMDLogSyncType apply_type) { + RGWMetadataObject *old_obj{nullptr}; +#warning what about attrs? + map attrs; + int ret = do_get(ctx, entry, &old_obj); + if (ret < 0 && ret != -ENOENT) { + return ret; + } + + std::unique_ptr oo(old_obj); + + auto old_ver = (!old_obj : ? old_obj->get_version()); + auto old_mtime = (!old_obj : ? old_obj->get_mtime()); + + // are we actually going to perform this put, or is it too old? + bool exists = (ret != -ENOENT); + if (!check_versions(exists, old_ver, old_mtime, + objv_tracker.write_version, obj->get_mtime(), + apply_type)) { + return STATUS_NO_APPLY; + } + + objv_tracker.read_version = old_ver; /* maintain the obj version we just read */ + + return put_checked(old_obj); +} + +int RGWMetadataHandlerPut_SObj::put_checked(RGWMetadataObject *_old_obj) +{ + RGWSI_MBSObj_PutParams params = { + .mtime = mtime, + .pattrs = pattrs, + }; + ceph::encode(be, params.bl); + int ret = meta_be->put_entry(ctx, params, + objv_tracker); + if (ret < 0) { + return ret; + } + + return 0; +} + +int RGWMetadataHandler::do_put(Put *put_op) +{ + int r = put_op->put_pre(); + if (r != 0) { /* r can also be STATUS_NO_APPLY */ + return r; + } + + r = put_op->put(); + if (r != 0) { + return r; + } + + r = put_op->post(); + if (r != 0) } /* e.g., -error or STATUS_APPLIED */ + return r; + } + + return 0; +} +} + int RGWMetadataHandler::get(string& entry, RGWMetadataObject **obj) { RGWSI_Meta_Ctx ctx; diff --git a/src/rgw/rgw_metadata.h b/src/rgw/rgw_metadata.h index 57b77920cbe..7eeee983095 100644 --- a/src/rgw/rgw_metadata.h +++ b/src/rgw/rgw_metadata.h @@ -54,11 +54,41 @@ protected: RGWSI_MetaBackend_Handle be_handle{0}; RGWSI_MetaBackend::ModuleRef be_module; + class Put { + protected: + RGWSI_MetaBackend::Context *ctx; + string& entry; + RGWMetadataObject *obj; + RGWObjVersionTracker& objv_tracker; + RGWMDLogSyncType apply_type; + public: + Put(RGWSI_MetaBackend::Context *ctx, string& entry, RGWMetadataObject *obj, + RGWObjVersionTracker& objv_tracker, RGWMDLogSyncType type) : ctx(_ctx), entry(_entry), + obj(_obj), objv_tracker(_objv_tracker), + apply_type(_type) {} + virtual ~Put() {} + + virtual int put_pre() { + return 0; + } + virtual int put() { + return 0; + } + virtual int put_post() { + return 0; + } + virtual int finalize() { + return 0; + } + }; + virtual int do_get(RGWSI_MetaBackend::Context *ctx, string& entry, RGWMetadataObject **obj) = 0; virtual int do_put(RGWSI_MetaBackend::Context *ctx, string& entry, RGWMetadataObject *obj, RGWObjVersionTracker& objv_tracker, RGWMDLogSyncType type) = 0; + virtual int do_put(Put *put_op); virtual int do_remove(RGWSI_MetaBackend::Context *ctx, string& entry, RGWObjVersionTracker& objv_tracker) = 0; + virtual Put *alloc_put_op() = 0; virtual int init_module() = 0; public: @@ -158,5 +188,18 @@ public: void parse_metadata_key(const string& metadata_key, string& type, string& entry); }; +class RGWMetadataHandlerPut_SObj : public RGWMetadataHandler::Put +{ +public: + RGWMetadataHandlerPut_SObj(RGWSI_MetaBackend::Context *ctx, string& entry, + RGWMetadataObject *obj, RGWObjVersionTracker& objv_tracker, + RGWMDLogSyncType type) : Put(ctx, entry, obj, objv_tracker, type) {} + ~RGWMetadataHandlerPut_SObj() {} + + int put() override; + + virtual int put_checked(RGWMetadataObject *_old_obj); +}; + #endif diff --git a/src/rgw/rgw_service.h b/src/rgw/rgw_service.h index 9a5fc720d0d..b06c7609801 100644 --- a/src/rgw/rgw_service.h +++ b/src/rgw/rgw_service.h @@ -82,7 +82,7 @@ struct RGWServices_Def std::unique_ptr sysobj; std::unique_ptr sysobj_core; std::unique_ptr sysobj_cache; - std::unique_ptr bucket; + std::unique_ptr user; RGWServices_Def(); ~RGWServices_Def(); diff --git a/src/rgw/rgw_user.cc b/src/rgw/rgw_user.cc index 9675469cbb2..170be976cbc 100644 --- a/src/rgw/rgw_user.cc +++ b/src/rgw/rgw_user.cc @@ -159,121 +159,6 @@ int rgw_store_user_info(RGWSI_User *user_svc, .exec(); } - -} - -static int do_store_user_info(RGWSI_MetaBackend *meta_be, - RGWSI_MetaBackend::Context *ctx, - RGWUserInfo& info, - RGWUserInfo *old_info, - RGWObjVersionTracker *objv_tracker, - real_time mtime, - bool exclusive, - map *pattrs) -{ - int ret; - RGWObjVersionTracker ot; - - if (objv_tracker) { - ot = *objv_tracker; - } - - if (ot.write_version.tag.empty()) { - if (ot.read_version.tag.empty()) { - ot.generate_new_write_ver(store->ctx()); - } else { - ot.write_version = ot.read_version; - ot.write_version.ver++; - } - } - - map::iterator iter; - for (iter = info.swift_keys.begin(); iter != info.swift_keys.end(); ++iter) { - if (old_info && old_info->swift_keys.count(iter->first) != 0) - continue; - RGWAccessKey& k = iter->second; - /* check if swift mapping exists */ - RGWUserInfo inf; - int r = do_get_user_info_by_swift(meta_be, ctx, k.id, inf); - if (r >= 0 && inf.user_id.compare(info.user_id) != 0) { - ldout(store->ctx(), 0) << "WARNING: can't store user info, swift id (" << k.id - << ") already mapped to another user (" << info.user_id << ")" << dendl; - return -EEXIST; - } - } - - if (!info.access_keys.empty()) { - /* check if access keys already exist */ - RGWUserInfo inf; - map::iterator iter = info.access_keys.begin(); - for (; iter != info.access_keys.end(); ++iter) { - RGWAccessKey& k = iter->second; - if (old_info && old_info->access_keys.count(iter->first) != 0) - continue; - int r = do_get_user_info_by_access_key(meta_be, ctx, k.id, inf); - if (r >= 0 && inf.user_id.compare(info.user_id) != 0) { - ldout(store->ctx(), 0) << "WARNING: can't store user info, access key already mapped to another user" << dendl; - return -EEXIST; - } - } - } - - RGWUID ui; - ui.user_id = info.user_id; - - bufferlist link_bl; - encode(ui, link_bl); - - bufferlist data_bl; - encode(ui, data_bl); - encode(info, data_bl); - - string key; - info.user_id.to_str(key); - - ret = meta_be->put_entry(key, data_bl, exclusive, &ot, mtime, pattrs); - if (ret < 0) - return ret; - - if (!info.user_email.empty()) { - if (!old_info || - old_info->user_email.compare(info.user_email) != 0) { /* only if new index changed */ - ret = rgw_put_system_obj(store, store->svc.zone->get_zone_params().user_email_pool, info.user_email, - link_bl, exclusive, NULL, real_time()); - if (ret < 0) - return ret; - } - } - - if (!info.access_keys.empty()) { - map::iterator iter = info.access_keys.begin(); - for (; iter != info.access_keys.end(); ++iter) { - RGWAccessKey& k = iter->second; - if (old_info && old_info->access_keys.count(iter->first) != 0) - continue; - - ret = rgw_put_system_obj(store, store->svc.zone->get_zone_params().user_keys_pool, k.id, - link_bl, exclusive, NULL, real_time()); - if (ret < 0) - return ret; - } - } - - map::iterator siter; - for (siter = info.swift_keys.begin(); siter != info.swift_keys.end(); ++siter) { - RGWAccessKey& k = siter->second; - if (old_info && old_info->swift_keys.count(siter->first) != 0) - continue; - - ret = rgw_put_system_obj(store, store->svc.zone->get_zone_params().user_swift_pool, k.id, - link_bl, exclusive, NULL, real_time()); - if (ret < 0) - return ret; - } - - return ret; -} - struct user_info_entry { RGWUserInfo info; RGWObjVersionTracker objv_tracker; @@ -2759,40 +2644,6 @@ int RGWUserAdminOp_Caps::remove(RGWRados *store, RGWUserAdminOpState& op_state, return 0; } -struct RGWUserCompleteInfo { - RGWUserInfo info; - map attrs; - bool has_attrs; - - RGWUserCompleteInfo() - : has_attrs(false) - {} - - void dump(Formatter * const f) const { - info.dump(f); - encode_json("attrs", attrs, f); - } - - void decode_json(JSONObj *obj) { - decode_json_obj(info, obj); - has_attrs = JSONDecoder::decode_json("attrs", attrs, obj); - } -}; - -class RGWUserMetadataObject : public RGWMetadataObject { - RGWUserCompleteInfo uci; -public: - RGWUserMetadataObject(const RGWUserCompleteInfo& _uci, obj_version& v, real_time m) - : uci(_uci) { - objv = v; - mtime = m; - } - - void dump(Formatter *f) const override { - uci.dump(f); - } -}; - class RGWUserMetadataHandler : public RGWMetadataHandler { int read_user_info_entry(RGWSI_MetaBackend::Context *ctx, string& entry, @@ -2867,28 +2718,22 @@ public: } int do_put(RGWSI_MetaBackend::Context *ctx, string& entry, - RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker, - RGWMDLogSyncType type) override { - RGWUserInstanceMetadataObject *obj = static_cast(_obj); - RGWUserCompleteInfo uci; - - map *pattrs = NULL; + RGWMetadataObject *obj, + RGWObjVersionTracker& objv_tracker, + RGWMDLogSyncType type) override; + int do_put_checked(RGWSI_MetaBackend::Context *ctx, string& entry, + RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker, + RGWMetadataObject *_old_obj) override { + RGWUserMetadataObject *obj = static_cast(_obj); + RGWUserMetadataObject *old_obj = static_cast(_old_obj); + RGWUserCompleteInfo& uci = obj->get_uci(); + + map *pattrs = nullptr; if (uci.has_attrs) { pattrs = &uci.attrs; } - RGWUserInfo old_info; - real_time orig_mtime; - int ret = read_user_info_entry(ctx, entry, old_info, &objv_tracker, &orig_mtime); - if (ret < 0 && ret != -ENOENT) - return ret; - - // are we actually going to perform this put, or is it too old? - bool exists = (ret != -ENOENT); - if (!check_versions(exists, objv_tracker.read_version, orig_mtime, - objv_tracker.write_version, mtime, sync_mode)) { - return STATUS_NO_APPLY; - } + RGWUserInfo *pold_info = (old_obj ? &old_obj->info : nullptr); ret = store_user_info_entry(ctx, entry, uci.info, &old_info, &objv_tracker, mtime, false, pattrs); if (ret < 0) { @@ -2982,6 +2827,51 @@ public: } }; +class RGWMetadataHandlerPut_User : public RGWMetadataHanderPut_SObj +{ + RGWUserMetadataHandler *handler; + RGWUserEntryMetadataObject *obj; +public: + RGWMetadataHandlerPut_User(RGWUserMetadataHandler *_handler, + RGWSI_MetaBackend::Context *ctx, string& entry, + RGWMetadataObject *_obj, RGWObjVersionTracker& objv_tracker, + RGWMDLogSyncType type) : RGWMetadataHanderPut_SObj(ctx, entry, obj, objv_tracker, type), + handler(_handler) { + obj = static_cast(_obj); + } + + int put_checked(RGWMetadataObject *_old_obj) override; +}; + +int RGWUserMetaHandler::do_put(RGWSI_MetaBackend::Context *ctx, string& entry, + RGWMetadataObject *obj, + RGWObjVersionTracker& objv_tracker, + RGWMDLogSyncType type) +{ + RGWMetadataHandlerPut_User op(this, ctx, entry, obj, objv_tracker, type); + return do_put(&op); +} + +int RGWMetadataHandlerPut_User::put_checked(RGWMetadataObject *_old_obj) +{ + RGWUserMetadataObject *old_obj = static_cast(_old_obj); + RGWUserCompleteInfo& uci = obj->get_uci(); + + map *pattrs = nullptr; + if (uci.has_attrs) { + pattrs = &uci.attrs; + } + + RGWUserInfo *pold_info = (old_obj ? &old_obj->info : nullptr); + + ret = store_user_info_entry(ctx, entry, uci.info, &old_info, &objv_tracker, mtime, false, pattrs); + if (ret < 0) { + return ret; + } + + return STATUS_APPLIED; +} + RGWMetadataHandler *RGWUserMetaHandlerAllocator::alloc() { return new RGWUserMetadataHandler; } diff --git a/src/rgw/rgw_user.h b/src/rgw/rgw_user.h index fc87ddaf698..40992415386 100644 --- a/src/rgw/rgw_user.h +++ b/src/rgw/rgw_user.h @@ -16,6 +16,7 @@ #include "common/Formatter.h" #include "rgw_formats.h" +#include "rgw_metadata.h" #define RGW_USER_ANON_ID "anonymous" @@ -768,13 +769,50 @@ public: RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher); }; -class RGWMetadataManager; +struct RGWUserCompleteInfo { + RGWUserInfo info; + map attrs; + bool has_attrs; + + RGWUserCompleteInfo() + : has_attrs(false) + {} + + void dump(Formatter * const f) const { + info.dump(f); + encode_json("attrs", attrs, f); + } + + void decode_json(JSONObj *obj) { + decode_json_obj(info, obj); + has_attrs = JSONDecoder::decode_json("attrs", attrs, obj); + } +}; + +class RGWUserMetadataObject : public RGWMetadataObject { + RGWUserCompleteInfo uci; +public: + RGWUserMetadataObject(const RGWUserCompleteInfo& _uci, obj_version& v, real_time m) + : uci(_uci) { + objv = v; + mtime = m; + } + + void dump(Formatter *f) const override { + uci.dump(f); + } -extern void rgw_user_init(RGWRados *store); + RGWUserCompleteInfo& get_uci() { + return uci; + } +}; -class RGWBucketMetaHandlerAllocator { +class RGWUserMetaHandlerAllocator { public: static RGWMetadataHandler *alloc(); }; +void rgw_user_init(RGWRados *store); + + #endif diff --git a/src/rgw/services/svc_user.cc b/src/rgw/services/svc_user.cc index cecb99365b8..7c9ee990a24 100644 --- a/src/rgw/services/svc_user.cc +++ b/src/rgw/services/svc_user.cc @@ -96,17 +96,17 @@ int RGWSI_User::User::SetOp::exec() return 0; } -int RGWSI_User::read_user_info(const rgw_user& user, - RGWUserInfo *info, - real_time *pmtime, - RGWObjVersionTracker *objv_tracker, - map *pattrs, - rgw_cache_entry_info *cache_info) +int RGWSI_User::read_user_info_meta(RGWSI_MetaBackend::Context *ctx, + string& entry, + RGWUserInfo& info, + RGWObjVersionTracker * const objv_tracker, + real_time * const pmtime, + rgw_cache_entry_info * const cache_info, + map * const pattrs) { bufferlist bl; RGWUID user_id; - string key = User::get_meta_key(user); RGWSI_MBSObj_GetParams params = { .pmtime = pmtime, .pattrs = pattrs, @@ -120,21 +120,304 @@ int RGWSI_User::read_user_info(const rgw_user& user, auto iter = bl.cbegin(); try { decode(user_id, iter); - if (user_id.user_id.compare(user) != 0) { - lderr(store->ctx()) << "ERROR: " << __func__ << "(): user id mismatch: " << user_id.user_id << " != " << user << dendl; + if (user_id.user_id.to_str().compare(entry) != 0) { + lderr(meta_be->ctx()) << "ERROR: rgw_get_user_info_by_uid(): user id mismatch: " << user_id.user_id.to_str() << " != " << entry << dendl; return -EIO; } if (!iter.end()) { decode(info, iter); } } catch (buffer::error& err) { - ldout(store->ctx(), 0) << "ERROR: failed to decode user info, caught buffer::error" << dendl; + ldout(meta_be->ctx(), 0) << "ERROR: failed to decode user info, caught buffer::error" << dendl; return -EIO; } return 0; } +int RGWSI_User::read_user_info(const rgw_user& user, + RGWUserInfo *info, + real_time *pmtime, + map *pattrs, + RGWObjVersionTracker *objv_tracker, + rgw_cache_entry_info *cache_info) +{ +#warning cache? + string key = User::get_meta_key(user); + RGWUserMetadataObject *meta; + int ret = user_meta_handler->get(key, (RGWMetadataObject **)&meta); + if (ret < 0) { + return ret; + } + + auto& uci = meta->get_uci(); + + if (info) { + *info = std::move(uci.info); + } + + if (pmtime) { + *pmtime = meta->get_mtime(); + } + + if (objv_tracker) { + objv_tracker->read_version = meta->get_version(); + } + + delete meta; + + return 0; +} + +class RGWMetaPut_User +{ + RGWSI_MetaBackend::Context *ctx; + string& entry; + RGWUserInfo& info; + RGWUserInfo *old_info; + RGWObjVersionTracker *objv_tracker; + real_time& mtime; + bool exclusive; + map *pattrs; + + RGWMetaPut_User(RGWSI_MetaBackend::Context *ctx, + string& entry, + RGWUserInfo& info, + RGWUserInfo *old_info, + RGWObjVersionTracker *objv_tracker, + real_time& mtime, + bool exclusive, + map *pattrs) : + ctx(ctx), entry(entry), + info(info), old_info(old_info), + objv_tracker(objv_tracker), mtime(mtime), + exclusive(exclusive), pattrs(patts) {} + + int prepare() { + int ret; + RGWObjVersionTracker ot; + + if (objv_tracker) { + ot = *objv_tracker; + } + + if (ot.write_version.tag.empty()) { + if (ot.read_version.tag.empty()) { + ot.generate_new_write_ver(store->ctx()); + } else { + ot.write_version = ot.read_version; + ot.write_version.ver++; + } + } + + map::iterator iter; + for (iter = info.swift_keys.begin(); iter != info.swift_keys.end(); ++iter) { + if (old_info && old_info->swift_keys.count(iter->first) != 0) + continue; + RGWAccessKey& k = iter->second; + /* check if swift mapping exists */ + RGWUserInfo inf; + int r = do_get_user_info_by_swift(meta_be, ctx, k.id, inf); + if (r >= 0 && inf.user_id.compare(info.user_id) != 0) { + ldout(store->ctx(), 0) << "WARNING: can't store user info, swift id (" << k.id + << ") already mapped to another user (" << info.user_id << ")" << dendl; + return -EEXIST; + } + } + + if (!info.access_keys.empty()) { + /* check if access keys already exist */ + RGWUserInfo inf; + map::iterator iter = info.access_keys.begin(); + for (; iter != info.access_keys.end(); ++iter) { + RGWAccessKey& k = iter->second; + if (old_info && old_info->access_keys.count(iter->first) != 0) + continue; + int r = do_get_user_info_by_access_key(meta_be, ctx, k.id, inf); + if (r >= 0 && inf.user_id.compare(info.user_id) != 0) { + ldout(store->ctx(), 0) << "WARNING: can't store user info, access key already mapped to another user" << dendl; + return -EEXIST; + } + } + } + + return 0; + } + + int put() { + RGWUID ui; + ui.user_id = info.user_id; + + bufferlist link_bl; + encode(ui, link_bl); + + bufferlist data_bl; + encode(ui, data_bl); + encode(info, data_bl); + + string key; + info.user_id.to_str(key); + + ret = svc.meta_be->put_entry(key, data_bl, exclusive, &ot, mtime, pattrs); + if (ret < 0) + return ret; + + return 0; + } + + int complete() { + if (!info.user_email.empty()) { + if (!old_info || + old_info->user_email.compare(info.user_email) != 0) { /* only if new index changed */ + ret = rgw_put_system_obj(store, store->svc.zone->get_zone_params().user_email_pool, info.user_email, + link_bl, exclusive, NULL, real_time()); + if (ret < 0) + return ret; + } + } + + if (!info.access_keys.empty()) { + map::iterator iter = info.access_keys.begin(); + for (; iter != info.access_keys.end(); ++iter) { + RGWAccessKey& k = iter->second; + if (old_info && old_info->access_keys.count(iter->first) != 0) + continue; + + ret = rgw_put_system_obj(store, store->svc.zone->get_zone_params().user_keys_pool, k.id, + link_bl, exclusive, NULL, real_time()); + if (ret < 0) + return ret; + } + } + + map::iterator siter; + for (siter = info.swift_keys.begin(); siter != info.swift_keys.end(); ++siter) { + RGWAccessKey& k = siter->second; + if (old_info && old_info->swift_keys.count(siter->first) != 0) + continue; + + ret = rgw_put_system_obj(store, store->svc.zone->get_zone_params().user_swift_pool, k.id, + link_bl, exclusive, NULL, real_time()); + if (ret < 0) + return ret; + } + + return 0; + } +}; + +int RGWSI_User::store_user_info_meta(RGWSI_MetaBackend::Context *ctx, + string& entry, + RGWUserInfo& info, + RGWUserInfo *old_info, + RGWObjVersionTracker *objv_tracker, + real_time& mtime, + bool exclusive, + map *pattrs) +{ + int ret; + RGWObjVersionTracker ot; + + if (objv_tracker) { + ot = *objv_tracker; + } + + if (ot.write_version.tag.empty()) { + if (ot.read_version.tag.empty()) { + ot.generate_new_write_ver(store->ctx()); + } else { + ot.write_version = ot.read_version; + ot.write_version.ver++; + } + } + + map::iterator iter; + for (iter = info.swift_keys.begin(); iter != info.swift_keys.end(); ++iter) { + if (old_info && old_info->swift_keys.count(iter->first) != 0) + continue; + RGWAccessKey& k = iter->second; + /* check if swift mapping exists */ + RGWUserInfo inf; + int r = do_get_user_info_by_swift(meta_be, ctx, k.id, inf); + if (r >= 0 && inf.user_id.compare(info.user_id) != 0) { + ldout(store->ctx(), 0) << "WARNING: can't store user info, swift id (" << k.id + << ") already mapped to another user (" << info.user_id << ")" << dendl; + return -EEXIST; + } + } + + if (!info.access_keys.empty()) { + /* check if access keys already exist */ + RGWUserInfo inf; + map::iterator iter = info.access_keys.begin(); + for (; iter != info.access_keys.end(); ++iter) { + RGWAccessKey& k = iter->second; + if (old_info && old_info->access_keys.count(iter->first) != 0) + continue; + int r = do_get_user_info_by_access_key(meta_be, ctx, k.id, inf); + if (r >= 0 && inf.user_id.compare(info.user_id) != 0) { + ldout(store->ctx(), 0) << "WARNING: can't store user info, access key already mapped to another user" << dendl; + return -EEXIST; + } + } + } + + RGWUID ui; + ui.user_id = info.user_id; + + bufferlist link_bl; + encode(ui, link_bl); + + bufferlist data_bl; + encode(ui, data_bl); + encode(info, data_bl); + + string key; + info.user_id.to_str(key); + + ret = svc.meta_be->put_entry(key, data_bl, exclusive, &ot, mtime, pattrs); + if (ret < 0) + return ret; + + if (!info.user_email.empty()) { + if (!old_info || + old_info->user_email.compare(info.user_email) != 0) { /* only if new index changed */ + ret = rgw_put_system_obj(store, store->svc.zone->get_zone_params().user_email_pool, info.user_email, + link_bl, exclusive, NULL, real_time()); + if (ret < 0) + return ret; + } + } + + if (!info.access_keys.empty()) { + map::iterator iter = info.access_keys.begin(); + for (; iter != info.access_keys.end(); ++iter) { + RGWAccessKey& k = iter->second; + if (old_info && old_info->access_keys.count(iter->first) != 0) + continue; + + ret = rgw_put_system_obj(store, store->svc.zone->get_zone_params().user_keys_pool, k.id, + link_bl, exclusive, NULL, real_time()); + if (ret < 0) + return ret; + } + } + + map::iterator siter; + for (siter = info.swift_keys.begin(); siter != info.swift_keys.end(); ++siter) { + RGWAccessKey& k = siter->second; + if (old_info && old_info->swift_keys.count(siter->first) != 0) + continue; + + ret = rgw_put_system_obj(store, store->svc.zone->get_zone_params().user_swift_pool, k.id, + link_bl, exclusive, NULL, real_time()); + if (ret < 0) + return ret; + } + + return ret; +} + int RGWSI_User::store_user_info(RGWUserInfo& user_info, bool exclusive, map& attrs, RGWObjVersionTracker *objv_tracker, @@ -144,7 +427,7 @@ int RGWSI_User::store_user_info(RGWUserInfo& user_info, bool exclusive, auto apply_type = (exclusive ? APPLY_EXCLUSIVE : APPLY_ALWAYS); RGWUserCompleteInfo bci{user_info, attrs}; RGWUserMetadataObject mdo(bci, objv_tracker->write_version, mtime); - return user_meta_handler->mutate(entry, &mdo, *objv_tracker, apply_type); + return user_meta_handler->put(entry, &mdo, *objv_tracker, apply_type); } int RGWSI_User::remove_user_info(const rgw_user& user, diff --git a/src/rgw/services/svc_user.h b/src/rgw/services/svc_user.h index a43a5c719e1..f5ab424d1c6 100644 --- a/src/rgw/services/svc_user.h +++ b/src/rgw/services/svc_user.h @@ -41,6 +41,7 @@ class RGWSI_User : public RGWServiceInstance RGWSI_SysObj *sysobj{nullptr}; RGWSI_SysObj_Cache *cache{nullptr}; RGWSI_Meta *meta{nullptr}; + RGWSI_SyncModules *sync_modules{nullptr}; } svc; RGWMetadataHandler *user_meta_handler; @@ -54,6 +55,22 @@ class RGWSI_User : public RGWServiceInstance using RGWChainedCacheImpl_user_info_cache_entry = RGWChainedCacheImpl; unique_ptr uinfo_cache; + int read_user_info_meta(RGWSI_MetaBackend::Context *ctx, + string& entry, + RGWUserInfo& info, + RGWObjVersionTracker * const objv_tracker, + real_time * const pmtime, + rgw_cache_entry_info * const cache_info, + map * const pattrs); + int store_user_info_meta(RGWSI_MetaBackend::Context *ctx, + string& entry, + RGWUserInfo& info, + RGWUserInfo *old_info, + RGWObjVersionTracker *objv_tracker, + real_time& mtime, + bool exclusive, + map *pattrs); + int do_start() override; public: RGWSI_User(CephContext *cct); @@ -170,8 +187,8 @@ public: int read_user_info(const rgw_user& user, RGWUserInfo *info, real_time *pmtime, - RGWObjVersionTracker *objv_tracker, map *pattrs, + RGWObjVersionTracker *objv_tracker, rgw_cache_entry_info *cache_info); int store_user_info(RGWUserInfo& user_info, bool exclusive, map& attrs, -- 2.39.5