]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: different atomic handling for small objects
authorYehuda Sadeh <yehuda@hq.newdream.net>
Thu, 5 Jan 2012 20:51:27 +0000 (12:51 -0800)
committerYehuda Sadeh <yehuda@hq.newdream.net>
Sat, 7 Jan 2012 00:53:02 +0000 (16:53 -0800)
12 files changed:
src/rgw/rgw_access.h
src/rgw/rgw_cache.h
src/rgw/rgw_fs.cc
src/rgw/rgw_fs.h
src/rgw/rgw_main.cc
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_swift_auth.h

index e0928c1f58b194ba6312370a79abdab6036757cf..db78cb6e6d78c675985ff2889a8b6e71be1df4d6 100644 (file)
@@ -229,7 +229,7 @@ public:
  /**
   * stat an object
   */
-  virtual int obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs) = 0;
+  virtual int obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs, bufferlist *first_chunk) = 0;
 
   virtual bool supports_tmap() { return false; }
 
@@ -255,6 +255,7 @@ public:
   virtual void *create_context(void *user_ctx) { return NULL; }
   virtual void destroy_context(void *ctx) {}
   virtual void set_atomic(void *ctx, rgw_obj& obj) {}
+  virtual void set_prefetch_data(void *ctx, rgw_obj& obj) {}
 
   // to notify upper layer that we need to do some operation on an object, and it's up to
   // the upper layer to schedule this operation.. e.g., log intent in intent log
index fdfbe024ed5b246c68ca4d1bf51e67ef526f9a21..82582389d51333b1f7be9db0b4b358e58f4fde90 100644 (file)
@@ -184,7 +184,7 @@ public:
 
   int get_obj(void *ctx, void **handle, rgw_obj& obj, char **data, off_t ofs, off_t end);
 
-  int obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs);
+  int obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs, bufferlist *first_chunk);
 
   int delete_obj(void *ctx, rgw_obj& obj, bool sync);
 };
@@ -348,13 +348,13 @@ int RGWCache<T>::put_obj_data(void *ctx, rgw_obj& obj, const char *data,
 }
 
 template <class T>
-int RGWCache<T>::obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs)
+int RGWCache<T>::obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs, bufferlist *first_chunk)
 {
   rgw_bucket bucket;
   string oid;
   normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid);
   if (bucket.name[0] != '.')
-    return T::obj_stat(ctx, obj, psize, pmtime, attrs);
+    return T::obj_stat(ctx, obj, psize, pmtime, attrs, first_chunk);
 
   string name = normal_name(bucket, oid);
 
@@ -371,7 +371,7 @@ int RGWCache<T>::obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmti
     mtime = info.meta.mtime;
     goto done;
   }
-  r = T::obj_stat(ctx, obj, &size, &mtime, &info.xattrs);
+  r = T::obj_stat(ctx, obj, &size, &mtime, &info.xattrs, first_chunk);
   if (r < 0) {
     if (r == -ENOENT) {
       info.status = r;
index 3fbed040338adf5f4e6bf71d5d6d1087789a51ee..4ba843365473db4f74316e5b01adcfcd21f8da36 100644 (file)
@@ -91,7 +91,7 @@ int RGWFS::list_buckets_next(RGWObjEnt& obj, RGWAccessHandle *handle)
   }
 }
 
-int RGWFS::obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs)
+int RGWFS::obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs, bufferlist *first_chunk)
 {
   return -ENOTSUP;
 }
index c78d53035e02a65865aba2d1815383f2730b8c41..2a5954c8b5488f3f93e97e2b38f0def24ec91d48 100644 (file)
@@ -60,7 +60,7 @@ public:
 
   void finish_get_obj(void **handle);
   int read(void *ctx, rgw_obj& obj, off_t ofs, size_t size, bufferlist& bl);
-  int obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs);
+  int obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs, bufferlist *prefetch_data);
 
   virtual int get_bucket_info(void *ctx, string& bucket_name, RGWBucketInfo& info);
   virtual int put_bucket_info(string& bucket_name, RGWBucketInfo& info, bool exclusive);
index 6cd7b5603f898bc2b3794d0ade1c5565a694579b..8d6de93c0a8a9ad00388d72e456625ece1dfe381 100644 (file)
@@ -205,7 +205,7 @@ void RGWProcess::handle_request(FCGX_Request *fcgx)
     abort_early(s, -ERR_USER_SUSPENDED);
     goto done;
   }
-  ret = handler->read_permissions();
+  ret = handler->read_permissions(op);
   if (ret < 0) {
     abort_early(s, ret);
     goto done;
index 020e2998ab3d08ec7c8d1af182cf47963c061351..efe3107bf73ec6873da14703a6260586ef84143c 100644 (file)
@@ -214,7 +214,6 @@ static int read_acls(struct req_state *s, RGWBucketInfo& bucket_info, RGWAccessC
     obj.set_ns(mp_ns);
   }
   obj.init(bucket, oid, object);
-
   int ret = get_policy_from_attr(s->obj_ctx, policy, obj);
   if (ret == -ENOENT && object.size()) {
     /* object does not exist checking the bucket's ACL to make sure
@@ -243,7 +242,7 @@ static int read_acls(struct req_state *s, RGWBucketInfo& bucket_info, RGWAccessC
  * only_bucket: If true, reads the bucket ACL rather than the object ACL.
  * Returns: 0 on success, -ERR# otherwise.
  */
-static int read_acls(struct req_state *s, bool only_bucket)
+static int read_acls(struct req_state *s, bool only_bucket, bool prefetch_data)
 {
   int ret = 0;
   string obj_str;
@@ -253,13 +252,6 @@ static int read_acls(struct req_state *s, bool only_bucket)
        return -ENOMEM;
   }
 
-  /* we're passed only_bucket = true when we specifically need the bucket's
-     acls, that happens on write operations */
-  if (!only_bucket) {
-    obj_str = s->object_str;
-    rgw_obj obj(s->bucket, obj_str);
-    rgwstore->set_atomic(s->obj_ctx, obj);
-  }
 
   RGWBucketInfo bucket_info;
   if (s->bucket_name_str.size()) {
@@ -272,6 +264,17 @@ static int read_acls(struct req_state *s, bool only_bucket)
     s->bucket_owner = bucket_info.owner;
   }
 
+  /* we're passed only_bucket = true when we specifically need the bucket's
+     acls, that happens on write operations */
+  if (!only_bucket) {
+    obj_str = s->object_str;
+    rgw_obj obj(s->bucket, obj_str);
+    rgwstore->set_atomic(s->obj_ctx, obj);
+    if (prefetch_data) {
+      rgwstore->set_prefetch_data(s->obj_ctx, obj);
+    }
+  }
+
   ret = read_acls(s, bucket_info, s->acl, s->bucket, obj_str);
 
   return ret;
@@ -279,6 +282,10 @@ static int read_acls(struct req_state *s, bool only_bucket)
 
 int RGWGetObj::verify_permission()
 {
+  obj.init(s->bucket, s->object_str);
+  rgwstore->set_atomic(s->obj_ctx, obj);
+  rgwstore->set_prefetch_data(s->obj_ctx, obj);
+
   if (!::verify_permission(s, RGW_PERM_READ))
     return -EACCES;
 
@@ -288,7 +295,6 @@ int RGWGetObj::verify_permission()
 void RGWGetObj::execute()
 {
   void *handle = NULL;
-  rgw_obj obj;
   utime_t start_time = s->time;
 
   perfcounter->inc(l_rgw_get);
@@ -301,8 +307,6 @@ void RGWGetObj::execute()
   if (ret < 0)
     goto done;
 
-  obj.init(s->bucket, s->object_str);
-  rgwstore->set_atomic(s->obj_ctx, obj);
   ret = rgwstore->prepare_get_obj(s->obj_ctx, obj, &ofs, &end, &attrs, mod_ptr,
                                   unmod_ptr, &lastmod, if_match, if_nomatch, &total_len, &s->obj_size, &handle, &s->err);
   if (ret < 0)
@@ -1065,7 +1069,7 @@ int RGWGetACLs::verify_permission()
 
 void RGWGetACLs::execute()
 {
-  ret = read_acls(s, false);
+  ret = read_acls(s, false, false);
 
   if (ret < 0) {
     send_response();
@@ -1636,9 +1640,9 @@ int RGWHandler::init(struct req_state *_s, FCGX_Request *fcgx)
   return 0;
 }
 
-int RGWHandler::do_read_permissions(bool only_bucket)
+int RGWHandler::do_read_permissions(RGWOp *op, bool only_bucket)
 {
-  int ret = read_acls(s, only_bucket);
+  int ret = read_acls(s, only_bucket, op->prefetch_data());
 
   if (ret < 0) {
     dout(10) << "read_permissions on " << s->bucket << ":" <<s->object_str << " only_bucket=" << only_bucket << " ret=" << ret << dendl;
index 6557c38a92839daf0d8d217765b680ab1d63046a..d973887ec425cf5343040844a236022ed7193a75 100644 (file)
@@ -33,6 +33,7 @@ public:
   virtual void init(struct req_state *s) {
     this->s = s;
   }
+  virtual bool prefetch_data() { return false; }
   virtual int verify_permission() = 0;
   virtual void execute() = 0;
 };
@@ -59,11 +60,14 @@ protected:
   int ret;
   bool get_data;
   bool partial_content;
+  rgw_obj obj;
 
   int init_common();
 public:
   RGWGetObj() {}
 
+  virtual bool prefetch_data() { return true; }
+
   virtual void init(struct req_state *s) {
     RGWOp::init(s);
     range_str = NULL;
@@ -604,7 +608,7 @@ class RGWHandler {
 protected:
   struct req_state *s;
 
-  int do_read_permissions(bool only_bucket);
+  int do_read_permissions(RGWOp *op, bool only_bucket);
 public:
   RGWHandler() {}
   virtual ~RGWHandler() {}
@@ -612,7 +616,7 @@ public:
 
   virtual RGWOp *get_op() = 0;
   virtual void put_op(RGWOp *op) = 0;
-  virtual int read_permissions() = 0;
+  virtual int read_permissions(RGWOp *op) = 0;
   virtual int authorize() = 0;
 };
 
index 0e3c9fc8d7b4024d4e09080b2bb0c780322fb373..993e88f4380b7c16a536ee5230d66ab9b10fbccc 100644 (file)
@@ -834,7 +834,7 @@ int RGWRados::copy_obj(void *ctx,
 
   ret = clone_obj(ctx, dest_obj, 0, tmp_obj, 0, end + 1, NULL, attrs, category);
   if (mtime)
-    obj_stat(ctx, tmp_obj, NULL, mtime, NULL);
+    obj_stat(ctx, tmp_obj, NULL, mtime, NULL, NULL);
 
   r = rgwstore->delete_obj(ctx, tmp_obj, false);
   if (r < 0)
@@ -1008,16 +1008,12 @@ int RGWRados::delete_obj(void *ctx, rgw_obj& obj, bool sync)
 int RGWRados::get_obj_state(RGWRadosCtx *rctx, rgw_obj& obj, librados::IoCtx& io_ctx, string& actual_obj, RGWObjState **state)
 {
   RGWObjState *s = rctx->get_state(obj);
-  dout(20) << "get_obj_state: rctx=" << (void *)rctx << " obj=" << obj << " state=" << (void *)s << dendl;
+  dout(20) << "get_obj_state: rctx=" << (void *)rctx << " obj=" << obj << " state=" << (void *)s << " s->prefetch_data=" << s->prefetch_data << dendl;
   *state = s;
   if (s->has_attrs)
     return 0;
 
-  ObjectReadOperation op;
-  op.getxattrs();
-  op.stat();
-  bufferlist outbl;
-  int r = obj_stat(rctx, obj, &s->size, &s->mtime, &s->attrset);
+  int r = obj_stat(rctx, obj, &s->size, &s->mtime, &s->attrset, (s->prefetch_data ? &s->data : NULL));
   if (r == -ENOENT) {
     s->exists = false;
     s->has_attrs = true;
@@ -1126,6 +1122,8 @@ int RGWRados::prepare_atomic_for_write_impl(RGWRadosCtx *rctx, rgw_obj& obj, lib
 
   RGWObjState *state = *pstate;
 
+  bool need_guard = (state->obj_tag.length() != 0);
+
   if (!state->is_atomic) {
     dout(20) << "prepare_atomic_for_write_impl: state is not atomic. state=" << (void *)state << dendl;
     return 0;
@@ -1135,7 +1133,9 @@ int RGWRados::prepare_atomic_for_write_impl(RGWRadosCtx *rctx, rgw_obj& obj, lib
       state->shadow_obj.size() == 0) {
     dout(0) << "can't clone object " << obj << " to shadow object, tag/shadow_obj haven't been set" << dendl;
     // FIXME: need to test object does not exist
-  } else {
+  } else if (state->size <= RGW_MAX_CHUNK_SIZE) {
+    dout(0) << "not cloning object, object size (" << state->size << ")" << " <= chunk size" << dendl;
+  }else {
     dout(0) << "cloning object " << obj << " to name=" << state->shadow_obj << dendl;
     rgw_obj dest_obj(obj.bucket, state->shadow_obj);
     dest_obj.set_ns(shadow_ns);
@@ -1165,7 +1165,9 @@ int RGWRados::prepare_atomic_for_write_impl(RGWRadosCtx *rctx, rgw_obj& obj, lib
       dout(0) << "ERROR: failed to clone object r=" << r << dendl;
       return r;
     }
+  }
 
+  if (need_guard) {
     /* first verify that the object wasn't replaced under */
     op.cmpxattr(RGW_ATTR_ID_TAG, LIBRADOS_CMPXATTR_OP_EQ, state->obj_tag);
     // FIXME: need to add FAIL_NOTEXIST_OK for racing deletion
@@ -1654,6 +1656,10 @@ int RGWRados::get_obj(void *ctx, void **handle, rgw_obj& obj,
   int r = append_atomic_test(rctx, obj, state->io_ctx, oid, op, &astate);
   if (r < 0)
     return r;
+  if (!ofs && astate && astate->data.length() >= len) {
+    bl = astate->data;
+    goto done;
+  }
 
   dout(20) << "rados->read ofs=" << ofs << " len=" << len << dendl;
   op.read(ofs, len);
@@ -1670,6 +1676,7 @@ int RGWRados::get_obj(void *ctx, void **handle, rgw_obj& obj,
     return r;
   }
 
+done:
   if (bl.length() > 0) {
     r = bl.length();
     *data = (char *)malloc(r);
@@ -1727,7 +1734,7 @@ int RGWRados::read(void *ctx, rgw_obj& obj, off_t ofs, size_t size, bufferlist&
   return r;
 }
 
-int RGWRados::obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs)
+int RGWRados::obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs, bufferlist *first_chunk)
 {
   rgw_bucket bucket;
   std::string oid, key;
@@ -1742,6 +1749,9 @@ int RGWRados::obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime,
   ObjectReadOperation op;
   op.getxattrs();
   op.stat();
+  if (first_chunk) {
+    op.read(0, RGW_MAX_CHUNK_SIZE);
+  }
   bufferlist outbl;
   r = io_ctx.operate(oid, &op, &outbl);
   if (r < 0)
@@ -1772,6 +1782,9 @@ int RGWRados::obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime,
     dout(0) << "ERROR: failed decoding object (obj=" << obj << ") info (either size or mtime), aborting" << dendl;
     return -EIO;
   }
+  if (first_chunk) {
+    oiter.copy_all(*first_chunk);
+  }
   if (psize)
     *psize = size;
   if (pmtime)
@@ -2416,7 +2429,7 @@ int RGWRados::process_intent_log(rgw_bucket& bucket, string& oid,
   cout << "processing intent log " << oid << std::endl;
   uint64_t size;
   rgw_obj obj(bucket, oid);
-  int r = obj_stat(NULL, obj, &size, NULL, NULL);
+  int r = obj_stat(NULL, obj, &size, NULL, NULL, NULL);
   if (r < 0) {
     cerr << "error while doing stat on " << bucket << ":" << oid
         << " " << cpp_strerror(-r) << std::endl;
index daa1e07303105d6e53b0cbcc26c0fa3b5824d012..e02220fe1aeaa5fa6fc3376472f7374003116120 100644 (file)
@@ -19,9 +19,12 @@ struct RGWObjState {
   time_t mtime;
   bufferlist obj_tag;
   string shadow_obj;
+  bool has_data;
+  bufferlist data;
+  bool prefetch_data;
 
   map<string, bufferlist> attrset;
-  RGWObjState() : is_atomic(false), has_attrs(0), exists(false) {}
+  RGWObjState() : is_atomic(false), has_attrs(0), exists(false), prefetch_data(false) {}
 
   bool get_attr(string name, bufferlist& dest) {
     map<string, bufferlist>::iterator iter = attrset.find(name);
@@ -40,6 +43,7 @@ struct RGWObjState {
     obj_tag.clear();
     shadow_obj.clear();
     attrset.clear();
+    data.clear();
   }
 };
 
@@ -63,6 +67,14 @@ struct RGWRadosCtx {
       objs_state[new_obj].is_atomic = true;
     }
   }
+  void set_prefetch_data(rgw_obj& obj) {
+    if (obj.object.size()) {
+      objs_state[obj].prefetch_data = true;
+    } else {
+      rgw_obj new_obj(rgw_root_bucket, obj.bucket.name);
+      objs_state[new_obj].prefetch_data = true;
+    }
+  }
   void set_intent_cb(int (*cb)(void *user_ctx, rgw_obj& obj, RGWIntentEvent intent)) {
     intent_cb = cb;
   }
@@ -271,7 +283,7 @@ public:
 
   virtual int read(void *ctx, rgw_obj& obj, off_t ofs, size_t size, bufferlist& bl);
 
-  virtual int obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs);
+  virtual int obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, map<string, bufferlist> *attrs, bufferlist *first_chunk);
 
   virtual bool supports_tmap() { return true; }
   virtual int tmap_get(rgw_obj& obj, bufferlist& header, std::map<string, bufferlist>& m);
@@ -299,6 +311,10 @@ public:
     RGWRadosCtx *rctx = (RGWRadosCtx *)ctx;
     rctx->set_atomic(obj);
   }
+  void set_prefetch_data(void *ctx, rgw_obj& obj) {
+    RGWRadosCtx *rctx = (RGWRadosCtx *)ctx;
+    rctx->set_prefetch_data(obj);
+  }
   void set_intent_cb(void *ctx, int (*cb)(void *user_ctx, rgw_obj& obj, RGWIntentEvent intent)) {
     RGWRadosCtx *rctx = (RGWRadosCtx *)ctx;
     rctx->set_intent_cb(cb);
index e3e303050a0adcff8e0245e277abcbe5552435c7..31c427e4ac728a92c9145b0bdaf8206f25f30720 100644 (file)
@@ -820,7 +820,7 @@ int RGWHandler_REST::preprocess(struct req_state *s, FCGX_Request *fcgx)
   return ret;
 }
 
-int RGWHandler_REST::read_permissions()
+int RGWHandler_REST::read_permissions(RGWOp *op_obj)
 {
   bool only_bucket;
 
@@ -847,7 +847,7 @@ int RGWHandler_REST::read_permissions()
     return -EINVAL;
   }
 
-  return do_read_permissions(only_bucket);
+  return do_read_permissions(op_obj, only_bucket);
 }
 
 RGWOp *RGWHandler_REST::get_op()
index b711cf87d8075e8c1587f6041e68b8b7e404a6df..b373c1d3ef9663fac62beeae868654d6abb559b3 100644 (file)
@@ -151,7 +151,7 @@ protected:
   virtual RGWOp *get_copy_op() = 0;
 
 public:
-  int read_permissions();
+  int read_permissions(RGWOp *op);
   RGWOp *get_op();
   void put_op(RGWOp *op);
 
index 95909a960150a5a28eb10935b5d6300606b482c9..677a0f4152e0bc43e58b8d336589aaf3c19d45ea 100644 (file)
@@ -24,7 +24,7 @@ public:
   void put_op(RGWOp *op);
 
   int authorize();
-  int read_permissions() { return 0; }
+  int read_permissions(RGWOp *op) { return 0; }
 };
 
 #endif