mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-19 12:52:37 +00:00
Merge pull request #66587 from ClickHouse/backport/24.6/66237
Backport #66237 to 24.6: Fix detection of number of CPUs in containers
This commit is contained in:
commit
293a9a0c6c
@ -3,8 +3,9 @@
|
|||||||
#include <base/defines.h>
|
#include <base/defines.h>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <string>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
bool cgroupsV2Enabled()
|
bool cgroupsV2Enabled()
|
||||||
{
|
{
|
||||||
@ -13,11 +14,11 @@ bool cgroupsV2Enabled()
|
|||||||
{
|
{
|
||||||
/// This file exists iff the host has cgroups v2 enabled.
|
/// This file exists iff the host has cgroups v2 enabled.
|
||||||
auto controllers_file = default_cgroups_mount / "cgroup.controllers";
|
auto controllers_file = default_cgroups_mount / "cgroup.controllers";
|
||||||
if (!std::filesystem::exists(controllers_file))
|
if (!fs::exists(controllers_file))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (const std::filesystem::filesystem_error &) /// all "underlying OS API errors", typically: permission denied
|
catch (const fs::filesystem_error &) /// all "underlying OS API errors", typically: permission denied
|
||||||
{
|
{
|
||||||
return false; /// not logging the exception as most callers fall back to cgroups v1
|
return false; /// not logging the exception as most callers fall back to cgroups v1
|
||||||
}
|
}
|
||||||
@ -33,8 +34,9 @@ bool cgroupsV2MemoryControllerEnabled()
|
|||||||
/// According to https://docs.kernel.org/admin-guide/cgroup-v2.html, file "cgroup.controllers" defines which controllers are available
|
/// According to https://docs.kernel.org/admin-guide/cgroup-v2.html, file "cgroup.controllers" defines which controllers are available
|
||||||
/// for the current + child cgroups. The set of available controllers can be restricted from level to level using file
|
/// for the current + child cgroups. The set of available controllers can be restricted from level to level using file
|
||||||
/// "cgroups.subtree_control". It is therefore sufficient to check the bottom-most nested "cgroup.controllers" file.
|
/// "cgroups.subtree_control". It is therefore sufficient to check the bottom-most nested "cgroup.controllers" file.
|
||||||
std::string cgroup = cgroupV2OfProcess();
|
fs::path cgroup_dir = cgroupV2PathOfProcess();
|
||||||
auto cgroup_dir = cgroup.empty() ? default_cgroups_mount : (default_cgroups_mount / cgroup);
|
if (cgroup_dir.empty())
|
||||||
|
return false;
|
||||||
std::ifstream controllers_file(cgroup_dir / "cgroup.controllers");
|
std::ifstream controllers_file(cgroup_dir / "cgroup.controllers");
|
||||||
if (!controllers_file.is_open())
|
if (!controllers_file.is_open())
|
||||||
return false;
|
return false;
|
||||||
@ -46,7 +48,7 @@ bool cgroupsV2MemoryControllerEnabled()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string cgroupV2OfProcess()
|
fs::path cgroupV2PathOfProcess()
|
||||||
{
|
{
|
||||||
#if defined(OS_LINUX)
|
#if defined(OS_LINUX)
|
||||||
chassert(cgroupsV2Enabled());
|
chassert(cgroupsV2Enabled());
|
||||||
@ -54,17 +56,18 @@ std::string cgroupV2OfProcess()
|
|||||||
/// A simpler way to get the membership is:
|
/// A simpler way to get the membership is:
|
||||||
std::ifstream cgroup_name_file("/proc/self/cgroup");
|
std::ifstream cgroup_name_file("/proc/self/cgroup");
|
||||||
if (!cgroup_name_file.is_open())
|
if (!cgroup_name_file.is_open())
|
||||||
return "";
|
return {};
|
||||||
/// With cgroups v2, there will be a *single* line with prefix "0::/"
|
/// With cgroups v2, there will be a *single* line with prefix "0::/"
|
||||||
/// (see https://docs.kernel.org/admin-guide/cgroup-v2.html)
|
/// (see https://docs.kernel.org/admin-guide/cgroup-v2.html)
|
||||||
std::string cgroup;
|
std::string cgroup;
|
||||||
std::getline(cgroup_name_file, cgroup);
|
std::getline(cgroup_name_file, cgroup);
|
||||||
static const std::string v2_prefix = "0::/";
|
static const std::string v2_prefix = "0::/";
|
||||||
if (!cgroup.starts_with(v2_prefix))
|
if (!cgroup.starts_with(v2_prefix))
|
||||||
return "";
|
return {};
|
||||||
cgroup = cgroup.substr(v2_prefix.length());
|
cgroup = cgroup.substr(v2_prefix.length());
|
||||||
return cgroup;
|
/// Note: The 'root' cgroup can have an empty cgroup name, this is valid
|
||||||
|
return default_cgroups_mount / cgroup;
|
||||||
#else
|
#else
|
||||||
return "";
|
return {};
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#if defined(OS_LINUX)
|
#if defined(OS_LINUX)
|
||||||
/// I think it is possible to mount the cgroups hierarchy somewhere else (e.g. when in containers).
|
/// I think it is possible to mount the cgroups hierarchy somewhere else (e.g. when in containers).
|
||||||
@ -16,7 +15,7 @@ bool cgroupsV2Enabled();
|
|||||||
/// Assumes that cgroupsV2Enabled() is enabled.
|
/// Assumes that cgroupsV2Enabled() is enabled.
|
||||||
bool cgroupsV2MemoryControllerEnabled();
|
bool cgroupsV2MemoryControllerEnabled();
|
||||||
|
|
||||||
/// Which cgroup does the process belong to?
|
/// Detects which cgroup v2 the process belongs to and returns the filesystem path to the cgroup.
|
||||||
/// Returns an empty string if the cgroup cannot be determined.
|
/// Returns an empty path the cgroup cannot be determined.
|
||||||
/// Assumes that cgroupsV2Enabled() is enabled.
|
/// Assumes that cgroupsV2Enabled() is enabled.
|
||||||
std::string cgroupV2OfProcess();
|
std::filesystem::path cgroupV2PathOfProcess();
|
||||||
|
@ -23,8 +23,9 @@ std::optional<uint64_t> getCgroupsV2MemoryLimit()
|
|||||||
if (!cgroupsV2MemoryControllerEnabled())
|
if (!cgroupsV2MemoryControllerEnabled())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
std::string cgroup = cgroupV2OfProcess();
|
std::filesystem::path current_cgroup = cgroupV2PathOfProcess();
|
||||||
auto current_cgroup = cgroup.empty() ? default_cgroups_mount : (default_cgroups_mount / cgroup);
|
if (current_cgroup.empty())
|
||||||
|
return {};
|
||||||
|
|
||||||
/// Open the bottom-most nested memory limit setting file. If there is no such file at the current
|
/// Open the bottom-most nested memory limit setting file. If there is no such file at the current
|
||||||
/// level, try again at the parent level as memory settings are inherited.
|
/// level, try again at the parent level as memory settings are inherited.
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
#define STRINGIFY(x) STRINGIFY_HELPER(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
@ -125,15 +126,16 @@ std::optional<std::string> getCgroupsV2FileName()
|
|||||||
if (!cgroupsV2MemoryControllerEnabled())
|
if (!cgroupsV2MemoryControllerEnabled())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
String cgroup = cgroupV2OfProcess();
|
fs::path current_cgroup = cgroupV2PathOfProcess();
|
||||||
auto current_cgroup = cgroup.empty() ? default_cgroups_mount : (default_cgroups_mount / cgroup);
|
if (current_cgroup.empty())
|
||||||
|
return {};
|
||||||
|
|
||||||
/// Return the bottom-most nested current memory file. If there is no such file at the current
|
/// Return the bottom-most nested current memory file. If there is no such file at the current
|
||||||
/// level, try again at the parent level as memory settings are inherited.
|
/// level, try again at the parent level as memory settings are inherited.
|
||||||
while (current_cgroup != default_cgroups_mount.parent_path())
|
while (current_cgroup != default_cgroups_mount.parent_path())
|
||||||
{
|
{
|
||||||
auto path = current_cgroup / "memory.current";
|
auto path = current_cgroup / "memory.current";
|
||||||
if (std::filesystem::exists(path))
|
if (fs::exists(path))
|
||||||
return {path};
|
return {path};
|
||||||
current_cgroup = current_cgroup.parent_path();
|
current_cgroup = current_cgroup.parent_path();
|
||||||
}
|
}
|
||||||
@ -143,7 +145,7 @@ std::optional<std::string> getCgroupsV2FileName()
|
|||||||
std::optional<std::string> getCgroupsV1FileName()
|
std::optional<std::string> getCgroupsV1FileName()
|
||||||
{
|
{
|
||||||
auto path = default_cgroups_mount / "memory/memory.stat";
|
auto path = default_cgroups_mount / "memory/memory.stat";
|
||||||
if (!std::filesystem::exists(path))
|
if (!fs::exists(path))
|
||||||
return {};
|
return {};
|
||||||
return {path};
|
return {path};
|
||||||
}
|
}
|
||||||
|
@ -37,12 +37,12 @@ uint32_t getCGroupLimitedCPUCores(unsigned default_cpu_count)
|
|||||||
/// cgroupsv2
|
/// cgroupsv2
|
||||||
if (cgroupsV2Enabled())
|
if (cgroupsV2Enabled())
|
||||||
{
|
{
|
||||||
/// First, we identify the cgroup the process belongs
|
/// First, we identify the path of the cgroup the process belongs
|
||||||
std::string cgroup = cgroupV2OfProcess();
|
std::filesystem::path cgroup_path = cgroupV2PathOfProcess();
|
||||||
if (cgroup.empty())
|
if (cgroup_path.empty())
|
||||||
return default_cpu_count;
|
return default_cpu_count;
|
||||||
|
|
||||||
auto current_cgroup = cgroup.empty() ? default_cgroups_mount : (default_cgroups_mount / cgroup);
|
auto current_cgroup = cgroup_path;
|
||||||
|
|
||||||
// Looking for cpu.max in directories from the current cgroup to the top level
|
// Looking for cpu.max in directories from the current cgroup to the top level
|
||||||
// It does not stop on the first time since the child could have a greater value than parent
|
// It does not stop on the first time since the child could have a greater value than parent
|
||||||
@ -62,7 +62,7 @@ uint32_t getCGroupLimitedCPUCores(unsigned default_cpu_count)
|
|||||||
}
|
}
|
||||||
current_cgroup = current_cgroup.parent_path();
|
current_cgroup = current_cgroup.parent_path();
|
||||||
}
|
}
|
||||||
current_cgroup = default_cgroups_mount / cgroup;
|
current_cgroup = cgroup_path;
|
||||||
// Looking for cpuset.cpus.effective in directories from the current cgroup to the top level
|
// Looking for cpuset.cpus.effective in directories from the current cgroup to the top level
|
||||||
while (current_cgroup != default_cgroups_mount.parent_path())
|
while (current_cgroup != default_cgroups_mount.parent_path())
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user