]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: handle racing object puts when object doesn't exist 1105/head
authorYehuda Sadeh <yehuda@inktank.com>
Thu, 16 Jan 2014 19:45:27 +0000 (11:45 -0800)
committerYehuda Sadeh <yehuda@inktank.com>
Thu, 16 Jan 2014 22:30:53 +0000 (14:30 -0800)
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 <yehuda@inktank.com>
src/rgw/rgw_rados.cc

index 530250f29e85b587a64cb6d652975231c2a8b079..fc23ddc5c5ac4ae63ee19d843dd90dd667d083ce 100644 (file)
@@ -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) {