// ----------------------------------------------------------------------
// File: QoSConfig.cc
// Author: Mihai Patrascoiu - CERN
// ----------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2019 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#include "mgm/qos/QoSConfig.hh"
#include "mgm/qos/QoSClass.hh"
#include "namespace/interface/IFileMD.hh"
#include
#include
#include
#include
EOSMGMNAMESPACE_BEGIN
//----------------------------------------------------------------------------
// Constructor
//----------------------------------------------------------------------------
QoSConfig::QoSConfig(const char* filename) : mFilename(filename)
{
mFile.open(filename);
}
//----------------------------------------------------------------------------
// Load the config file into a map of QoS Classes
//----------------------------------------------------------------------------
std::map
QoSConfig::LoadConfig()
{
std::map map;
if (IsValid()) {
std::string errs;
Json::CharReaderBuilder reader;
Json::Value root;
bool ok = parseFromStream(reader, mFile, &root, &errs);
if (ok) {
for (auto& it: root) {
// Create QoS class
auto qosclass_ptr = QoSConfig::CreateQoSClass(it);
if (qosclass_ptr) {
map.emplace(qosclass_ptr->name, *qosclass_ptr.get());
}
}
} else {
eos_static_err("msg=\"failed parsing JSON config file\" emsg=\"%s\"",
errs.c_str());
}
}
return map;
}
//----------------------------------------------------------------------------
// Build a QoS Class object from JSON
//----------------------------------------------------------------------------
std::shared_ptr
QoSConfig::CreateQoSClass(const Json::Value& qos_json)
{
std::ostringstream info;
std::vector transitions;
std::vector locations;
eos::IFileMD::QoSAttrMap attributes;
int cdmi_redundancy = -1;
int cdmi_latency = -1;
std::string name;
// Lambda function -- Check if member exists,
// otherwise write it as missing to the to the output stream
auto hasMember = [&info](const Json::Value& json, const char* key) -> bool {
if (json.isMember(key)) {
return true;
}
info << (info.tellp() != 0 ? " " : "") << key;
return false;
};
try {
// Extract name
if (hasMember(qos_json, "name")) {
name = qos_json["name"].asString();
}
// Extract transition list
if (hasMember(qos_json, "transition")) {
for (auto& it: qos_json["transition"]) {
transitions.emplace_back(it.asString());
}
}
// Extract metadata attributes
if (hasMember(qos_json, "metadata")) {
auto field = qos_json["metadata"];
if (hasMember(field, CDMI_REDUNDANCY_TAG)) {
cdmi_redundancy = field[CDMI_REDUNDANCY_TAG].asInt();
}
if (hasMember(field, CDMI_LATENCY_TAG)) {
cdmi_latency = field[CDMI_LATENCY_TAG].asInt();
}
if (hasMember(field, CDMI_PLACEMENT_TAG)) {
for (auto& it: field[CDMI_PLACEMENT_TAG]) {
locations.emplace_back(it.asString());
}
}
}
// Extract class attributes
if (hasMember(qos_json, "attributes")) {
auto field = qos_json["attributes"];
if (hasMember(field, "layout")) {
attributes["layout"] = field["layout"].asString();
}
if (hasMember(field, "replica")) {
attributes["replica"] = field["replica"].asString();
}
if (hasMember(field, "checksum")) {
attributes["checksum"] = field["checksum"].asString();
}
if (hasMember(field, "placement")) {
attributes["placement"] = field["placement"].asString();
}
}
} catch (const Json::Exception& e) {
eos_static_err("msg=\"json conversion exception\" emsg=\"%s\"",
e.what());
return nullptr;
}
if (info.tellp() != 0) {
eos_static_notice("msg=\"failed to construct QoS class\" "
"missing_fields=\"%s\"", info.str().c_str());
return nullptr;
}
return shared_ptr(
new QoSClass(name, cdmi_redundancy, cdmi_latency,
transitions, locations, attributes));
}
//----------------------------------------------------------------------------
//! Return string representation of a QoS class
//----------------------------------------------------------------------------
std::string
QoSConfig::QoSClassToString(const eos::mgm::QoSClass& qos)
{
std::ostringstream out;
auto arrayToString = [](auto& array) -> std::string {
std::ostringstream out;
out << "[";
for (auto& it: array) {
out << " " << it << ",";
}
out.seekp((array.size() ? -1 : 0), std::ios_base::end);
out << " ]";
return out.str();
};
out << "name=" << qos.name << std::endl
<< "transition=" << arrayToString(qos.transitions) << std::endl
<< CDMI_REDUNDANCY_TAG << "=" << qos.cdmi_redundancy << std::endl
<< CDMI_PLACEMENT_TAG << "=" << arrayToString(qos.locations) << std::endl
<< CDMI_LATENCY_TAG << "=" << qos.cdmi_latency << std::endl;
for (auto& it: qos.attributes) {
out << it.first << "=" << it.second << std::endl;
}
return out.str();
}
//----------------------------------------------------------------------------
//! Return JSON representation of a QoS class
//----------------------------------------------------------------------------
Json::Value
QoSConfig::QoSClassToJson(const eos::mgm::QoSClass& qos)
{
Json::Value json;
json["name"] = qos.name;
json["transition"] = Json::arrayValue;
for (auto& transition: qos.transitions) {
json["transition"].append(transition);
}
json["metadata"] = Json::objectValue;
json["metadata"][CDMI_REDUNDANCY_TAG] = (Json::UInt) qos.cdmi_redundancy;
json["metadata"][CDMI_LATENCY_TAG] = (Json::UInt) qos.cdmi_latency;
json["metadata"][CDMI_PLACEMENT_TAG] = Json::arrayValue;
for (auto& location: qos.locations) {
json["metadata"][CDMI_PLACEMENT_TAG].append(location);
}
json["attributes"] = Json::objectValue;
for (auto& it: qos.attributes) {
json["attributes"][it.first] = it.second;
}
return json;
}
EOSMGMNAMESPACE_END