#include "common/ceph_json.h"
#include "include/utime.h"
-// for testing DELETE ME
-#include <fstream>
-#include <include/types.h>
-
#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>
#include <boost/lexical_cast.hpp>
+#include <include/types.h>
-#include "json_spirit/json_spirit_writer_template.h"
+// Enable boost.json's header-only mode ("https://github.com/boostorg/json?tab=readme-ov-file#header-only"):
+#include <boost/json/src.hpp>
-using namespace json_spirit;
+#include <memory>
+#include <fstream>
using std::ifstream;
using std::pair;
}
}
-JSONObjIter::JSONObjIter()
-{
-}
-
-JSONObjIter::~JSONObjIter()
-{
-}
-
void JSONObjIter::set(const JSONObjIter::map_iter_t &_cur, const JSONObjIter::map_iter_t &_last)
{
cur = _cur;
++cur;
}
+// IMPORTANT: The returned pointer is intended as NON-OWNING (i.e. the JSONObjIter is responsible for it):
JSONObj *JSONObjIter::operator*()
{
- return cur->second;
+ return cur->second.get();
}
// does not work, FIXME
return out;
}
-JSONObj::~JSONObj()
-{
- for (auto iter = children.begin(); iter != children.end(); ++iter) {
- JSONObj *obj = iter->second;
- delete obj;
- }
-}
-
-
void JSONObj::add_child(string el, JSONObj *obj)
{
- children.insert(pair<string, JSONObj *>(el, obj));
+ auto p = std::unique_ptr<JSONObj>(obj);
+
+ children.insert({el, std::move(p)});
}
bool JSONObj::get_attr(string name, data_val& attr)
}
/* accepts a JSON Array or JSON Object contained in
- * a JSON Spirit Value, v, and creates a JSONObj for each
+ * a Boost.JSON value, v, and creates a Ceph JSONObj for each
* child contained in v
*/
-void JSONObj::handle_value(Value v)
-{
- if (v.type() == obj_type) {
- Object temp_obj = v.get_obj();
- for (Object::size_type i = 0; i < temp_obj.size(); i++) {
- Pair temp_pair = temp_obj[i];
- string temp_name = temp_pair.name_;
- Value temp_value = temp_pair.value_;
- JSONObj *child = new JSONObj;
- child->init(this, temp_value, temp_name);
- add_child(temp_name, child);
- }
- } else if (v.type() == array_type) {
- Array temp_array = v.get_array();
- Value value;
+void JSONObj::handle_value(boost::json::value v)
+{
+ if (auto op = v.if_object()) {
- for (unsigned j = 0; j < temp_array.size(); j++) {
- Value cur = temp_array[j];
- string temp_name;
+ for (const auto& kvp : *op)
+ {
+ JSONObj *child = new JSONObj;
- JSONObj *child = new JSONObj;
- child->init(this, cur, temp_name);
- add_child(child->get_name(), child);
- }
+ child->init(this, kvp.value(), kvp.key());
+
+ add_child(kvp.key(), child);
+ }
+
+ return;
}
+
+ if (auto ap = v.if_array()) {
+ for (const auto& kvp : *ap)
+ {
+ JSONObj *child = new JSONObj;
+ child->init(this, kvp, "");
+
+ add_child(child->get_name(), child);
+ }
+ }
+
+ // unknown type is not-an-error
}
-void JSONObj::init(JSONObj *p, Value v, string n)
+void JSONObj::init(JSONObj *parent_node, boost::json::value data_in, std::string name_in)
{
- name = n;
- parent = p;
- data = v;
+ parent = parent_node;
+ data = data_in;
+ name = name_in;
- handle_value(v);
- if (v.type() == str_type) {
- val.set(v.get_str(), true);
- } else {
- val.set(json_spirit::write_string(v), false);
+ handle_value(data_in);
+
+ if (auto vp = data_in.if_string())
+ val.set(*vp, true);
+ else {
+ val.set(boost::json::serialize(data_in), false);
}
- attr_map.insert(pair<string,data_val>(name, val));
+
+ attr_map.insert({name, val});
}
JSONObj *JSONObj::get_parent()
bool JSONObj::is_object()
{
- return (data.type() == obj_type);
+ return data.is_object();
}
bool JSONObj::is_array()
{
- return (data.type() == array_type);
+ return data.is_array();
}
vector<string> JSONObj::get_array_elements()
{
- vector<string> elements;
- Array temp_array;
+ vector<string> elements;
- if (data.type() == array_type)
- temp_array = data.get_array();
+ boost::json::array temp_array;
- int array_size = temp_array.size();
- if (array_size > 0)
- for (int i = 0; i < array_size; i++) {
- Value temp_value = temp_array[i];
- string temp_string;
- temp_string = write(temp_value, raw_utf8);
- elements.push_back(temp_string);
- }
+ if (auto ap = data.if_array())
+ temp_array = *ap;
- return elements;
-}
+ auto array_size = temp_array.size();
-JSONParser::JSONParser() : buf_len(0), success(true)
-{
-}
+ if (array_size > 0) {
+ for (boost::json::array::size_type i = 0; i < array_size; i++) {
+ boost::json::value temp_value = temp_array[i];
+ string temp_string;
+ temp_string = boost::json::serialize(temp_value);
+ elements.push_back(temp_string);
+ }
+ }
-JSONParser::~JSONParser()
-{
+ return elements;
}
-
-
void JSONParser::handle_data(const char *s, int len)
{
json_buffer.append(s, len); // check for problems with null termination FIXME
// parse a supplied JSON fragment
bool JSONParser::parse(const char *buf_, int len)
{
- if (!buf_) {
- set_failure();
+ if (!buf_ || 0 >= len) {
return false;
}
- string json_string(buf_, len);
- success = read(json_string, data);
- if (success) {
- handle_value(data);
- if (data.type() != obj_type &&
- data.type() != array_type) {
- if (data.type() == str_type) {
- val.set(data.get_str(), true);
- } else {
- const std::string& s = json_spirit::write_string(data);
- if (s.size() == (uint64_t)len) { /* Check if entire string is read */
- val.set(s, false);
- } else {
- set_failure();
- }
- }
- }
- } else {
- set_failure();
- }
+ std::string_view json_string_view(buf_, len);
+
+ std::error_code ec;
+ data = boost::json::parse(json_string_view, ec);
+
+ if(ec)
+ return false;
+
+ // recursively evaluate the result:
+ handle_value(data);
- return success;
+ if (data.is_object() or data.is_array())
+ return true;
+
+ if (data.is_string()) {
+ val.set(data.as_string(), true);
+ return true;
+ }
+
+ // For any other kind of value:
+ std::string s = boost::json::serialize(data);
+
+ if (s.size() == static_cast<uint64_t>(len)) { // entire string was read
+ val.set(s, false);
+ return true;
+ }
+
+ // Could not parse and convert:
+ return false;
}
// parse the internal json_buffer up to len
bool JSONParser::parse(int len)
{
- string json_string = json_buffer.substr(0, len);
- success = read(json_string, data);
- if (success)
- handle_value(data);
- else
- set_failure();
+ std::string_view json_string(std::begin(json_buffer), len + std::begin(json_buffer));
+
+ std::error_code ec;
+ if(data = boost::json::parse(json_string, ec); ec)
+ return false;
- return success;
+ handle_value(data);
+
+ return true;
}
// parse the complete internal json_buffer
bool JSONParser::parse()
{
- success = read(json_buffer, data);
- if (success)
- handle_value(data);
- else
- set_failure();
+ std::error_code ec;
+
+ data = boost::json::parse(json_buffer, ec);
- return success;
+ if(ec)
+ return false;
+
+ handle_value(data);
+
+ return true;
}
-// parse a supplied ifstream, for testing. DELETE ME
+// parse a supplied ifstream:
bool JSONParser::parse(const char *file_name)
{
- ifstream is(file_name);
- success = read(is, data);
- if (success)
- handle_value(data);
- else
- set_failure();
+ ifstream is(file_name);
+
+ std::error_code ec;
+ data = boost::json::parse(is, ec);
+
+ if(ec)
+ return false;
+
+ handle_value(data);
- return success;
+ return true;
}
#ifndef CEPH_JSON_H
#define CEPH_JSON_H
-#include <deque>
#include <map>
#include <set>
-#include <stdexcept>
+#include <deque>
#include <string>
+#include <iostream>
+#include <stdexcept>
#include <typeindex>
-#include <include/types.h>
+
+#include <boost/json.hpp>
+#include <boost/optional.hpp>
#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
-#include <boost/optional.hpp>
+
+#include <include/types.h>
#include <include/ceph_fs.h>
-#include "common/ceph_time.h"
-#include "json_spirit/json_spirit.h"
+#include "common/ceph_time.h"
#include "Formatter.h"
-
-
class JSONObj;
class JSONObjIter {
- typedef std::map<std::string, JSONObj *>::iterator map_iter_t;
+
+ using map_iter_t = std::map<std::string, std::unique_ptr<JSONObj>>::iterator;
+
map_iter_t cur;
map_iter_t last;
public:
- JSONObjIter();
- ~JSONObjIter();
void set(const JSONObjIter::map_iter_t &_cur, const JSONObjIter::map_iter_t &_end);
void operator++();
+
+ // IMPORTANT: The returned pointer is intended as NON-OWNING (i.e. JSONObjIter
+ // is responsible for it):
JSONObj *operator*();
bool end() const {
}
};
-class JSONObj
+class JSONObj
{
- JSONObj *parent;
+ using children_multimap_t = std::multimap<std::string, std::unique_ptr<JSONObj>>;
+ using children_multimap_value_type = typename children_multimap_t::value_type;
+
+ JSONObj *parent = nullptr;
+
public:
struct data_val {
std::string str;
quoted = q;
}
};
+
protected:
std::string name; // corresponds to obj_type in XMLObj
- json_spirit::Value data;
- struct data_val val;
+
+ boost::json::value data;
+
+ data_val val;
+
bool data_quoted{false};
- std::multimap<std::string, JSONObj *> children;
- std::map<std::string, data_val> attr_map;
- void handle_value(json_spirit::Value v);
-public:
+ std::multimap<std::string, std::unique_ptr<JSONObj>> children;
+
+ std::map<std::string, data_val> attr_map;
- JSONObj() : parent(NULL){}
+ void handle_value(boost::json::value v);
- virtual ~JSONObj();
+public:
+ virtual ~JSONObj() = default;
- void init(JSONObj *p, json_spirit::Value v, std::string n);
+public:
+ void init(JSONObj *parent_node, boost::json::value data_in, std::string name_in);
std::string& get_name() { return name; }
data_val& get_data_val() { return val; }
+
const std::string& get_data() { return val.str; }
bool get_data(const std::string& key, data_val *dest);
+
JSONObj *get_parent();
+
+ // Note: takes ownership of child:
void add_child(std::string el, JSONObj *child);
+
bool get_attr(std::string name, data_val& attr);
+
JSONObjIter find(const std::string& name);
JSONObjIter find_first();
JSONObjIter find_first(const std::string& name);
bool is_array();
bool is_object();
+
std::vector<std::string> get_array_elements();
};
class JSONParser : public JSONObj
{
- int buf_len;
+ int buf_len = 0;
std::string json_buffer;
- bool success;
+
public:
- JSONParser();
- ~JSONParser() override;
void handle_data(const char *s, int len);
bool parse(const char *buf_, int len);
bool parse(const char *file_name);
const char *get_json() { return json_buffer.c_str(); }
- void set_failure() { success = false; }
};
void encode_json(const char *name, const JSONObj::data_val& v, ceph::Formatter *f);
JSONDecoder(ceph::buffer::list& bl) {
if (!parser.parse(bl.c_str(), bl.length())) {
- std::cout << "JSONDecoder::err()" << std::endl;
+ std::cout << "JSONDecoder::err()" << std::endl; // JFW: do we still want this here?
throw JSONDecoder::err("failed to parse JSON input");
}
}
#include "PyModuleRegistry.h"
#include "PyUtil.h"
+#include "json_spirit/json_spirit.h"
+
#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_mgr
#undef dout_prefix
}
void MetadataUpdate::finish(int r)
+try
{
daemon_state.clear_updating(key);
if (r == 0) {
if (key.type == "mds" || key.type == "osd" ||
key.type == "mgr" || key.type == "mon") {
- json_spirit::mValue json_result;
- bool read_ok = json_spirit::read(
- outbl.to_str(), json_result);
- if (!read_ok) {
+
+ std::error_code ec;
+
+ boost::json::value json_result = boost::json::parse(outbl.to_str(), ec);
+
+ if (ec) {
dout(1) << "mon returned invalid JSON for " << key << dendl;
return;
}
- if (json_result.type() != json_spirit::obj_type) {
+ if (!json_result.is_object()) {
dout(1) << "mon returned valid JSON " << key
<< " but not an object: '" << outbl.to_str() << "'" << dendl;
return;
}
dout(4) << "mon returned valid metadata JSON for " << key << dendl;
- json_spirit::mObject daemon_meta = json_result.get_obj();
+ boost::json::object daemon_meta = json_result.get_object();
// Skip daemon who doesn't have hostname yet
if (daemon_meta.count("hostname") == 0) {
std::map<string,string> m;
{
std::lock_guard l(state->lock);
- state->hostname = daemon_meta.at("hostname").get_str();
+ state->hostname = daemon_meta.at("hostname").get_string();
if (key.type == "mds" || key.type == "mgr" || key.type == "mon") {
daemon_meta.erase("name");
}
daemon_meta.erase("hostname");
for (const auto &[key, val] : daemon_meta) {
- m.emplace(key, val.get_str());
+ m.emplace(key, val.get_string());
}
}
daemon_state.update_metadata(state, m);
} else {
auto state = std::make_shared<DaemonState>(daemon_state.types);
state->key = key;
- state->hostname = daemon_meta.at("hostname").get_str();
+ state->hostname = daemon_meta.at("hostname").get_string();
if (key.type == "mds" || key.type == "mgr" || key.type == "mon") {
daemon_meta.erase("name");
std::map<string,string> m;
for (const auto &[key, val] : daemon_meta) {
- m.emplace(key, val.get_str());
+ m.emplace(key, val.get_string());
}
state->set_metadata(m);
<< ": " << cpp_strerror(r) << dendl;
}
}
+catch(const std::exception& e)
+{
+ dout(1) << "!!JFW: mon caught: " << e.what() << dendl;
+}
void Mgr::background_init(Context *completion)
{
std::map<std::string, std::string> loaded;
for (auto &key_str : cmd.json_result.get_array()) {
- std::string const key = key_str.get_str();
+ std::string const key = key_str.get_string().c_str();
dout(20) << "saw key '" << key << "'" << dendl;
}
void Mgr::load_all_metadata()
+try
{
ceph_assert(ceph_mutex_is_locked_by_me(lock));
ceph_assert(osd_cmd.r == 0);
for (auto &metadata_val : mds_cmd.json_result.get_array()) {
- json_spirit::mObject daemon_meta = metadata_val.get_obj();
+ boost::json::object daemon_meta = metadata_val.get_object();
if (daemon_meta.count("hostname") == 0) {
dout(1) << "Skipping incomplete metadata entry" << dendl;
continue;
DaemonStatePtr dm = std::make_shared<DaemonState>(daemon_state.types);
dm->key = DaemonKey{"mds",
- daemon_meta.at("name").get_str()};
- dm->hostname = daemon_meta.at("hostname").get_str();
+ daemon_meta.at("name").get_string().c_str()};
+ dm->hostname = daemon_meta.at("hostname").get_string().c_str();
daemon_meta.erase("name");
daemon_meta.erase("hostname");
for (const auto &[key, val] : daemon_meta) {
- dm->metadata.emplace(key, val.get_str());
+ dm->metadata.emplace(key, val.get_string());
}
daemon_state.insert(dm);
}
for (auto &metadata_val : mon_cmd.json_result.get_array()) {
- json_spirit::mObject daemon_meta = metadata_val.get_obj();
+ boost::json::object daemon_meta = metadata_val.get_object();
if (daemon_meta.count("hostname") == 0) {
dout(1) << "Skipping incomplete metadata entry" << dendl;
continue;
DaemonStatePtr dm = std::make_shared<DaemonState>(daemon_state.types);
dm->key = DaemonKey{"mon",
- daemon_meta.at("name").get_str()};
- dm->hostname = daemon_meta.at("hostname").get_str();
+ daemon_meta.at("name").get_string().c_str()};
+ dm->hostname = daemon_meta.at("hostname").get_string().c_str();
daemon_meta.erase("name");
daemon_meta.erase("hostname");
std::map<string,string> m;
for (const auto &[key, val] : daemon_meta) {
- m.emplace(key, val.get_str());
+ m.emplace(key, val.get_string());
}
dm->set_metadata(m);
}
for (auto &osd_metadata_val : osd_cmd.json_result.get_array()) {
- json_spirit::mObject osd_metadata = osd_metadata_val.get_obj();
+ boost::json::object osd_metadata = osd_metadata_val.get_object();
if (osd_metadata.count("hostname") == 0) {
dout(1) << "Skipping incomplete metadata entry" << dendl;
continue;
}
- dout(4) << osd_metadata.at("hostname").get_str() << dendl;
+ dout(4) << osd_metadata.at("hostname").get_string() << dendl;
DaemonStatePtr dm = std::make_shared<DaemonState>(daemon_state.types);
dm->key = DaemonKey{"osd",
- stringify(osd_metadata.at("id").get_int())};
- dm->hostname = osd_metadata.at("hostname").get_str();
+ stringify(osd_metadata.at("id").get_int64())};
+ dm->hostname = osd_metadata.at("hostname").get_string();
osd_metadata.erase("id");
osd_metadata.erase("hostname");
- std::map<string,string> m;
- for (const auto &i : osd_metadata) {
- m[i.first] = i.second.get_str();
+ map<string,string> m;
+ for (const auto &[k, v] : osd_metadata) {
+ m[k] = v.get_string();
}
dm->set_metadata(m);
daemon_state.insert(dm);
}
}
+catch(const std::exception& e)
+{
+ dout(1) << "JFW: load_all_metadata(): caught " << e.what() << dendl;
+}
void Mgr::handle_osd_map()
{
#include "common/Cond.h"
#include "mon/MonClient.h"
+#include <boost/json.hpp>
+
class Command
{
protected:
virtual ~Command() {}
};
-
class JSONCommand : public Command
{
public:
- json_spirit::mValue json_result;
+ boost::json::value json_result;
void wait() override
{
Command::wait();
if (r == 0) {
+ boost::system::error_code ec;
+
+ json_result = boost::json::parse(outbl.to_str(), ec);
+
+ if(ec)
+ r = -EINVAL;
+
+/*JFW:
bool read_ok = json_spirit::read(
outbl.to_str(), json_result);
if (!read_ok) {
r = -EINVAL;
}
+*/
}
}
};