From f23ceff814085d6e4a62bb51848162c4bc2f7482 Mon Sep 17 00:00:00 2001 From: Kannan Dorairaj Date: Wed, 14 Aug 2019 10:45:26 +0530 Subject: [PATCH] Resolves issue #146: Registered new command for hostInfo --- src/ExtCmd.actor.cpp | 24 ++ src/error_definitions.h | 1 + thirdparty/bson-cpp/CMakeLists.txt | 2 + thirdparty/bson-cpp/bson.h | 3 +- thirdparty/bson-cpp/system_info.cpp | 545 ++++++++++++++++++++++++++++ thirdparty/bson-cpp/system_info.h | 97 +++++ 6 files changed, 671 insertions(+), 1 deletion(-) create mode 100644 thirdparty/bson-cpp/system_info.cpp create mode 100644 thirdparty/bson-cpp/system_info.h diff --git a/src/ExtCmd.actor.cpp b/src/ExtCmd.actor.cpp index ce00844..15705dc 100644 --- a/src/ExtCmd.actor.cpp +++ b/src/ExtCmd.actor.cpp @@ -498,6 +498,30 @@ struct RenameCollectionCmd { }; REGISTER_CMD(RenameCollectionCmd, "renamecollection"); +struct HostInfoCmd { + static const char* name; + static Future> call(Reference ec, + Reference query, + Reference reply) { + bson::HOSTINFO hostInfo; + bson::BSONObj systemInfo = hostInfo.getSystemInfo(); + bson::BSONObj osInfo = hostInfo.getOsInfo(); + bson::BSONObj extraInfo = hostInfo.getExtraInfo(); + try { + if (!systemInfo.isEmpty() || !osInfo.isEmpty() || !extraInfo.isEmpty()) { + reply->addDocument( + BSON("system" << systemInfo << "os" << osInfo << "extra" << extraInfo << "ok" << 1.0)); + } else { + throw unable_to_fetch_the_hostinfo(); + } + } catch (Error& e) { + reply->addDocument(BSON("$err" << e.what() << "code" << e.code() << "ok" << 1.0)); + } + return Future>(reply); + } +}; +REGISTER_CMD(HostInfoCmd, "hostinfo"); + ACTOR static Future> getStreamCount(Reference ec, Reference query, Reference reply) { diff --git a/src/error_definitions.h b/src/error_definitions.h index 30a875b..9ead930 100644 --- a/src/error_definitions.h +++ b/src/error_definitions.h @@ -76,6 +76,7 @@ DOCLAYER_ERROR(multiple_index_construction, 20004, "tried to create multiple ind DOCLAYER_ERROR(unique_index_background_construction, 20005, "tried to create unique indexes in background"); DOCLAYER_ERROR(empty_set_on_insert, 20009, "$setOnInsert is empty"); DOCLAYER_ERROR(cant_modify_id, 20010, "You may not modify '_id' in an update"); +DOCLAYER_ERROR(unable_to_fetch_the_hostinfo, 20011, "Unable to fetch the HostInfo"); DOCLAYER_ERROR(update_operator_empty_parameter, 26840, diff --git a/thirdparty/bson-cpp/CMakeLists.txt b/thirdparty/bson-cpp/CMakeLists.txt index 9ea4414..fd2fdb4 100644 --- a/thirdparty/bson-cpp/CMakeLists.txt +++ b/thirdparty/bson-cpp/CMakeLists.txt @@ -29,6 +29,8 @@ add_library(bsoncpp "util/hex.h" "util/misc.h" "util/optime.h" + "system_info.h" + "system_info.cpp" "util/time_support.h" ) diff --git a/thirdparty/bson-cpp/bson.h b/thirdparty/bson-cpp/bson.h index b276921..72c2d04 100644 --- a/thirdparty/bson-cpp/bson.h +++ b/thirdparty/bson-cpp/bson.h @@ -40,4 +40,5 @@ #include "bsonobjbuilder.h" #include "bsonobjiterator.h" #include "bson-inl.h" -#include "bson_db.h" \ No newline at end of file +#include "bson_db.h" +#include "system_info.h" diff --git a/thirdparty/bson-cpp/system_info.cpp b/thirdparty/bson-cpp/system_info.cpp new file mode 100644 index 0000000..33899c9 --- /dev/null +++ b/thirdparty/bson-cpp/system_info.cpp @@ -0,0 +1,545 @@ +/* + * system_info.cpp + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * MongoDB is a registered trademark of MongoDB, Inc. + */ + +#include +#include "system_info.h" +#include + +#if defined(__linux__) +#include +#include +#include +#include +#include +#include +#include +#elif defined(__APPLE__) +#include +#include +#include +#include +#endif + + +namespace bson { + +#if defined(__linux__) + + // Read the file and returns matching paramater value + std::string HOSTINFO::readFromFile(std::string findParam, std::string delimiter, std::string filePath) { + std::string paramValue; + std::string key; + std::ifstream fin; + fin.open(filePath); + + if(fin.good()) { + while(getline(fin, paramValue)) { + size_t pos = 0; + pos = paramValue.find(delimiter); + if (pos != std::string::npos) { + key = paramValue.substr(0, pos); + if(key.compare(findParam) == 0) { + paramValue.erase(0, pos + delimiter.length()); + break; + } + } + } + } + + fin.close(); + // returns parameter value or empty string + return paramValue; + } + + std::string HOSTINFO::readLineFromFile(const char* fileName) { + FILE* f; + char fstr[1024] = {0}; + + f = fopen(fileName, "r"); + if (f != nullptr) { + if (fgets(fstr, 1023, f) != nullptr) { + // Assign NULL character at end of the string + fstr[strlen(fstr) < 1 ? 0 : strlen(fstr) - 1] = '\0'; + } + fclose(f); + } + return fstr; + } + + int HOSTINFO::getCpuAddressSize() { + std::string cpuAddressSize; + cpuAddressSize = readFromFile("cache_alignment\t", ":", "/proc/cpuinfo"); + if(!cpuAddressSize.empty()) { + return std::stol(cpuAddressSize, nullptr); + } + return -1; + } + + int HOSTINFO::getMemSizeMB() { + std::string memSizeMB; + memSizeMB = readFromFile("MemTotal", ":", "/proc/meminfo"); + if(!memSizeMB.empty()) { + std::string::size_type sz; + long MB = std::stol(memSizeMB, &sz); + MB = MB/1024; + return MB; + } + return -1; + } + + long long HOSTINFO::getMemLimitMB() { + std::string cgmemlimit; + long long memLimit; + long long sysMemBytes = getMemSizeMB(); + if (sysMemBytes != -1) { + cgmemlimit = readLineFromFile("/sys/fs/cgroup/memory/memory.limit_in_bytes"); + if (!cgmemlimit.empty()) { + //Converting Megabytes to Bytes + sysMemBytes = sysMemBytes * 1024 * 1024; + memLimit = std::stoll(cgmemlimit, nullptr); + memLimit = std::min(sysMemBytes, memLimit); + return (memLimit/(1024*1024)); + } + } + return sysMemBytes; + } + + int HOSTINFO::getNumCores() { + return sysconf(_SC_NPROCESSORS_ONLN); + } + + bool HOSTINFO::checkNumaEnabled() { + //std::ifstream fin; + std::string line; + bool hasMultipleNodes = false; + bool hasNumaMaps = false; + hasMultipleNodes = boost::filesystem::exists("/sys/devices/system/node/node1"); + hasNumaMaps = boost::filesystem::exists("/proc/self/numa_maps"); + if (hasMultipleNodes && hasNumaMaps) { + line = readLineFromFile("/proc/self/numa_maps"); + if (!line.empty()) { + size_t pos = line.find(' '); + if (pos != std::string::npos) { + if (line.substr(pos + 1, 10).find("interleave") == std::string::npos) { + return true; + } + } + } + } + return false; + } + + void HOSTINFO::getOsRelease(std::string& osName,std::string& osVersion) { + if(boost::filesystem::exists("/etc/lsb-release")) { + osName = readFromFile("DISTRIB_ID", "=", "/etc/lsb-release"); + osVersion = readFromFile("DISTRIB_RELEASE", "=", "/etc/lsb-release"); + } else if (boost::filesystem::exists("/etc/centos-release")) { + osName = readLineFromFile("/etc/centos-release"); + std::string version = readLineFromFile("/proc/sys/kernel/osrelease"); + if (!version.empty()) { + osVersion = "Kernel " + version; + } + } else { + osName = readFromFile("ID", "=", "/etc/os-release"); + osVersion = readFromFile("VERSION_ID", "=", "/etc/os-release"); + } + } + + std::string HOSTINFO::getVersionString() { + return readLineFromFile("/proc/version"); + } + + std::string HOSTINFO::getVersionSignature() { + return readLineFromFile("/proc/version_signature"); + } + + std::string HOSTINFO::getCpuFrequencyMHZ() { + return readFromFile("cpu MHz\t\t", ":", "/proc/cpuinfo"); + } + + std::string HOSTINFO::getCpuFeatures() { + return readFromFile("flags\t\t", ":", "/proc/cpuinfo"); + } + + std::string HOSTINFO::getLibcVersion() { + return gnu_get_libc_version(); + } + + long long HOSTINFO::getPageSize() { + return sysconf(_SC_PAGESIZE); + } + + int HOSTINFO::getNumPages() { + return sysconf(_SC_PHYS_PAGES); + } + + int HOSTINFO::getMaxOpenFiles() { + return sysconf(_SC_OPEN_MAX); + } + + // Returns bson object of system related information + bson::BSONObj HOSTINFO::getSystemInfo() { + bson::BSONObjBuilder bsystem; + struct utsname buffer; + int value; + int uname_ret = uname(&buffer); + + bsystem.appendDate("currentTime", jsTime()); + + if (uname_ret != -1) { + bsystem.append("hostname", buffer.nodename); + } + + value = getCpuAddressSize(); + if (value != -1) { + bsystem.append("cpuAddrSize", value); + } + + value = getMemSizeMB(); + if (value != -1) { + bsystem.append("memSizeMB", value); + } + + value = static_cast(getMemLimitMB()); + if (value != -1) { + bsystem.append("memLimitMB", value); + } + + value = getNumCores(); + if (value != -1) { + bsystem.append("numCores", value); + } + + if (uname_ret != -1) { + bsystem.append("cpuArch", buffer.machine); + } + + bsystem.append("numaEnabled", checkNumaEnabled()); + return bsystem.obj(); + } + + // Returns bson object of OS related information + bson::BSONObj HOSTINFO::getOsInfo() { + struct utsname buffer; + std::string osName; + std::string osVersion; + int uname_ret = uname(&buffer); + bson::BSONObjBuilder bos; + + getOsRelease(osName, osVersion); + + if (uname_ret != -1) { + bos.append("type", buffer.sysname); + } + + if(!osName.empty()) { + bos.append("name", osName); + } + if(!osVersion.empty()) { + bos.append("version", osVersion); + } + return bos.obj(); + } + + // Returns bson object of generic information + bson::BSONObj HOSTINFO::getExtraInfo() { + struct utsname buffer; + std::string versionSignature = getVersionSignature(); + std::string versionString = getVersionString(); + std::string cpuFrequency = getCpuFrequencyMHZ(); + std::string libcVersion = getLibcVersion(); + std::string cpuFeatures = getCpuFeatures(); + bson::BSONObjBuilder bExtra; + + int uname_ret = uname(&buffer); + int value; + + if(!versionString.empty()) { + bExtra.append("versionString", versionString); + } + + if(!libcVersion.empty()) { + bExtra.append("libcVersion", libcVersion ); + } + + if(!versionSignature.empty()) { + bExtra.append("versionSignature", versionSignature); + } + + if (uname_ret != -1) { + bExtra.append("kernelVersion", buffer.release); + } + + if(!cpuFrequency.empty()) { + boost::algorithm::trim_left(cpuFrequency); + bExtra.append("cpuFrequencyMHz", cpuFrequency ); + } + + if(!cpuFeatures.empty()) { + boost::algorithm::trim_left(cpuFeatures); + bExtra.append("cpuFeatures", cpuFeatures ); + } + + long long pageSize = getPageSize(); + if (pageSize != -1) { + bExtra.append("pageSize", pageSize); + } + + value = getNumPages(); + if (value != -1) { + bExtra.append("numPages", value); + } + + value = getMaxOpenFiles(); + if (value != -1) { + bExtra.append("maxOpenFiles", value); + } + + return bExtra.obj(); + } + +#elif defined(__APPLE__) + // Get a sysctl string value by name + std::string HOSTINFO::getSysctlByName(const char* sysctlName) { + std::string value; + size_t len; + int status; + do { + status = sysctlbyname(sysctlName, nullptr, &len, nullptr, 0); + if (status == -1) + break; + value.resize(len); + status = sysctlbyname(sysctlName, &*value.begin(), &len, nullptr, 0); + } while (status == -1 && errno == ENOMEM); + + if (status == -1) { + // returns empty string + return std::string(); + } + + return value.c_str(); + } + + // Get a sysctl integer value by name + long long HOSTINFO::getSysctlByValue(const char* sysctlName) { + long long value = 0; + size_t len = sizeof(value); + + if (sysctlbyname(sysctlName, &value, &len, nullptr, 0) < 0) { + return -1; + } + + // returns not more than 8 bytes since type is long long. + if (len > 8) { + return -1; + } + + return value; + } + + int HOSTINFO::getCpuAddressSize() { + int cpuAddressSize = getSysctlByValue("hw.cpu64bit_capable"); + + if (cpuAddressSize == -1) { + return -1; + } + + return (cpuAddressSize ? 64 : 32); + } + + int HOSTINFO::getMemSizeMB() { + long long memSize = getSysctlByValue("hw.memsize"); + if (memSize == -1) + return -1; + + memSize = memSize/(1024*1024); + return memSize; + } + + int HOSTINFO::getNumCores() { + return getSysctlByValue("hw.ncpu"); + } + + bool HOSTINFO::checkNumaEnabled() { + return false; + } + + std::string HOSTINFO::getOsRelease() { + return getSysctlByName("kern.osrelease"); + } + + std::string HOSTINFO::getVersionString() { + return getSysctlByName("kern.version"); + } + + int HOSTINFO::getAlwaysFullSync() { + return getSysctlByValue("vfs.generic.always_do_fullfsync"); + } + + int HOSTINFO::getNfsAsync() { + return getSysctlByValue("vfs.generic.nfs.client.allow_async"); + } + + std::string HOSTINFO::getModel() { + return getSysctlByName("hw.model"); + } + + int HOSTINFO::getPhysicalCores() { + return getSysctlByValue("machdep.cpu.core_count"); + } + + int HOSTINFO::getCpuFrequencyMHZ() { + return (getSysctlByValue("hw.cpufrequency") / (1000 * 1000)); + } + + std::string HOSTINFO::getCpuString() { + return getSysctlByName("machdep.cpu.brand_string"); + } + + std::string HOSTINFO::getCpuFeatures() { + std::string cpuFeatures = getSysctlByName("machdep.cpu.features") + std::string(" ") + getSysctlByName("machdep.cpu.extfeatures"); + return cpuFeatures; + } + + int HOSTINFO::getPageSize() { + return getSysctlByValue("hw.pagesize"); + } + + std::string HOSTINFO::getScheduler() { + return getSysctlByName("kern.sched"); + } + + // Returns bson object of system related information + bson::BSONObj HOSTINFO::getSystemInfo() { + bson::BSONObjBuilder bsystem; + struct utsname buffer; + int value; + int uname_ret = uname(&buffer); + + bsystem.appendDate("currentTime", jsTime()); + + if (uname_ret != -1) { + bsystem.append("hostname", buffer.nodename); + } + + value = getCpuAddressSize(); + if (value != -1) { + bsystem.append("cpuAddrSize", value); + } + + value = getMemSizeMB(); + if (value != -1) { + bsystem.append("memSizeMB", value); + bsystem.append("memLimitMB", value); + } + + value = getNumCores(); + if (value != -1) { + bsystem.append("numCores", value); + } + + if (uname_ret != -1) { + bsystem.append("cpuArch", buffer.machine); + } + + bsystem.append("numaEnabled", checkNumaEnabled()); + + return bsystem.obj(); + } + + // Returns bson object of OS related information + bson::BSONObj HOSTINFO::getOsInfo() { + bson::BSONObjBuilder bos; + std::string osVersion; + + osVersion = getOsRelease(); + + bos.append("type", "Darwin"); + bos.append("name", "Mac OS X"); + + if(!osVersion.empty()) { + bos.append("version", osVersion); + } + + return bos.obj(); + } + + // Returns bson object of generic information + bson::BSONObj HOSTINFO::getExtraInfo() { + bson::BSONObjBuilder bExtra; + std::string versionString = getVersionString(); + std::string model = getModel(); + std::string cpuString = getCpuString(); + std::string cpuFeatures = getCpuFeatures(); + std::string scheduler = getScheduler(); + + int value; + + if(!versionString.empty()) { + bExtra.append("versionString", versionString); + } + + value = getAlwaysFullSync(); + if (value != -1) { + bExtra.append("alwaysFullSync", value); + } + + value = getNfsAsync(); + if (value != -1) { + bExtra.append("nfsAsync", value); + } + + if(!model.empty()) { + bExtra.append("model", model); + } + + value = getPhysicalCores(); + if (value != -1) { + bExtra.append("physicalCores", value); + } + + value = getCpuFrequencyMHZ(); + if (value != -1) { + bExtra.append("cpuFrequencyMHz", value); + } + + if(!cpuString.empty()) { + bExtra.append("cpuString",cpuString); + } + + if(!cpuFeatures.empty()) { + bExtra.append("cpuFeatures",cpuFeatures ); + } + + value = getPageSize(); + if (value != -1) { + bExtra.append("pageSize", value); + } + + if(!scheduler.empty()) { + bExtra.append("scheduler", scheduler ); + } + + return bExtra.obj(); + } +#endif +} diff --git a/thirdparty/bson-cpp/system_info.h b/thirdparty/bson-cpp/system_info.h new file mode 100644 index 0000000..ed2c09b --- /dev/null +++ b/thirdparty/bson-cpp/system_info.h @@ -0,0 +1,97 @@ +/* + * system_info.h + * + * This source file is part of the FoundationDB open source project + * + * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "bson.h" + +namespace bson { + class HOSTINFO { + public: + HOSTINFO() {} + ~HOSTINFO() {} + + // returns bson object with physical system information + bson::BSONObj getSystemInfo(); + + // returns bson object with Operating System information + bson::BSONObj getOsInfo(); + + // returns bson object with CPU,kernel related information + bson::BSONObj getExtraInfo(); + private: + // returns 64 or 32 bit machine + int getCpuAddressSize(); + // returns total memory of machine + int getMemSizeMB(); + // returns total number of CPU cores in this machine + int getNumCores(); + // returns system supports NUMA or not + bool checkNumaEnabled(); + // returns kernel version + std::string getVersionString(); + // returns supported features of this CPU + std::string getCpuFeatures(); +#if defined(__linux__) + // returns matching string value from given path + std::string readFromFile(std::string findName, std::string delimiter, std::string filePath); + // returns a line from a file + std::string readLineFromFile(const char* fileName); + // returns OS name and version + void getOsRelease(std::string& osName,std::string& osVersion); + // returns linux kernel version and upstream version + std::string getVersionSignature(); + // returns dynamic cpu frequency + std::string getCpuFrequencyMHZ(); + // returns version of glibc + std::string getLibcVersion(); + // returns number of pages of physical memory + int getNumPages(); + // returns maximum number of files a process can open + int getMaxOpenFiles(); + // returns size of a page in bytes + long long getPageSize(); + // returns cgroup memory limit + long long getMemLimitMB(); +#elif defined(__APPLE__) + // returns kernel information of Mac OS in string format + std::string getSysctlByName(const char* sysctlName); + // returns kernel information of Mac OS in long long format + long long getSysctlByValue(const char* sysctlName); + // returns OS version + std::string getOsRelease(); + // returns VFS related information + int getAlwaysFullSync(); + int getNfsAsync(); + // returns Mac Model number + std::string getModel(); + // returns physical core count + int getPhysicalCores(); + // returns dynamic cpu frequency + int getCpuFrequencyMHZ(); + // returns CPU information + std::string getCpuString(); + // returns size of a page in bytes + int getPageSize(); + // returns OS scheduler information + std::string getScheduler(); +#endif + }; +}