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:
Yehuda Sadeh 2013-06-15 18:41:21 -07:00
parent 8eae1b8ba2
commit a2cf14fe27
9 changed files with 51 additions and 41 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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);
}

View File

@ -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()

View File

@ -234,7 +234,7 @@ protected:
RGWAccessControlPolicy policy;
string location_constraint;
RGWObjVersionTracker objv_tracker;
rgw_bucket bucket;
RGWBucketInfo info;
bufferlist in_data;

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}