//------------------------------------------------------------------------------
// File: ConversionInfo.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/convert/ConversionInfo.hh"
#include "common/Logging.hh"
EOSMGMNAMESPACE_BEGIN
//----------------------------------------------------------------------------
// Constructor
//----------------------------------------------------------------------------
ConversionInfo::ConversionInfo(const eos::common::FileId::fileid_t fid,
const eos::common::LayoutId::layoutid_t lid,
const eos::common::GroupLocator& location,
const std::string& plct_policy,
const bool update_ctime,
const std::string& app_tag) :
mFid(fid), mLid(lid), mLocation(location), mPlctPolicy(plct_policy),
mUpdateCtime(update_ctime), mAppTag(app_tag)
{
char buff[4096];
snprintf(buff, std::size(buff), "%016llx:%s.%i#%08lx",
mFid, mLocation.getSpace().c_str(), mLocation.getIndex(), mLid);
std::string conversion {buff};
if (!mPlctPolicy.empty()) { // ~
conversion += "~";
conversion += mPlctPolicy;
}
if (!mAppTag.empty()) {
conversion += "^";
conversion += mAppTag;
conversion += "^";
}
if (mUpdateCtime) {
conversion += UPDATE_CTIME;
}
mConversionString = conversion;
}
//----------------------------------------------------------------------------
// Parse a conversion string representation into a conversion info object
//
// A conversion string has the following format:
// :#[^app_tag^][~][+]
//----------------------------------------------------------------------------
std::shared_ptr ConversionInfo::parseConversionString(
std::string sconversion)
{
using eos::common::FileId;
using eos::common::LayoutId;
using eos::common::GroupLocator;
const char* errmsg = "unable to parse conversion string";
FileId::fileid_t fid = 0;
LayoutId::layoutid_t lid = 0;
GroupLocator location;
std::string policy;
std::string app_tag;
bool update_ctime {false};
std::size_t conv_pos = 0;
if (sconversion.empty()) {
eos_static_err("%s", "msg=\"conversion string is empty\"");
return nullptr;
}
// Check if ctime needs to be updated
if (*sconversion.rbegin() == UPDATE_CTIME) {
update_ctime = true;
sconversion.erase(sconversion.end() - 1);
}
// Parse file id
size_t pos = sconversion.find(":");
if ((pos == std::string::npos) || (pos != 16)) {
eos_static_err("msg=\"%s\" conversion_string=%s "
"reason=\"invalid fxid\"", errmsg, sconversion.c_str());
return nullptr;
} else {
std::string hexfid = sconversion.substr(0, pos).c_str();
try {
fid = std::stoull(hexfid, &conv_pos, 16);
} catch (...) { }
if (conv_pos != hexfid.length()) {
fid = 0;
}
}
// Parse space/group location
sconversion.erase(0, pos + 1);
pos = sconversion.find("#");
if (pos == std::string::npos) {
eos_static_err("msg=\"%s\" conversion_string=%s "
"reason=\"invalid space\"", errmsg, sconversion.c_str());
return nullptr;
} else {
std::string spacegroup = sconversion.substr(0, pos);
(void) GroupLocator::parseGroup(spacegroup, location);
if (location.getSpace().empty()) {
return nullptr;
}
}
// Parse app_tag
sconversion.erase(0, pos + 1);
pos = sconversion.find('^');
if (pos != std::string::npos) {
auto end_pos = sconversion.find('^', pos + 1);
if (end_pos == std::string::npos) {
eos_static_err("msg='%s' conversion_string=%s ",
"reason=\"invalid app tag\"", errmsg, sconversion.c_str());
return nullptr;
}
// Parse only substr excluding ^
app_tag = sconversion.substr(pos + 1, end_pos - (pos + 1));
// Erase [start, size including trailing ^]
sconversion.erase(pos, (end_pos - pos) + 1);
}
// Parse layout id
pos = sconversion.find("~");
std::string hexlid = sconversion.c_str();
if (pos != std::string::npos) {
hexlid = sconversion.substr(0, pos).c_str();
}
try {
lid = std::stoll(hexlid, &conv_pos, 16);
} catch (...) {}
if (conv_pos != hexlid.length()) {
lid = 0;
}
if (!fid || !lid) {
eos_static_err("msg=\"%s\" conversion_string=%s "
"reason=\"invalid fid or lid\"", errmsg, sconversion.c_str());
return nullptr;
}
// Parse placement policy
if (pos != std::string::npos) {
policy = sconversion.substr(pos + 1);
}
return std::make_shared(fid, lid, location, policy,
update_ctime, app_tag);
}
EOSMGMNAMESPACE_END