This is an automated email from the ASF dual-hosted git repository. mzhu pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 8d372e14b0240aa5735a7c0cf36e03e7b3344bd1 Author: Meng Zhu <[email protected]> AuthorDate: Tue May 28 16:27:16 2019 +0200 Added methods to subtract `ResourceQuantities` from `ResourceLimits`. This patch also makes `ResourceLimits` a friend class of `ResourceQuantities` to achieve one-pass operation complexities. Also added unit test. Review: https://reviews.apache.org/r/70735 --- src/common/resource_quantities.cpp | 44 +++++++++++++++++++++++++++++++++ src/common/resource_quantities.hpp | 8 ++++++ src/tests/resource_quantities_tests.cpp | 34 +++++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/src/common/resource_quantities.cpp b/src/common/resource_quantities.cpp index 40c7ef1..f79b678 100644 --- a/src/common/resource_quantities.cpp +++ b/src/common/resource_quantities.cpp @@ -517,6 +517,7 @@ bool ResourceLimits::operator!=(const ResourceLimits& that) const } +// TODO(mzhu): Given the friendship, optimize this to be one pass. bool ResourceLimits::contains(const ResourceQuantities& quantities) const { foreachpair (const string& name, const Value::Scalar& quantity, quantities) { @@ -531,6 +532,49 @@ bool ResourceLimits::contains(const ResourceQuantities& quantities) const } +ResourceLimits& ResourceLimits::operator-=(const ResourceQuantities& quantities) +{ + size_t limitsIndex = 0u; + size_t quantitiesIndex = 0u; + + // Since both limits and quantities are sorted in alphabetical order, we can + // walk them at the same time. + while (limitsIndex < size() && quantitiesIndex < quantities.size()) { + pair<string, Value::Scalar>& limit = limits.at(limitsIndex); + const pair<string, Value::Scalar>& quantity = + quantities.quantities.at(quantitiesIndex); + + if (limit.first < quantity.first) { + // Item exists in limits but not in quantities i.e. + // finite limit minus zero quantity. + ++limitsIndex; + } else if (limit.first > quantity.first) { + // Item exists in quantities but not in limits i.e. + // infinite limit minus finite quantity. + ++quantitiesIndex; + } else { + // Item exists in both limits and quantities i.e. + // finite limits minus finite quantity. + limit.second = std::max(limit.second - quantity.second, + Value::Scalar()); + ++limitsIndex; + ++quantitiesIndex; + } + } + + return *this; +} + + +ResourceLimits ResourceLimits::operator-( + const ResourceQuantities& quantities) const +{ + ResourceLimits result = *this; + result -= quantities; + return result; +} + + void ResourceLimits::set( const std::string& name, const Value::Scalar& scalar) { diff --git a/src/common/resource_quantities.hpp b/src/common/resource_quantities.hpp index 718ce14..538256b 100644 --- a/src/common/resource_quantities.hpp +++ b/src/common/resource_quantities.hpp @@ -29,6 +29,9 @@ namespace mesos { namespace internal { +// Forward declaration. +class ResourceLimits; + // An efficient collection of resource quantities. All values are guaranteed // to be positive and finite. @@ -144,6 +147,8 @@ public: ResourceQuantities operator-(const ResourceQuantities& quantities) const; private: + friend class ResourceLimits; + void add(const std::string& name, const Value::Scalar& scalar); void add(const std::string& name, double value); @@ -238,6 +243,9 @@ public: bool contains(const ResourceQuantities& quantities) const; + ResourceLimits& operator-=(const ResourceQuantities& quantities); + ResourceLimits operator-(const ResourceQuantities& quantities) const; + private: // Set the limit of the resource with `name` to `scalar`. // Note, the existing limit of the resource will be overwritten. diff --git a/src/tests/resource_quantities_tests.cpp b/src/tests/resource_quantities_tests.cpp index ebe53be..f018c8a 100644 --- a/src/tests/resource_quantities_tests.cpp +++ b/src/tests/resource_quantities_tests.cpp @@ -542,6 +542,40 @@ TEST(LimitsTest, ContainsQuantities) } +TEST(LimitsTest, SubtractQuantities) +{ + auto limits = [](const string& resourceLimitsString) { + return CHECK_NOTERROR(ResourceLimits::fromString(resourceLimitsString)); + }; + + auto subtract = [](const string& resourceLimitsString, + const string& resourceQuantitiesString) { + ResourceLimits limits = + CHECK_NOTERROR(ResourceLimits::fromString(resourceLimitsString)); + ResourceQuantities quantities = + CHECK_NOTERROR(ResourceQuantities::fromString(resourceQuantitiesString)); + + return limits - quantities; + }; + + EXPECT_EQ(limits(""), subtract("", "")); + EXPECT_EQ(limits(""), subtract("", "cpus:10")); + + EXPECT_EQ(limits("cpus:1"), subtract("cpus:1", "")); + + EXPECT_EQ(limits("cpus:0"), subtract("cpus:1", "cpus:1")); + EXPECT_EQ(limits("cpus:0"), subtract("cpus:1", "cpus:2")); + + EXPECT_EQ(limits("cpus:0;mem:10"), subtract("cpus:1;mem:10", "cpus:1")); + EXPECT_EQ( + limits("cpus:0;mem:10"), subtract("cpus:1;mem:10", "cpus:1;disk:10")); + + EXPECT_EQ( + limits("cpus:0;mem:5"), + subtract("cpus:1;mem:10", "cpus:1;mem:5;disk:10")); +} + + } // namespace tests { } // namespace internal { } // namespace mesos {
