mirror of
https://github.com/ceph/ceph
synced 2025-01-20 10:01:45 +00:00
rgw: preserve bucket creation time across different zones / regions
Keep bucket creation time in RGWBucketInfo, and make use of it where necessary. Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
This commit is contained in:
parent
8eae1b8ba2
commit
a2cf14fe27
@ -72,7 +72,7 @@ int rgw_read_user_buckets(RGWRados *store, string user_id, RGWUserBuckets& bucke
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rgw_add_bucket(RGWRados *store, string user_id, rgw_bucket& bucket)
|
||||
int rgw_add_bucket(RGWRados *store, string user_id, rgw_bucket& bucket, time_t creation_time)
|
||||
{
|
||||
int ret;
|
||||
string& bucket_name = bucket.name;
|
||||
@ -82,7 +82,10 @@ int rgw_add_bucket(RGWRados *store, string user_id, rgw_bucket& bucket)
|
||||
RGWBucketEnt new_bucket;
|
||||
new_bucket.bucket = bucket;
|
||||
new_bucket.size = 0;
|
||||
time(&new_bucket.mtime);
|
||||
if (!creation_time)
|
||||
time(&new_bucket.creation_time);
|
||||
else
|
||||
new_bucket.creation_time = creation_time;
|
||||
::encode(new_bucket, bl);
|
||||
|
||||
string buckets_obj_id;
|
||||
@ -147,7 +150,10 @@ int RGWBucket::create_bucket(string bucket_str, string& user_id, string& region_
|
||||
|
||||
rgw_bucket& bucket = bucket_info.bucket;
|
||||
|
||||
ret = store->create_bucket(user_id, bucket, region_name, attrs, objv_tracker, NULL, NULL);
|
||||
RGWBucketInfo new_info;
|
||||
|
||||
ret = store->create_bucket(user_id, bucket, region_name, attrs, objv_tracker,
|
||||
NULL, bucket_info.creation_time, NULL, &new_info);
|
||||
if (ret && ret != -EEXIST)
|
||||
goto done;
|
||||
|
||||
@ -159,7 +165,7 @@ int RGWBucket::create_bucket(string bucket_str, string& user_id, string& region_
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = rgw_add_bucket(store, user_id, bucket);
|
||||
ret = rgw_add_bucket(store, user_id, bucket, new_info.creation_time);
|
||||
|
||||
if (ret == -EEXIST)
|
||||
ret = 0;
|
||||
@ -236,7 +242,7 @@ void check_bad_user_bucket_mapping(RGWRados *store, const string& user_id, bool
|
||||
cout << "bucket info mismatch: expected " << actual_bucket << " got " << bucket << std::endl;
|
||||
if (fix) {
|
||||
cout << "fixing" << std::endl;
|
||||
r = rgw_add_bucket(store, user_id, actual_bucket);
|
||||
r = rgw_add_bucket(store, user_id, actual_bucket, bucket_info.creation_time);
|
||||
if (r < 0) {
|
||||
cerr << "failed to fix bucket: " << cpp_strerror(-r) << std::endl;
|
||||
}
|
||||
@ -443,7 +449,7 @@ int RGWBucket::link(RGWBucketAdminOpState& op_state, std::string *err_msg)
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = rgw_add_bucket(store, user_id, bucket);
|
||||
r = rgw_add_bucket(store, user_id, bucket, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
@ -1359,7 +1365,7 @@ public:
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rgw_add_bucket(store, bci.info.owner, bci.info.bucket);
|
||||
ret = rgw_add_bucket(store, bci.info.owner, bci.info.bucket, bci.info.creation_time);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -93,7 +93,7 @@ extern void rgw_bucket_init(RGWMetadataManager *mm);
|
||||
extern int rgw_read_user_buckets(RGWRados *store, string user_id, RGWUserBuckets& buckets,
|
||||
const string& marker, uint64_t max, bool need_stats);
|
||||
|
||||
extern int rgw_add_bucket(RGWRados *store, string user_id, rgw_bucket& bucket);
|
||||
extern int rgw_add_bucket(RGWRados *store, string user_id, rgw_bucket& bucket, time_t creation_time);
|
||||
extern int rgw_remove_user_bucket_info(RGWRados *store, string user_id, rgw_bucket& bucket);
|
||||
|
||||
extern int rgw_remove_object(RGWRados *store, rgw_bucket& bucket, std::string& object);
|
||||
|
@ -597,17 +597,19 @@ struct RGWBucketInfo
|
||||
string owner;
|
||||
uint32_t flags;
|
||||
string region;
|
||||
time_t creation_time;
|
||||
|
||||
void encode(bufferlist& bl) const {
|
||||
ENCODE_START(5, 4, bl);
|
||||
ENCODE_START(6, 4, bl);
|
||||
::encode(bucket, bl);
|
||||
::encode(owner, bl);
|
||||
::encode(flags, bl);
|
||||
::encode(region, bl);
|
||||
::encode(creation_time, bl);
|
||||
ENCODE_FINISH(bl);
|
||||
}
|
||||
void decode(bufferlist::iterator& bl) {
|
||||
DECODE_START_LEGACY_COMPAT_LEN_32(5, 4, 4, bl);
|
||||
DECODE_START_LEGACY_COMPAT_LEN_32(6, 4, 4, bl);
|
||||
::decode(bucket, bl);
|
||||
if (struct_v >= 2)
|
||||
::decode(owner, bl);
|
||||
@ -615,6 +617,8 @@ struct RGWBucketInfo
|
||||
::decode(flags, bl);
|
||||
if (struct_v >= 5)
|
||||
::decode(region, bl);
|
||||
if (struct_v >= 6)
|
||||
::decode(creation_time, bl);
|
||||
DECODE_FINISH(bl);
|
||||
}
|
||||
void dump(Formatter *f) const;
|
||||
@ -622,7 +626,7 @@ struct RGWBucketInfo
|
||||
|
||||
void decode_json(JSONObj *obj);
|
||||
|
||||
RGWBucketInfo() : flags(0) {}
|
||||
RGWBucketInfo() : flags(0), creation_time(0) {}
|
||||
};
|
||||
WRITE_CLASS_ENCODER(RGWBucketInfo)
|
||||
|
||||
@ -779,15 +783,15 @@ struct RGWBucketEnt {
|
||||
rgw_bucket bucket;
|
||||
size_t size;
|
||||
size_t size_rounded;
|
||||
time_t mtime;
|
||||
time_t creation_time;
|
||||
uint64_t count;
|
||||
|
||||
RGWBucketEnt() : size(0), size_rounded(0), mtime(0), count(0) {}
|
||||
RGWBucketEnt() : size(0), size_rounded(0), creation_time(0), count(0) {}
|
||||
|
||||
void encode(bufferlist& bl) const {
|
||||
ENCODE_START(5, 5, bl);
|
||||
uint64_t s = size;
|
||||
__u32 mt = mtime;
|
||||
__u32 mt = creation_time;
|
||||
string empty_str; // originally had the bucket name here, but we encode bucket later
|
||||
::encode(empty_str, bl);
|
||||
::encode(s, bl);
|
||||
@ -807,7 +811,7 @@ struct RGWBucketEnt {
|
||||
::decode(s, bl);
|
||||
::decode(mt, bl);
|
||||
size = s;
|
||||
mtime = mt;
|
||||
creation_time = mt;
|
||||
if (struct_v >= 2)
|
||||
::decode(count, bl);
|
||||
if (struct_v >= 3)
|
||||
@ -819,13 +823,6 @@ struct RGWBucketEnt {
|
||||
}
|
||||
void dump(Formatter *f) const;
|
||||
static void generate_test_instances(list<RGWBucketEnt*>& o);
|
||||
void clear() {
|
||||
bucket.clear();
|
||||
size = 0;
|
||||
size_rounded = 0;
|
||||
mtime = 0;
|
||||
count = 0;
|
||||
}
|
||||
};
|
||||
WRITE_CLASS_ENCODER(RGWBucketEnt)
|
||||
|
||||
|
@ -435,6 +435,7 @@ void rgw_bucket::decode_json(JSONObj *obj) {
|
||||
void RGWBucketInfo::dump(Formatter *f) const
|
||||
{
|
||||
encode_json("bucket", bucket, f);
|
||||
encode_json("creation_time", creation_time, f);
|
||||
encode_json("owner", owner, f);
|
||||
encode_json("flags", flags, f);
|
||||
encode_json("region", region, f);
|
||||
@ -442,6 +443,7 @@ void RGWBucketInfo::dump(Formatter *f) const
|
||||
|
||||
void RGWBucketInfo::decode_json(JSONObj *obj) {
|
||||
JSONDecoder::decode_json("bucket", bucket, obj);
|
||||
JSONDecoder::decode_json("creation_time", creation_time, obj);
|
||||
JSONDecoder::decode_json("owner", owner, obj);
|
||||
JSONDecoder::decode_json("flags", flags, obj);
|
||||
JSONDecoder::decode_json("region", region, obj);
|
||||
@ -465,7 +467,7 @@ void RGWBucketEnt::dump(Formatter *f) const
|
||||
encode_json("bucket", bucket, f);
|
||||
encode_json("size", size, f);
|
||||
encode_json("size_rounded", size_rounded, f);
|
||||
encode_json("mtime", mtime, f);
|
||||
encode_json("mtime", creation_time, f); /* mtime / creation time discrepency needed for backward compatibility */
|
||||
encode_json("count", count, f);
|
||||
}
|
||||
|
||||
|
@ -909,8 +909,9 @@ void RGWCreateBucket::execute()
|
||||
}
|
||||
}
|
||||
|
||||
rgw_bucket master_bucket;
|
||||
RGWBucketInfo master_info;
|
||||
rgw_bucket *pmaster_bucket;
|
||||
time_t creation_time;
|
||||
|
||||
if (!store->region.is_master) {
|
||||
JSONParser jp;
|
||||
@ -919,12 +920,15 @@ void RGWCreateBucket::execute()
|
||||
return;
|
||||
|
||||
JSONDecoder::decode_json("object_ver", objv, &jp);
|
||||
JSONDecoder::decode_json("bucket", master_bucket, &jp);
|
||||
JSONDecoder::decode_json("bucket_info", master_info, &jp);
|
||||
ldout(s->cct, 20) << "parsed: objv.tag=" << objv.tag << " objv.ver=" << objv.ver << dendl;
|
||||
pmaster_bucket = &master_bucket;
|
||||
ldout(s->cct, 20) << "got creation time: << " << master_info.creation_time << dendl;
|
||||
pmaster_bucket= &master_info.bucket;
|
||||
creation_time = master_info.creation_time;
|
||||
pobjv = &objv;
|
||||
} else {
|
||||
pmaster_bucket = NULL;
|
||||
creation_time = 0;
|
||||
}
|
||||
|
||||
string region_name;
|
||||
@ -943,7 +947,8 @@ void RGWCreateBucket::execute()
|
||||
attrs[RGW_ATTR_ACL] = aclbl;
|
||||
|
||||
s->bucket.name = s->bucket_name_str;
|
||||
ret = store->create_bucket(s->user.user_id, s->bucket, region_name, attrs, objv_tracker, pobjv, pmaster_bucket, true);
|
||||
ret = store->create_bucket(s->user.user_id, s->bucket, region_name, attrs, objv_tracker, pobjv,
|
||||
creation_time, pmaster_bucket, &info, true);
|
||||
/* continue if EEXIST and create_bucket will fail below. this way we can recover
|
||||
* from a partial create by retrying it. */
|
||||
ldout(s->cct, 20) << "rgw_create_bucket returned ret=" << ret << " bucket=" << s->bucket << dendl;
|
||||
@ -959,14 +964,6 @@ void RGWCreateBucket::execute()
|
||||
* info, verify that the reported bucket owner is the current user.
|
||||
* If all is ok then update the user's list of buckets
|
||||
*/
|
||||
RGWBucketInfo info;
|
||||
map<string, bufferlist> attrs;
|
||||
int r = store->get_bucket_info(NULL, s->bucket.name, info, &s->objv_tracker, NULL, &attrs);
|
||||
if (r < 0) {
|
||||
ldout(s->cct, 0) << "ERROR: get_bucket_info on bucket=" << s->bucket.name << " returned err=" << r << " after create_bucket returned -EEXIST" << dendl;
|
||||
ret = r;
|
||||
return;
|
||||
}
|
||||
if (info.owner.compare(s->user.user_id) != 0) {
|
||||
ret = -ERR_BUCKET_EXISTS;
|
||||
return;
|
||||
@ -974,14 +971,12 @@ void RGWCreateBucket::execute()
|
||||
s->bucket = info.bucket;
|
||||
}
|
||||
|
||||
ret = rgw_add_bucket(store, s->user.user_id, s->bucket);
|
||||
ret = rgw_add_bucket(store, s->user.user_id, s->bucket, info.creation_time);
|
||||
if (ret && !existed && ret != -EEXIST) /* if it exists (or previously existed), don't remove it! */
|
||||
rgw_remove_user_bucket_info(store, s->user.user_id, s->bucket);
|
||||
|
||||
if (ret == -EEXIST)
|
||||
ret = -ERR_BUCKET_EXISTS;
|
||||
|
||||
bucket = s->bucket;
|
||||
}
|
||||
|
||||
int RGWDeleteBucket::verify_permission()
|
||||
|
@ -234,7 +234,7 @@ protected:
|
||||
RGWAccessControlPolicy policy;
|
||||
string location_constraint;
|
||||
RGWObjVersionTracker objv_tracker;
|
||||
rgw_bucket bucket;
|
||||
RGWBucketInfo info;
|
||||
|
||||
bufferlist in_data;
|
||||
|
||||
|
@ -1680,7 +1680,9 @@ int RGWRados::create_bucket(string& owner, rgw_bucket& bucket,
|
||||
map<std::string, bufferlist>& attrs,
|
||||
RGWObjVersionTracker& objv_tracker,
|
||||
obj_version *pobjv,
|
||||
time_t creation_time,
|
||||
rgw_bucket *pmaster_bucket,
|
||||
RGWBucketInfo *pinfo,
|
||||
bool exclusive)
|
||||
{
|
||||
#define MAX_CREATE_RETRIES 20 /* need to bound retries */
|
||||
@ -1729,6 +1731,10 @@ int RGWRados::create_bucket(string& owner, rgw_bucket& bucket,
|
||||
info.bucket = bucket;
|
||||
info.owner = owner;
|
||||
info.region = region_name;
|
||||
if (!creation_time)
|
||||
time(&info.creation_time);
|
||||
else
|
||||
info.creation_time = creation_time;
|
||||
ret = put_bucket_info(bucket.name, info, exclusive, &objv_tracker, &attrs);
|
||||
if (ret == -EEXIST) {
|
||||
librados::IoCtx index_ctx; // context for new bucket
|
||||
@ -1747,6 +1753,8 @@ int RGWRados::create_bucket(string& owner, rgw_bucket& bucket,
|
||||
return r;
|
||||
}
|
||||
}
|
||||
if (pinfo)
|
||||
*pinfo = info;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -779,7 +779,9 @@ public:
|
||||
map<std::string,bufferlist>& attrs,
|
||||
RGWObjVersionTracker& objv_tracker,
|
||||
obj_version *pobjv,
|
||||
time_t creation_time,
|
||||
rgw_bucket *master_bucket,
|
||||
RGWBucketInfo *pinfo,
|
||||
bool exclusive = true);
|
||||
virtual int add_bucket_placement(std::string& new_pool);
|
||||
virtual int remove_bucket_placement(std::string& new_pool);
|
||||
|
@ -35,7 +35,7 @@ void dump_bucket(struct req_state *s, RGWBucketEnt& obj)
|
||||
{
|
||||
s->formatter->open_object_section("Bucket");
|
||||
s->formatter->dump_string("Name", obj.bucket.name);
|
||||
dump_time(s, "CreationDate", &obj.mtime);
|
||||
dump_time(s, "CreationDate", &obj.creation_time);
|
||||
s->formatter->close_section();
|
||||
}
|
||||
|
||||
@ -430,7 +430,7 @@ void RGWCreateBucket_ObjStore_S3::send_response()
|
||||
|
||||
f.open_object_section("info");
|
||||
encode_json("object_ver", objv_tracker.read_version, &f);
|
||||
encode_json("bucket", bucket, &f);
|
||||
encode_json("bucket_info", info, &f);
|
||||
f.close_section();
|
||||
rgw_flush_formatter_and_reset(s, &f);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user