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);
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);
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);
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;
#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
{ 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" },
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) {}
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)
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;
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."
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);
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)