This is an automated email from the ASF dual-hosted git repository.
bmahler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git
The following commit(s) were added to refs/heads/master by this push:
new aed4041fd [cgroups2] Introduced an interface to set a hard memory
limit.
aed4041fd is described below
commit aed4041fda2d605f1714f8a49ef34608356bab55
Author: Devin Leamy <[email protected]>
AuthorDate: Mon Apr 15 15:53:51 2024 -0400
[cgroups2] Introduced an interface to set a hard memory limit.
The "memory.max" control contains the hard memory limit that a cgroup
and its descendants must remain below.
We introduce `cgroups2::memory::set_max` and `cgroups2::memory::max`
to set and get this limit.
This closes #557
---
src/linux/cgroups2.cpp | 44 ++++++++++++++++++++++++++++++
src/linux/cgroups2.hpp | 14 ++++++++++
src/tests/containerizer/cgroups2_tests.cpp | 21 ++++++++++++++
3 files changed, 79 insertions(+)
diff --git a/src/linux/cgroups2.cpp b/src/linux/cgroups2.cpp
index e70e80780..f9912564b 100644
--- a/src/linux/cgroups2.cpp
+++ b/src/linux/cgroups2.cpp
@@ -769,9 +769,33 @@ Try<cpu::BandwidthLimit> max(const string& cgroup)
namespace memory {
+namespace internal {
+
+// Parse a byte limit from a string.
+//
+// Format: "max" OR a u64_t string representing bytes.
+Result<Bytes> parse_bytelimit(const string& value)
+{
+ const string trimmed = strings::trim(value);
+ if (trimmed == "max") {
+ return None();
+ }
+
+ Try<uint64_t> bytes = numify<uint64_t>(trimmed);
+ if (bytes.isError()) {
+ return Error("Failed to numify '" + trimmed + "': " + bytes.error());
+ }
+
+ return Bytes(*bytes);
+}
+
+} // namespace internal {
+
+
namespace control {
const string CURRENT = "memory.current";
+const string MAX = "memory.max";
const string MIN = "memory.min";
} // namespace control {
@@ -804,6 +828,26 @@ Try<Bytes> min(const string& cgroup)
return Bytes(*contents);
}
+
+Try<Nothing> set_max(const string& cgroup, const Option<Bytes>& limit)
+{
+ return cgroups2::write(
+ cgroup,
+ control::MAX,
+ limit.isNone() ? "max" : stringify(limit->bytes()));
+}
+
+
+Result<Bytes> max(const string& cgroup)
+{
+ Try<string> contents = cgroups2::read<string>(cgroup, control::MAX);
+ if (contents.isError()) {
+ return Error("Failed to read 'memory.max': " + contents.error());
+ }
+
+ return internal::parse_bytelimit(*contents);
+}
+
} // namespace memory {
namespace devices {
diff --git a/src/linux/cgroups2.hpp b/src/linux/cgroups2.hpp
index efd37dc11..e87ea0113 100644
--- a/src/linux/cgroups2.hpp
+++ b/src/linux/cgroups2.hpp
@@ -261,6 +261,20 @@ Try<Nothing> set_min(const std::string& cgroup, const
Bytes& bytes);
// Cannot be used for the root cgroup.
Try<Bytes> min(const std::string& cgroup);
+
+// Set the maximum memory that can be used by a cgroup and its descendants.
+// If the limit is reached and memory cannot be reclaimed, then the OOM
+// killer will be invoked on the container.
+// If limit is None, then there is no maximum memory limit.
+// Cannot be used for the root cgroup.
+Try<Nothing> set_max(const std::string& cgroup, const Option<Bytes>& limit);
+
+
+// Get the maximum memory that can be used by a cgroup and its descendants.
+// If the returned limit is None, then there is no maximum memory limit.
+// Cannot be used for the root cgroup.
+Result<Bytes> max(const std::string& cgroup);
+
} // namespace memory {
namespace devices {
diff --git a/src/tests/containerizer/cgroups2_tests.cpp
b/src/tests/containerizer/cgroups2_tests.cpp
index 6da6f7d1c..221f612a8 100644
--- a/src/tests/containerizer/cgroups2_tests.cpp
+++ b/src/tests/containerizer/cgroups2_tests.cpp
@@ -344,6 +344,27 @@ TEST_F(Cgroups2Test, ROOT_CGROUPS2_MemoryMinimum)
}
+TEST_F(Cgroups2Test, ROOT_CGROUPS2_MemoryMaximum)
+{
+ ASSERT_SOME(enable_controllers({"memory"}));
+
+ ASSERT_SOME(cgroups2::create(TEST_CGROUP));
+ ASSERT_SOME(cgroups2::controllers::enable(TEST_CGROUP, {"memory"}));
+
+ Bytes limit = Bytes(os::pagesize()) * 5;
+
+ // Does not exist for the root cgroup.
+ EXPECT_ERROR(cgroups2::memory::max(cgroups2::ROOT_CGROUP));
+ EXPECT_ERROR(cgroups2::memory::set_max(cgroups2::ROOT_CGROUP, limit));
+
+ EXPECT_SOME(cgroups2::memory::set_max(TEST_CGROUP, limit));
+ EXPECT_SOME_EQ(limit, cgroups2::memory::max(TEST_CGROUP));
+
+ EXPECT_SOME(cgroups2::memory::set_max(TEST_CGROUP, None()));
+ EXPECT_NONE(cgroups2::memory::max(TEST_CGROUP));
+}
+
+
// Check that byte amounts written to the memory controller are rounded
// down to the nearest page size.
TEST_F(Cgroups2Test, ROOT_CGROUPS2_MemoryBytesRounding)