/**
* 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; }
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
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);
};
}
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);
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;
}
}
-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;
}
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);
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;
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
* 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;
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()) {
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;
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;
void RGWGetObj::execute()
{
void *handle = NULL;
- rgw_obj obj;
utime_t start_time = s->time;
perfcounter->inc(l_rgw_get);
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)
void RGWGetACLs::execute()
{
- ret = read_acls(s, false);
+ ret = read_acls(s, false, false);
if (ret < 0) {
send_response();
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;
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;
};
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;
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() {}
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;
};
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)
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;
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;
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);
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
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);
return r;
}
+done:
if (bl.length() > 0) {
r = bl.length();
*data = (char *)malloc(r);
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;
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)
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)
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;
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);
obj_tag.clear();
shadow_obj.clear();
attrset.clear();
+ data.clear();
}
};
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;
}
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);
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);
return ret;
}
-int RGWHandler_REST::read_permissions()
+int RGWHandler_REST::read_permissions(RGWOp *op_obj)
{
bool only_bucket;
return -EINVAL;
}
- return do_read_permissions(only_bucket);
+ return do_read_permissions(op_obj, only_bucket);
}
RGWOp *RGWHandler_REST::get_op()
virtual RGWOp *get_copy_op() = 0;
public:
- int read_permissions();
+ int read_permissions(RGWOp *op);
RGWOp *get_op();
void put_op(RGWOp *op);
void put_op(RGWOp *op);
int authorize();
- int read_permissions() { return 0; }
+ int read_permissions(RGWOp *op) { return 0; }
};
#endif