From: Yehuda Sadeh Date: Thu, 16 Jan 2014 19:45:27 +0000 (-0800) Subject: rgw: handle racing object puts when object doesn't exist X-Git-Tag: v0.78~267^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=86c15480fc3e33b9a3b84d0af68d8398fc732bae;p=ceph.git rgw: handle racing object puts when object doesn't exist If the object didn't exist before and now we have multiple puts coming in concurrently, we need to make sure that we behave correctly. Only one needs to win, the other one can fail silently. We do that by setting exclusive flag on the object creation and handling the error correctly. Note that we still want to return -EEXIST in some cases (when the exclusive flag is passed to put_obj_meta(), e.g., on bucket creation). Signed-off-by: Yehuda Sadeh --- diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index 530250f29e8..fc23ddc5c5a 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -2367,7 +2367,9 @@ int RGWRados::put_obj_meta_impl(void *ctx, rgw_obj& obj, uint64_t size, return r; r = io_ctx.operate(oid, &op); - if (r < 0) + if (r < 0) /* we can expect to get -ECANCELED if object was replaced under, + or -ENOENT if was removed, or -EEXIST if it did not exist + before and now it does */ goto done_cancel; if (objv_tracker) { @@ -2403,11 +2405,17 @@ done_cancel: if (ret < 0) { ldout(cct, 0) << "ERROR: complete_update_index_cancel() returned ret=" << ret << dendl; } - /* we lost in a race, object was already overwritten, we + /* we lost in a race. There are a few options: + * - existing object was rewritten (ECANCELED) + * - non existing object was created (EEXIST) + * - object was removed (ENOENT) * should treat it as a success */ - if (r == -ECANCELED || r == -ENOENT) + if ((r == -ECANCELED || r == -ENOENT) || + (!(flags & PUT_OBJ_EXCL) && r == -EEXIST)) { r = 0; + } + return r; } @@ -3497,8 +3505,12 @@ int RGWRados::prepare_atomic_for_write_impl(RGWRadosCtx *rctx, rgw_obj& obj, } if (reset_obj) { - op.create(false); - op.remove(); + if (state->exists) { + op.create(false); + op.remove(); + } else { + op.create(true); + } } if (ptag) {