//------------------------------------------------------------------------------
// File: FileSystem.cc
// Author: Andreas-Joachim Peters - CERN
//------------------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2011 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 "common/Namespace.hh"
#include "common/FileSystem.hh"
#include "common/Logging.hh"
#include "common/StringUtils.hh"
#include "common/ParseUtils.hh"
#include "common/Assert.hh"
#include "common/Constants.hh"
#include "common/ParseUtils.hh"
#include "common/StringConversion.hh"
#include "mq/MessagingRealm.hh"
#include
EOSCOMMONNAMESPACE_BEGIN;
//------------------------------------------------------------------------------
// Contains a batch of key-value updates on the attributes of a filesystem.
//------------------------------------------------------------------------------
FileSystemUpdateBatch::FileSystemUpdateBatch() {}
//------------------------------------------------------------------------------
// Set filesystem ID - durable.
//------------------------------------------------------------------------------
void FileSystemUpdateBatch::setId(fsid_t fsid)
{
setLongLongDurable("id", fsid);
}
//----------------------------------------------------------------------------
// Set the draining status - local.
//----------------------------------------------------------------------------
void FileSystemUpdateBatch::setDrainStatusLocal(DrainStatus status)
{
setStringLocal("local.drain", FileSystem::GetDrainStatusAsString(status));
}
//------------------------------------------------------------------------------
// Set durable string.
//
// All observers of this filesystem are guaranteed to receive the update
// eventually, and all updates are guaranteed to be applied in the same
// order for all observers.
//------------------------------------------------------------------------------
void FileSystemUpdateBatch::setStringDurable(const std::string& key,
const std::string& value)
{
mBatch.SetDurable(key, value);
}
//------------------------------------------------------------------------------
// Set transient string. Depending on network instabilities,
// process restarts, or the phase of the moon, some or all observers of this
// filesystem may or may not receive the update.
//
// Transient updates may be applied out of order, and if multiple subscribers
// try to modify the same value, it's possible that observers will not all
// converge on a single consistent value.
//------------------------------------------------------------------------------
void FileSystemUpdateBatch::setStringTransient(const std::string& key,
const std::string& value)
{
mBatch.SetTransient(key, value);
}
//------------------------------------------------------------------------------
// Set local string. This node, and only this node will store the value,
// and only until process restart.
//------------------------------------------------------------------------------
void FileSystemUpdateBatch::setStringLocal(const std::string& key,
const std::string& value)
{
mBatch.SetLocal(key, value);
}
//------------------------------------------------------------------------------
// Set durable int64_t - serialize as string automatically.
//------------------------------------------------------------------------------
void FileSystemUpdateBatch::setLongLongDurable(const std::string& key,
int64_t value)
{
return setStringDurable(key, std::to_string(value));
}
//------------------------------------------------------------------------------
// Set transient int64_t - serialize as string automatically.
//------------------------------------------------------------------------------
void FileSystemUpdateBatch::setLongLongTransient(const std::string& key,
int64_t value)
{
return setStringTransient(key, std::to_string(value));
}
//------------------------------------------------------------------------------
// Set local int64_t - serialize as string automatically.
//------------------------------------------------------------------------------
void FileSystemUpdateBatch::setLongLongLocal(const std::string& key,
int64_t value)
{
return setStringLocal(key, std::to_string(value));
}
//------------------------------------------------------------------------------
// Get durable updates map
//------------------------------------------------------------------------------
const mq::SharedHashWrapper::Batch&
FileSystemUpdateBatch::getBatch() const
{
return mBatch;
}
//------------------------------------------------------------------------------
// Empty constructor
//------------------------------------------------------------------------------
FstLocator::FstLocator() {}
//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
FstLocator::FstLocator(const std::string& host, int port)
: mHost(host), mPort(port) {}
//------------------------------------------------------------------------------
// Get host
//------------------------------------------------------------------------------
std::string FstLocator::getHost() const
{
return mHost;
}
//------------------------------------------------------------------------------
// Get port
//------------------------------------------------------------------------------
int FstLocator::getPort() const
{
return mPort;
}
//------------------------------------------------------------------------------
// Get fst queuepath
//------------------------------------------------------------------------------
std::string FstLocator::getQueuePath() const
{
return SSTR("/eos/" << mHost << ":" << mPort << "/fst");
}
//------------------------------------------------------------------------------
// Get host:port
//------------------------------------------------------------------------------
std::string FstLocator::getHostPort() const
{
return SSTR(mHost << ":" << mPort);
}
//------------------------------------------------------------------------------
// Try to parse from queuepath
//------------------------------------------------------------------------------
bool FstLocator::fromQueuePath(const std::string& queuepath, FstLocator& out)
{
std::string queue = queuepath;
if (!startsWith(queue, "/eos/")) {
return false;
}
queue.erase(0, 5);
//----------------------------------------------------------------------------
// Chop /eos/, extract host+port
//----------------------------------------------------------------------------
size_t slashLocation = queue.find("/");
if (slashLocation == std::string::npos) {
return false;
}
std::string hostPort = std::string(queue.begin(),
queue.begin() + slashLocation);
queue.erase(0, slashLocation);
//----------------------------------------------------------------------------
// Separate host from port
//----------------------------------------------------------------------------
size_t separator = hostPort.find(":");
if (separator == std::string::npos) {
return false;
}
out.mHost = std::string(hostPort.begin(), hostPort.begin() + separator);
hostPort.erase(0, separator + 1);
int64_t port;
if (!ParseInt64(hostPort, port)) {
return false;
}
out.mPort = port;
//----------------------------------------------------------------------------
// Chop "/fst/"
//----------------------------------------------------------------------------
if (queue != "/fst") {
return false;
}
return true;
}
//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
GroupLocator::GroupLocator() {}
//------------------------------------------------------------------------------
// Get group (space.index)
//------------------------------------------------------------------------------
std::string GroupLocator::getGroup() const
{
return mGroup;
}
//------------------------------------------------------------------------------
// Get space
//------------------------------------------------------------------------------
std::string GroupLocator::getSpace() const
{
return mSpace;
}
//------------------------------------------------------------------------------
// Get index
//------------------------------------------------------------------------------
int GroupLocator::getIndex() const
{
return mIndex;
}
//------------------------------------------------------------------------------
// Parse full group (space.index)
//
// NOTE: In case parsing fails, out will still be filled
// with "description.0" to match legacy behaviour.
//------------------------------------------------------------------------------
bool GroupLocator::parseGroup(const std::string& description,
GroupLocator& out)
{
size_t dot = description.find(".");
if (dot == std::string::npos) {
out.mGroup = description;
out.mSpace = description;
out.mIndex = 0;
if (description != eos::common::EOS_SPARE_GROUP) {
eos_static_notice("Unable to parse group: %s, assuming index is zero",
description.c_str());
return false;
}
return true;
}
out.mGroup = description;
out.mSpace = std::string(description.c_str(), dot);
std::string index = std::string(description.begin() + dot + 1,
description.end());
int64_t idx;
if (!ParseInt64(index, idx)) {
eos_static_crit("Could not parse integer index in group: %s",
description.c_str());
out.mIndex = 0;
return false;
}
out.mIndex = idx;
return true;
}
//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
FileSystemCoreParams::FileSystemCoreParams(uint32_t id,
const FileSystemLocator& fsLocator, const GroupLocator& grpLocator,
const std::string& uuid, ConfigStatus cfg, const std::string& sharedfs)
: mFsId(id), mLocator(fsLocator), mGroup(grpLocator), mUuid(uuid),
mConfigStatus(cfg), mSharedFs(sharedfs) {}
//------------------------------------------------------------------------------
// Get locator
//------------------------------------------------------------------------------
const FileSystemLocator& FileSystemCoreParams::getLocator() const
{
return mLocator;
}
//------------------------------------------------------------------------------
//! Get group locator
//------------------------------------------------------------------------------
const GroupLocator& FileSystemCoreParams::getGroupLocator() const
{
return mGroup;
}
//------------------------------------------------------------------------------
//! Get id
//------------------------------------------------------------------------------
uint32_t FileSystemCoreParams::getId() const
{
return mFsId;
}
//------------------------------------------------------------------------------
//! Get uuid
//------------------------------------------------------------------------------
std::string FileSystemCoreParams::getUuid() const
{
return mUuid;
}
//------------------------------------------------------------------------------
// Get SharedFs name
//------------------------------------------------------------------------------
std::string FileSystemCoreParams::getSharedFs() const
{
return mSharedFs;
}
//------------------------------------------------------------------------------
// Get current ConfigStatus
//------------------------------------------------------------------------------
ConfigStatus FileSystemCoreParams::getConfigStatus() const
{
return mConfigStatus;
}
//------------------------------------------------------------------------------
// Get queuepath
//------------------------------------------------------------------------------
std::string FileSystemCoreParams::getQueuePath() const
{
return mLocator.getQueuePath();
}
//------------------------------------------------------------------------------
// Get host
//------------------------------------------------------------------------------
std::string FileSystemCoreParams::getHost() const
{
return mLocator.getHost();
}
//------------------------------------------------------------------------------
// Get hostport
//------------------------------------------------------------------------------
std::string FileSystemCoreParams::getHostPort() const
{
return mLocator.getHostPort();
}
//------------------------------------------------------------------------------
// Get FST queue
//------------------------------------------------------------------------------
std::string FileSystemCoreParams::getFSTQueue() const
{
return mLocator.getFSTQueue();
}
//------------------------------------------------------------------------------
// Get group (space.index)
//------------------------------------------------------------------------------
std::string FileSystemCoreParams::getGroup() const
{
return mGroup.getGroup();
}
//------------------------------------------------------------------------------
// Get space
//------------------------------------------------------------------------------
std::string FileSystemCoreParams::getSpace() const
{
return mGroup.getSpace();
}
//------------------------------------------------------------------------------
//! Default constructor for fs_snapshot_t
//------------------------------------------------------------------------------
FileSystem::fs_snapshot_t::fs_snapshot_t()
{
mId = 0;
mQueue = "";
mQueuePath = "";
mGroup = "";
mPath = "";
mUuid = "";
mHost = "";
mHostPort = "";
mProxyGroup = "";
mS3Credentials = "";
mFileStickyProxyDepth = -1;
mPort = 0;
mErrMsg = "";
mGeoTag = "";
mPublishTimestamp = 0;
mStatus = BootStatus::kDown;
mConfigStatus = ConfigStatus::kOff;
mDrainStatus = DrainStatus::kNoDrain;
mHeadRoom = 0;
mErrCode = 0;
mBootSentTime = 0;
mBootDoneTime = 0;
mDiskUtilization = 0;
mNetEthRateMiB = 0;
mNetInRateMiB = 0;
mNetOutRateMiB = 0;
mDiskWriteRateMb = 0;
mDiskReadRateMb = 0;
mDiskType = 0;
mDiskBsize = 0;
mDiskBlocks = 0;
mDiskBfree = 0;
mDiskBused = 0;
mDiskBavail = 0;
mDiskFiles = 0;
mDiskFfree = 0;
mDiskFused = 0;
mFiles = 0;
mDiskNameLen = 0;
mDiskRopen = 0;
mDiskWopen = 0;
mMaxDiskRopen = 0;
mMaxDiskWopen = 0;
mScanIoRate = 0;
mScanEntryInterval = 0;
mScanRainEntryInterval = 0;
mScanDiskInterval = 0;
mScanNsInterval = 0;
mScanNsRate = 0;
mFsckRefreshInterval = 0;
}
//------------------------------------------------------------------------------
// "Absorb" all information contained within coreParams into this object.
// Fields which are not present in coreParams (ie mNetInRateMiB) remain
// unchanged.
//------------------------------------------------------------------------------
void FileSystem::fs_snapshot_t::fillFromCoreParams(const FileSystemCoreParams&
coreParams)
{
mId = coreParams.getId();
mQueue = coreParams.getFSTQueue();
mQueuePath = coreParams.getQueuePath();
mGroup = coreParams.getGroup();
mPath = coreParams.getLocator().getStoragePath();
mUuid = coreParams.getUuid();
mHost = coreParams.getHost();
mHostPort = coreParams.getHostPort();
mPort = coreParams.getLocator().getPort();
mConfigStatus = coreParams.getConfigStatus();
mSharedFs = coreParams.getSharedFs();
}
//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
FileSystem::FileSystem(const FileSystemLocator& locator,
mq::MessagingRealm* realm, bool bc2mgm)
: mLocator(locator), mHashLocator(locator, bc2mgm),
mRealm(realm), mActStatus(ActiveStatus::kOffline)
{
mInternalBootStatus = BootStatus::kDown;
cStatus = BootStatus::kDown;
cConfigStatus = ConfigStatus::kOff;
cStatusTime = 0;
cConfigTime = 0;
if (mRealm) {
mq::SharedHashWrapper::Batch upd_batch;
upd_batch.SetDurable("queue", mLocator.getFSTQueue());
upd_batch.SetDurable("queuepath", mLocator.getQueuePath());
upd_batch.SetDurable("path", mLocator.getStoragePath());
upd_batch.SetDurable("hostport", locator.getHostPort());
upd_batch.SetDurable("host", locator.getHost());
upd_batch.SetDurable("port", std::to_string(locator.getPort()));
upd_batch.SetLocal("local.drain", "nodrain");
if (!mRealm->haveQDB() && !bc2mgm) {
upd_batch.SetDurable("configstatus", "down");
}
mq::SharedHashWrapper(mRealm, mHashLocator).set(upd_batch);
}
}
//------------------------------------------------------------------------------
// Delete shared hash object corresponding to this file system and also
// broadcast the message. This should be called only when an explicit removal
// of the file system is request though "fs rm".
//------------------------------------------------------------------------------
void FileSystem::DeleteSharedHash()
{
mq::SharedHashWrapper::deleteHash(mRealm, mHashLocator);
}
//------------------------------------------------------------------------------
// Get underlying hash locator
//------------------------------------------------------------------------------
SharedHashLocator FileSystem::getHashLocator() const
{
return mHashLocator;
}
//------------------------------------------------------------------------------
// Return the given status as a string
//------------------------------------------------------------------------------
const char*
FileSystem::GetStatusAsString(BootStatus status)
{
if (status == BootStatus::kDown) {
return "down";
}
if (status == BootStatus::kOpsError) {
return "opserror";
}
if (status == BootStatus::kBootFailure) {
return "bootfailure";
}
if (status == BootStatus::kBootSent) {
return "bootsent";
}
if (status == BootStatus::kBooting) {
return "booting";
}
if (status == BootStatus::kBooted) {
return "booted";
}
return "unknown";
}
//------------------------------------------------------------------------------
// Return given drain status as a string
//------------------------------------------------------------------------------
const char*
FileSystem::GetDrainStatusAsString(DrainStatus status)
{
if (status == DrainStatus::kNoDrain) {
return "nodrain";
}
if (status == DrainStatus::kDrainPrepare) {
return "prepare";
}
if (status == DrainStatus::kDrainWait) {
return "waiting";
}
if (status == DrainStatus::kDraining) {
return "draining";
}
if (status == DrainStatus::kDrained) {
return "drained";
}
if (status == DrainStatus::kDrainStalling) {
return "stalling";
}
if (status == DrainStatus::kDrainExpired) {
return "expired";
}
if (status == DrainStatus::kDrainFailed) {
return "failed";
}
return "unknown";
}
//------------------------------------------------------------------------------
// Return given configuration status as a string
//------------------------------------------------------------------------------
const char*
FileSystem::GetConfigStatusAsString(ConfigStatus status)
{
switch (status) {
case ConfigStatus::kUnknown: {
return "unknown";
}
case ConfigStatus::kOff: {
return "off";
}
case ConfigStatus::kEmpty: {
return "empty";
}
case ConfigStatus::kDrainDead: {
return "draindead";
}
case ConfigStatus::kGroupDrain: {
return "groupdrain";
}
case ConfigStatus::kDrain: {
return "drain";
}
case ConfigStatus::kRO: {
return "ro";
}
case ConfigStatus::kWO: {
return "wo";
}
case ConfigStatus::kRW: {
return "rw";
}
default: {
return "unknown";
}
}
}
//------------------------------------------------------------------------------
// Return given Active status as a string
//------------------------------------------------------------------------------
const char*
FileSystem::GetActiveStatusAsString(ActiveStatus status)
{
if (status == ActiveStatus::kOnline) {
return "online";
} else if (status == ActiveStatus::kOffline) {
return "offline";
} else if (status == ActiveStatus::kOverload) {
return "overload";
} else {
return "undef";
}
}
//------------------------------------------------------------------------------
// Get the status from a string representation
//------------------------------------------------------------------------------
BootStatus
FileSystem::GetStatusFromString(const char* ss)
{
if (!ss) {
return BootStatus::kDown;
}
if (!strcmp(ss, "down")) {
return BootStatus::kDown;
}
if (!strcmp(ss, "opserror")) {
return BootStatus::kOpsError;
}
if (!strcmp(ss, "bootfailure")) {
return BootStatus::kBootFailure;
}
if (!strcmp(ss, "bootsent")) {
return BootStatus::kBootSent;
}
if (!strcmp(ss, "booting")) {
return BootStatus::kBooting;
}
if (!strcmp(ss, "booted")) {
return BootStatus::kBooted;
}
return BootStatus::kDown;
}
//------------------------------------------------------------------------------
// Return configuration status from a string representation
//------------------------------------------------------------------------------
ConfigStatus
FileSystem::GetConfigStatusFromString(const char* ss)
{
if (!ss) {
return ConfigStatus::kOff;
}
if (!strcmp(ss, "unknown")) {
return ConfigStatus::kUnknown;
}
if (!strcmp(ss, "off")) {
return ConfigStatus::kOff;
}
if (!strcmp(ss, "empty")) {
return ConfigStatus::kEmpty;
}
if (!strcmp(ss, "draindead")) {
return ConfigStatus::kDrainDead;
}
if (!strcmp(ss, "drain")) {
return ConfigStatus::kDrain;
}
if (!strcmp(ss, "ro")) {
return ConfigStatus::kRO;
}
if (!strcmp(ss, "wo")) {
return ConfigStatus::kWO;
}
if (!strcmp(ss, "rw")) {
return ConfigStatus::kRW;
}
if (!strcmp(ss, "down")) {
return ConfigStatus::kOff;
}
return ConfigStatus::kUnknown;
}
//------------------------------------------------------------------------------
// Return drains status from string representation
//------------------------------------------------------------------------------
DrainStatus
FileSystem::GetDrainStatusFromString(const char* ss)
{
if (!ss) {
return DrainStatus::kNoDrain;
}
if (!strcmp(ss, "nodrain")) {
return DrainStatus::kNoDrain;
}
if (!strcmp(ss, "prepare")) {
return DrainStatus::kDrainPrepare;
}
if (!strcmp(ss, "wait")) {
return DrainStatus::kDrainWait;
}
if (!strcmp(ss, "draining")) {
return DrainStatus::kDraining;
}
if (!strcmp(ss, "stalling")) {
return DrainStatus::kDrainStalling;
}
if (!strcmp(ss, "drained")) {
return DrainStatus::kDrained;
}
if (!strcmp(ss, "expired")) {
return DrainStatus::kDrainExpired;
}
if (!strcmp(ss, "failed")) {
return DrainStatus::kDrainFailed;
}
return DrainStatus::kNoDrain;
}
//----------------------------------------------------------------------------
//! Set the activation status
//----------------------------------------------------------------------------
void
FileSystem::SetActiveStatus(ActiveStatus active)
{
if (mActStatus != active) {
mActStatus = active;
SetString("stat.active", GetActiveStatusAsString(mActStatus), false);
}
}
//------------------------------------------------------------------------------
// Apply the given batch of updates
//------------------------------------------------------------------------------
bool FileSystem::applyBatch(const FileSystemUpdateBatch& batch)
{
return mq::SharedHashWrapper(mRealm, mHashLocator).set(batch.getBatch());
}
//------------------------------------------------------------------------------
// Apply the given core parameters
//------------------------------------------------------------------------------
bool FileSystem::applyCoreParams(const FileSystemCoreParams& params)
{
FileSystemUpdateBatch batch;
batch.setStringDurable("uuid", params.getUuid());
batch.setStringDurable("schedgroup", params.getGroupLocator().getGroup());
batch.setStringDurable("configstatus",
GetConfigStatusAsString(params.getConfigStatus()));
batch.setId(params.getId());
return applyBatch(batch);
}
//------------------------------------------------------------------------------
// Set a local long long
//------------------------------------------------------------------------------
bool FileSystem::SetLongLongLocal(const std::string& key, int64_t value)
{
common::FileSystemUpdateBatch batch;
batch.setLongLongLocal(key, value);
return this->applyBatch(batch);
}
//------------------------------------------------------------------------------
// Set a key-value pair in a filesystem and evt. broadcast it.
//------------------------------------------------------------------------------
bool FileSystem::SetString(const char* key, const char* str, bool broadcast)
{
return mq::SharedHashWrapper(mRealm, mHashLocator).set(key, str, broadcast);
}
//------------------------------------------------------------------------------
// Remove a key from a filesystem and evt. broadcast it.
//------------------------------------------------------------------------------
bool FileSystem::RemoveKey(const char* key, bool broadcast)
{
return mq::SharedHashWrapper(mRealm, mHashLocator).del(key, broadcast);
}
//------------------------------------------------------------------------------
// Get all keys in a vector of strings.
//------------------------------------------------------------------------------
bool FileSystem::GetKeys(std::vector& keys)
{
return mq::SharedHashWrapper(mRealm, mHashLocator).getKeys(keys);
}
//------------------------------------------------------------------------------
// Get the string value by key
//------------------------------------------------------------------------------
std::string FileSystem::GetString(const char* key)
{
std::string skey = key;
if (skey == "") {
return "1";
}
return mq::SharedHashWrapper(mRealm, mHashLocator).get(key);
}
//------------------------------------------------------------------------------
// Get a long long value by key
//------------------------------------------------------------------------------
long long FileSystem::GetLongLong(const char* key)
{
return ParseLongLong(GetString(key));
}
//------------------------------------------------------------------------------
// Get a double value by key
//------------------------------------------------------------------------------
double FileSystem::GetDouble(const char* key)
{
return ParseDouble(GetString(key));
}
//--------------------------------------------------------------------------
//! Get used bytes
//--------------------------------------------------------------------------
uint64_t
FileSystem::GetUsedbytes()
{
return GetLongLong("stat.statfs.usedbytes");
}
//--------------------------------------------------------------------------
//! Get space name
//--------------------------------------------------------------------------
std::string
FileSystem::GetSpace()
{
return getCoreParams().getSpace();
}
//------------------------------------------------------------------------------
// Get shared file system name
//------------------------------------------------------------------------------
std::string FileSystem::getSharedFs()
{
return getCoreParams().getSharedFs();
}
//------------------------------------------------------------------------------
// Serializes hash contents as follows 'key1=val1 key2=val2 ... keyn=valn'
// but return only keys that don't start with filter_prefix.
//------------------------------------------------------------------------------
std::string
FileSystem::SerializeWithFilter(const std::map&
contents,
std::list filter_prefixes)
{
using eos::common::StringConversion;
std::string key;
std::string val;
std::ostringstream oss;
bool filter_out;
filter_prefixes.push_back("drainstatus");
for (auto it = contents.begin(); it != contents.end(); it++) {
key = it->first.c_str();
filter_out = false;
for (const auto& prefix : filter_prefixes) {
if (prefix.length() && (key.find(prefix) == 0)) {
filter_out = true;
break;
}
}
if (filter_out) {
eos_static_debug("msg=\"filter out\" key=\"%s\"", key.c_str());
} else {
val = it->second;
if ((val[0] == '"') && (val[val.length() - 1] == '"')) {
std::string to_encode = val.substr(1, val.length() - 2);
std::string encoded = StringConversion::curl_default_escaped(to_encode);
if (!encoded.empty()) {
val = '"';
val += encoded;
val += '"';
}
}
oss << key << "=" << val.c_str() << " ";
}
}
return oss.str();
}
//------------------------------------------------------------------------------
// Print contents onto a table: Originally implemented in XrdMqSharedHash.
//
// Format contents of the hash map to be displayed using the table object.
//
// @param table_mq_header table header
// @param talbe_md_data table data
// @param format format has to be provided as a chain separated by "|" of
// the following tags
// "key=:width=:format=[+][-][slfo]:unit=:tag=:condition=="
// -> to print a key of the attached children
// "sep=" -> to put a seperator
// "header=1" -> to put a header with description on top - this must be the
// first format tag.
// "indent=" -> indent the output
// The formats are:
// 's' : print as string
// 'S' : print as short string (truncated after .)
// 'l' : print as long long
// 'f' : print as double
// 'o' : print as =
// '-' : left align the printout
// '+' : convert numbers into k,M,G,T,P ranges
// The unit is appended to every number:
// e.g. 1500 with unit=B would end up as '1.5 kB'
// "tag=" -> use instead of the variable name to print the header
// @param filter to filter out hash content
//------------------------------------------------------------------------------
static void printOntoTable(mq::SharedHashWrapper& hash,
TableHeader& table_mq_header,
TableData& table_mq_data, std::string format, const std::string& filter)
{
using eos::common::StringConversion;
std::vector formattoken;
StringConversion::Tokenize(format, formattoken, "|");
table_mq_data.emplace_back();
for (unsigned int i = 0; i < formattoken.size(); ++i) {
std::vector tagtoken;
std::map formattags;
StringConversion::Tokenize(formattoken[i], tagtoken, ":");
for (unsigned int j = 0; j < tagtoken.size(); ++j) {
std::vector keyval;
StringConversion::Tokenize(tagtoken[j], keyval, "=");
if (keyval.size() >= 2) {
formattags[keyval[0]] = keyval[1];
}
}
if (formattags.count("format")) {
unsigned int width = atoi(formattags["width"].c_str());
std::string format = formattags["format"];
std::string unit = formattags["unit"];
// Normal member printout
if (formattags.count("key")) {
if (format.find("s") != std::string::npos) {
table_mq_data.back().push_back(
TableCell(hash.get(formattags["key"]), format));
}
if (format.find("S") != std::string::npos) {
std::string shortstring = hash.get(formattags["key"].c_str());
const size_t pos = shortstring.find(".");
if (pos != std::string::npos) {
shortstring.erase(pos);
}
table_mq_data.back().push_back(TableCell(shortstring, format));
}
if ((format.find("l")) != std::string::npos) {
table_mq_data.back().push_back(
TableCell(hash.getLongLong(formattags["key"].c_str()), format, unit));
}
if ((format.find("f")) != std::string::npos) {
table_mq_data.back().push_back(
TableCell(hash.getDouble(formattags["key"].c_str()), format, unit));
}
XrdOucString name = formattags["key"].c_str();
if (format.find("o") == std::string::npos) { //only for table output
name.replace("stat.", "");
name.replace("stat.statfs.", "");
name.replace("local.", "");
if (formattags.count("tag")) {
name = formattags["tag"].c_str();
}
}
table_mq_header.push_back(std::make_tuple(name.c_str(), width, format));
}
if (formattags.count("compute")) {
if (formattags["compute"] == "usage") {
// compute the percentage usage
long long used_bytes = hash.getLongLong("stat.statfs.usedbytes");
long long capacity = hash.getLongLong("stat.statfs.capacity");
long long headroom = hash.getLongLong("headroom");
double usage = 0;
if (capacity) {
usage = 100.0 * (used_bytes + headroom) / (capacity);
if (usage > 100.0) {
usage = 100.0;
}
}
table_mq_data.back().push_back(
TableCell(usage, format, unit));
table_mq_header.push_back(std::make_tuple("usage", width, format));
}
}
}
}
//we check for filters
bool toRemove = false;
if (filter.find("d") != string::npos) {
std::string drain = hash.get("local.drain");
// @note there is a bug when initializing local.drain on an fs which is not
// propagated to the shared hash therefore, we need to also exclude the
// the empty drain status from the list of active drainings
if (drain.empty() || (drain == "nodrain")) {
toRemove = true;
}
}
if (filter.find("e") != string::npos) {
int err = (int) hash.getLongLong("stat.errc");
if (err == 0) {
toRemove = true;
}
}
if (toRemove) {
table_mq_data.pop_back();
}
}
//------------------------------------------------------------------------------
// Store a configuration key-val pair.
// Internally, these keys are not prefixed with 'stat.'
//------------------------------------------------------------------------------
void
FileSystem::CreateConfig(std::string& key, std::string& val)
{
key = mLocator.getQueuePath();
val.clear();
std::map contents;
mq::SharedHashWrapper(mRealm, mHashLocator).getContents(contents);
val = SerializeWithFilter(contents, {"stat.", "local."});
}
//------------------------------------------------------------------------------
// Retrieve FileSystem's core parameters
//------------------------------------------------------------------------------
FileSystemCoreParams FileSystem::getCoreParams()
{
mq::SharedHashWrapper hash(mRealm, mHashLocator);
std::string id;
if (!hash.get("id", id) || id.empty()) {
return FileSystemCoreParams(0, FileSystemLocator(), GroupLocator(), "",
ConfigStatus::kOff, "");
}
GroupLocator groupLocator;
GroupLocator::parseGroup(hash.get("schedgroup"), groupLocator);
std::string uuid = hash.get("uuid");
ConfigStatus cfg = GetConfigStatusFromString(hash.get("configstatus").c_str());
std::string sharedfs = hash.get("sharedfs");
return FileSystemCoreParams(atoi(id.c_str()), mLocator, groupLocator, uuid,
cfg, sharedfs);
}
//------------------------------------------------------------------------------
// Snapshots all variables of a filesystem into a snapshot struct
//------------------------------------------------------------------------------
bool
FileSystem::SnapShotFileSystem(FileSystem::fs_snapshot_t& fs, bool dolock)
{
mq::SharedHashWrapper hash(mRealm, mHashLocator, dolock, false);
std::string tmp;
if (!hash.get("id", tmp)) {
eos_static_err("%s", "msg=\"failed to get file system id\"");
fs = {};
return false;
}
fs.mId = hash.getLongLong("id");
fs.mQueue = mLocator.getFSTQueue();
fs.mQueuePath = mLocator.getQueuePath();
fs.mGroup = hash.get("schedgroup");
fs.mUuid = hash.get("uuid");
fs.mHost = mLocator.getHost();
fs.mHostPort = mLocator.getHostPort();
fs.mProxyGroup = hash.get("proxygroup");
fs.mS3Credentials = hash.get("s3credentials");
fs.mFileStickyProxyDepth = -1;
if (hash.get("filestickyproxydepth").size()) {
fs.mFileStickyProxyDepth = hash.getLongLong("filestickyproxydepth");
}
fs.mPort = mLocator.getPort();
GroupLocator groupLocator;
GroupLocator::parseGroup(fs.mGroup, groupLocator);
fs.mSpace = groupLocator.getSpace();
fs.mGroupIndex = groupLocator.getIndex();
fs.mPath = mLocator.getStoragePath();
fs.mErrMsg = hash.get("stat.errmsg");
fs.mGeoTag = hash.get("stat.geotag");
fs.mForceGeoTag.clear();
if (hash.get("forcegeotag").size()) {
std::string forceGeoTag = hash.get("forcegeotag");
if (forceGeoTag != "") {
fs.mGeoTag = forceGeoTag;
fs.mForceGeoTag = forceGeoTag;
}
}
fs.mPublishTimestamp = (size_t) hash.getLongLong("stat.publishtimestamp");
fs.mStatus = GetStatusFromString(hash.get("stat.boot").c_str());
fs.mConfigStatus = GetConfigStatusFromString(hash.get("configstatus").c_str());
fs.mDrainStatus = GetDrainStatusFromString(hash.get("local.drain").c_str());
fs.mActiveStatus = mActStatus.load();
//headroom can be configured as KMGTP so the string should be properly converted
fs.mHeadRoom = StringConversion::GetSizeFromString(hash.get("headroom"));
fs.mErrCode = (unsigned int) hash.getLongLong("stat.errc");
fs.mBootSentTime = (time_t) hash.getLongLong("bootsenttime");
fs.mBootDoneTime = (time_t) hash.getLongLong("stat.bootdonetime");
fs.mDiskUtilization = hash.getDouble("stat.disk.load");
fs.mNetEthRateMiB = hash.getDouble("stat.net.ethratemib");
fs.mNetInRateMiB = hash.getDouble("stat.net.inratemib");
fs.mNetOutRateMiB = hash.getDouble("stat.net.outratemib");
fs.mDiskWriteRateMb = hash.getDouble("stat.disk.writeratemb");
fs.mDiskReadRateMb = hash.getDouble("stat.disk.readratemb");
fs.mDiskType = (long) hash.getLongLong("stat.statfs.type");
fs.mDiskFreeBytes = hash.getLongLong("stat.statfs.freebytes");
fs.mDiskCapacity = hash.getLongLong("stat.statfs.capacity");
fs.mDiskBsize = (long) hash.getLongLong("stat.statfs.bsize");
fs.mDiskBlocks = (long) hash.getLongLong("stat.statfs.blocks");
fs.mDiskBfree = (long) hash.getLongLong("stat.statfs.bfree");
fs.mDiskBused = (long) hash.getLongLong("stat.statfs.bused");
fs.mDiskBavail = (long) hash.getLongLong("stat.statfs.bavail");
fs.mDiskFiles = (long) hash.getLongLong("stat.statfs.files");
fs.mDiskFfree = (long) hash.getLongLong("stat.statfs.ffree");
fs.mDiskFused = (long) hash.getLongLong("stat.statfs.fused");
fs.mDiskFilled = (double) hash.getDouble("stat.statfs.filled");
fs.mNominalFilled = (double) hash.getDouble("stat.nominal.filled");
fs.mFiles = (long) hash.getLongLong("stat.usedfiles");
fs.mDiskNameLen = (long) hash.getLongLong("stat.statfs.namelen");
fs.mDiskRopen = (long) hash.getLongLong("stat.ropen");
fs.mDiskWopen = (long) hash.getLongLong("stat.wopen");
fs.mMaxDiskRopen = (long) hash.getLongLong("max.ropen");
fs.mMaxDiskWopen = (long) hash.getLongLong("max.wopen");
fs.mScanIoRate = (long) hash.getLongLong(eos::common::SCAN_IO_RATE_NAME);
fs.mScanEntryInterval = (long)hash.getLongLong
(eos::common::SCAN_ENTRY_INTERVAL_NAME);
fs.mScanRainEntryInterval =
(long)hash.getLongLong(eos::common::SCAN_RAIN_ENTRY_INTERVAL_NAME);
fs.mScanDiskInterval = (long)hash.getLongLong(
eos::common::SCAN_DISK_INTERVAL_NAME);
fs.mScanNsInterval = (long)hash.getLongLong(eos::common::SCAN_NS_INTERVAL_NAME);
fs.mScanNsRate = (long)hash.getLongLong(eos::common::SCAN_NS_RATE_NAME);
fs.mFsckRefreshInterval = (long) hash.getLongLong(
eos::common::FSCK_REFRESH_INTERVAL_NAME);
fs.mGracePeriod = (time_t) hash.getLongLong("graceperiod");
fs.mDrainPeriod = (time_t) hash.getLongLong("drainperiod");
return true;
}
//----------------------------------------------------------------------------
// Return the configuration status (via cache)
//----------------------------------------------------------------------------
ConfigStatus
FileSystem::GetConfigStatus(bool cached)
{
XrdSysMutexHelper lock(cConfigLock);
if (cached) {
time_t now = time(NULL);
if (now - cConfigTime) {
cConfigTime = now;
} else {
return cConfigStatus;
}
}
cConfigStatus = GetConfigStatusFromString(GetString("configstatus").c_str());
return cConfigStatus;
}
//----------------------------------------------------------------------------
// Return the filesystem status (via a cache)
//----------------------------------------------------------------------------
BootStatus
FileSystem::GetStatus(bool cached)
{
XrdSysMutexHelper lock(cStatusLock);
if (cached) {
time_t now = time(NULL);
if (now - cStatusTime) {
cStatusTime = now;
} else {
return cStatus;
}
}
cStatus = GetStatusFromString(GetString("stat.boot").c_str());
return cStatus;
}
//----------------------------------------------------------------------------
// Function printing the file system info to the table
//----------------------------------------------------------------------------
void
FileSystem::Print(TableHeader& table_mq_header, TableData& table_mq_data,
std::string listformat, const std::string& filter)
{
mq::SharedHashWrapper hash(mRealm, mHashLocator);
printOntoTable(hash, table_mq_header, table_mq_data, listformat, filter);
}
//------------------------------------------------------------------------------
// Convert input to file system id
//------------------------------------------------------------------------------
eos::common::FileSystem::fsid_t
FileSystem::ConvertToFsid(const std::string& value)
{
eos::common::FileSystem::fsid_t fsid = 0ul;
try {
size_t pos = 0;
fsid = std::stoul(value, &pos);
if (pos != value.length()) {
throw std::runtime_error("failed fsid conversion");
}
} catch (...) {
fsid = 0ul;
}
return fsid;
}
EOSCOMMONNAMESPACE_END;