]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: propagate mtime from remote rgw on copy
authorYehuda Sadeh <yehuda@inktank.com>
Wed, 12 Jun 2013 01:51:14 +0000 (18:51 -0700)
committerYehuda Sadeh <yehuda@inktank.com>
Wed, 12 Jun 2013 01:51:14 +0000 (18:51 -0700)
Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
src/rgw/rgw_op.cc
src/rgw/rgw_op.h
src/rgw/rgw_rados.cc
src/rgw/rgw_rados.h
src/rgw/rgw_rest.cc
src/rgw/rgw_rest.h
src/rgw/rgw_rest_client.cc
src/rgw/rgw_rest_client.h
src/rgw/rgw_rest_conn.cc
src/rgw/rgw_rest_conn.h
src/rgw/rgw_rest_s3.cc

index 86618bd674b20f21bdbd537907f4f87c8197482e..c30987b8e22170339891d865996c65d6722c68a7 100644 (file)
@@ -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);
 }
 
index 55011b4102fa2116d461650f6026b749fced3702..09238778cff95873fbb9e56480e22d72f4fd849a 100644 (file)
@@ -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) {
index d115fc731a47bad19b32e38b4b74c92f7bbe5844..05d9ceffc01d52bbeb55f1eee717ebbc99627e94 100644 (file)
@@ -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;
 
index cee93e913c06abec3c532497fdac3765736841be..771cde77e9576528e79c09a63f2c4cfec9c779bc 100644 (file)
@@ -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);
   }
index 764614337747efca2295d0659eccba356f68f85c..d2c277446fd5beda9166f1bea477a213a99beb78 100644 (file)
@@ -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;
   }
index e3b20bd7160460c7015d13ffa8e4105515cd07db..0b7204fe9cb173936c245c5b0b4bc13d6f0d611b 100644 (file)
@@ -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);
index 7a78bb8f9cd7b78a72b8d4ce64b54a2d4a912f7a..aa01b499f2cd91d6b32b74bd60874074b591a19e 100644 (file)
@@ -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;
 }
index cb744f4f695cee51f2900345000d57a54ce0a5d8..a7cc571819fb6253d617bc2cb80800e5e39a00e6 100644 (file)
@@ -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; }
 };
index 8dc2c502d537ef7b0a771b633c1cfd46d7c26421..71f97d861f5cc7ea8efc3796a68b261354fd463d 100644 (file)
@@ -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;
index 5119cdc250e1eeaac324ea218e3f48a42dc34ff5..f9e35e4dedf36f7a6b7e1a6acf42426c55e1891b 100644 (file)
@@ -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
index 831959f25478069ddcc3433c2b93e7a321f5cf3a..4aaf1cd3bae6066cf06d639a52eab7a26dd2d0b6 100644 (file)
@@ -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);
 }