//------------------------------------------------------------------------------ // File: DirEos.cc // Author: Elvin-Alin Sindrilaru - 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 "DirEos.hh" #include "Configuration.hh" /*----------------------------------------------------------------------------*/ #include "common/LayoutId.hh" #include "XrdCl/XrdClFileSystem.hh" #include "XrdSfs/XrdSfsInterface.hh" /*----------------------------------------------------------------------------*/ EOSBMKNAMESPACE_BEGIN //------------------------------------------------------------------------------ // Constructor //------------------------------------------------------------------------------ DirEos::DirEos(const std::string& dirPath, const std::string& eosInstance): eos::common::LogId(), mDirPath(dirPath), mFs(NULL) { XrdCl::URL url(eosInstance); if (!url.IsValid()) { eos_err("URL is not valid"); exit(-1); } mFs = new XrdCl::FileSystem(url); if (!mFs) { eos_err("Error while trying to get XrdCl::FileSystem object"); exit(-1); } } //------------------------------------------------------------------------------ // Destructor //------------------------------------------------------------------------------ DirEos::~DirEos() { delete mFs; } //------------------------------------------------------------------------------ // Check if directory exists //------------------------------------------------------------------------------ bool DirEos::Exist() { bool ret = true; std::string request; XrdCl::Buffer arg; XrdCl::Buffer* response = 0; request = mDirPath; request += "?"; request += "mgm.pcmd=stat"; arg.FromString(request); XrdCl::XRootDStatus status = mFs->Query(XrdCl::QueryCode::OpaqueFile, arg, response); if (status.IsOK()) { unsigned long long sval[10]; unsigned long long ival[6]; char tag[1024]; int items = sscanf(response->GetBuffer(), "%s %llu %llu %llu %llu %llu %llu %llu %llu " "%llu %llu %llu %llu %llu %llu %llu %llu", tag, (unsigned long long*) &sval[0], (unsigned long long*) &sval[1], (unsigned long long*) &sval[2], (unsigned long long*) &sval[3], (unsigned long long*) &sval[4], (unsigned long long*) &sval[5], (unsigned long long*) &sval[6], (unsigned long long*) &sval[7], (unsigned long long*) &sval[8], (unsigned long long*) &sval[9], (unsigned long long*) &ival[0], (unsigned long long*) &ival[1], (unsigned long long*) &ival[2], (unsigned long long*) &ival[3], (unsigned long long*) &ival[4], (unsigned long long*) &ival[5]); if ((items != 17) || (strcmp(tag, "stat:"))) { ret = false; } } else { ret = false; } delete response; return ret; } //------------------------------------------------------------------------------ // Set extended attribute //------------------------------------------------------------------------------ bool DirEos::SetXattr(const std::string& attrName, const std::string& attrValue) { bool retc = true; std::string request; XrdCl::Buffer arg; XrdCl::Buffer* response = 0; request = mDirPath; request += "?"; request += "mgm.pcmd=xattr&"; request += "mgm.subcmd=set&"; request += "mgm.xattrname="; request += attrName; request += "&"; request += "mgm.xattrvalue="; request += attrValue; arg.FromString(request); XrdCl::XRootDStatus status = mFs->Query(XrdCl::QueryCode::OpaqueFile, arg, response); if (status.IsOK()) { int ret; int items = 0; char tag[1024]; // Parse output items = sscanf(response->GetBuffer(), "%s retc=%i", tag, &ret); if ((items != 2) || (strcmp(tag, "setxattr:"))) { retc = false; } } else { retc = false; } delete response; return retc; } //------------------------------------------------------------------------------ // Create directory //------------------------------------------------------------------------------ bool DirEos::Create() { mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP; XrdCl::Access::Mode mode_xrdcl = eos::common::LayoutId::MapModeSfs2XrdCl(mode); XrdCl::XRootDStatus status = mFs->MkDir(mDirPath, XrdCl::MkDirFlags::MakePath, mode_xrdcl); return status.IsOK(); } //------------------------------------------------------------------------------ // Check that the extended attribute matched the reference value //------------------------------------------------------------------------------ bool DirEos::CheckXattr(const std::string& attrName, const std::string& refValue) { bool retc = true; std::string request; XrdCl::Buffer arg; XrdCl::Buffer* response = 0; request = mDirPath; request += "?"; request += "mgm.pcmd=xattr&"; request += "mgm.subcmd=get&"; request += "mgm.xattrname="; request += attrName; arg.FromString(request); XrdCl::XRootDStatus status = mFs->Query(XrdCl::QueryCode::OpaqueFile, arg, response); if (status.IsOK()) { int ret; int items = 0; char tag[1024]; char rval[4096]; // Parse output items = sscanf(response->GetBuffer(), "%s retc=%i value=%s", tag, &ret, rval); if ((items != 3) || (strcmp(tag, "getxattr:"))) { fprintf(stderr, "[%s] Directory does not have the required xattr.\n", __FUNCTION__); retc = false; } else { std::string attr_value = rval; if (attr_value.compare(refValue)) { // Attr value is different from refValue retc = false; } } } else { retc = false; } delete response; return retc; } //------------------------------------------------------------------------------ // Get files from benchmark directory having the requried file size //------------------------------------------------------------------------------ std::vector DirEos::GetMatchingFiles(const uint64_t fileSize) { std::vector vect_filenames; XrdCl::DirectoryList* response = 0; XrdCl::DirListFlags::Flags flags = XrdCl::DirListFlags::Stat; XrdCl::XRootDStatus status = mFs->DirList(mDirPath, flags, response); std::string full_path; if (status.IsOK()) { for (XrdCl::DirectoryList::ConstIterator iter = response->Begin(); iter != response->End(); ++iter) { XrdCl::DirectoryList::ListEntry* list_entry = static_cast(*iter); if (list_entry->GetStatInfo()->GetSize() == fileSize) { full_path = mDirPath; full_path += list_entry->GetName(); vect_filenames.push_back(full_path); } } } delete response; return vect_filenames; } //------------------------------------------------------------------------------ // Check if directory matches with the supplied low level configuration //------------------------------------------------------------------------------ bool DirEos::MatchConfig(const ConfigProto& llconfig) { if (!CheckXattr("user.admin.forced.layout", Configuration::GetFileLayout(llconfig.filelayout()))) { eos_warning("Directory attributes do not match with configuration"); return false; } // If this is a replica file type we check the number of preplicas if (llconfig.filelayout() == ConfigProto_FileLayoutType_REPLICA) { if (!CheckXattr("user.admin.forced.nstripes", std::to_string((long long int)llconfig.noreplicas()))) { eos_warning("Number of replicas does not match with configuration"); return false; } } return true; } //------------------------------------------------------------------------------ // Set the extended attributes of the directory so that they match the config //------------------------------------------------------------------------------ bool DirEos::SetConfig(const ConfigProto& llconfig) { // OBS: These predefined configuration are the ones that we expect to be // used in production and therefore we set them like this bool ret = true; if (llconfig.filelayout() == ConfigProto_FileLayoutType_PLAIN) { ret = SetXattr("user.admin.forced.layout", "plain"); ret |= SetXattr("user.admin.forced.checksum", "adler"); ret |= SetXattr("user.admin.forced.blockchecksum", "crc32c"); ret |= SetXattr("user.admin.forced.blocksize", "1MB"); } else if (llconfig.filelayout() == ConfigProto_FileLayoutType_REPLICA) { ret = SetXattr("user.admin.forced.layout", "replica"); ret |= SetXattr("user.admin.forced.nstripes", std::to_string((long long int)llconfig.noreplicas())); ret |= SetXattr("user.admin.forced.checksum", "adler"); ret |= SetXattr("user.admin.forced.blockchecksum", "crc32c"); ret |= SetXattr("user.admin.forced.blocksize", "1M"); } else if (llconfig.filelayout() == ConfigProto_FileLayoutType_ARCHIVE) { ret = SetXattr("user.admin.forced.layout", "archive"); ret |= SetXattr("user.admin.forced.blockchecksum", "crc32c"); ret |= SetXattr("user.admin.forced.blocksize", "1M"); } else if (llconfig.filelayout() == ConfigProto_FileLayoutType_RAIDDP) { ret = SetXattr("user.admin.forced.layout", "raiddp"); ret |= SetXattr("user.admin.forced.nstripes", "6"); ret |= SetXattr("user.admin.forced.blockchecksum", "crc32c"); ret |= SetXattr("user.admin.forced.blocksize", "1M"); } else if (llconfig.filelayout() == ConfigProto_FileLayoutType_RAID6) { ret = SetXattr("user.admin.forced.layout", "raid6"); ret |= SetXattr("user.admin.forced.nstripes", "6"); ret |= SetXattr("user.admin.forced.blockchecksum", "crc32c"); ret |= SetXattr("user.admin.forced.blocksize", "1M"); } if (!ret) { cerr << "Error while trying to set extended attributes." << endl; return ret; } return ret; } //------------------------------------------------------------------------------ //! Remove directory //------------------------------------------------------------------------------ bool DirEos::Remove() { XrdCl::XRootDStatus status = mFs->RmDir(mDirPath); return status.IsOK(); } EOSBMKNAMESPACE_END