You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by mz...@apache.org on 2019/01/10 00:54:10 UTC
[mesos] 03/04: Added a `Resources` method
`contains(ResourceQuantities)`.
This is an automated email from the ASF dual-hosted git repository.
mzhu pushed a commit to branch 1.4.x
in repository https://gitbox.apache.org/repos/asf/mesos.git
commit caadacccf066f21f79c556b33fde2a10b82ca3f5
Author: Meng Zhu <mz...@mesosphere.io>
AuthorDate: Wed Dec 19 14:49:11 2018 -0800
Added a `Resources` method `contains(ResourceQuantities)`.
This method checks if the quantities of this `Resources` is a
superset of the given `ResourceQuantities`. If a `Resource` object
is `SCALAR` type, its quantity is its scalar value. For `RANGES`
and `SET` type, their quantities are the number of different
instances in the range or set. For example, "range:[1-5]" has a
quantity of 5 and "set:{a,b}" has a quantity of 2.
Also added a dedicated test.
Review: https://reviews.apache.org/r/69601
---
include/mesos/resources.hpp | 14 +++++++
include/mesos/v1/resources.hpp | 11 +++++
src/common/resources.cpp | 44 +++++++++++++++++++
src/tests/resources_tests.cpp | 95 ++++++++++++++++++++++++++++++++++++++++++
src/v1/resources.cpp | 45 ++++++++++++++++++++
5 files changed, 209 insertions(+)
diff --git a/include/mesos/resources.hpp b/include/mesos/resources.hpp
index 6cc36a3..27b2a77 100644
--- a/include/mesos/resources.hpp
+++ b/include/mesos/resources.hpp
@@ -53,6 +53,11 @@
namespace mesos {
+// Forward declaration.
+class ResourceConversion;
+
+namespace internal { class ResourceQuantities; }
+
// NOTE: Resource objects stored in the class are always valid, are in
// the "post-reservation-refinement" format, and kept combined if possible.
// It is the caller's responsibility to validate any Resource object or
@@ -376,6 +381,15 @@ public:
// Checks if this Resources contains the given Resource.
bool contains(const Resource& that) const;
+ // Checks if the quantities of this `Resources` is a superset of the
+ // given `ResourceQuantities`. If a `Resource` object is `SCALAR` type,
+ // its quantity is its scalar value. For `RANGES` and `SET` type, their
+ // quantities are the number of different instances in the range or set.
+ // For example, "range:[1-5]" has a quantity of 5 and "set:{a,b}" has a
+ // quantity of 2.
+ bool contains(
+ const mesos::internal::ResourceQuantities& quantities) const;
+
// Count the Resource objects that match the specified value.
//
// NOTE:
diff --git a/include/mesos/v1/resources.hpp b/include/mesos/v1/resources.hpp
index 03db6ba..868adb6 100644
--- a/include/mesos/v1/resources.hpp
+++ b/include/mesos/v1/resources.hpp
@@ -51,6 +51,9 @@
// but instead just written for correct semantics.
namespace mesos {
+
+namespace internal { class ResourceQuantities; }
+
namespace v1 {
// NOTE: Resource objects stored in the class are always valid, are in
@@ -376,6 +379,14 @@ public:
// Checks if this Resources contains the given Resource.
bool contains(const Resource& that) const;
+ // Checks if the quantities of this `Resources` is a superset of the
+ // given `ResourceQuantities`. If a `Resource` object is `SCALAR` type,
+ // its quantity is its scalar value. For `RANGES` and `SET` type, their
+ // quantities are the number of different instances in the range or set.
+ // For example, "range:[1-5]" has a quantity of 5 and "set:{a,b}" has a
+ // quantity of 2.
+ bool contains(
+ const mesos::internal::ResourceQuantities& quantities) const;
// Count the Resource objects that match the specified value.
//
// NOTE:
diff --git a/src/common/resources.cpp b/src/common/resources.cpp
index c859131..d9e9e51 100644
--- a/src/common/resources.cpp
+++ b/src/common/resources.cpp
@@ -38,16 +38,20 @@
#include <stout/strings.hpp>
#include <stout/unreachable.hpp>
+#include "common/resource_quantities.hpp"
#include "common/resources_utils.hpp"
using std::map;
using std::ostream;
+using std::pair;
using std::set;
using std::string;
using std::vector;
using google::protobuf::RepeatedPtrField;
+using mesos::internal::ResourceQuantities;
+
namespace mesos {
/////////////////////////////////////////////////
@@ -1346,6 +1350,46 @@ bool Resources::contains(const Resource& that) const
}
+// This function assumes all quantities with the same name are merged
+// in the input `quantities` which is a guaranteed property of
+// `ResourceQuantities`.
+bool Resources::contains(const ResourceQuantities& quantities) const
+{
+ foreach (auto& quantity, quantities){
+ double remaining = quantity.second.value();
+
+ foreach (const Resource& r, get(quantity.first)) {
+ switch (r.type()) {
+ case Value::SCALAR: remaining -= r.scalar().value(); break;
+ case Value::SET: remaining -= r.set().item_size(); break;
+ case Value::RANGES:
+ foreach (const Value::Range& range, r.ranges().range()) {
+ remaining -= range.end() - range.begin() + 1;
+ if (remaining <= 0) {
+ break;
+ }
+ }
+ break;
+ case Value::TEXT:
+ LOG(FATAL) << "Unexpected TEXT type resource " << r << " in "
+ << *this;
+ break;
+ }
+
+ if (remaining <= 0) {
+ break;
+ }
+ }
+
+ if (remaining > 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
size_t Resources::count(const Resource& that) const
{
foreach (const Resource_& resource_, resources) {
diff --git a/src/tests/resources_tests.cpp b/src/tests/resources_tests.cpp
index 21ad1ff..2f92fbf 100644
--- a/src/tests/resources_tests.cpp
+++ b/src/tests/resources_tests.cpp
@@ -31,6 +31,8 @@
#include <mesos/v1/resources.hpp>
+#include "common/resource_quantities.hpp"
+
#include "internal/evolve.hpp"
#include "master/master.hpp"
@@ -55,6 +57,8 @@ using mesos::internal::evolve;
using mesos::internal::protobuf::createLabel;
+using mesos::internal::ResourceQuantities;
+
namespace mesos {
namespace internal {
namespace tests {
@@ -1972,6 +1976,97 @@ TEST(ResourcesTest, isScalarQuantity)
}
+TEST(ResourcesTest, ContainsResourceQuantities)
+{
+ auto resources = [](const string& s) {
+ return Resources::parse(s).get();
+ };
+
+ auto quantities = [](const string& s) {
+ return ResourceQuantities::fromString(s).get();
+ };
+
+ // Empty case tests.
+
+ Resources emptyResources;
+ ResourceQuantities emptyQuantities;
+
+ EXPECT_TRUE(emptyResources.contains(emptyQuantities));
+ EXPECT_FALSE(emptyResources.contains(quantities("cpus:1")));
+ EXPECT_TRUE(resources("cpus:1").contains(emptyQuantities));
+
+ // Single scalar resource tests.
+
+ EXPECT_TRUE(resources("cpus:2").contains(quantities("cpus:1")));
+
+ EXPECT_TRUE(resources("cpus:1").contains(quantities("cpus:1")));
+
+ EXPECT_FALSE(resources("cpus:0.5").contains(quantities("cpus:1")));
+
+ // Single range resource tests.
+
+ EXPECT_TRUE(resources("ports:[1-3]").contains(quantities("ports:2")));
+
+ EXPECT_TRUE(resources("ports:[1-2]").contains(quantities("ports:2")));
+
+ EXPECT_FALSE(resources("ports:[1-1]").contains(quantities("ports:2")));
+
+ // Single set resources tests.
+
+ EXPECT_TRUE(resources("features:{a,b,c}").contains(quantities("features:2")));
+
+ EXPECT_TRUE(resources("features:{a,b}").contains(quantities("features:2")));
+
+ EXPECT_FALSE(resources("features:{a}").contains(quantities("features:2")));
+
+ // Multiple resources tests.
+
+ EXPECT_TRUE(resources("cpus:3;ports:[1-3];features:{a,b,c};mem:10")
+ .contains(quantities("cpus:3;ports:3;features:3")));
+
+ EXPECT_TRUE(resources("cpus:3;ports:[1-3];features:{a,b,c}")
+ .contains(quantities("cpus:3;ports:3;features:3")));
+
+ EXPECT_FALSE(resources("cpus:1;ports:[1-3];features:{a,b,c}")
+ .contains(quantities("cpus:3;ports:3;features:3")));
+
+ EXPECT_FALSE(resources("cpus:3;ports:[1-3]")
+ .contains(quantities("cpus:3;ports:3;features:3")));
+
+ // Duplicate names.
+
+ EXPECT_FALSE(resources("cpus(role1):2").contains(quantities("cpus:3")));
+
+ EXPECT_TRUE(resources("cpus(role1):2;cpus:1").contains(quantities("cpus:3")));
+
+ Resource::ReservationInfo reservation =
+ createDynamicReservationInfo("role", "principal");
+ Resources resources_ = createReservedResource("ports", "[1-10]", reservation);
+
+ EXPECT_FALSE(resources_.contains(quantities("ports:12")));
+
+ resources_ += Resources::parse("ports:[20-25]").get(); // 15 ports in total.
+
+ EXPECT_TRUE(resources_.contains(quantities("ports:12")));
+
+ resources_ = createPersistentVolume(
+ Megabytes(64),
+ "role1",
+ "id1",
+ "path1",
+ None(),
+ None(),
+ "principal1",
+ true); // Shared.
+
+ EXPECT_FALSE(resources_.contains(quantities("disk:128")));
+
+ resources_ += Resources::parse("disk:64").get(); // 128M disk in total.
+
+ EXPECT_TRUE(resources_.contains(quantities("disk:128")));
+}
+
+
TEST(ReservedResourcesTest, Validation)
{
// Unreserved.
diff --git a/src/v1/resources.cpp b/src/v1/resources.cpp
index aa1da43..91b482f 100644
--- a/src/v1/resources.cpp
+++ b/src/v1/resources.cpp
@@ -39,14 +39,19 @@
#include <stout/strings.hpp>
#include <stout/unreachable.hpp>
+#include "common/resource_quantities.hpp"
+
using std::map;
using std::ostream;
+using std::pair;
using std::set;
using std::string;
using std::vector;
using google::protobuf::RepeatedPtrField;
+using mesos::internal::ResourceQuantities;
+
namespace mesos {
namespace v1 {
@@ -1374,6 +1379,46 @@ bool Resources::contains(const Resource& that) const
}
+// This function assumes all quantities with the same name are merged
+// in the input `quantities` which is a guaranteed property of
+// `ResourceQuantities`.
+bool Resources::contains(const ResourceQuantities& quantities) const
+{
+ foreach (auto& quantity, quantities){
+ double remaining = quantity.second.value();
+
+ foreach (const Resource& r, get(quantity.first)) {
+ switch (r.type()) {
+ case Value::SCALAR: remaining -= r.scalar().value(); break;
+ case Value::SET: remaining -= r.set().item_size(); break;
+ case Value::RANGES:
+ foreach (const Value::Range& range, r.ranges().range()) {
+ remaining -= range.end() - range.begin() + 1;
+ if (remaining <= 0) {
+ break;
+ }
+ }
+ break;
+ case Value::TEXT:
+ LOG(FATAL) << "Unexpected TEXT type resource " << r << " in "
+ << *this;
+ break;
+ }
+
+ if (remaining <= 0) {
+ break;
+ }
+ }
+
+ if (remaining > 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
size_t Resources::count(const Resource& that) const
{
foreach (const Resource_& resource_, resources) {