cout << " --read-only set zone as read-only (when adding to zonegroup)\n";
cout << " --redirect-zone specify zone id to redirect when response is 404 (not found)\n";
cout << " --placement-id placement id for zonegroup placement commands\n";
+ cout << " --storage-class storage class for zonegroup placement commands\n";
cout << " --tags=<list> list of tags for zonegroup placement add and modify commands\n";
cout << " --tags-add=<list> list of tags to add for zonegroup placement modify command\n";
cout << " --tags-rm=<list> list of tags to remove for zonegroup placement modify command\n";
string quota_scope;
string object_version;
string placement_id;
+ string storage_class;
list<string> tags;
list<string> tags_add;
list<string> tags_rm;
zonegroup_new_name = val;
} else if (ceph_argparse_witharg(args, i, &val, "--placement-id", (char*)NULL)) {
placement_id = val;
+ } else if (ceph_argparse_witharg(args, i, &val, "--storage-class", (char*)NULL)) {
+ storage_class = val;
} else if (ceph_argparse_witharg(args, i, &val, "--tags", (char*)NULL)) {
get_str_list(val, tags);
} else if (ceph_argparse_witharg(args, i, &val, "--tags-add", (char*)NULL)) {
return EINVAL;
}
+ rgw_placement_rule rule;
+ rule.from_str(placement_id);
+
+ if (!rule.storage_class.empty() && !storage_class.empty() &&
+ rule.storage_class != storage_class) {
+ cerr << "ERROR: provided contradicting storage class configuration" << std::endl;
+ return EINVAL;
+ } else if (rule.storage_class.empty()) {
+ rule.storage_class = storage_class;
+ }
+
RGWZoneGroup zonegroup(zonegroup_id, zonegroup_name);
int ret = zonegroup.init(g_ceph_context, store->svc.sysobj);
if (ret < 0) {
return -ret;
}
- if (opt_cmd == OPT_ZONEGROUP_PLACEMENT_ADD) {
- RGWZoneGroupPlacementTarget target;
- target.name = placement_id;
- for (auto& t : tags) {
- target.tags.insert(t);
- }
- zonegroup.placement_targets[placement_id] = target;
- } else if (opt_cmd == OPT_ZONEGROUP_PLACEMENT_MODIFY) {
+ if (opt_cmd == OPT_ZONEGROUP_PLACEMENT_ADD ||
+ opt_cmd == OPT_ZONEGROUP_PLACEMENT_MODIFY) {
RGWZoneGroupPlacementTarget& target = zonegroup.placement_targets[placement_id];
if (!tags.empty()) {
target.tags.clear();
for (auto& t : tags_add) {
target.tags.insert(t);
}
+ target.storage_classes.insert(rule.get_storage_class());
} else if (opt_cmd == OPT_ZONEGROUP_PLACEMENT_RM) {
zonegroup.placement_targets.erase(placement_id);
} else if (opt_cmd == OPT_ZONEGROUP_PLACEMENT_DEFAULT) {
<< placement_id << "'" << std::endl;
return -ENOENT;
}
- zonegroup.default_placement = placement_id;
+ zonegroup.default_placement = rule;
}
zonegroup.post_process_params();
RGWZonePlacementInfo& info = zone.placement_pools[placement_id];
info.index_pool = *index_pool;
- info.data_pool = *data_pool;
+ if (storage_class.empty()) {
+ info.data_pools[RGW_STORAGE_CLASS_STANDARD] = *data_pool;
+ } else {
+ info.data_pools[storage_class] = *data_pool;
+ }
if (data_extra_pool) {
info.data_extra_pool = *data_extra_pool;
}
info.index_pool = *index_pool;
}
if (data_pool && !data_pool->empty()) {
- info.data_pool = *data_pool;
+ if (storage_class.empty()) {
+ info.data_pools[RGW_STORAGE_CLASS_STANDARD] = *data_pool;
+ } else {
+ info.data_pools[storage_class] = *data_pool;
+ }
}
if (data_extra_pool) {
info.data_extra_pool = *data_extra_pool;
formatter->dump_string("bucket", bucket.name);
formatter->dump_string("tenant", bucket.tenant);
formatter->dump_string("zonegroup", bucket_info.zonegroup);
- formatter->dump_string("placement_rule", bucket_info.placement_rule);
+ formatter->dump_string("placement_rule", bucket_info.placement_rule.to_str());
::encode_json("explicit_placement", bucket.explicit_placement, formatter);
formatter->dump_string("id", bucket.bucket_id);
formatter->dump_string("marker", bucket.marker);
* user through custom HTTP header named X-Static-Large-Object. */
#define RGW_ATTR_SLO_UINDICATOR RGW_ATTR_META_PREFIX "static-large-object"
#define RGW_ATTR_X_ROBOTS_TAG RGW_ATTR_PREFIX "x-robots-tag"
+#define RGW_ATTR_STORAGE_CLASS RGW_ATTR_PREFIX "storage_class"
#define RGW_ATTR_PG_VER RGW_ATTR_PREFIX "pg_ver"
#define RGW_ATTR_SOURCE_ZONE RGW_ATTR_PREFIX "source_zone"
TYPE_ROLE=4
};
+static string RGW_STORAGE_CLASS_STANDARD = "STANDARD";
+
+struct rgw_placement_rule {
+ std::string name;
+ std::string storage_class;
+
+ rgw_placement_rule() {}
+ rgw_placement_rule(const string& _n, const string& _sc) : name(_n), storage_class(_sc) {}
+
+
+ bool empty() const {
+ return name.empty() && storage_class.empty();
+ }
+
+ void clear() {
+ name.clear();
+ storage_class.clear();
+ }
+
+ void init(const string& n, const string& c) {
+ name = n;
+ storage_class = c;
+ }
+
+ const string& get_storage_class() const {
+ if (storage_class.empty()) {
+ return RGW_STORAGE_CLASS_STANDARD;
+ }
+ return storage_class;
+ }
+
+ int compare(const rgw_placement_rule& r) const {
+ int c = name.compare(r.name);
+ if (c != 0) {
+ return c;
+ }
+ return get_storage_class().compare(r.get_storage_class());
+ }
+
+ bool operator==(const rgw_placement_rule& r) const {
+ return (name == r.name &&
+ get_storage_class() == r.get_storage_class());
+ }
+
+ bool operator!=(const rgw_placement_rule& r) const {
+ return !(*this == r);
+ }
+
+ void encode(bufferlist& bl) const {
+ /* no ENCODE_START/END due to backward compatibility */
+ std::string s = to_str();
+ ceph::encode(s, bl);
+ }
+
+ void decode(bufferlist::const_iterator& bl) {
+ std::string s;
+ ceph::decode(s, bl);
+ from_str(s);
+ }
+
+ std::string to_str() const {
+ if (standard_storage_class()) {
+ return name;
+ }
+ return name + "/" + storage_class;
+ }
+
+ void from_str(const std::string& s) {
+ size_t pos = s.find("/");
+ if (pos == std::string::npos) {
+ name = s;
+ return;
+ }
+ name = s.substr(0, pos);
+ if (pos < s.size() - 1) {
+ storage_class = s.substr(pos + 1);
+ }
+ }
+
+ bool standard_storage_class() const {
+ return storage_class.empty() || storage_class == RGW_STORAGE_CLASS_STANDARD;
+ }
+};
+WRITE_CLASS_ENCODER(rgw_placement_rule)
+
+void encode_json(const char *name, const rgw_placement_rule& val, ceph::Formatter *f);
+void decode_json_obj(rgw_placement_rule& v, JSONObj *obj);
+
+inline ostream& operator<<(ostream& out, const rgw_placement_rule& rule) {
+ return out << rule.to_str();
+}
struct RGWUserInfo
{
rgw_user user_id;
RGWUserCaps caps;
__u8 admin;
__u8 system;
- string default_placement;
+ rgw_placement_rule default_placement;
list<string> placement_tags;
RGWQuotaInfo bucket_quota;
map<int, string> temp_url_keys;
uint32_t flags;
string zonegroup;
ceph::real_time creation_time;
- string placement_rule;
+ rgw_placement_rule placement_rule;
bool has_instance_obj;
RGWObjVersionTracker objv_tracker; /* we don't need to serialize this, for runtime tracking */
obj_version ep_objv; /* entry point object version, for runtime tracking only */
string effective_uri;
string request_params;
string domain;
+ string storage_class;
req_info(CephContext *cct, const RGWEnv *env);
void rebuild_from(req_info& src);
/* The placement_rule is necessary to calculate per-storage-policy statics
* of the Swift API. Although the info available in RGWBucketInfo, we need
* to duplicate it here to not affect the performance of buckets listing. */
- std::string placement_rule;
+ rgw_placement_rule placement_rule;
RGWBucketEnt()
: size(0),
ENCODE_FINISH(bl);
}
void decode(bufferlist::const_iterator& bl) {
- DECODE_START_LEGACY_COMPAT_LEN(6, 5, 5, bl);
+ DECODE_START_LEGACY_COMPAT_LEN(7, 5, 5, bl);
__u32 mt;
uint64_t s;
string empty_str; // backward compatibility
pool = rgw_pool(s);
}
+void encode_json(const char *name, const rgw_placement_rule& r, Formatter *f)
+{
+ encode_json(name, r.to_str(), f);
+}
+
+void decode_json_obj(rgw_placement_rule& v, JSONObj *obj)
+{
+ string s;
+ decode_json_obj(s, obj);
+ v.from_str(s);
+}
+
void RGWOLHInfo::dump(Formatter *f) const
{
encode_json("target", target, f);
void rgw_obj_select::dump(Formatter *f) const
{
- f->dump_string("placement_rule", placement_rule);
+ f->dump_string("placement_rule", placement_rule.to_str());
f->dump_object("obj", obj);
f->dump_object("raw_obj", raw_obj);
f->dump_bool("is_raw", is_raw);
if (system) { /* no need to show it for every user */
encode_json("system", (bool)system, f);
}
- encode_json("default_placement", default_placement, f);
+ encode_json("default_placement", default_placement.name, f);
+ encode_json("default_storage_class", default_placement.get_storage_class(), f);
encode_json("placement_tags", placement_tags, f);
encode_json("bucket_quota", bucket_quota, f);
encode_json("user_quota", user_quota, f);
bool sys = false;
JSONDecoder::decode_json("system", sys, obj);
system = (__u8)sys;
- JSONDecoder::decode_json("default_placement", default_placement, obj);
+ JSONDecoder::decode_json("default_placement", default_placement.name, obj);
+ JSONDecoder::decode_json("default_storage_class", default_placement.storage_class, obj);
JSONDecoder::decode_json("placement_tags", placement_tags, obj);
JSONDecoder::decode_json("bucket_quota", bucket_quota, obj);
JSONDecoder::decode_json("user_quota", user_quota, obj);
if (zonegroup.empty()) {
JSONDecoder::decode_json("region", zonegroup, obj);
}
- JSONDecoder::decode_json("placement_rule", placement_rule, obj);
+ string pr;
+ JSONDecoder::decode_json("placement_rule", pr, obj);
+ placement_rule.from_str(pr);
JSONDecoder::decode_json("has_instance_obj", has_instance_obj, obj);
JSONDecoder::decode_json("quota", quota, obj);
JSONDecoder::decode_json("num_shards", num_shards, obj);
utime_t ut(creation_time);
encode_json("mtime", ut, f); /* mtime / creation time discrepency needed for backward compatibility */
encode_json("count", count, f);
- encode_json("placement_rule", placement_rule, f);
+ encode_json("placement_rule", placement_rule.to_str(), f);
}
void RGWUploadPartInfo::dump(Formatter *f) const
void RGWZonePlacementInfo::dump(Formatter *f) const
{
encode_json("index_pool", index_pool, f);
- encode_json("data_pool", data_pool, f);
+ encode_json("data_pools", data_pools, f);
encode_json("data_extra_pool", data_extra_pool, f);
encode_json("index_type", (uint32_t)index_type, f);
encode_json("compression", compression_type, f);
void RGWZonePlacementInfo::decode_json(JSONObj *obj)
{
JSONDecoder::decode_json("index_pool", index_pool, obj);
- JSONDecoder::decode_json("data_pool", data_pool, obj);
+ JSONDecoder::decode_json("data_pools", data_pools, obj);
+ if (JSONDecoder::decode_json("data_pool", standard_data_pool, obj)) {
+ data_pools[RGW_STORAGE_CLASS_STANDARD] = standard_data_pool;
+ } else {
+ auto iter = data_pools.find(RGW_STORAGE_CLASS_STANDARD);
+ if (iter != data_pools.end()) {
+ standard_data_pool = iter->second;
+ }
+ }
JSONDecoder::decode_json("data_extra_pool", data_extra_pool, obj);
uint32_t it;
JSONDecoder::decode_json("index_type", it, obj);
{
encode_json("name", name, f);
encode_json("tags", tags, f);
+ encode_json("storage_classes", storage_classes, f);
}
void RGWZoneGroupPlacementTarget::decode_json(JSONObj *obj)
{
JSONDecoder::decode_json("name", name, obj);
JSONDecoder::decode_json("tags", tags, obj);
+ JSONDecoder::decode_json("storage_classes", storage_classes, obj);
+ if (storage_classes.empty()) {
+ storage_classes.insert(RGW_STORAGE_CLASS_STANDARD);
+ }
}
void RGWZoneGroup::dump(Formatter *f) const
JSONDecoder::decode_json("master_zone", master_zone, obj);
JSONDecoder::decode_json("zones", zones, decode_zones, obj);
JSONDecoder::decode_json("placement_targets", placement_targets, decode_placement_targets, obj);
- JSONDecoder::decode_json("default_placement", default_placement, obj);
+ JSONDecoder::decode_json("default_placement", default_placement.name, obj);
+ JSONDecoder::decode_json("default_storage_class", default_placement.storage_class, obj);
JSONDecoder::decode_json("realm_id", realm_id, obj);
}
/* operator[] still can create a new entry for storage policy seen
* for first time. */
- auto& policy_stats = policies_stats[bucket.placement_rule];
+ auto& policy_stats = policies_stats[bucket.placement_rule.to_str()];
policy_stats.bytes_used += bucket.size;
policy_stats.bytes_used_rounded += bucket.size_rounded;
policy_stats.buckets_count++;
/* operator[] still can create a new entry for storage policy seen
* for first time. */
- auto& policy_stats = policies_stats[bucket.placement_rule];
+ auto& policy_stats = policies_stats[bucket.placement_rule.to_str()];
policy_stats.bytes_used += bucket.size;
policy_stats.bytes_used_rounded += bucket.size_rounded;
policy_stats.buckets_count++;
}
const auto& zonegroup = store->svc.zone->get_zonegroup();
- if (!placement_rule.empty() &&
- !zonegroup.placement_targets.count(placement_rule)) {
- ldpp_dout(this, 0) << "placement target (" << placement_rule << ")"
+ if (!placement_rule.name.empty() &&
+ !zonegroup.placement_targets.count(placement_rule.name)) {
+ ldpp_dout(this, 0) << "placement target (" << placement_rule.name << ")"
<< " doesn't exist in the placement targets of zonegroup"
<< " (" << store->svc.zone->get_zonegroup().api_name << ")" << dendl;
op_ret = -ERR_INVALID_LOCATION_CONSTRAINT;
}
if (s->bucket_exists) {
- string selected_placement_rule;
+ rgw_placement_rule selected_placement_rule;
rgw_bucket bucket;
bucket.tenant = s->bucket_tenant;
bucket.name = s->bucket_name;
static CompressorRef get_compressor_plugin(const req_state *s,
const std::string& compression_type)
{
+#warning FIXME different compression types per placement rule + storage_class
if (compression_type != "random") {
return Compressor::create(s->cct, compression_type);
}
filter = encrypt.get();
} else {
const auto& compression_type = store->svc.zone->get_zone_params().get_compression_type(
- s->bucket_info.placement_rule);
+ s->bucket_info.placement_rule.name);
if (compression_type != "none") {
plugin = Compressor::create(s->cct, compression_type);
if (!plugin) {
}
- std::string placement_rule;
+ rgw_placement_rule placement_rule;
+ placement_rule.storage_class = s->info.storage_class;
if (bucket_exists) {
- std::string selected_placement_rule;
+ rgw_placement_rule selected_placement_rule;
rgw_bucket bucket;
bucket.tenant = s->bucket_tenant;
bucket.name = s->bucket_name;
/* No filters by default. */
DataProcessor *filter = &processor;
+#warning add storage_class compression
const auto& compression_type = store->svc.zone->get_zone_params().get_compression_type(
- binfo.placement_rule);
+ binfo.placement_rule.name);
CompressorRef plugin;
boost::optional<RGWPutObj_Compress> compressor;
if (compression_type != "none") {
protected:
RGWAccessControlPolicy policy;
string location_constraint;
- string placement_rule;
+ rgw_placement_rule placement_rule;
RGWBucketInfo info;
obj_version ep_objv;
bool has_cors;
uint32_t policy_rw_mask;
RGWAccessControlPolicy policy;
RGWCORSConfiguration cors_config;
- string placement_rule;
+ rgw_placement_rule placement_rule;
boost::optional<std::string> swift_ver_location;
public:
protected:
RGWRados *const store;
const RGWBucketInfo& bucket_info;
- const string *ptail_placement_rule;
+ const rgw_placement_rule *ptail_placement_rule;
const rgw_user& owner;
RGWObjectCtx& obj_ctx;
rgw_obj head_obj;
public:
ManifestObjectProcessor(Aio *aio, RGWRados *store,
const RGWBucketInfo& bucket_info,
- const string *ptail_placement_rule,
+ const rgw_placement_rule *ptail_placement_rule,
const rgw_user& owner, RGWObjectCtx& obj_ctx,
const rgw_obj& head_obj)
: HeadObjectProcessor(0),
public:
AtomicObjectProcessor(Aio *aio, RGWRados *store,
const RGWBucketInfo& bucket_info,
- const string *ptail_placement_rule,
+ const rgw_placement_rule *ptail_placement_rule,
const rgw_user& owner,
RGWObjectCtx& obj_ctx, const rgw_obj& head_obj,
std::optional<uint64_t> olh_epoch,
public:
MultipartObjectProcessor(Aio *aio, RGWRados *store,
const RGWBucketInfo& bucket_info,
- const string *ptail_placement_rule,
+ const rgw_placement_rule *ptail_placement_rule,
const rgw_user& owner, RGWObjectCtx& obj_ctx,
const rgw_obj& head_obj,
const std::string& upload_id, uint64_t part_num,
static bool rgw_get_obj_data_pool(const RGWZoneGroup& zonegroup, const RGWZoneParams& zone_params,
- const string& placement_id, const rgw_obj& obj, rgw_pool *pool)
+ const rgw_placement_rule& head_placement_rule,
+ const rgw_obj& obj, rgw_pool *pool)
{
- if (!zone_params.get_head_data_pool(placement_id, obj, pool)) {
+ if (!zone_params.get_head_data_pool(head_placement_rule, obj, pool)) {
RGWZonePlacementInfo placement;
- if (!zone_params.get_placement(zonegroup.default_placement, &placement)) {
+ if (!zone_params.get_placement(zonegroup.default_placement.name, &placement)) {
return false;
}
if (!obj.in_extra_data) {
- *pool = placement.data_pool;
+#warning zonegroup default placement backward compatibility json decode/encode
+ *pool = placement.get_data_pool(zonegroup.default_placement.storage_class);
} else {
*pool = placement.get_data_extra_pool();
}
}
static bool rgw_obj_to_raw(const RGWZoneGroup& zonegroup, const RGWZoneParams& zone_params,
- const string& placement_id, const rgw_obj& obj, rgw_raw_obj *raw_obj)
+ const rgw_placement_rule& head_placement_rule,
+ const rgw_obj& obj, rgw_raw_obj *raw_obj)
{
get_obj_bucket_and_oid_loc(obj, raw_obj->oid, raw_obj->loc);
- return rgw_get_obj_data_pool(zonegroup, zone_params, placement_id, obj, &raw_obj->pool);
+ return rgw_get_obj_data_pool(zonegroup, zone_params, head_placement_rule, obj, &raw_obj->pool);
}
rgw_raw_obj rgw_obj_select::get_raw_obj(const RGWZoneGroup& zonegroup, const RGWZoneParams& zone_params) const
if (manifest->explicit_objs) {
++explicit_iter;
- if (explicit_iter == manifest->objs.end()) {
- ofs = manifest->obj_size;
- return;
- }
-
update_explicit_pos();
update_location();
}
int RGWObjManifest::generator::create_begin(CephContext *cct, RGWObjManifest *_m,
- const string& head_placement_rule,
- const string *tail_placement_rule,
+ const rgw_placement_rule& head_placement_rule,
+ const rgw_placement_rule *tail_placement_rule,
const rgw_bucket& _b, const rgw_obj& _obj)
{
manifest = _m;
return 0;
}
-int RGWRados::get_max_chunk_size(const string& placement_rule, const rgw_obj& obj, uint64_t *max_chunk_size)
+int RGWRados::get_max_chunk_size(const rgw_placement_rule& placement_rule, const rgw_obj& obj, uint64_t *max_chunk_size)
{
rgw_pool pool;
if (!get_obj_data_pool(placement_rule, obj, &pool)) {
auto& zonegroup = svc.zone->get_zonegroup();
auto& zone_params = svc.zone->get_zone_params();
- const string *rule = &bucket_info.placement_rule;
+ const rgw_placement_rule *rule = &bucket_info.placement_rule;
if (rule->empty()) {
rule = &zonegroup.default_placement;
}
- auto iter = zone_params.placement_pools.find(*rule);
+ auto iter = zone_params.placement_pools.find(rule->name);
if (iter == zone_params.placement_pools.end()) {
ldout(cct, 0) << "could not find placement rule " << *rule << " within zonegroup " << dendl;
return -EINVAL;
int RGWRados::create_bucket(const RGWUserInfo& owner, rgw_bucket& bucket,
const string& zonegroup_id,
- const string& placement_rule,
+ const rgw_placement_rule& placement_rule,
const string& swift_ver_location,
const RGWQuotaInfo * pquota_info,
map<std::string, bufferlist>& attrs,
bool exclusive)
{
#define MAX_CREATE_RETRIES 20 /* need to bound retries */
- string selected_placement_rule_name;
+ rgw_placement_rule selected_placement_rule;
RGWZonePlacementInfo rule_info;
for (int i = 0; i < MAX_CREATE_RETRIES; i++) {
int ret = 0;
ret = svc.zone->select_bucket_placement(owner, zonegroup_id, placement_rule,
- &selected_placement_rule_name, &rule_info);
+ &selected_placement_rule, &rule_info);
if (ret < 0)
return ret;
info.bucket = bucket;
info.owner = owner.user_id;
info.zonegroup = zonegroup_id;
- info.placement_rule = selected_placement_rule_name;
+ info.placement_rule = selected_placement_rule;
info.index_type = rule_info.index_type;
info.swift_ver_location = swift_ver_location;
info.swift_versioning = (!swift_ver_location.empty());
return rgw_get_obj_data_pool(svc.zone->get_zonegroup(), svc.zone->get_zone_params(), placement_rule, obj, pool);
}
-bool RGWRados::obj_to_raw(const string& placement_rule, const rgw_obj& obj, rgw_raw_obj *raw_obj)
+bool RGWRados::obj_to_raw(const rgw_placement_rule& placement_rule, const rgw_obj& obj, rgw_raw_obj *raw_obj)
{
get_obj_bucket_and_oid_loc(obj, raw_obj->oid, raw_obj->loc);
rgw::AioThrottle aio(cct->_conf->rgw_put_obj_min_window_size);
using namespace rgw::putobj;
- string *ptail_rule{nullptr};
+ rgw_placement_rule *ptail_rule{nullptr};
#warning FIXME ptail_rule
AtomicObjectProcessor processor(&aio, this, dest_bucket_info, ptail_rule, user_id,
obj_ctx, dest_obj, olh_epoch, tag);
boost::optional<RGWPutObj_Compress> compressor;
CompressorRef plugin;
+#warning compression type
const auto& compression_type = svc.zone->get_zone_params().get_compression_type(
- dest_bucket_info.placement_rule);
+ dest_bucket_info.placement_rule.name);
if (compression_type != "none") {
plugin = Compressor::create(cct, compression_type);
if (!plugin) {
rgw_obj& src_obj,
RGWBucketInfo& dest_bucket_info,
RGWBucketInfo& src_bucket_info,
- const string *ptail_rule,
+ const rgw_placement_rule *ptail_rule,
real_time *src_mtime,
real_time *mtime,
const real_time *mod_ptr,
rgw_pool src_pool;
rgw_pool dest_pool;
- const string *src_rule{nullptr};
+ const rgw_placement_rule *src_rule{nullptr};
if (astate->has_manifest) {
src_rule = &astate->manifest.get_tail_placement().placement_rule;
int RGWRados::copy_obj_data(RGWObjectCtx& obj_ctx,
RGWBucketInfo& dest_bucket_info,
- const string *ptail_rule,
+ const rgw_placement_rule *ptail_rule,
RGWRados::Object::Read& read_op, off_t end,
const rgw_obj& dest_obj,
real_time *mtime,
return true;
}
+
struct rgw_bucket_placement {
- string placement_rule;
+ rgw_placement_rule placement_rule;
rgw_bucket bucket;
void dump(Formatter *f) const;
};
class rgw_obj_select {
- string placement_rule;
+ rgw_placement_rule placement_rule;
rgw_obj obj;
rgw_raw_obj raw_obj;
bool is_raw;
return *this;
}
- void set_placement_rule(const string& rule) {
+ void set_placement_rule(const rgw_placement_rule& rule) {
placement_rule = rule;
}
void dump(Formatter *f) const;
rgw_obj obj;
uint64_t head_size;
- string head_placement_rule;
+ rgw_placement_rule head_placement_rule;
uint64_t max_head_size;
string prefix;
return (obj_size > head_size);
}
- void set_head(const string& placement_rule, const rgw_obj& _o, uint64_t _s) {
+ void set_head(const rgw_placement_rule& placement_rule, const rgw_obj& _o, uint64_t _s) {
head_placement_rule = placement_rule;
obj = _o;
head_size = _s;
return obj;
}
- void set_tail_placement(const string& placement_rule, const rgw_bucket& _b) {
+ void set_tail_placement(const rgw_placement_rule& placement_rule, const rgw_bucket& _b) {
tail_placement.placement_rule = placement_rule;
tail_placement.bucket = _b;
}
return tail_placement;
}
- const string& get_head_placement_rule() {
+ const rgw_placement_rule& get_head_placement_rule() {
return head_placement_rule;
}
generator() : manifest(NULL), last_ofs(0), cur_part_ofs(0), cur_part_id(0),
cur_stripe(0), cur_stripe_size(0) {}
int create_begin(CephContext *cct, RGWObjManifest *manifest,
- const string& head_placement_rule,
- const string *tail_placement_rule,
+ const rgw_placement_rule& head_placement_rule,
+ const rgw_placement_rule *tail_placement_rule,
const rgw_bucket& bucket,
const rgw_obj& obj);
int get_required_alignment(const rgw_pool& pool, uint64_t *alignment);
int get_max_chunk_size(const rgw_pool& pool, uint64_t *max_chunk_size);
- int get_max_chunk_size(const string& placement_rule, const rgw_obj& obj, uint64_t *max_chunk_size);
+ int get_max_chunk_size(const rgw_placement_rule& placement_rule, const rgw_obj& obj, uint64_t *max_chunk_size);
uint32_t get_max_bucket_shards() {
return rgw_shards_max();
int clean_bucket_index(RGWBucketInfo& bucket_info, int num_shards);
void create_bucket_id(string *bucket_id);
- bool get_obj_data_pool(const string& placement_rule, const rgw_obj& obj, rgw_pool *pool);
- bool obj_to_raw(const string& placement_rule, const rgw_obj& obj, rgw_raw_obj *raw_obj);
+ bool get_obj_data_pool(const rgw_placement_rule& placement_rule, const rgw_obj& obj, rgw_pool *pool);
+ bool obj_to_raw(const rgw_placement_rule& placement_rule, const rgw_obj& obj, rgw_raw_obj *raw_obj);
int create_bucket(const RGWUserInfo& owner, rgw_bucket& bucket,
const string& zonegroup_id,
- const string& placement_rule,
+ const rgw_placement_rule& placement_rule,
const string& swift_ver_location,
const RGWQuotaInfo * pquota_info,
map<std::string,bufferlist>& attrs,
rgw_obj& src_obj,
RGWBucketInfo& dest_bucket_info,
RGWBucketInfo& src_bucket_info,
- const string *ptail_rule,
+ const rgw_placement_rule *ptail_rule,
ceph::real_time *src_mtime,
ceph::real_time *mtime,
const ceph::real_time *mod_ptr,
int copy_obj_data(RGWObjectCtx& obj_ctx,
RGWBucketInfo& dest_bucket_info,
- const string *ptail_rule,
+ const rgw_placement_rule *ptail_rule,
RGWRados::Object::Read& read_op, off_t end,
const rgw_obj& dest_obj,
ceph::real_time *mtime,
{ RGW_ATTR_CONTENT_ENC, "Content-Encoding" },
{ RGW_ATTR_USER_MANIFEST, "X-Object-Manifest" },
{ RGW_ATTR_X_ROBOTS_TAG , "X-Robots-Tag" },
+ { RGW_ATTR_STORAGE_CLASS , "X-Amz-Storage-Class" },
/* RGW_ATTR_AMZ_WEBSITE_REDIRECT_LOCATION header depends on access mode:
* S3 endpoint: x-amz-website-redirect-location
* S3Website endpoint: Location
{ "HTTP_CONTENT_DISPOSITION", RGW_ATTR_CONTENT_DISP },
{ "HTTP_CONTENT_ENCODING", RGW_ATTR_CONTENT_ENC },
{ "HTTP_X_ROBOTS_TAG", RGW_ATTR_X_ROBOTS_TAG },
+ { "HTTP_X_AMZ_STORAGE_CLASS", RGW_ATTR_STORAGE_CLASS },
};
map<string, string> rgw_to_http_attrs;
size_t pos = location_constraint.find(':');
if (pos != string::npos) {
- placement_rule = location_constraint.substr(pos + 1);
+ placement_rule.init(location_constraint.substr(pos + 1), s->info.storage_class);
location_constraint = location_constraint.substr(0, pos);
}
}
}
+ const char *sc = s->info.env->get("HTTP_X_AMZ_STORAGE_CLASS");
+ if (sc) {
+ s->info.storage_class = sc;
+ }
+
return RGWHandler_REST::init(store, s, cio);
}
if (write_acl.size()) {
dump_header(s, "X-Container-Write", write_acl);
}
- if (!s->bucket_info.placement_rule.empty()) {
- dump_header(s, "X-Storage-Policy", s->bucket_info.placement_rule);
+ if (!s->bucket_info.placement_rule.name.empty()) {
+ dump_header(s, "X-Storage-Policy", s->bucket_info.placement_rule.name);
}
+ dump_header(s, "X-Storage-Class", s->bucket_info.placement_rule.get_storage_class());
/* Dump user-defined metadata items and generic attrs. */
const size_t PREFIX_LEN = sizeof(RGW_ATTR_META_PREFIX) - 1;
location_constraint = store->svc.zone->get_zonegroup().api_name;
get_rmattrs_from_headers(s, CONT_PUT_ATTR_PREFIX,
CONT_REMOVE_ATTR_PREFIX, rmattr_names);
- placement_rule = s->info.env->get("HTTP_X_STORAGE_POLICY", "");
+ placement_rule.init(s->info.env->get("HTTP_X_STORAGE_POLICY", ""), s->info.storage_class);
return get_swift_versioning_settings(s, swift_ver_location);
}
get_rmattrs_from_headers(s, CONT_PUT_ATTR_PREFIX, CONT_REMOVE_ATTR_PREFIX,
rmattr_names);
- placement_rule = s->info.env->get("HTTP_X_STORAGE_POLICY", "");
+ placement_rule.init(s->info.env->get("HTTP_X_STORAGE_POLICY", ""), s->info.storage_class);
return get_swift_versioning_settings(s, swift_ver_location);
}
for (const auto& placement_targets : zonegroup.placement_targets) {
formatter.open_object_section("policy");
- if (placement_targets.second.name.compare(zonegroup.default_placement) == 0)
+ if (placement_targets.second.name.compare(zonegroup.default_placement.name) == 0)
formatter.dump_bool("default", true);
formatter.dump_string("name", placement_targets.second.name.c_str());
formatter.close_section();
s->op = OP_PUT;
}
+ s->info.storage_class = s->info.env->get("HTTP_X_OBJECT_STORAGE_CLASS", "");
+
return RGWHandler_REST::init(store, s, cio);
}
RGWZoneGroupPlacementTarget placement_target;
placement_target.name = "default-placement";
placement_targets[placement_target.name] = placement_target;
- default_placement = "default-placement";
+ default_placement.name = "default-placement";
RGWZoneParams zone_params(default_zone_name);
}
if (default_placement.empty() && !placement_targets.empty()) {
- default_placement = placement_targets.begin()->first;
+ default_placement.init(placement_targets.begin()->first, RGW_STORAGE_CLASS_STANDARD);
}
}
pool_names.insert(zone.reshard_pool);
for(auto& iter : zone.placement_pools) {
pool_names.insert(iter.second.index_pool);
- pool_names.insert(iter.second.data_pool);
+ for (auto& pi : iter.second.data_pools) {
+ pool_names.insert(pi.second);
+ }
pool_names.insert(iter.second.data_extra_pool);
}
}
for(auto& iter : placement_pools) {
iter.second.index_pool = fix_zone_pool_dup(pools, name, "." + default_bucket_index_pool_suffix,
iter.second.index_pool);
- iter.second.data_pool = fix_zone_pool_dup(pools, name, "." + default_storage_pool_suffix,
- iter.second.data_pool);
+ for (auto& pi : iter.second.data_pools) {
+ pi.second = fix_zone_pool_dup(pools, name, "." + default_storage_pool_suffix,
+ pi.second);
+ }
iter.second.data_extra_pool= fix_zone_pool_dup(pools, name, "." + default_storage_extra_pool_suffix,
iter.second.data_extra_pool);
}
/* a new system, let's set new placement info */
RGWZonePlacementInfo default_placement;
default_placement.index_pool = name + "." + default_bucket_index_pool_suffix;
- default_placement.data_pool = name + "." + default_storage_pool_suffix;
+ default_placement.data_pools[RGW_STORAGE_CLASS_STANDARD] = name + "." + default_storage_pool_suffix;
default_placement.data_extra_pool = name + "." + default_storage_extra_pool_suffix;
placement_pools["default-placement"] = default_placement;
}
struct RGWZonePlacementInfo {
rgw_pool index_pool;
- rgw_pool data_pool;
+ rgw_pool standard_data_pool;
rgw_pool data_extra_pool; /* if not set we should use data_pool */
+ map<string, rgw_pool> data_pools;
RGWBucketIndexType index_type;
std::string compression_type;
RGWZonePlacementInfo() : index_type(RGWBIType_Normal) {}
void encode(bufferlist& bl) const {
- ENCODE_START(6, 1, bl);
+ ENCODE_START(7, 1, bl);
encode(index_pool.to_str(), bl);
encode(data_pool.to_str(), bl);
encode(data_extra_pool.to_str(), bl);
/*
* return data pool of the head object
*/
- bool get_head_data_pool(const std::string& placement_id, const rgw_obj& obj, rgw_pool *pool) const {
+ bool get_head_data_pool(const rgw_placement_rule& placement_rule, const rgw_obj& obj, rgw_pool *pool) const {
const rgw_data_placement_target& explicit_placement = obj.bucket.explicit_placement;
if (!explicit_placement.data_pool.empty()) {
if (!obj.in_extra_data) {
}
return true;
}
- if (placement_id.empty()) {
+ if (placement_rule.empty()) {
return false;
}
- auto iter = placement_pools.find(placement_id);
+ auto iter = placement_pools.find(placement_rule.name);
if (iter == placement_pools.end()) {
return false;
}
if (!obj.in_extra_data) {
- *pool = iter->second.data_pool;
+ *pool = iter->second.get_data_pool(placement_rule.storage_class);
} else {
*pool = iter->second.get_data_extra_pool();
}
struct RGWZoneGroupPlacementTarget {
std::string name;
set<std::string> tags;
+ set<std::string> storage_classes;
bool user_permitted(const list<std::string>& user_tags) const {
if (tags.empty()) {
}
void encode(bufferlist& bl) const {
- ENCODE_START(1, 1, bl);
+ ENCODE_START(2, 1, bl);
encode(name, bl);
encode(tags, bl);
+ encode(storage_classes, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::const_iterator& bl) {
- DECODE_START(1, bl);
+ DECODE_START(2, bl);
decode(name, bl);
decode(tags, bl);
+ if (struct_v >= 2) {
+ decode(storage_classes, bl);
+ }
+ if (storage_classes.empty()) {
+ storage_classes.insert(RGW_STORAGE_CLASS_STANDARD);
+ }
DECODE_FINISH(bl);
}
void dump(Formatter *f) const;
};
WRITE_CLASS_ENCODER(RGWZoneGroupPlacementTarget)
-
struct RGWZoneGroup : public RGWSystemMetaObj {
std::string api_name;
list<std::string> endpoints;
map<std::string, RGWZone> zones;
map<std::string, RGWZoneGroupPlacementTarget> placement_targets;
- std::string default_placement;
+ rgw_placement_rule default_placement;
list<std::string> hostnames;
list<std::string> hostnames_s3website;
}
-int RGWSI_Zone::select_new_bucket_location(const RGWUserInfo& user_info, const string& zonegroup_id, const string& request_rule,
- string *pselected_rule_name, RGWZonePlacementInfo *rule_info)
-
+int RGWSI_Zone::select_new_bucket_location(const RGWUserInfo& user_info, const string& zonegroup_id,
+ const rgw_placement_rule& request_rule,
+ rgw_placement_rule *pselected_rule_name, RGWZonePlacementInfo *rule_info)
{
/* first check that zonegroup exists within current period. */
RGWZoneGroup zonegroup;
return ret;
}
+ const rgw_placement_rule *used_rule;
+
/* find placement rule. Hierarchy: request rule > user default rule > zonegroup default rule */
std::map<std::string, RGWZoneGroupPlacementTarget>::const_iterator titer;
- if (!request_rule.empty()) {
- titer = zonegroup.placement_targets.find(request_rule);
+ if (!request_rule.name.empty()) {
+ used_rule = &request_rule;
+ titer = zonegroup.placement_targets.find(request_rule.name);
if (titer == zonegroup.placement_targets.end()) {
ldout(cct, 0) << "could not find requested placement id " << request_rule
<< " within zonegroup " << dendl;
return -ERR_INVALID_LOCATION_CONSTRAINT;
}
} else if (!user_info.default_placement.empty()) {
- titer = zonegroup.placement_targets.find(user_info.default_placement);
+ used_rule = &user_info.default_placement;
+ titer = zonegroup.placement_targets.find(user_info.default_placement.name);
if (titer == zonegroup.placement_targets.end()) {
ldout(cct, 0) << "could not find user default placement id " << user_info.default_placement
<< " within zonegroup " << dendl;
return -ERR_INVALID_LOCATION_CONSTRAINT;
}
} else {
- if (zonegroup.default_placement.empty()) { // zonegroup default rule as fallback, it should not be empty.
+ if (zonegroup.default_placement.name.empty()) { // zonegroup default rule as fallback, it should not be empty.
ldout(cct, 0) << "misconfiguration, zonegroup default placement id should not be empty." << dendl;
return -ERR_ZONEGROUP_DEFAULT_PLACEMENT_MISCONFIGURATION;
} else {
- titer = zonegroup.placement_targets.find(zonegroup.default_placement);
+ used_rule = &zonegroup.default_placement;
+ titer = zonegroup.placement_targets.find(zonegroup.default_placement.name);
if (titer == zonegroup.placement_targets.end()) {
ldout(cct, 0) << "could not find zonegroup default placement id " << zonegroup.default_placement
<< " within zonegroup " << dendl;
return -EPERM;
}
- if (pselected_rule_name)
- *pselected_rule_name = titer->first;
+ const string *storage_class = &request_rule.storage_class;
+
+ if (storage_class->empty()) {
+ storage_class = &used_rule->storage_class;
+ }
+
+ rgw_placement_rule rule(titer->first, *storage_class);
- return select_bucket_location_by_rule(titer->first, rule_info);
+ if (pselected_rule_name) {
+ *pselected_rule_name = rule;
+ }
+
+ return select_bucket_location_by_rule(rule, rule_info);
}
-int RGWSI_Zone::select_bucket_location_by_rule(const string& location_rule, RGWZonePlacementInfo *rule_info)
+int RGWSI_Zone::select_bucket_location_by_rule(const rgw_placement_rule& location_rule, RGWZonePlacementInfo *rule_info)
{
- if (location_rule.empty()) {
+ if (location_rule.name.empty()) {
/* we can only reach here if we're trying to set a bucket location from a bucket
* created on a different zone, using a legacy / default pool configuration
*/
* checking it for the local zone, because that's where this bucket object is going to
* reside.
*/
- auto piter = zone_params->placement_pools.find(location_rule);
+ auto piter = zone_params->placement_pools.find(location_rule.name);
if (piter == zone_params->placement_pools.end()) {
/* couldn't find, means we cannot really place data for this bucket in this zone */
ldout(cct, 0) << "ERROR: This zone does not contain placement rule "
return -EINVAL;
}
+#warning FIXME check that location_rule.storage_class exists in piter->second
+
RGWZonePlacementInfo& placement_info = piter->second;
if (rule_info) {
return 0;
}
-int RGWSI_Zone::select_bucket_placement(const RGWUserInfo& user_info, const string& zonegroup_id, const string& placement_rule,
- string *pselected_rule_name, RGWZonePlacementInfo *rule_info)
+int RGWSI_Zone::select_bucket_placement(const RGWUserInfo& user_info, const string& zonegroup_id,
+ const rgw_placement_rule& placement_rule,
+ rgw_placement_rule *pselected_rule, RGWZonePlacementInfo *rule_info)
{
if (!zone_params->placement_pools.empty()) {
return select_new_bucket_location(user_info, zonegroup_id, placement_rule,
- pselected_rule_name, rule_info);
+ pselected_rule, rule_info);
}
- if (pselected_rule_name) {
- pselected_rule_name->clear();
+ if (pselected_rule) {
+ pselected_rule->clear();
}
if (rule_info) {
}
pool_name = miter->first;
- rule_info->data_pool = pool_name;
+ rule_info->data_pools[RGW_STORAGE_CLASS_STANDARD] = pool_name;
rule_info->data_extra_pool = pool_name;
rule_info->index_pool = pool_name;
rule_info->index_type = RGWBIType_Normal;
RGWRESTConn *get_zone_conn_by_name(const string& name);
bool find_zone_id_by_name(const string& name, string *id);
- int select_bucket_placement(const RGWUserInfo& user_info, const string& zonegroup_id, const string& rule,
- string *pselected_rule_name, RGWZonePlacementInfo *rule_info);
+ int select_bucket_placement(const RGWUserInfo& user_info, const string& zonegroup_id,
+ const rgw_placement_rule& rule,
+ rgw_placement_rule *pselected_rule, RGWZonePlacementInfo *rule_info);
int select_legacy_bucket_placement(RGWZonePlacementInfo *rule_info);
- int select_new_bucket_location(const RGWUserInfo& user_info, const string& zonegroup_id, const string& rule,
- string *pselected_rule_name, RGWZonePlacementInfo *rule_info);
- int select_bucket_location_by_rule(const string& location_rule, RGWZonePlacementInfo *rule_info);
+ int select_new_bucket_location(const RGWUserInfo& user_info, const string& zonegroup_id,
+ const rgw_placement_rule& rule,
+ rgw_placement_rule *pselected_rule_name, RGWZonePlacementInfo *rule_info);
+ int select_bucket_location_by_rule(const rgw_placement_rule& location_rule, RGWZonePlacementInfo *rule_info);
int add_bucket_placement(const rgw_pool& new_pool);
int remove_bucket_placement(const rgw_pool& old_pool);