summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYehuda Sadeh <yehuda@inktank.com>2013-06-11 18:51:14 -0700
committerYehuda Sadeh <yehuda@inktank.com>2013-06-11 18:51:14 -0700
commit95434d16086af1d005aa4ac2d5c583c6787f987b (patch)
tree50c5ee4e76e89a11ce73425af2c13ed0d89161b1
parent00743d50e09f48c71ce47f6b61907fa48a42f114 (diff)
downloadceph-95434d16086af1d005aa4ac2d5c583c6787f987b.tar.gz
rgw: propagate mtime from remote rgw on copy
Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
-rw-r--r--src/rgw/rgw_op.cc27
-rw-r--r--src/rgw/rgw_op.h6
-rw-r--r--src/rgw/rgw_rados.cc6
-rw-r--r--src/rgw/rgw_rados.h4
-rw-r--r--src/rgw/rgw_rest.cc20
-rw-r--r--src/rgw/rgw_rest.h1
-rw-r--r--src/rgw/rgw_rest_client.cc49
-rw-r--r--src/rgw/rgw_rest_client.h10
-rw-r--r--src/rgw/rgw_rest_conn.cc8
-rw-r--r--src/rgw/rgw_rest_conn.h4
-rw-r--r--src/rgw/rgw_rest_s3.cc3
11 files changed, 97 insertions, 41 deletions
diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc
index 86618bd674b..c30987b8e22 100644
--- a/src/rgw/rgw_op.cc
+++ b/src/rgw/rgw_op.cc
@@ -1022,9 +1022,9 @@ int RGWPutObj::verify_permission()
return 0;
}
-int RGWPutObjProcessor::complete(string& etag, map<string, bufferlist>& attrs)
+int RGWPutObjProcessor::complete(string& etag, time_t *mtime, map<string, bufferlist>& attrs)
{
- int r = do_complete(etag, attrs);
+ int r = do_complete(etag, mtime, attrs);
if (r < 0)
return r;
@@ -1060,7 +1060,7 @@ protected:
int prepare(RGWRados *store, struct req_state *s);
int handle_data(bufferlist& bl, off_t ofs, void **phandle);
int throttle_data(void *handle) { return 0; }
- int do_complete(string& etag, map<string, bufferlist>& attrs);
+ int do_complete(string& etag, time_t *mtime, map<string, bufferlist>& attrs);
public:
RGWPutObjProcessor_Plain() : ofs(0) {}
@@ -1086,9 +1086,9 @@ int RGWPutObjProcessor_Plain::handle_data(bufferlist& bl, off_t _ofs, void **pha
return 0;
}
-int RGWPutObjProcessor_Plain::do_complete(string& etag, map<string, bufferlist>& attrs)
+int RGWPutObjProcessor_Plain::do_complete(string& etag, time_t *mtime, map<string, bufferlist>& attrs)
{
- int r = store->put_obj_meta(s->obj_ctx, obj, data.length(), attrs,
+ int r = store->put_obj_meta(s->obj_ctx, obj, data.length(), mtime, attrs,
RGW_OBJ_CATEGORY_MAIN, PUT_OBJ_CREATE,
&data);
return r;
@@ -1210,7 +1210,7 @@ protected:
virtual bool immutable_head() { return false; }
int prepare(RGWRados *store, struct req_state *s);
- virtual int do_complete(string& etag, map<string, bufferlist>& attrs);
+ virtual int do_complete(string& etag, time_t *mtime, map<string, bufferlist>& attrs);
void prepare_next_part(off_t ofs);
void complete_parts();
@@ -1291,7 +1291,7 @@ void RGWPutObjProcessor_Atomic::complete_parts()
prepare_next_part(obj_len);
}
-int RGWPutObjProcessor_Atomic::do_complete(string& etag, map<string, bufferlist>& attrs)
+int RGWPutObjProcessor_Atomic::do_complete(string& etag, time_t *mtime, map<string, bufferlist>& attrs)
{
complete_parts();
@@ -1302,6 +1302,7 @@ int RGWPutObjProcessor_Atomic::do_complete(string& etag, map<string, bufferlist>
extra_params.data = &first_chunk;
extra_params.manifest = &manifest;
extra_params.ptag = &s->req_id; /* use req_id as operation tag */
+ extra_params.mtime = mtime;
int r = store->put_obj_meta(s->obj_ctx, head_obj, obj_len, attrs,
RGW_OBJ_CATEGORY_MAIN, PUT_OBJ_CREATE,
@@ -1317,7 +1318,7 @@ class RGWPutObjProcessor_Multipart : public RGWPutObjProcessor_Atomic
protected:
bool immutable_head() { return true; }
int prepare(RGWRados *store, struct req_state *s);
- int do_complete(string& etag, map<string, bufferlist>& attrs);
+ int do_complete(string& etag, time_t *mtime, map<string, bufferlist>& attrs);
public:
RGWPutObjProcessor_Multipart(uint64_t _p) : RGWPutObjProcessor_Atomic(_p) {}
@@ -1347,11 +1348,11 @@ int RGWPutObjProcessor_Multipart::prepare(RGWRados *store, struct req_state *s)
return 0;
}
-int RGWPutObjProcessor_Multipart::do_complete(string& etag, map<string, bufferlist>& attrs)
+int RGWPutObjProcessor_Multipart::do_complete(string& etag, time_t *mtime, map<string, bufferlist>& attrs)
{
complete_parts();
- int r = store->put_obj_meta(s->obj_ctx, head_obj, s->obj_size, attrs, RGW_OBJ_CATEGORY_MAIN, 0);
+ int r = store->put_obj_meta(s->obj_ctx, head_obj, s->obj_size, mtime, attrs, RGW_OBJ_CATEGORY_MAIN, 0);
if (r < 0)
return r;
@@ -1514,7 +1515,7 @@ void RGWPutObj::execute()
rgw_get_request_metadata(s->cct, s->info, attrs);
- ret = processor->complete(etag, attrs);
+ ret = processor->complete(etag, &mtime, attrs);
done:
dispose_processor(processor);
perfcounter->tinc(l_rgw_put_lat,
@@ -1630,7 +1631,7 @@ void RGWPostObj::execute()
attrs[RGW_ATTR_CONTENT_TYPE] = ct_bl;
}
- ret = processor->complete(etag, attrs);
+ ret = processor->complete(etag, NULL, attrs);
done:
dispose_processor(processor);
@@ -2233,7 +2234,7 @@ void RGWInitMultipart::execute()
obj.init_ns(s->bucket, tmp_obj_name, mp_ns);
// the meta object will be indexed with 0 size, we c
- ret = store->put_obj_meta(s->obj_ctx, obj, 0, attrs, RGW_OBJ_CATEGORY_MULTIMETA, PUT_OBJ_CREATE_EXCL);
+ ret = store->put_obj_meta(s->obj_ctx, obj, 0, NULL, attrs, RGW_OBJ_CATEGORY_MULTIMETA, PUT_OBJ_CREATE_EXCL);
} while (ret == -EEXIST);
}
diff --git a/src/rgw/rgw_op.h b/src/rgw/rgw_op.h
index 55011b4102f..09238778cff 100644
--- a/src/rgw/rgw_op.h
+++ b/src/rgw/rgw_op.h
@@ -274,7 +274,7 @@ protected:
struct req_state *s;
bool is_complete;
- virtual int do_complete(string& etag, map<string, bufferlist>& attrs) = 0;
+ virtual int do_complete(string& etag, time_t *mtime, map<string, bufferlist>& attrs) = 0;
list<rgw_obj> objs;
@@ -291,7 +291,7 @@ public:
};
virtual int handle_data(bufferlist& bl, off_t ofs, void **phandle) = 0;
virtual int throttle_data(void *handle) = 0;
- virtual int complete(string& etag, map<string, bufferlist>& attrs);
+ virtual int complete(string& etag, time_t *mtime, map<string, bufferlist>& attrs);
};
class RGWPutObj : public RGWOp {
@@ -307,6 +307,7 @@ protected:
bool chunked_upload;
RGWAccessControlPolicy policy;
const char *obj_manifest;
+ time_t mtime;
public:
RGWPutObj() {
@@ -316,6 +317,7 @@ public:
supplied_etag = NULL;
chunked_upload = false;
obj_manifest = NULL;
+ mtime = 0;
}
virtual void init(RGWRados *store, struct req_state *s, RGWHandler *h) {
diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc
index d115fc731a4..05d9ceffc01 100644
--- a/src/rgw/rgw_rados.cc
+++ b/src/rgw/rgw_rados.cc
@@ -1975,7 +1975,7 @@ int RGWRados::copy_obj(void *ctx,
map<string, bufferlist> src_attrs;
- RGWRESTStreamRequest *out_stream_req;
+ RGWRESTStreamWriteRequest *out_stream_req;
int ret = rest_conn->put_obj_init(user_id, dest_obj, astate->size, attrset, &out_stream_req);
if (ret < 0)
@@ -1985,7 +1985,9 @@ int RGWRados::copy_obj(void *ctx,
if (ret < 0)
return ret;
- ret = rest_conn->complete_request(out_stream_req);
+ string etag;
+
+ ret = rest_conn->complete_request(out_stream_req, etag, mtime);
if (ret < 0)
return ret;
diff --git a/src/rgw/rgw_rados.h b/src/rgw/rgw_rados.h
index cee93e913c0..771cde77e95 100644
--- a/src/rgw/rgw_rados.h
+++ b/src/rgw/rgw_rados.h
@@ -679,10 +679,10 @@ public:
RGWObjManifest *manifest, const string *ptag, list<string> *remove_objs,
bool modify_version, RGWObjVersionTracker *objv_tracker);
- virtual int put_obj_meta(void *ctx, rgw_obj& obj, uint64_t size,
+ virtual int put_obj_meta(void *ctx, rgw_obj& obj, uint64_t size, time_t *mtime,
map<std::string, bufferlist>& attrs, RGWObjCategory category, int flags,
const bufferlist *data = NULL) {
- return put_obj_meta_impl(ctx, obj, size, NULL, attrs, category, flags,
+ return put_obj_meta_impl(ctx, obj, size, mtime, attrs, category, flags,
NULL, data, NULL, NULL, NULL,
false, NULL);
}
diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc
index 76461433774..d2c277446fd 100644
--- a/src/rgw/rgw_rest.cc
+++ b/src/rgw/rgw_rest.cc
@@ -302,7 +302,7 @@ void dump_redirect(struct req_state *s, const string& redirect)
s->cio->print("Location: %s\n", redirect.c_str());
}
-void dump_last_modified(struct req_state *s, time_t t)
+static void dump_time_header(struct req_state *s, const char *name, time_t t)
{
char timestr[TIME_BUF_SIZE];
@@ -314,7 +314,23 @@ void dump_last_modified(struct req_state *s, time_t t)
if (strftime(timestr, sizeof(timestr), "%a, %d %b %Y %H:%M:%S %Z", tmp) == 0)
return;
- int r = s->cio->print("Last-Modified: %s\n", timestr);
+ int r = s->cio->print("%s: %s\n", name, timestr);
+ if (r < 0) {
+ ldout(s->cct, 0) << "ERROR: s->cio->print() returned err=" << r << dendl;
+ }
+}
+
+void dump_last_modified(struct req_state *s, time_t t)
+{
+ dump_time_header(s, "Last-Modified", t);
+}
+
+void dump_epoch_header(struct req_state *s, const char *name, time_t t)
+{
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%lld", (long long)t);
+
+ int r = s->cio->print("%s: %s\n", name, buf);
if (r < 0) {
ldout(s->cct, 0) << "ERROR: s->cio->print() returned err=" << r << dendl;
}
diff --git a/src/rgw/rgw_rest.h b/src/rgw/rgw_rest.h
index e3b20bd7160..0b7204fe9cb 100644
--- a/src/rgw/rgw_rest.h
+++ b/src/rgw/rgw_rest.h
@@ -314,6 +314,7 @@ extern void list_all_buckets_start(struct req_state *s);
extern void dump_owner(struct req_state *s, string& id, string& name, const char *section = NULL);
extern void dump_content_length(struct req_state *s, uint64_t len);
extern void dump_etag(struct req_state *s, const char *etag);
+extern void dump_epoch_header(struct req_state *s, const char *name, time_t t);
extern void dump_last_modified(struct req_state *s, time_t t);
extern void abort_early(struct req_state *s, int err);
extern void dump_range(struct req_state *s, uint64_t ofs, uint64_t end, uint64_t total_size);
diff --git a/src/rgw/rgw_rest_client.cc b/src/rgw/rgw_rest_client.cc
index 7a78bb8f9cd..aa01b499f2c 100644
--- a/src/rgw/rgw_rest_client.cc
+++ b/src/rgw/rgw_rest_client.cc
@@ -6,6 +6,7 @@
#include "common/ceph_crypto_cms.h"
#include "common/armor.h"
+#include "common/strtol.h"
#define dout_subsys ceph_subsys_rgw
@@ -43,7 +44,13 @@ int RGWRESTSimpleRequest::receive_header(void *ptr, size_t len)
char buf[len + 1];
size_t i;
for (i = 0; i < len && *src; ++i, ++src) {
- buf[i] = toupper(*src);
+ switch (*src) {
+ case '-':
+ buf[i] = '_';
+ break;
+ default:
+ buf[i] = toupper(*src);
+ }
}
buf[i] = '\0';
out_headers[buf] = l;
@@ -252,9 +259,9 @@ int RGWRESTSimpleRequest::forward_request(RGWAccessKey& key, req_info& info, siz
}
class RGWRESTStreamOutCB : public RGWGetDataCB {
- RGWRESTStreamRequest *req;
+ RGWRESTStreamWriteRequest *req;
public:
- RGWRESTStreamOutCB(RGWRESTStreamRequest *_req) : req(_req) {}
+ RGWRESTStreamOutCB(RGWRESTStreamWriteRequest *_req) : req(_req) {}
int handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len); /* callback for object iteration when sending data */
};
@@ -272,12 +279,12 @@ int RGWRESTStreamOutCB::handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len)
return req->add_output_data(new_bl);
}
-RGWRESTStreamRequest::~RGWRESTStreamRequest()
+RGWRESTStreamWriteRequest::~RGWRESTStreamWriteRequest()
{
delete cb;
}
-int RGWRESTStreamRequest::add_output_data(bufferlist& bl)
+int RGWRESTStreamWriteRequest::add_output_data(bufferlist& bl)
{
lock.Lock();
if (status < 0) {
@@ -362,7 +369,7 @@ static void add_grants_headers(map<int, string>& grants, map<string, string>& at
}
}
-int RGWRESTStreamRequest::put_obj_init(RGWAccessKey& key, rgw_obj& obj, uint64_t obj_size, map<string, bufferlist>& attrs)
+int RGWRESTStreamWriteRequest::put_obj_init(RGWAccessKey& key, rgw_obj& obj, uint64_t obj_size, map<string, bufferlist>& attrs)
{
string resource = obj.bucket.name + "/" + obj.object;
string new_url = url;
@@ -444,11 +451,11 @@ int RGWRESTStreamRequest::put_obj_init(RGWAccessKey& key, rgw_obj& obj, uint64_t
return 0;
}
-int RGWRESTStreamRequest::send_data(void *ptr, size_t len)
+int RGWRESTStreamWriteRequest::send_data(void *ptr, size_t len)
{
uint64_t sent = 0;
- dout(20) << "RGWRESTStreamRequest::send_data()" << dendl;
+ dout(20) << "RGWRESTStreamWriteRequest::send_data()" << dendl;
lock.Lock();
if (pending_send.empty() || status < 0) {
lock.Unlock();
@@ -489,11 +496,35 @@ int RGWRESTStreamRequest::send_data(void *ptr, size_t len)
}
-int RGWRESTStreamRequest::complete()
+void set_str_from_headers(map<string, string>& out_headers, const string& header_name, string& str)
+{
+ map<string, string>::iterator iter = out_headers.find(header_name);
+ if (iter != out_headers.end()) {
+ str = iter->second;
+ } else {
+ str.clear();
+ }
+}
+
+
+int RGWRESTStreamWriteRequest::complete(string& etag, time_t *mtime)
{
int ret = complete_request(handle);
if (ret < 0)
return ret;
+ set_str_from_headers(out_headers, "ETAG", etag);
+ if (mtime) {
+ string mtime_str;
+ set_str_from_headers(out_headers, "RGWX_MTIME", mtime_str);
+ string err;
+ long t = strict_strtol(mtime_str.c_str(), 10, &err);
+ if (!err.empty()) {
+ ldout(cct, 0) << "ERROR: failed converting mtime (" << mtime_str << ") to int " << dendl;
+ return -EINVAL;
+ }
+ *mtime = (time_t)t;
+ }
+
return status;
}
diff --git a/src/rgw/rgw_rest_client.h b/src/rgw/rgw_rest_client.h
index cb744f4f695..a7cc571819f 100644
--- a/src/rgw/rgw_rest_client.h
+++ b/src/rgw/rgw_rest_client.h
@@ -53,7 +53,7 @@ public:
};
-class RGWRESTStreamRequest : public RGWRESTSimpleRequest {
+class RGWRESTStreamWriteRequest : public RGWRESTSimpleRequest {
Mutex lock;
list<bufferlist> pending_send;
void *handle;
@@ -62,12 +62,12 @@ public:
int add_output_data(bufferlist& bl);
int send_data(void *ptr, size_t len);
- RGWRESTStreamRequest(CephContext *_cct, string& _url, list<pair<string, string> > *_headers,
+ RGWRESTStreamWriteRequest(CephContext *_cct, string& _url, list<pair<string, string> > *_headers,
list<pair<string, string> > *_params) : RGWRESTSimpleRequest(_cct, _url, _headers, _params),
- lock("RGWRESTStreamRequest"), handle(NULL), cb(NULL) {}
- ~RGWRESTStreamRequest();
+ lock("RGWRESTStreamWriteRequest"), handle(NULL), cb(NULL) {}
+ ~RGWRESTStreamWriteRequest();
int put_obj_init(RGWAccessKey& key, rgw_obj& obj, uint64_t obj_size, map<string, bufferlist>& attrs);
- int complete();
+ int complete(string& etag, time_t *mtime);
RGWGetDataCB *get_out_cb() { return cb; }
};
diff --git a/src/rgw/rgw_rest_conn.cc b/src/rgw/rgw_rest_conn.cc
index 8dc2c502d53..71f97d861f5 100644
--- a/src/rgw/rgw_rest_conn.cc
+++ b/src/rgw/rgw_rest_conn.cc
@@ -47,7 +47,7 @@ public:
};
int RGWRegionConnection::put_obj_init(const string& uid, rgw_obj& obj, uint64_t obj_size,
- map<string, bufferlist>& attrs, RGWRESTStreamRequest **req)
+ map<string, bufferlist>& attrs, RGWRESTStreamWriteRequest **req)
{
string url;
int ret = get_url(url);
@@ -57,13 +57,13 @@ int RGWRegionConnection::put_obj_init(const string& uid, rgw_obj& obj, uint64_t
list<pair<string, string> > params;
params.push_back(make_pair<string, string>(RGW_SYS_PARAM_PREFIX "uid", uid));
params.push_back(make_pair<string, string>(RGW_SYS_PARAM_PREFIX "region", region));
- *req = new RGWRESTStreamRequest(cct, url, NULL, &params);
+ *req = new RGWRESTStreamWriteRequest(cct, url, NULL, &params);
return (*req)->put_obj_init(key, obj, obj_size, attrs);
}
-int RGWRegionConnection::complete_request(RGWRESTStreamRequest *req)
+int RGWRegionConnection::complete_request(RGWRESTStreamWriteRequest *req, string& etag, time_t *mtime)
{
- int ret = req->complete();
+ int ret = req->complete(etag, mtime);
delete req;
return ret;
diff --git a/src/rgw/rgw_rest_conn.h b/src/rgw/rgw_rest_conn.h
index 5119cdc250e..f9e35e4dedf 100644
--- a/src/rgw/rgw_rest_conn.h
+++ b/src/rgw/rgw_rest_conn.h
@@ -25,8 +25,8 @@ public:
/* async request */
int put_obj_init(const string& uid, rgw_obj& obj, uint64_t obj_size,
- map<string, bufferlist>& attrs, RGWRESTStreamRequest **req);
- int complete_request(RGWRESTStreamRequest *req);
+ map<string, bufferlist>& attrs, RGWRESTStreamWriteRequest **req);
+ int complete_request(RGWRESTStreamWriteRequest *req, string& etag, time_t *mtime);
};
#endif
diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc
index 831959f2547..4aaf1cd3bae 100644
--- a/src/rgw/rgw_rest_s3.cc
+++ b/src/rgw/rgw_rest_s3.cc
@@ -480,6 +480,9 @@ void RGWPutObj_ObjStore_S3::send_response()
dump_etag(s, etag.c_str());
dump_content_length(s, 0);
}
+ if (s->system_request && mtime) {
+ dump_epoch_header(s, "Rgwx-Mtime", mtime);
+ }
dump_errno(s);
end_header(s);
}