//------------------------------------------------------------------------------ //! @file com_ns.cc //------------------------------------------------------------------------------ /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2017 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/StringTokenizer.hh" #include "common/StringConversion.hh" #include "common/ParseUtils.hh" #include "console/ConsoleMain.hh" #include "console/commands/ICmdHelper.hh" void com_ns_help(); //------------------------------------------------------------------------------ //! Class NsHelper //------------------------------------------------------------------------------ class NsHelper: public ICmdHelper { public: //---------------------------------------------------------------------------- //! Constructor //! //! @param opts global options //---------------------------------------------------------------------------- NsHelper(const GlobalOptions& opts): ICmdHelper(opts) { mIsAdmin = true; } //---------------------------------------------------------------------------- //! Destructor //---------------------------------------------------------------------------- ~NsHelper() = default; //---------------------------------------------------------------------------- //! Parse command line input //! //! @param arg input //! //! @return true if successful, otherwise false //---------------------------------------------------------------------------- bool ParseCommand(const char* arg); }; //------------------------------------------------------------------------------ // Parse command line input //------------------------------------------------------------------------------ bool NsHelper::ParseCommand(const char* arg) { const char* option; std::string soption; eos::console::NsProto* ns = mReq.mutable_ns(); eos::common::StringTokenizer tokenizer(arg); tokenizer.GetLine(); option = tokenizer.GetToken(); std::string cmd = (option ? option : ""); if (cmd == "stat") { eos::console::NsProto_StatProto* stat = ns->mutable_stat(); if (!(option = tokenizer.GetToken())) { stat->set_monitor(false); } else { while (true) { soption = option; if (soption == "-a") { stat->set_groupids(true); } else if (soption == "-m") { stat->set_monitor(true); } else if (soption == "-n") { stat->set_numericids(true); } else if (soption == "--reset") { stat->set_reset(true); } else { return false; } if (!(option = tokenizer.GetToken())) { break; } } } } else if (cmd == "mutex") { using eos::console::NsProto_MutexProto; NsProto_MutexProto* mutex = ns->mutable_mutex(); if (!(option = tokenizer.GetToken())) { mutex->set_list(true); } else { while (true) { soption = option; if (soption == "--toggletime") { mutex->set_toggle_timing(true); } else if (soption == "--toggleorder") { mutex->set_toggle_order(true); } else if (soption == "--toggledeadlock") { mutex->set_toggle_deadlock(true); } else if (soption == "--smplrate1") { mutex->set_sample_rate1(true); } else if (soption == "--smplrate10") { mutex->set_sample_rate10(true); } else if (soption == "--smplrate100") { mutex->set_sample_rate100(true); } else if (soption == "--setblockedtime") { option = tokenizer.GetToken(); if (option) { mutex->set_blockedtime(std::stoul(option)); } else { return false; } } else { return false; } if (!(option = tokenizer.GetToken())) { break; } } } } else if (cmd == "compact") { using eos::console::NsProto_CompactProto; NsProto_CompactProto* compact = ns->mutable_compact(); if (!(option = tokenizer.GetToken())) { return false; } else { soption = option; if (soption == "off") { compact->set_on(false); } else if (soption == "on") { compact->set_on(true); if ((option = tokenizer.GetToken())) { soption = option; int64_t delay = 0; try { delay = std::stol(soption); } catch (std::exception& e) { return false; } compact->set_delay(delay); if ((option = tokenizer.GetToken())) { soption = option; int64_t interval = 0; try { interval = std::stol(soption); } catch (std::exception& e) { return false; } compact->set_interval(interval); if ((option = tokenizer.GetToken())) { soption = option; if (soption == "files") { compact->set_type(NsProto_CompactProto::FILES); } else if (soption == "directories") { compact->set_type(NsProto_CompactProto::DIRS); } else if (soption == "all") { compact->set_type(NsProto_CompactProto::ALL); } else if (soption == "files-repair") { compact->set_type(NsProto_CompactProto::FILES_REPAIR); } else if (soption == "directories-repair") { compact->set_type(NsProto_CompactProto::DIRS_REPAIR); } else if (soption == "all-repair") { compact->set_type(NsProto_CompactProto::ALL_REPAIR); } else { return false; } } } } } else { return false; } } } else if (cmd == "master") { using eos::console::NsProto_MasterProto; NsProto_MasterProto* master = ns->mutable_master(); if (!(option = tokenizer.GetToken())) { master->set_op(NsProto_MasterProto::LOG); } else { soption = option; if (soption == "--log") { master->set_op(NsProto_MasterProto::LOG); } else if (soption == "--log-clear") { master->set_op(NsProto_MasterProto::LOG_CLEAR); } else if (soption == "--enable") { master->set_op(NsProto_MasterProto::ENABLE); } else if (soption == "--disable") { master->set_op(NsProto_MasterProto::DISABLE); } else { master->set_host(soption); } } } else if (cmd == "recompute_tree_size") { using eos::console::NsProto_TreeSizeProto; NsProto_TreeSizeProto* tree = ns->mutable_tree(); if (!(option = tokenizer.GetToken())) { return false; } else { while (true) { int pos = 0; soption = option; if (soption == "--depth") { if (!(option = tokenizer.GetToken())) { return false; } soption = option; try { tree->set_depth(std::stoul(soption)); } catch (const std::exception& e) { return false; } } else if ((soption.find("cid:") == 0)) { pos = soption.find(':') + 1; tree->mutable_container()->set_cid(soption.substr(pos)); } else if (soption.find("cxid:") == 0) { pos = soption.find(':') + 1; tree->mutable_container()->set_cxid(soption.substr(pos)); } else { // this should be a plain path tree->mutable_container()->set_path(soption); } if (!(option = tokenizer.GetToken())) { break; } } } } else if (cmd == "recompute_quotanode") { using eos::console::NsProto_QuotaSizeProto; NsProto_QuotaSizeProto* quota = ns->mutable_quota(); if (!(option = tokenizer.GetToken())) { return false; } else { while (true) { int pos = 0; soption = option; if ((soption.find("cid:") == 0)) { pos = soption.find(':') + 1; quota->mutable_container()->set_cid(soption.substr(pos)); } else if (soption.find("cxid:") == 0) { pos = soption.find(':') + 1; quota->mutable_container()->set_cxid(soption.substr(pos)); } else { // this should be a plain path quota->mutable_container()->set_path(soption); } if (!(option = tokenizer.GetToken())) { break; } } } } else if (cmd == "update_quotanode") { using eos::console::NsProto_QuotaSizeProto; NsProto_QuotaSizeProto* quota = ns->mutable_quota(); if (!(option = tokenizer.GetToken())) { return false; } else { int npar = 0; while (true) { int pos = 0; soption = option; if ((soption.find("cid:") == 0)) { pos = soption.find(':') + 1; quota->mutable_container()->set_cid(soption.substr(pos)); } else if (soption.find("cxid:") == 0) { pos = soption.find(':') + 1; quota->mutable_container()->set_cxid(soption.substr(pos)); } else if (soption.find("uid:") == 0) { pos = soption.find(':') + 1; quota->set_uid(soption.substr(pos)); } else if (soption.find("gid:") == 0) { pos = soption.find(':') + 1; quota->set_gid(soption.substr(pos)); } else if (soption.find("bytes:") == 0) { pos = soption.find(':') + 1; quota->set_used_bytes(strtoul(soption.substr(pos).c_str(),0,10)); npar++; } else if (soption.find("physicalbytes:") == 0) { pos = soption.find(':') + 1; quota->set_physical_bytes(strtoul(soption.substr(pos).c_str(),0,10)); npar++; } else if (soption.find("inodes:") == 0) { pos = soption.find(':') + 1; quota->set_used_inodes(strtoul(soption.substr(pos).c_str(),0,10)); npar++; } else { // this should be a plain path quota->mutable_container()->set_path(soption); } if (!(option = tokenizer.GetToken())) { break; } } if (npar && (npar != 3)) { return false; } } } else if (cmd == "cache") { eos::console::NsProto_CacheProto* cache = ns->mutable_cache(); if (!(option = tokenizer.GetToken())) { return false; } soption = option; if (soption == "set") { if (!(option = tokenizer.GetToken())) { return false; } soption = option; if (soption == "-f") { cache->set_op(eos::console::NsProto_CacheProto::SET_FILE); } else if (soption == "-d") { cache->set_op(eos::console::NsProto_CacheProto::SET_DIR); } else { return false; } if (!(option = tokenizer.GetToken())) { return false; } uint64_t max_num = 0ull, max_size = 0ull; try { max_num = std::stoull(option); } catch (const std::exception& e) { return false; } if ((option = tokenizer.GetToken())) { try { max_size = eos::common::StringConversion::GetDataSizeFromString(option); } catch (const std::exception& e) { return false; } } cache->set_max_num(max_num); cache->set_max_size(max_size); } else if (soption == "drop") { if (!(option = tokenizer.GetToken())) { cache->set_op(eos::console::NsProto_CacheProto::DROP_ALL); } else { soption = option; if (soption == "-f") { cache->set_op(eos::console::NsProto_CacheProto::DROP_FILE); } else if (soption == "-d") { cache->set_op(eos::console::NsProto_CacheProto::DROP_DIR); } else { return false; } } } else if (soption == "drop-single-file") { if (!(option = tokenizer.GetToken())) { return false; } uint64_t target; try { target = std::stoull(option); } catch (const std::exception& e) { return false; } cache->set_op(eos::console::NsProto_CacheProto::DROP_SINGLE_FILE); cache->set_single_to_drop(target); } else if (soption == "drop-single-container") { if (!(option = tokenizer.GetToken())) { return false; } uint64_t target; try { target = std::stoull(option); } catch (const std::exception& e) { return false; } cache->set_op(eos::console::NsProto_CacheProto::DROP_SINGLE_CONTAINER); cache->set_single_to_drop(target); } else { return false; } } else if (cmd == "max_drain_threads") { using eos::console::NsProto_DrainSizeProto; NsProto_DrainSizeProto* drain_sz = ns->mutable_drain(); if (!(option = tokenizer.GetToken())) { return false; } else { soption = option; uint64_t max_num_threads {0ull}; try { max_num_threads = std::stoull(soption); if (max_num_threads < 4) { max_num_threads = 4; } } catch (const std::exception& e) { return false; } drain_sz->set_max_num(max_num_threads); } } else if (cmd == "reserve-ids") { using eos::console::NsProto_ReserveIdsProto; NsProto_ReserveIdsProto* reserve = ns->mutable_reserve(); if (!(option = tokenizer.GetToken())) { return false; } int64_t fileID = 0; if (!eos::common::ParseInt64(option, fileID) || fileID < 0) { return false; } // --- if (!(option = tokenizer.GetToken())) { return false; } int64_t containerID = 0; if (!eos::common::ParseInt64(option, containerID) || containerID < 0) { return false; } reserve->set_fileid(fileID); reserve->set_containerid(containerID); } else if (cmd == "benchmark") { using eos::console::NsProto_BenchmarkProto; NsProto_BenchmarkProto* benchmark = ns->mutable_benchmark(); if (!(option = tokenizer.GetToken())) { return false; } int64_t n_threads = 0; int64_t n_subdirs = 0; int64_t n_subfiles = 0; if (!eos::common::ParseInt64(option, n_threads) || n_threads < 0) { return false; } // --- if (!(option = tokenizer.GetToken())) { return false; } if (!eos::common::ParseInt64(option, n_subdirs) || n_subdirs < 0) { return false; } // --- if (!(option = tokenizer.GetToken())) { return false; } if (!eos::common::ParseInt64(option, n_subfiles) || n_subfiles < 0) { return false; } if ( (option = tokenizer.GetToken()) ) { benchmark->set_prefix(option); } benchmark->set_threads(n_threads); benchmark->set_subdirs(n_subdirs); benchmark->set_subfiles(n_subfiles); } else if (cmd == "") { eos::console::NsProto_StatProto* stat = ns->mutable_stat(); stat->set_summary(true); } else { return false; } return true; } //------------------------------------------------------------------------------ // Ns command entrypoint //------------------------------------------------------------------------------ int com_ns(char* arg) { if (wants_help(arg)) { com_ns_help(); global_retc = EINVAL; return EINVAL; } NsHelper ns(gGlobalOpts); if (!ns.ParseCommand(arg)) { com_ns_help(); global_retc = EINVAL; return EINVAL; } global_retc = ns.Execute(); return global_retc; } //------------------------------------------------------------------------------ // Print help message //------------------------------------------------------------------------------ void com_ns_help() { std::ostringstream oss; oss << "Usage: ns [stat|mutex|compact|master|cache|benchmark]" << std::endl << " print or configure basic namespace parameters" << std::endl << " ns stat [-a] [-m] [-n] [--reset]" << std::endl << " print namespace statistics" << std::endl << " -a : break down by uid/gid" << std::endl << " -m : display in monitoring format =" << std::endl << " -n : display numerical uid/gid(s)" << std::endl << " --reset : reset namespace counters" << std::endl << std::endl << " ns mutex [