From bdf53ab3c383513ff579e278693a35314dd7a0b2 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Wed, 16 Nov 2016 16:20:17 -0800 Subject: [PATCH] rgw: clean rgw_obj Instead of storing the oid and the name, just store the name and calculate it when needed (same goes to locator). Also give more coherent names to the various fields. Signed-off-by: Yehuda Sadeh --- src/rgw/rgw_admin.cc | 4 +- src/rgw/rgw_bucket.cc | 8 +- src/rgw/rgw_common.h | 229 ++++++++++++++++--------------------- src/rgw/rgw_gc.cc | 8 +- src/rgw/rgw_json_enc.cc | 4 +- src/rgw/rgw_orphan.cc | 4 +- src/rgw/rgw_rados.cc | 42 ++++--- src/rgw/rgw_rados.h | 4 +- src/rgw/rgw_rest_client.cc | 4 +- 9 files changed, 143 insertions(+), 164 deletions(-) diff --git a/src/rgw/rgw_admin.cc b/src/rgw/rgw_admin.cc index a2a65477b96eb..00eaf47ad3f3a 100644 --- a/src/rgw/rgw_admin.cc +++ b/src/rgw/rgw_admin.cc @@ -1293,9 +1293,9 @@ int set_user_quota(int opt_cmd, RGWUser& user, RGWUserAdminOpState& op_state, in static bool bucket_object_check_filter(const string& name) { string ns; - string obj = name; + string obj; string instance; - return rgw_obj::translate_raw_obj_to_obj_in_ns(obj, instance, ns); + return rgw_obj::translate_oid_to_obj_in_ns(name, obj, instance, ns); } int check_min_obj_stripe_size(RGWRados *store, RGWBucketInfo& bucket_info, rgw_obj& obj, uint64_t min_stripe_size, bool *need_rewrite) diff --git a/src/rgw/rgw_bucket.cc b/src/rgw/rgw_bucket.cc index 508cd0cfd92a7..966c8ea34ec1c 100644 --- a/src/rgw/rgw_bucket.cc +++ b/src/rgw/rgw_bucket.cc @@ -496,12 +496,12 @@ void check_bad_user_bucket_mapping(RGWRados *store, const rgw_user& user_id, } while (!done); } -static bool bucket_object_check_filter(const string& name) +static bool bucket_object_check_filter(const string& oid) { string ns; string ver; - string obj = name; - return rgw_obj::translate_raw_obj_to_obj_in_ns(obj, ns, ver); + string name; + return rgw_obj::translate_oid_to_obj_in_ns(oid, name, ns, ver); } int rgw_remove_object(RGWRados *store, RGWBucketInfo& bucket_info, rgw_bucket& bucket, rgw_obj_key& key) @@ -650,7 +650,7 @@ int rgw_remove_bucket_bypass_gc(RGWRados *store, rgw_bucket& bucket, ret = store->get_obj_state(&obj_ctx, obj, &astate, false); if (ret == -ENOENT) { - dout(1) << "WARNING: cannot find obj state for obj " << obj.get_object() << dendl; + dout(1) << "WARNING: cannot find obj state for obj " << obj.get_oid() << dendl; continue; } if (ret < 0) { diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index c1f968f90fe71..bac7019f39a14 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -1650,90 +1650,67 @@ struct RGWBucketEnt { }; WRITE_CLASS_ENCODER(RGWBucketEnt) -class rgw_obj { - std::string orig_obj; - std::string loc; - std::string object; - std::string instance; -public: - const std::string& get_object() const { return object; } - const std::string& get_orig_obj() const { return orig_obj; } - const std::string& get_loc() const { return loc; } - const std::string& get_instance() const { return instance; } +struct rgw_obj { rgw_bucket bucket; - std::string placement_id; std::string ns; + std::string name; + std::string instance; + std::string placement_id; + + bool in_extra_data{false}; /* in-memory only member, does not serialize */ - bool in_extra_data; /* in-memory only member, does not serialize */ + const std::string& get_name() const { return name; } + const std::string& get_instance() const { return instance; } // Represents the hash index source for this object once it is set (non-empty) std::string index_hash_source; - rgw_obj() : in_extra_data(false) {} - rgw_obj(const rgw_bucket& b, const std::string& o) : in_extra_data(false) { - init(b, o); + rgw_obj() {} + rgw_obj(const rgw_bucket& b, const std::string& name) { + init(b, name); } rgw_obj(const rgw_bucket& b, const rgw_obj_key& k) : in_extra_data(false) { from_index_key(b, k); } - void init(const rgw_bucket& b, const std::string& o) { + void init(const rgw_bucket& b, const std::string& name) { bucket = b; - set_obj(o); - reset_loc(); + set_name(name); } - void init_ns(const rgw_bucket& b, const std::string& o, const std::string& n) { + void init_ns(const rgw_bucket& b, const std::string& name, const std::string& n) { bucket = b; set_ns(n); - set_obj(o); - reset_loc(); - } - int set_ns(const char *n) { - if (!n) - return -EINVAL; - string ns_str(n); - return set_ns(ns_str); + set_name(name); } - int set_ns(const string& n) { - if (n[0] == '_') - return -EINVAL; + void set_ns(const string& n) { ns = n; - set_obj(orig_obj); - return 0; } - int set_instance(const string& i) { - if (i[0] == '_') - return -EINVAL; + void set_instance(const string& i) { instance = i; - set_obj(orig_obj); - return 0; - } - - int clear_instance() { - return set_instance(string()); } - void set_loc(const string& k) { - loc = k; + void clear_instance() { + instance.clear(); } - void reset_loc() { - loc.clear(); + string get_loc() const { /* * For backward compatibility. Older versions used to have object locator on all objects, - * however, the orig_obj was the effective object locator. This had the same effect as not + * however, the name was the effective object locator. This had the same effect as not * having object locator at all for most objects but the ones that started with underscore as * these were escaped. */ - if (orig_obj[0] == '_' && ns.empty()) { - loc = orig_obj; + if (name[0] == '_' && ns.empty()) { + return name; } + + return string(); } bool empty() const { - return object.empty(); + return name.empty(); } - bool have_null_instance() { + bool have_null_instance() const { return instance == "null"; } @@ -1741,34 +1718,30 @@ public: return !instance.empty(); } - bool need_to_encode_instance() { + bool need_to_encode_instance() const { return have_instance() && !have_null_instance(); } - void set_obj(const string& o) { - object.reserve(128); + void set_name(const string& n) { + name = n; + } - orig_obj = o; + string get_oid() const { if (ns.empty() && !need_to_encode_instance()) { - if (o.empty()) { - return; - } - if (o.size() < 1 || o[0] != '_') { - object = o; - return; - } - object = "_"; - object.append(o); - } else { - object = "_"; - object.append(ns); - if (need_to_encode_instance()) { - object.append(string(":") + instance); + if (name.size() < 1 || name[0] != '_') { + return name; } - object.append("_"); - object.append(o); + return string("_") + name; } - reset_loc(); + + string oid = "_"; + oid.append(ns); + if (need_to_encode_instance()) { + oid.append(string(":") + instance); + } + oid.append("_"); + oid.append(name); + return oid; } /* @@ -1776,15 +1749,15 @@ public: */ string get_index_key_name() const { if (ns.empty()) { - if (orig_obj.size() < 1 || orig_obj[0] != '_') { - return orig_obj; + if (name.size() < 1 || name[0] != '_') { + return name; } - return string("_") + orig_obj; + return string("_") + name; }; char buf[ns.size() + 16]; snprintf(buf, sizeof(buf), "_%s_", ns.c_str()); - return string(buf) + orig_obj; + return string(buf) + name; }; void from_index_key(const rgw_bucket& b, const rgw_obj_key& key) { @@ -1826,7 +1799,7 @@ public: } const string& get_hash_object() const { - return index_hash_source.empty() ? orig_obj : index_hash_source; + return index_hash_source.empty() ? name : index_hash_source; } /** * Translate a namespace-mangled object name to the user-facing name @@ -1836,8 +1809,8 @@ public: * and cuts down the name to the unmangled version. If it is not * part of the given namespace, it returns false. */ - static bool translate_raw_obj_to_obj_in_ns(string& obj, string& instance, string& ns) { - if (obj[0] != '_') { + static bool translate_oid_to_obj_in_ns(const string& oid, string& name, string& instance, string& ns) { + if (oid[0] != '_') { if (ns.empty()) { return true; } @@ -1845,7 +1818,7 @@ public: } string obj_ns; - bool ret = parse_raw_oid(obj, &obj, &instance, &obj_ns); + bool ret = parse_raw_oid(oid, &name, &instance, &obj_ns); if (!ret) { return ret; } @@ -1888,30 +1861,30 @@ public: * It returns true after successfully doing so, or * false if it fails. */ - static bool strip_namespace_from_object(string& obj, string& ns, string& instance) { + static bool strip_namespace_from_name(string& name, string& ns, string& instance) { ns.clear(); instance.clear(); - if (obj[0] != '_') { + if (name[0] != '_') { return true; } - size_t pos = obj.find('_', 1); + size_t pos = name.find('_', 1); if (pos == string::npos) { return false; } - if (obj[1] == '_') { - obj = obj.substr(1); + if (name[1] == '_') { + name = name.substr(1); return true; } - size_t period_pos = obj.find('.'); + size_t period_pos = name.find('.'); if (period_pos < pos) { return false; } - ns = obj.substr(1, pos-1); - obj = obj.substr(pos+1, string::npos); + ns = name.substr(1, pos-1); + name = name.substr(pos+1, string::npos); parse_ns_field(ns, instance); return true; @@ -1926,44 +1899,47 @@ public: } void encode(bufferlist& bl) const { - ENCODE_START(5, 3, bl); - ::encode(bucket.name, bl); - ::encode(loc, bl); - ::encode(ns, bl); - ::encode(object, bl); + ENCODE_START(6, 6, bl); ::encode(bucket, bl); + ::encode(ns, bl); + ::encode(name, bl); ::encode(instance, bl); - if (!ns.empty() || !instance.empty()) { - ::encode(orig_obj, bl); - } + ::encode(placement_id, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { - DECODE_START_LEGACY_COMPAT_LEN(5, 3, 3, bl); - ::decode(bucket.name, bl); - ::decode(loc, bl); - ::decode(ns, bl); - ::decode(object, bl); - if (struct_v >= 2) - ::decode(bucket, bl); - if (struct_v >= 4) - ::decode(instance, bl); - if (ns.empty() && instance.empty()) { - if (object[0] != '_') { - orig_obj = object; - } else { - orig_obj = object.substr(1); - } - } else { - if (struct_v >= 5) { - ::decode(orig_obj, bl); + DECODE_START_LEGACY_COMPAT_LEN(6, 3, 3, bl); + if (struct_v < 6) { + string s; + ::decode(bucket.name, bl); /* bucket.name */ + ::decode(s, bl); /* loc */ + ::decode(ns, bl); + ::decode(name, bl); + if (struct_v >= 2) + ::decode(bucket, bl); + if (struct_v >= 4) + ::decode(instance, bl); + if (ns.empty() && instance.empty()) { + if (name[0] == '_') { + name = name.substr(1); + } } else { - ssize_t pos = object.find('_', 1); - if (pos < 0) { - throw buffer::error(); + if (struct_v >= 5) { + ::decode(name, bl); + } else { + ssize_t pos = name.find('_', 1); + if (pos < 0) { + throw buffer::error(); + } + name = name.substr(pos); } - orig_obj = object.substr(pos); } + } else { + ::decode(bucket, bl); + ::decode(ns, bl); + ::decode(name, bl); + ::decode(instance, bl); + ::decode(placement_id, bl); } DECODE_FINISH(bl); } @@ -1971,22 +1947,19 @@ public: static void generate_test_instances(list& o); bool operator==(const rgw_obj& o) const { - return (object.compare(o.object) == 0) && - (bucket.name.compare(o.bucket.name) == 0) && + return (name.compare(o.name) == 0) && + (bucket == o.bucket) && (ns.compare(o.ns) == 0) && - (instance.compare(o.instance) == 0); + (instance.compare(o.instance) == 0); /* should not compare placement_id */ } bool operator<(const rgw_obj& o) const { - int r = bucket.name.compare(o.bucket.name); + int r = name.compare(o.name); if (r == 0) { - r = bucket.bucket_id.compare(o.bucket.bucket_id); + r = bucket.bucket_id.compare(o.bucket.bucket_id); /* not comparing bucket.name, if bucket_id is equal so will be bucket.name */ if (r == 0) { - r = object.compare(o.object); + r = ns.compare(o.ns); if (r == 0) { - r = ns.compare(o.ns); - if (r == 0) { - r = instance.compare(o.instance); - } + r = instance.compare(o.instance); } } } @@ -2011,7 +1984,7 @@ struct rgw_cache_entry_info { }; inline ostream& operator<<(ostream& out, const rgw_obj &o) { - return out << o.bucket.name << ":" << o.get_object(); + return out << o.bucket.name << ":" << o.get_oid(); } static inline void buf_to_hex(const unsigned char *buf, int len, char *str) diff --git a/src/rgw/rgw_gc.cc b/src/rgw/rgw_gc.cc index c9251141f2ee9..6f1dd44802869 100644 --- a/src/rgw/rgw_gc.cc +++ b/src/rgw/rgw_gc.cc @@ -197,18 +197,18 @@ int RGWGC::process(int index, int max_secs) ctx->locator_set_key(obj.loc); rgw_obj key_obj; - key_obj.set_obj(obj.key.name); + key_obj.set_name(obj.key.name); key_obj.set_instance(obj.key.instance); - dout(0) << "gc::process: removing " << obj.pool << ":" << key_obj.get_object() << dendl; + dout(0) << "gc::process: removing " << obj.pool << ":" << key_obj.get_oid() << dendl; ObjectWriteOperation op; cls_refcount_put(op, info.tag, true); - ret = ctx->operate(key_obj.get_object(), &op); + ret = ctx->operate(key_obj.get_oid(), &op); if (ret == -ENOENT) ret = 0; if (ret < 0) { remove_tag = false; - dout(0) << "failed to remove " << obj.pool << ":" << key_obj.get_object() << "@" << obj.loc << dendl; + dout(0) << "failed to remove " << obj.pool << ":" << key_obj.get_oid() << "@" << obj.loc << dendl; } if (going_down()) // leave early, even if tag isn't removed, it's ok diff --git a/src/rgw/rgw_json_enc.cc b/src/rgw/rgw_json_enc.cc index afe1631c9ed9f..bb274fd3aa17d 100644 --- a/src/rgw/rgw_json_enc.cc +++ b/src/rgw/rgw_json_enc.cc @@ -814,11 +814,9 @@ void rgw_raw_obj::decode_json(JSONObj *obj) { void rgw_obj::dump(Formatter *f) const { encode_json("bucket", bucket, f); - encode_json("key", loc, f); encode_json("ns", ns, f); - encode_json("object", object, f); + encode_json("name", name, f); encode_json("instance", instance, f); - encode_json("orig_obj", orig_obj, f); } void RGWDefaultSystemMetaObjInfo::dump(Formatter *f) const { diff --git a/src/rgw/rgw_orphan.cc b/src/rgw/rgw_orphan.cc index e32a03f41f9ce..fa04badf152a3 100644 --- a/src/rgw/rgw_orphan.cc +++ b/src/rgw/rgw_orphan.cc @@ -41,7 +41,7 @@ static string obj_fingerprint(const string& oid, const char *force_ns = NULL) rgw_obj new_obj(b, obj_name); new_obj.set_ns(force_ns); new_obj.set_instance(obj_instance); - s = obj_marker + "_" + new_obj.get_object(); + s = obj_marker + "_" + new_obj.get_oid(); } /* cut out suffix */ @@ -424,7 +424,7 @@ int RGWOrphanSearch::handle_stat_result(map >& oids, RGWRados: set obj_oids; rgw_bucket& bucket = result.obj.bucket; if (!result.has_manifest) { /* a very very old object, or part of a multipart upload during upload */ - const string loc = bucket.bucket_id + "_" + result.obj.get_object(); + const string loc = bucket.bucket_id + "_" + result.obj.get_oid(); obj_oids.insert(obj_fingerprint(loc)); /* diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index 132b9469762d8..84da096835e77 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -5154,7 +5154,7 @@ int RGWRados::Bucket::List::list_objects(int max, vector *result, const bool cur_end_marker_valid = !params.end_marker.empty(); prefix_obj.set_ns(params.ns); - prefix_obj.set_obj(params.prefix); + prefix_obj.set_name(params.prefix); string cur_prefix = prefix_obj.get_index_key_name(); string bigger_than_delim; @@ -6008,7 +6008,7 @@ int RGWRados::fix_tail_obj_locator(rgw_bucket& bucket, rgw_obj_key& key, bool fi } string bad_loc; - prepend_bucket_marker(bucket, loc.get_orig_obj(), bad_loc); + prepend_bucket_marker(bucket, loc.get_name(), bad_loc); /* create a new ioctx with the bad locator */ librados::IoCtx src_ioctx; @@ -6152,7 +6152,7 @@ int RGWRados::swift_versioning_copy(RGWObjectCtx& obj_ctx, string client_id; string op_id; - const string& src_name = obj.get_object(); + const string& src_name = obj.get_oid(); char buf[src_name.size() + 32]; struct timespec ts = ceph::real_clock::to_timespec(state->mtime); snprintf(buf, sizeof(buf), "%03x%s/%lld.%06ld", (int)src_name.size(), @@ -6314,7 +6314,7 @@ int RGWRados::swift_versioning_restore(RGWObjectCtx& obj_ctx, return ret; }; - const std::string& obj_name = obj.get_object(); + const std::string& obj_name = obj.get_oid(); const auto prefix = boost::str(boost::format("%03x%s") % obj_name.size() % obj_name); @@ -6352,7 +6352,7 @@ int RGWRados::Object::Write::_do_write_meta(uint64_t size, uint64_t accounted_si rgw_obj& obj = target->get_obj(); - if (obj.get_object().empty()) { + if (obj.get_oid().empty()) { ldout(store->ctx(), 0) << "ERROR: " << __func__ << "(): cannot write object with empty name" << dendl; return -EIO; } @@ -7131,7 +7131,7 @@ int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx, set_mtime_weight.high_precision = high_precision_time; RGWPutObjProcessor_Atomic processor(obj_ctx, - dest_bucket_info, dest_obj.bucket, dest_obj.get_orig_obj(), + dest_bucket_info, dest_obj.bucket, dest_obj.get_name(), cct->_conf->rgw_obj_stripe_size, tag, dest_bucket_info.versioning_enabled()); const string& instance = dest_obj.get_instance(); if (instance != "null") { @@ -7165,7 +7165,7 @@ int RGWRados::fetch_remote_obj(RGWObjectCtx& obj_ctx, conn = iter->second; } - string obj_name = dest_obj.bucket.name + "/" + dest_obj.get_object(); + string obj_name = dest_obj.bucket.name + "/" + dest_obj.get_oid(); RGWOpStateSingleOp *opstate = NULL; @@ -7449,7 +7449,7 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx, bool remote_src; bool remote_dest; - append_rand_alpha(cct, dest_obj.get_object(), shadow_oid, 32); + append_rand_alpha(cct, dest_obj.get_oid(), shadow_oid, 32); shadow_obj.init_ns(dest_obj.bucket, shadow_oid, shadow_ns); remote_dest = !get_zonegroup().equals(dest_bucket_info.zonegroup); @@ -7460,7 +7460,7 @@ int RGWRados::copy_obj(RGWObjectCtx& obj_ctx, return -EINVAL; } - ldout(cct, 5) << "Copy object " << src_obj.bucket << ":" << src_obj.get_object() << " => " << dest_obj.bucket << ":" << dest_obj.get_object() << dendl; + ldout(cct, 5) << "Copy object " << src_obj.bucket << ":" << src_obj.get_oid() << " => " << dest_obj.bucket << ":" << dest_obj.get_oid() << dendl; if (remote_src || !source_zone.empty()) { return fetch_remote_obj(obj_ctx, user_id, client_id, op_id, true, info, source_zone, @@ -7708,7 +7708,7 @@ int RGWRados::copy_obj_data(RGWObjectCtx& obj_ctx, append_rand_alpha(cct, tag, tag, 32); RGWPutObjProcessor_Atomic processor(obj_ctx, - dest_bucket_info, dest_obj.bucket, dest_obj.get_object(), + dest_bucket_info, dest_obj.bucket, dest_obj.get_oid(), cct->_conf->rgw_obj_stripe_size, tag, dest_bucket_info.versioning_enabled()); if (version_id) { processor.set_version_id(*version_id); @@ -7842,7 +7842,9 @@ int RGWRados::delete_bucket(RGWBucketInfo& bucket_info, RGWObjVersionTracker& ob for (eiter = ent_map.begin(); eiter != ent_map.end(); ++eiter) { obj = eiter->second.key; - if (rgw_obj::translate_raw_obj_to_obj_in_ns(obj.name, instance, ns)) + /* obj.name actually contains index key that is formatted similar to oid */ + + if (rgw_obj::translate_oid_to_obj_in_ns(obj.name, obj.name, instance, ns)) return -ENOTEMPTY; } } while (is_truncated); @@ -12223,20 +12225,26 @@ int RGWRados::check_disk_state(librados::IoCtx io_ctx, uint8_t suggest_flag = (get_zone().log_data ? CEPH_RGW_DIR_SUGGEST_LOG_OP : 0); rgw_obj obj; - std::string oid, instance, loc, ns; + std::string name, instance, loc, ns; rgw_obj_key key; key.set(list_state.key); - oid = key.name; - if (!rgw_obj::strip_namespace_from_object(oid, ns, instance)) { + name = key.name; + if (!rgw_obj::strip_namespace_from_name(name, ns, instance)) { // well crap assert(0 == "got bad object name off disk"); } - obj.init(bucket, oid); - obj.set_loc(list_state.locator); + obj.init(bucket, name); obj.set_ns(ns); obj.set_instance(key.instance); + + string oid; get_obj_bucket_and_oid_loc(obj, oid, loc); - io_ctx.locator_set_key(loc); + + if (loc != list_state.locator) { + ldout(cct, 0) << "WARNING: generated locator (" << loc << ") is different from listed locator (" << list_state.locator << ")" << dendl; + } + + io_ctx.locator_set_key(list_state.locator); RGWObjState *astate = NULL; RGWObjectCtx rctx(this); diff --git a/src/rgw/rgw_rados.h b/src/rgw/rgw_rados.h index a70dc2286e09c..41baf4f193362 100644 --- a/src/rgw/rgw_rados.h +++ b/src/rgw/rgw_rados.h @@ -67,7 +67,7 @@ static inline void prepend_bucket_marker(const rgw_bucket& bucket, const string& static inline void get_obj_bucket_and_oid_loc(const rgw_obj& obj, string& oid, string& locator) { const rgw_bucket& bucket = obj.bucket; - prepend_bucket_marker(bucket, obj.get_object(), oid); + prepend_bucket_marker(bucket, obj.get_oid(), oid); const string& loc = obj.get_loc(); if (!loc.empty()) { prepend_bucket_marker(bucket, loc, locator); @@ -498,7 +498,7 @@ public: * when the explicit objs manifest was around, and it got copied. */ rgw_obj& obj_0 = objs[0].loc; - if (!obj_0.get_object().empty() && obj_0.ns.empty()) { + if (!obj_0.get_oid().empty() && obj_0.ns.empty()) { objs[0].loc = obj; objs[0].size = head_size; } diff --git a/src/rgw/rgw_rest_client.cc b/src/rgw/rgw_rest_client.cc index 907640a98403e..9bbb4f7453b77 100644 --- a/src/rgw/rgw_rest_client.cc +++ b/src/rgw/rgw_rest_client.cc @@ -428,7 +428,7 @@ static void add_grants_headers(map& grants, map& attrs) { - string resource = obj.bucket.name + "/" + obj.get_object(); + string resource = obj.bucket.name + "/" + obj.get_oid(); string new_url = url; if (new_url[new_url.size() - 1] != '/') new_url.append("/"); @@ -619,7 +619,7 @@ int RGWRESTStreamRWRequest::get_obj(RGWAccessKey& key, map& extr { string urlsafe_bucket, urlsafe_object; url_encode(obj.bucket.get_key(':', 0), urlsafe_bucket); - url_encode(obj.get_orig_obj(), urlsafe_object); + url_encode(obj.get_name(), urlsafe_object); string resource = urlsafe_bucket + "/" + urlsafe_object; return get_resource(key, extra_headers, resource); -- 2.39.5