]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: add preliminary support for sync update policies on metadata sync
authorGreg Farnum <greg@inktank.com>
Tue, 16 Jul 2013 19:23:13 +0000 (12:23 -0700)
committerGreg Farnum <greg@inktank.com>
Thu, 25 Jul 2013 22:59:24 +0000 (15:59 -0700)
We want to be able to conditionally apply new updates:
1) if we already have a newer version than the sync is applying for some
reason (replay of logs?), we don't want to go back in time.
2) If both zones were active at the same time, then we'd like to be
able to do a merge based on timestamps.

In order to support this, we add a sync_type flag to the implementations of
RGWMetadataHandler::put, and then check the version or the mtime of the
incoming put to what we have on disk, and refuse the update if needed.
We return the 204 NoContent success code when refusing sync; for the
moment the conversion is automatic but we're going to pull it out in
the next couple commits.

This commit does not complete the feature: we don't provide an interface
for specifying a different sync protocol.

Signed-off-by: Greg Farnum <greg@inktank.com>
src/rgw/rgw_bucket.cc
src/rgw/rgw_common.h
src/rgw/rgw_http_errors.h
src/rgw/rgw_metadata.cc
src/rgw/rgw_metadata.h
src/rgw/rgw_user.cc

index 7b22f44790b74f9dbb1405fb205f077f44e1c123..13a778e2db4948476c32e7bef0cc04531de63d04 100644 (file)
@@ -1394,7 +1394,8 @@ public:
     return 0;
   }
 
-  int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker, time_t mtime, JSONObj *obj) {
+  int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker,
+          time_t mtime, JSONObj *obj, sync_type_t sync_type) {
     RGWBucketEntryPoint be, old_be;
     decode_json_obj(be, obj);
 
@@ -1406,6 +1407,12 @@ public:
     if (ret < 0 && ret != -ENOENT)
       return ret;
 
+    // are we actually going to perform this put, or is it too old?
+    if (!check_versions(old_ot.read_version, orig_mtime,
+                       objv_tracker.write_version, mtime, sync_type)) {
+      return STATUS_NO_APPLY;
+    }
+
     objv_tracker.read_version = old_ot.read_version; /* maintain the obj version we just read */
 
     ret = store->put_bucket_entrypoint_info(entry, be, false, objv_tracker, mtime);
@@ -1536,7 +1543,8 @@ public:
     return 0;
   }
 
-  int put(RGWRados *store, string& oid, RGWObjVersionTracker& objv_tracker, time_t mtime, JSONObj *obj) {
+  int put(RGWRados *store, string& oid, RGWObjVersionTracker& objv_tracker,
+          time_t mtime, JSONObj *obj, sync_type_t sync_type) {
     RGWBucketCompleteInfo bci, old_bci;
     decode_json_obj(bci, obj);
 
@@ -1562,6 +1570,12 @@ public:
       bci.info.bucket.index_pool = old_bci.info.bucket.index_pool;
     }
 
+    // are we actually going to perform this put, or is it too old?
+    if (!check_versions(old_bci.info.objv_tracker.read_version, orig_mtime,
+                       objv_tracker.write_version, mtime, sync_type)) {
+      return STATUS_NO_APPLY;
+    }
+
     /* record the read version (if any), store the new version */
     bci.info.objv_tracker.read_version = old_bci.info.objv_tracker.read_version;
     bci.info.objv_tracker.write_version = objv_tracker.write_version;
index 1d3596d44183f32fbcf5022d42c3cad07c7c3721..2638bc119b0abb86def061d484415b35ea806d60 100644 (file)
@@ -99,6 +99,7 @@ using ceph::crypto::MD5;
 #define STATUS_NO_CONTENT        1902
 #define STATUS_PARTIAL_CONTENT   1903
 #define STATUS_REDIRECT          1904
+#define STATUS_NO_APPLY          1905
 
 #define ERR_INVALID_BUCKET_NAME  2000
 #define ERR_INVALID_OBJECT_NAME  2001
index 1eb4e12e695cf514b27dd3a563b22e2cfcd682dd..e48fb9a72c3dd1d2f5f6e331ffc0b09ec9c05f26 100644 (file)
@@ -15,6 +15,7 @@ const static struct rgw_http_errors RGW_HTTP_ERRORS[] = {
     { STATUS_ACCEPTED, 202, "Accepted" },
     { STATUS_NO_CONTENT, 204, "NoContent" },
     { STATUS_PARTIAL_CONTENT, 206, "" },
+    { STATUS_NO_APPLY, 204, "NoContent" },
     { ERR_PERMANENT_REDIRECT, 301, "PermanentRedirect" },
     { STATUS_REDIRECT, 303, "" },
     { ERR_NOT_MODIFIED, 304, "NotModified" },
index 7be73e6ca0cf20df113d56451049accbb5119eee..1afe991ff50433ea7693c777b6c22367fc93ed78 100644 (file)
@@ -194,7 +194,8 @@ public:
   virtual string get_type() { return string(); }
 
   virtual int get(RGWRados *store, string& entry, RGWMetadataObject **obj) { return -ENOTSUP; }
-  virtual int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker, time_t mtime, JSONObj *obj) { return -ENOTSUP; }
+  virtual int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker,
+                  time_t mtime, JSONObj *obj, sync_type_t sync_type) { return -ENOTSUP; }
 
   virtual void get_pool_and_oid(RGWRados *store, const string& key, rgw_bucket& bucket, string& oid) {}
 
@@ -357,7 +358,10 @@ int RGWMetadataManager::put(string& metadata_key, bufferlist& bl)
     return -EINVAL;
   }
 
-  return handler->put(store, entry, objv_tracker, mtime, jo);
+  RGWMetadataHandler::sync_type_t sync_type;
+  sync_type = RGWMetadataHandler::APPLY_ALWAYS;
+
+  return handler->put(store, entry, objv_tracker, mtime, jo, sync_type);
 }
 
 int RGWMetadataManager::remove(string& metadata_key)
index 2cc9110191aab2dc1d461e5b15fde0e0816edb10..be9daaa0ba554598fef7f6e2157f5dbcdcfc877e 100644 (file)
@@ -44,14 +44,18 @@ class RGWMetadataManager;
 class RGWMetadataHandler {
   friend class RGWMetadataManager;
 
-protected:
-  virtual void get_pool_and_oid(RGWRados *store, const string& key, rgw_bucket& bucket, string& oid) = 0;
 public:
+  enum sync_type_t {
+    APPLY_ALWAYS,
+    APPLY_UPDATES,
+    APPLY_NEWER
+  };
   virtual ~RGWMetadataHandler() {}
   virtual string get_type() = 0;
 
   virtual int get(RGWRados *store, string& entry, RGWMetadataObject **obj) = 0;
-  virtual int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker, time_t mtime, JSONObj *obj) = 0;
+  virtual int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker,
+                  time_t mtime, JSONObj *obj, sync_type_t type) = 0;
   virtual int remove(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker) = 0;
 
   virtual int list_keys_init(RGWRados *store, void **phandle) = 0;
@@ -62,6 +66,33 @@ public:
   virtual void get_hash_key(const string& section, const string& key, string& hash_key) {
     hash_key = section + ":" + key;
   }
+
+protected:
+  virtual void get_pool_and_oid(RGWRados *store, const string& key, rgw_bucket& bucket, string& oid) = 0;
+  /**
+   * Compare an incoming versus on-disk tag/version+mtime combo against
+   * the sync mode to see if the new one should replace the on-disk one.
+   *
+   * @return true if the update should proceed, false otherwise.
+   */
+  bool check_versions(const obj_version& ondisk, const time_t& ondisk_time,
+                      const obj_version& incoming, const time_t& incoming_time,
+                      sync_type_t sync_mode) {
+    switch (sync_mode) {
+    case APPLY_UPDATES:
+      if ((ondisk.tag != incoming.tag) ||
+         (ondisk.ver >= incoming.ver))
+       return false;
+      break;
+    case APPLY_NEWER:
+      if (ondisk_time >= incoming_time)
+       return false;
+      break;
+    case APPLY_ALWAYS: //deliberate fall-thru -- we always apply!
+    default: break;
+    }
+    return true;
+  }
 };
 
 #define META_LOG_OBJ_PREFIX "meta.log."
index a1a0577c490984d771730c911feb239f9541e1bc..7722d332c7ab9a10cbbfdb84e3047483ec9627d7 100644 (file)
@@ -2295,7 +2295,8 @@ public:
     return 0;
   }
 
-  int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker, time_t mtime, JSONObj *obj) {
+  int put(RGWRados *store, string& entry, RGWObjVersionTracker& objv_tracker,
+          time_t mtime, JSONObj *obj, sync_type_t sync_mode) {
     RGWUserInfo info;
 
     decode_json_obj(info, obj);
@@ -2306,6 +2307,11 @@ public:
     if (ret < 0 && ret != -ENOENT)
       return ret;
 
+    // are we actually going to perform this put, or is it too old?
+    if (!check_versions(objv_tracker.read_version, orig_mtime,
+                       objv_tracker.write_version, mtime, sync_mode)) {
+      return STATUS_NO_APPLY;
+    }
 
     ret = rgw_store_user_info(store, info, &old_info, &objv_tracker, mtime, false);
     if (ret < 0)