diff --git a/src/rgw/rgw_bucket.cc b/src/rgw/rgw_bucket.cc index 7b22f44790b..13a778e2db4 100644 --- a/src/rgw/rgw_bucket.cc +++ b/src/rgw/rgw_bucket.cc @@ -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; diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index 1d3596d4418..2638bc119b0 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -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 diff --git a/src/rgw/rgw_http_errors.h b/src/rgw/rgw_http_errors.h index 1eb4e12e695..e48fb9a72c3 100644 --- a/src/rgw/rgw_http_errors.h +++ b/src/rgw/rgw_http_errors.h @@ -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" }, diff --git a/src/rgw/rgw_metadata.cc b/src/rgw/rgw_metadata.cc index 7be73e6ca0c..1afe991ff50 100644 --- a/src/rgw/rgw_metadata.cc +++ b/src/rgw/rgw_metadata.cc @@ -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) diff --git a/src/rgw/rgw_metadata.h b/src/rgw/rgw_metadata.h index 2cc9110191a..be9daaa0ba5 100644 --- a/src/rgw/rgw_metadata.h +++ b/src/rgw/rgw_metadata.h @@ -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." diff --git a/src/rgw/rgw_user.cc b/src/rgw/rgw_user.cc index a1a0577c490..7722d332c7a 100644 --- a/src/rgw/rgw_user.cc +++ b/src/rgw/rgw_user.cc @@ -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)