// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
// vim: ts=8 sw=2 sts=2 expandtab
+#include <cmath>
+#include <cstdint>
+#include <limits>
#include <stack>
#include <fcntl.h>
#include <algorithm>
return PEER_CONFIG_KEY_PREFIX + "/" + fs_name + "/" + uuid;
}
-bool get_json_value(const json_spirit::mObject& obj,
- const std::string& key,
- json_spirit::mValue *val) {
- auto it = obj.find(key);
- if (it != obj.end()) {
- *val = it->second;
- return true;
- }
- return false;
-}
-
struct C_PersistSyncStatAio : Context {
std::string dir_root;
void PeerReplayer::apply_persisted_dir_sync_stat(SnapSyncStat &sync_stat,
const bufferlist &bl) {
- json_spirit::mValue root;
- if (!json_spirit::read(bl.to_str(), root) || root.type() != json_spirit::obj_type) {
- return;
- }
+ try {
+ json_spirit::mValue root;
+ if (!json_spirit::read(bl.to_str(), root) || root.type() != json_spirit::obj_type) {
+ return;
+ }
- auto &obj = root.get_obj();
- json_spirit::mValue v;
+ auto &obj = root.get_obj();
+ json_spirit::mValue v;
- if (get_json_value(obj, "last_synced_snap", &v) && v.type() == json_spirit::obj_type) {
- auto &last_synced_snap = v.get_obj();
- if (get_json_value(last_synced_snap, "id", &v)) {
- uint64_t snap_id = v.get_uint64();
- if (get_json_value(last_synced_snap, "name", &v)) {
- sync_stat.last_synced_snap = std::make_pair(snap_id, v.get_str());
+ // Copy the object out of v before reading nested fields. get_json_value()
+ // would otherwise overwrite v and leave a dangling reference into its Object.
+ if (get_json_value(obj, "last_synced_snap", &v) && v.type() == json_spirit::obj_type) {
+ const json_spirit::mObject last_synced_snap = v.get_obj();
+ uint64_t snap_id;
+ std::string snap_name;
+ if (get_json_uint64(last_synced_snap, "id", &snap_id) &&
+ get_json_string(last_synced_snap, "name", &snap_name)) {
+ sync_stat.last_synced_snap = std::make_pair(snap_id, snap_name);
+ }
+ double value;
+ if (get_json_real(last_synced_snap, "crawl_duration", &value)) {
+ sync_stat.last_sync_crawl_duration = value;
+ }
+ if (get_json_real(last_synced_snap, "datasync_queue_wait_duration", &value)) {
+ sync_stat.last_sync_datasync_queue_wait_duration = value;
+ }
+ if (get_json_real(last_synced_snap, "sync_duration", &value)) {
+ sync_stat.last_sync_duration = value;
+ }
+ if (get_json_real(last_synced_snap, "sync_time_stamp", &value)) {
+ // set_from_double() casts into __u32; reject non-finite / out-of-range.
+ if (std::isfinite(value) &&
+ value >= 0.0 &&
+ value <= static_cast<double>(std::numeric_limits<uint32_t>::max())) {
+ sync_stat.last_synced.set_from_double(value);
+ } else {
+ derr << ": persisted sync_time_stamp out of range; ignoring" << dendl;
+ }
+ }
+ uint64_t uval;
+ if (get_json_uint64(last_synced_snap, "sync_bytes", &uval)) {
+ sync_stat.last_sync_bytes = uval;
+ }
+ if (get_json_uint64(last_synced_snap, "sync_files", &uval)) {
+ sync_stat.last_sync_files = uval;
}
}
- if (get_json_value(last_synced_snap, "crawl_duration", &v)) {
- sync_stat.last_sync_crawl_duration = v.get_real();
- }
- if (get_json_value(last_synced_snap, "datasync_queue_wait_duration", &v)) {
- sync_stat.last_sync_datasync_queue_wait_duration = v.get_real();
- }
- if (get_json_value(last_synced_snap, "sync_duration", &v)) {
- sync_stat.last_sync_duration = v.get_real();
- }
- if (get_json_value(last_synced_snap, "sync_time_stamp", &v)) {
- sync_stat.last_synced.set_from_double(v.get_real());
- }
- if (get_json_value(last_synced_snap, "sync_bytes", &v)) {
- sync_stat.last_sync_bytes = v.get_uint64();
- }
- if (get_json_value(last_synced_snap, "sync_files", &v)) {
- sync_stat.last_sync_files = v.get_uint64();
- }
+ } catch (const std::exception &e) {
+ derr << ": failed to apply persisted sync stat: " << e.what() << dendl;
}
}
return snapshot_dir_path(cct, dir_root) + "/" + snap_name;
}
+bool get_json_value(const json_spirit::mObject& obj,
+ const std::string& key,
+ json_spirit::mValue *val) {
+ auto it = obj.find(key);
+ if (it != obj.end()) {
+ *val = it->second;
+ return true;
+ }
+ return false;
+}
+
+bool get_json_string(const json_spirit::mObject& obj,
+ const std::string& key,
+ std::string *val) {
+ json_spirit::mValue v;
+ if (!get_json_value(obj, key, &v)) {
+ return false;
+ }
+ if (v.type() != json_spirit::str_type) {
+ derr << ": persisted sync stat key '" << key
+ << "' has type " << v.type()
+ << " (expected string); ignoring" << dendl;
+ return false;
+ }
+ *val = v.get_str();
+ return true;
+}
+
+bool get_json_uint64(const json_spirit::mObject& obj,
+ const std::string& key,
+ uint64_t *val) {
+ json_spirit::mValue v;
+ if (!get_json_value(obj, key, &v)) {
+ return false;
+ }
+ if (v.type() != json_spirit::int_type) {
+ derr << ": persisted sync stat key '" << key
+ << "' has type " << v.type()
+ << " (expected int); ignoring" << dendl;
+ return false;
+ }
+ // json_spirit reports signed and unsigned as int_type; get_uint64()
+ // would cast a negative value to a huge uint64_t.
+ if (!v.is_uint64() && v.get_int64() < 0) {
+ derr << ": persisted sync stat key '" << key
+ << "' has negative value; ignoring" << dendl;
+ return false;
+ }
+ *val = v.get_uint64();
+ return true;
+}
+
+bool get_json_real(const json_spirit::mObject& obj,
+ const std::string& key,
+ double *val) {
+ json_spirit::mValue v;
+ if (!get_json_value(obj, key, &v)) {
+ return false;
+ }
+ if (v.type() != json_spirit::int_type &&
+ v.type() != json_spirit::real_type) {
+ derr << ": persisted sync stat key '" << key
+ << "' has type " << v.type()
+ << " (expected int or real); ignoring" << dendl;
+ return false;
+ }
+ *val = v.get_real();
+ return true;
+}
+
} // namespace mirror
} // namespace cephfs
#include <string>
#include "Types.h"
+#include "json_spirit/json_spirit.h"
namespace cephfs {
namespace mirror {
int mount(RadosRef cluster, const Filesystem &filesystem, bool cross_check_fscid,
MountRef *mount);
+// Typed JSON field getters. Use a local mValue so callers can keep a live
+// copy/reference of a parent object without get_json_value() overwriting it.
+bool get_json_value(const json_spirit::mObject& obj,
+ const std::string& key,
+ json_spirit::mValue *val);
+bool get_json_string(const json_spirit::mObject& obj,
+ const std::string& key,
+ std::string *val);
+bool get_json_uint64(const json_spirit::mObject& obj,
+ const std::string& key,
+ uint64_t *val);
+bool get_json_real(const json_spirit::mObject& obj,
+ const std::string& key,
+ double *val);
+
} // namespace mirror
} // namespace cephfs