Re-organized the functions in C++ Resources. Review: https://reviews.apache.org/r/28078
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/bdf2d9d4 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/bdf2d9d4 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/bdf2d9d4 Branch: refs/heads/master Commit: bdf2d9d410aeda6733a3d1ccdcd61ae7e89dac4a Parents: 7ff4920 Author: Jie Yu <[email protected]> Authored: Fri Nov 14 10:14:24 2014 -0800 Committer: Jie Yu <[email protected]> Committed: Wed Nov 19 00:14:25 2014 -0800 ---------------------------------------------------------------------- include/mesos/resources.hpp | 154 ++++----- src/common/resources.cpp | 697 ++++++++++++++++++++------------------- 2 files changed, 428 insertions(+), 423 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/bdf2d9d4/include/mesos/resources.hpp ---------------------------------------------------------------------- diff --git a/include/mesos/resources.hpp b/include/mesos/resources.hpp index 0e37170..c2ba597 100644 --- a/include/mesos/resources.hpp +++ b/include/mesos/resources.hpp @@ -19,6 +19,7 @@ #ifndef __RESOURCES_HPP__ #define __RESOURCES_HPP__ +#include <iostream> #include <string> #include <mesos/mesos.hpp> @@ -26,6 +27,7 @@ #include <stout/bytes.hpp> #include <stout/option.hpp> +#include <stout/try.hpp> /** @@ -50,28 +52,66 @@ * names is a no-op. */ - namespace mesos { - bool operator == (const Resource& left, const Resource& right); bool operator != (const Resource& left, const Resource& right); + + bool operator <= (const Resource& left, const Resource& right); -Resource operator + (const Resource& left, const Resource& right); -Resource operator - (const Resource& left, const Resource& right); + + Resource& operator += (Resource& left, const Resource& right); +Resource operator + (const Resource& left, const Resource& right); Resource& operator -= (Resource& left, const Resource& right); +Resource operator - (const Resource& left, const Resource& right); + + // Return true iff both Resources have the same name, type, and role. bool matches(const Resource& left, const Resource& right); -std::ostream& operator << (std::ostream& stream, const Resource& resource); - // TODO(bmahler): Ensure that the underlying resources are kept // in a flattened state: MESOS-1714. class Resources { public: + /** + * Parses the value and returns a Resource with the given name and role. + */ + static Try<Resource> parse( + const std::string& name, + const std::string& value, + const std::string& role); + + /** + * Parses resources in the form "name:value (role);name:value...". + * Any name/value pair that doesn't specify a role is assigned to defaultRole. + */ + static Try<Resources> parse( + const std::string& s, + const std::string& defaultRole = "*"); + + /** + * Returns true iff this resource has a name, a valid type, i.e. scalar, + * range, or set, and has the appropriate value set for its type. + */ + static bool isValid(const Resource& resource); + + /** + * Returns true iff this resource is valid and allocatable. In particular, + * a scalar is allocatable if it's value is greater than zero, a ranges + * is allocatable if there is at least one valid range in it, and a set + * is allocatable if it has at least one item. + */ + static bool isAllocatable(const Resource& resource); + + /** + * Returns true iff this resource is zero valued, i.e. is zero for scalars, + * has a range size of zero for ranges, and has no items for sets. + */ + static bool isZero(const Resource& resource); + Resources() {} /*implicit*/ @@ -95,57 +135,16 @@ public: return *this; } - /** - * Returns a Resources object with only the allocatable resources. - */ - Resources allocatable() const; - size_t size() const { return resources.size(); } /** - * Using this operator makes it easy to copy a resources object into - * a protocol buffer field. + * Returns all resources in this object that are marked with the + * specified role. */ - operator const google::protobuf::RepeatedPtrField<Resource>& () const - { - return resources; - } - - bool operator == (const Resources& that) const; - - bool operator != (const Resources& that) const - { - return !(*this == that); - } - - bool operator <= (const Resources& that) const; - - Resources operator + (const Resources& that) const; - - Resources operator - (const Resources& that) const; - - Resources& operator += (const Resources& that); - - Resources& operator -= (const Resources& that); - - Resources operator + (const Resource& that) const; - - Resources operator - (const Resource& that) const; - - Resources& operator += (const Resource& that) - { - *this = *this + that; - return *this; - } - - Resources& operator -= (const Resource& that) - { - *this = *this - that; - return *this; - } + Resources extract(const std::string& role) const; /** * Returns a Resources object with the same amount of each resource @@ -155,12 +154,6 @@ public: Resources flatten(const std::string& role = "*") const; /** - * Returns all resources in this object that are marked with the - * specified role. - */ - Resources extract(const std::string& role) const; - - /** * Finds a number of resources equal to toFind in these Resources * and returns them marked with appropriate roles. For each resource * type, resources are first taken from the specified role, then @@ -185,6 +178,11 @@ public: template <typename T> T get(const std::string& name, const T& t) const; + /** + * Returns a Resources object with only the allocatable resources. + */ + Resources allocatable() const; + // Helpers to get known resource types. // TODO(vinod): Fix this when we make these types as first class protobufs. Option<double> cpus() const; @@ -215,46 +213,32 @@ public: const_iterator end() const { return resources.end(); } /** - * Parses the value and returns a Resource with the given name and role. + * Using this operator makes it easy to copy a resources object into + * a protocol buffer field. */ - static Try<Resource> parse( - const std::string& name, - const std::string& value, - const std::string& role); + operator const google::protobuf::RepeatedPtrField<Resource>& () const; - /** - * Parses resources in the form "name:value (role);name:value...". - * Any name/value pair that doesn't specify a role is assigned to defaultRole. - */ - static Try<Resources> parse( - const std::string& s, - const std::string& defaultRole = "*"); + bool operator == (const Resources& that) const; + bool operator != (const Resources& that) const; - /** - * Returns true iff this resource has a name, a valid type, i.e. scalar, - * range, or set, and has the appropriate value set for its type. - */ - static bool isValid(const Resource& resource); + bool operator <= (const Resources& that) const; - /** - * Returns true iff this resource is valid and allocatable. In particular, - * a scalar is allocatable if it's value is greater than zero, a ranges - * is allocatable if there is at least one valid range in it, and a set - * is allocatable if it has at least one item. - */ - static bool isAllocatable(const Resource& resource); + Resources operator + (const Resource& that) const; + Resources operator + (const Resources& that) const; + Resources& operator += (const Resource& that); + Resources& operator += (const Resources& that); - /** - * Returns true iff this resource is zero valued, i.e. is zero for scalars, - * has a range size of zero for ranges, and has no items for sets. - */ - static bool isZero(const Resource& resource); + Resources operator - (const Resource& that) const; + Resources operator - (const Resources& that) const; + Resources& operator -= (const Resource& that); + Resources& operator -= (const Resources& that); private: google::protobuf::RepeatedPtrField<Resource> resources; }; +std::ostream& operator << (std::ostream& stream, const Resource& resource); std::ostream& operator << (std::ostream& stream, const Resources& resources); http://git-wip-us.apache.org/repos/asf/mesos/blob/bdf2d9d4/src/common/resources.cpp ---------------------------------------------------------------------- diff --git a/src/common/resources.cpp b/src/common/resources.cpp index e9a0c85..1ffebbb 100644 --- a/src/common/resources.cpp +++ b/src/common/resources.cpp @@ -18,7 +18,6 @@ #include <stdint.h> -#include <iostream> #include <vector> #include <glog/logging.h> @@ -28,7 +27,6 @@ #include <stout/foreach.hpp> #include <stout/strings.hpp> -#include <stout/try.hpp> using std::ostream; using std::string; @@ -59,14 +57,6 @@ bool operator != (const Resource& left, const Resource& right) } -bool matches(const Resource& left, const Resource& right) -{ - return left.name() == right.name() && - left.type() == right.type() && - left.role() == right.role(); -} - - bool operator <= (const Resource& left, const Resource& right) { if (matches(left, right)) { @@ -83,39 +73,37 @@ bool operator <= (const Resource& left, const Resource& right) } -Resource operator + (const Resource& left, const Resource& right) +Resource& operator += (Resource& left, const Resource& right) { - Resource result = left; - if (matches(left, right)) { if (left.type() == Value::SCALAR) { - result.mutable_scalar()->MergeFrom(left.scalar() + right.scalar()); + left.mutable_scalar()->MergeFrom(left.scalar() + right.scalar()); } else if (left.type() == Value::RANGES) { - result.mutable_ranges()->Clear(); - result.mutable_ranges()->MergeFrom(left.ranges() + right.ranges()); + left.mutable_ranges()->Clear(); + left.mutable_ranges()->MergeFrom(left.ranges() + right.ranges()); } else if (left.type() == Value::SET) { - result.mutable_set()->Clear(); - result.mutable_set()->MergeFrom(left.set() + right.set()); + left.mutable_set()->Clear(); + left.mutable_set()->MergeFrom(left.set() + right.set()); } } - return result; + return left; } -Resource operator - (const Resource& left, const Resource& right) +Resource operator + (const Resource& left, const Resource& right) { Resource result = left; if (matches(left, right)) { if (left.type() == Value::SCALAR) { - result.mutable_scalar()->MergeFrom(left.scalar() - right.scalar()); + result.mutable_scalar()->MergeFrom(left.scalar() + right.scalar()); } else if (left.type() == Value::RANGES) { result.mutable_ranges()->Clear(); - result.mutable_ranges()->MergeFrom(left.ranges() - right.ranges()); + result.mutable_ranges()->MergeFrom(left.ranges() + right.ranges()); } else if (left.type() == Value::SET) { result.mutable_set()->Clear(); - result.mutable_set()->MergeFrom(left.set() - right.set()); + result.mutable_set()->MergeFrom(left.set() + right.set()); } } @@ -123,17 +111,17 @@ Resource operator - (const Resource& left, const Resource& right) } -Resource& operator += (Resource& left, const Resource& right) +Resource& operator -= (Resource& left, const Resource& right) { if (matches(left, right)) { if (left.type() == Value::SCALAR) { - left.mutable_scalar()->MergeFrom(left.scalar() + right.scalar()); + left.mutable_scalar()->MergeFrom(left.scalar() - right.scalar()); } else if (left.type() == Value::RANGES) { left.mutable_ranges()->Clear(); - left.mutable_ranges()->MergeFrom(left.ranges() + right.ranges()); + left.mutable_ranges()->MergeFrom(left.ranges() - right.ranges()); } else if (left.type() == Value::SET) { left.mutable_set()->Clear(); - left.mutable_set()->MergeFrom(left.set() + right.set()); + left.mutable_set()->MergeFrom(left.set() - right.set()); } } @@ -141,188 +129,223 @@ Resource& operator += (Resource& left, const Resource& right) } -Resource& operator -= (Resource& left, const Resource& right) +Resource operator - (const Resource& left, const Resource& right) { + Resource result = left; + if (matches(left, right)) { if (left.type() == Value::SCALAR) { - left.mutable_scalar()->MergeFrom(left.scalar() - right.scalar()); + result.mutable_scalar()->MergeFrom(left.scalar() - right.scalar()); } else if (left.type() == Value::RANGES) { - left.mutable_ranges()->Clear(); - left.mutable_ranges()->MergeFrom(left.ranges() - right.ranges()); + result.mutable_ranges()->Clear(); + result.mutable_ranges()->MergeFrom(left.ranges() - right.ranges()); } else if (left.type() == Value::SET) { - left.mutable_set()->Clear(); - left.mutable_set()->MergeFrom(left.set() - right.set()); + result.mutable_set()->Clear(); + result.mutable_set()->MergeFrom(left.set() - right.set()); } } - return left; + return result; } -ostream& operator << (ostream& stream, const Resource& resource) +bool matches(const Resource& left, const Resource& right) { - stream << resource.name() << "(" << resource.role() << "):"; + return left.name() == right.name() && + left.type() == right.type() && + left.role() == right.role(); +} - switch (resource.type()) { - case Value::SCALAR: stream << resource.scalar(); break; - case Value::RANGES: stream << resource.ranges(); break; - case Value::SET: stream << resource.set(); break; - default: - LOG(FATAL) << "Unexpected Value type: " << resource.type(); - break; + +Try<Resource> Resources::parse( + const string& name, + const string& text, + const string& role) +{ + Resource resource; + Try<Value> result = internal::values::parse(text); + + if (result.isError()) { + return Error("Failed to parse resource " + name + + " text " + text + + " error " + result.error()); + } else{ + Value value = result.get(); + resource.set_name(name); + resource.set_role(role); + + if (value.type() == Value::RANGES) { + resource.set_type(Value::RANGES); + resource.mutable_ranges()->MergeFrom(value.ranges()); + } else if (value.type() == Value::SET) { + resource.set_type(Value::SET); + resource.mutable_set()->MergeFrom(value.set()); + } else if (value.type() == Value::SCALAR) { + resource.set_type(Value::SCALAR); + resource.mutable_scalar()->MergeFrom(value.scalar()); + } else { + return Error("Bad type for resource " + name + + " text " + text + + " type " + Value::Type_Name(value.type())); + } } - return stream; + return resource; } -Resources Resources::allocatable() const +Try<Resources> Resources::parse(const string& s, const string& defaultRole) { - Resources result; + Resources resources; - foreach (const Resource& resource, resources) { - if (isAllocatable(resource)) { - result.resources.Add()->MergeFrom(resource); + vector<string> tokens = strings::tokenize(s, ";"); + + foreach (const string& token, tokens) { + vector<string> pair = strings::tokenize(token, ":"); + if (pair.size() != 2) { + return Error("Bad value for resources, missing or extra ':' in " + token); + } + + string name; + string role; + size_t openParen = pair[0].find("("); + if (openParen == string::npos) { + name = strings::trim(pair[0]); + role = defaultRole; + } else { + size_t closeParen = pair[0].find(")"); + if (closeParen == string::npos || closeParen < openParen) { + return Error("Bad value for resources, mismatched parentheses in " + + token); + } + + name = strings::trim(pair[0].substr(0, openParen)); + role = strings::trim(pair[0].substr(openParen + 1, + closeParen - openParen - 1)); + } + + Try<Resource> resource = Resources::parse(name, pair[1], role); + if (resource.isError()) { + return Error(resource.error()); } + resources += resource.get(); } - return result; + return resources; } -bool Resources::operator == (const Resources& that) const +bool Resources::isValid(const Resource& resource) { - if (size() != that.size()) { + if (!resource.has_name() || + resource.name() == "" || + !resource.has_type() || + !Value::Type_IsValid(resource.type())) { return false; } - foreach (const Resource& resource, resources) { - Option<Resource> option = that.get(resource); - if (option.isNone()) { - return false; - } else { - if (!(resource == option.get())) { - return false; - } - } + if (resource.type() == Value::SCALAR) { + return resource.has_scalar(); + } else if (resource.type() == Value::RANGES) { + return resource.has_ranges(); + } else if (resource.type() == Value::SET) { + return resource.has_set(); + } else if (resource.type() == Value::TEXT) { + // Resources doesn't support text. + return false; } - return true; + return false; } -bool Resources::operator <= (const Resources& that) const +bool Resources::isAllocatable(const Resource& resource) { - foreach (const Resource& resource, resources) { - Option<Resource> option = that.get(resource); - if (option.isNone()) { - if (!isZero(resource)) { + if (isValid(resource)) { + if (resource.type() == Value::SCALAR) { + if (resource.scalar().value() <= 0) { return false; } - } else { - if (!(resource <= option.get())) { + } else if (resource.type() == Value::RANGES) { + if (resource.ranges().range_size() == 0) { + return false; + } else { + for (int i = 0; i < resource.ranges().range_size(); i++) { + const Value::Range& range = resource.ranges().range(i); + + // Ensure the range make sense (isn't inverted). + if (range.begin() > range.end()) { + return false; + } + + // Ensure ranges don't overlap (but not necessarily coalesced). + for (int j = i + 1; j < resource.ranges().range_size(); j++) { + if (range.begin() <= resource.ranges().range(j).begin() && + resource.ranges().range(j).begin() <= range.end()) { + return false; + } + } + } + } + } else if (resource.type() == Value::SET) { + if (resource.set().item_size() == 0) { return false; + } else { + for (int i = 0; i < resource.set().item_size(); i++) { + const string& item = resource.set().item(i); + + // Ensure no duplicates. + for (int j = i + 1; j < resource.set().item_size(); j++) { + if (item == resource.set().item(j)) { + return false; + } + } + } } } + + return true; } - return true; + return false; } -Resources Resources::operator + (const Resources& that) const +bool Resources::isZero(const Resource& resource) { - Resources result(*this); - - foreach (const Resource& resource, that.resources) { - result += resource; + if (resource.type() == Value::SCALAR) { + return resource.scalar().value() == 0; + } else if (resource.type() == Value::RANGES) { + return resource.ranges().range_size() == 0; + } else if (resource.type() == Value::SET) { + return resource.set().item_size() == 0; } - return result; + return false; } -Resources Resources::operator - (const Resources& that) const +Resources Resources::extract(const string& role) const { - Resources result(*this); + Resources r; - foreach (const Resource& resource, that.resources) { - result -= resource; + foreach (const Resource& resource, resources) { + if (resource.role() == role) { + r += resource; + } } - return result; + return r; } -Resources& Resources::operator += (const Resources& that) +Resources Resources::flatten(const string& role) const { - foreach (const Resource& resource, that.resources) { - *this += resource; - } - - return *this; -} + Resources flattened; - -Resources& Resources::operator -= (const Resources& that) -{ - foreach (const Resource& resource, that.resources) { - *this -= resource; - } - - return *this; -} - - -Resources Resources::operator + (const Resource& that) const -{ - Resources result; - - bool added = false; - - foreach (const Resource& resource, resources) { - if (matches(resource, that)) { - result.resources.Add()->MergeFrom(resource + that); - added = true; - } else { - result.resources.Add()->MergeFrom(resource); - } - } - - if (!added) { - result.resources.Add()->MergeFrom(that); - } - - return result; -} - - -Resources Resources::operator - (const Resource& that) const -{ - Resources result; - - foreach (const Resource& resource, resources) { - if (matches(resource, that)) { - Resource r = resource - that; - if (!isZero(r)) { - result.resources.Add()->MergeFrom(r); - } - } else { - result.resources.Add()->MergeFrom(resource); - } - } - - return result; -} - - -Resources Resources::flatten(const string& role) const -{ - Resources flattened; - - foreach (const Resource& r, resources) { - Resource toRemove = r; - toRemove.set_role(role); + foreach (const Resource& r, resources) { + Resource toRemove = r; + toRemove.set_role(role); bool found = false; for (int i = 0; i < flattened.resources.size(); i++) { @@ -344,20 +367,6 @@ Resources Resources::flatten(const string& role) const } -Resources Resources::extract(const string& role) const -{ - Resources r; - - foreach (const Resource& resource, resources) { - if (resource.role() == role) { - r += resource; - } - } - - return r; -} - - Option<Resources> Resources::find( const Resources& toFind, const string& role) const @@ -439,6 +448,92 @@ Option<Resources> Resources::getAll(const Resource& r) const } +template <> +Value::Scalar Resources::get( + const string& name, + const Value::Scalar& scalar) const +{ + Value::Scalar total; + bool found = false; + + foreach (const Resource& resource, resources) { + if (resource.name() == name && + resource.type() == Value::SCALAR) { + total += resource.scalar(); + found = true; + } + } + + if (found) { + return total; + } + + return scalar; +} + + +template <> +Value::Ranges Resources::get( + const string& name, + const Value::Ranges& ranges) const +{ + Value::Ranges total; + bool found = false; + + foreach (const Resource& resource, resources) { + if (resource.name() == name && + resource.type() == Value::RANGES) { + total += resource.ranges(); + found = true; + } + } + + if (found) { + return total; + } + + return ranges; +} + + +template <> +Value::Set Resources::get( + const string& name, + const Value::Set& set) const +{ + Value::Set total; + bool found = false; + + foreach (const Resource& resource, resources) { + if (resource.name() == name && + resource.type() == Value::SET) { + total += resource.set(); + found = true; + } + } + + if (found) { + return total; + } + + return set; +} + + +Resources Resources::allocatable() const +{ + Resources result; + + foreach (const Resource& resource, resources) { + if (isAllocatable(resource)) { + result.resources.Add()->MergeFrom(resource); + } + } + + return result; +} + + Option<double> Resources::cpus() const { double total= 0; @@ -573,249 +668,176 @@ Option<Value::Ranges> Resources::ephemeral_ports() const } -Try<Resource> Resources::parse( - const string& name, - const string& text, - const string& role) +Resources::operator const google::protobuf::RepeatedPtrField<Resource>& () const { - Resource resource; - Try<Value> result = internal::values::parse(text); + return resources; +} - if (result.isError()) { - return Error("Failed to parse resource " + name + - " text " + text + - " error " + result.error()); - } else{ - Value value = result.get(); - resource.set_name(name); - resource.set_role(role); - if (value.type() == Value::RANGES) { - resource.set_type(Value::RANGES); - resource.mutable_ranges()->MergeFrom(value.ranges()); - } else if (value.type() == Value::SET) { - resource.set_type(Value::SET); - resource.mutable_set()->MergeFrom(value.set()); - } else if (value.type() == Value::SCALAR) { - resource.set_type(Value::SCALAR); - resource.mutable_scalar()->MergeFrom(value.scalar()); - } else { - return Error("Bad type for resource " + name + - " text " + text + - " type " + Value::Type_Name(value.type())); +bool Resources::operator == (const Resources& that) const +{ + if (size() != that.size()) { + return false; + } + + foreach (const Resource& resource, resources) { + Option<Resource> option = that.get(resource); + if (option.isNone()) { + return false; + } else { + if (!(resource == option.get())) { + return false; + } } } - return resource; + return true; } -Try<Resources> Resources::parse(const string& s, const string& defaultRole) +bool Resources::operator != (const Resources& that) const { - Resources resources; + return !(*this == that); +} - vector<string> tokens = strings::tokenize(s, ";"); - foreach (const string& token, tokens) { - vector<string> pair = strings::tokenize(token, ":"); - if (pair.size() != 2) { - return Error("Bad value for resources, missing or extra ':' in " + token); - } - - string name; - string role; - size_t openParen = pair[0].find("("); - if (openParen == string::npos) { - name = strings::trim(pair[0]); - role = defaultRole; +bool Resources::operator <= (const Resources& that) const +{ + foreach (const Resource& resource, resources) { + Option<Resource> option = that.get(resource); + if (option.isNone()) { + if (!isZero(resource)) { + return false; + } } else { - size_t closeParen = pair[0].find(")"); - if (closeParen == string::npos || closeParen < openParen) { - return Error("Bad value for resources, mismatched parentheses in " + - token); + if (!(resource <= option.get())) { + return false; } - - name = strings::trim(pair[0].substr(0, openParen)); - role = strings::trim(pair[0].substr(openParen + 1, - closeParen - openParen - 1)); } - - Try<Resource> resource = Resources::parse(name, pair[1], role); - if (resource.isError()) { - return Error(resource.error()); - } - resources += resource.get(); } - return resources; + return true; } -bool Resources::isValid(const Resource& resource) +Resources Resources::operator + (const Resource& that) const { - if (!resource.has_name() || - resource.name() == "" || - !resource.has_type() || - !Value::Type_IsValid(resource.type())) { - return false; + Resources result; + + bool added = false; + + foreach (const Resource& resource, resources) { + if (matches(resource, that)) { + result.resources.Add()->MergeFrom(resource + that); + added = true; + } else { + result.resources.Add()->MergeFrom(resource); + } } - if (resource.type() == Value::SCALAR) { - return resource.has_scalar(); - } else if (resource.type() == Value::RANGES) { - return resource.has_ranges(); - } else if (resource.type() == Value::SET) { - return resource.has_set(); - } else if (resource.type() == Value::TEXT) { - // Resources doesn't support text. - return false; + if (!added) { + result.resources.Add()->MergeFrom(that); } - return false; + return result; } -bool Resources::isAllocatable(const Resource& resource) +Resources Resources::operator + (const Resources& that) const { - if (isValid(resource)) { - if (resource.type() == Value::SCALAR) { - if (resource.scalar().value() <= 0) { - return false; - } - } else if (resource.type() == Value::RANGES) { - if (resource.ranges().range_size() == 0) { - return false; - } else { - for (int i = 0; i < resource.ranges().range_size(); i++) { - const Value::Range& range = resource.ranges().range(i); - - // Ensure the range make sense (isn't inverted). - if (range.begin() > range.end()) { - return false; - } + Resources result(*this); - // Ensure ranges don't overlap (but not necessarily coalesced). - for (int j = i + 1; j < resource.ranges().range_size(); j++) { - if (range.begin() <= resource.ranges().range(j).begin() && - resource.ranges().range(j).begin() <= range.end()) { - return false; - } - } - } - } - } else if (resource.type() == Value::SET) { - if (resource.set().item_size() == 0) { - return false; - } else { - for (int i = 0; i < resource.set().item_size(); i++) { - const std::string& item = resource.set().item(i); + foreach (const Resource& resource, that.resources) { + result += resource; + } - // Ensure no duplicates. - for (int j = i + 1; j < resource.set().item_size(); j++) { - if (item == resource.set().item(j)) { - return false; - } - } - } - } - } + return result; +} - return true; - } - return false; +Resources& Resources::operator += (const Resource& that) +{ + *this = *this + that; + return *this; } -bool Resources::isZero(const Resource& resource) +Resources& Resources::operator += (const Resources& that) { - if (resource.type() == Value::SCALAR) { - return resource.scalar().value() == 0; - } else if (resource.type() == Value::RANGES) { - return resource.ranges().range_size() == 0; - } else if (resource.type() == Value::SET) { - return resource.set().item_size() == 0; + foreach (const Resource& resource, that.resources) { + *this += resource; } - return false; + return *this; } -template <> -Value::Scalar Resources::get( - const std::string& name, - const Value::Scalar& scalar) const +Resources Resources::operator - (const Resource& that) const { - Value::Scalar total; - bool found = false; + Resources result; foreach (const Resource& resource, resources) { - if (resource.name() == name && - resource.type() == Value::SCALAR) { - total += resource.scalar(); - found = true; + if (matches(resource, that)) { + Resource r = resource - that; + if (!isZero(r)) { + result.resources.Add()->MergeFrom(r); + } + } else { + result.resources.Add()->MergeFrom(resource); } } - if (found) { - return total; + return result; +} + + +Resources Resources::operator - (const Resources& that) const +{ + Resources result(*this); + + foreach (const Resource& resource, that.resources) { + result -= resource; } - return scalar; + return result; } -template <> -Value::Ranges Resources::get( - const std::string& name, - const Value::Ranges& ranges) const +Resources& Resources::operator -= (const Resource& that) { - Value::Ranges total; - bool found = false; + *this = *this - that; + return *this; +} - foreach (const Resource& resource, resources) { - if (resource.name() == name && - resource.type() == Value::RANGES) { - total += resource.ranges(); - found = true; - } - } - if (found) { - return total; +Resources& Resources::operator -= (const Resources& that) +{ + foreach (const Resource& resource, that.resources) { + *this -= resource; } - return ranges; + return *this; } -template <> -Value::Set Resources::get( - const std::string& name, - const Value::Set& set) const +ostream& operator << (ostream& stream, const Resource& resource) { - Value::Set total; - bool found = false; - - foreach (const Resource& resource, resources) { - if (resource.name() == name && - resource.type() == Value::SET) { - total += resource.set(); - found = true; - } - } + stream << resource.name() << "(" << resource.role() << "):"; - if (found) { - return total; + switch (resource.type()) { + case Value::SCALAR: stream << resource.scalar(); break; + case Value::RANGES: stream << resource.ranges(); break; + case Value::SET: stream << resource.set(); break; + default: + LOG(FATAL) << "Unexpected Value type: " << resource.type(); + break; } - return set; + return stream; } -std::ostream& operator << ( - std::ostream& stream, - const Resources& resources) +ostream& operator << (ostream& stream, const Resources& resources) { mesos::Resources::const_iterator it = resources.begin(); @@ -829,5 +851,4 @@ std::ostream& operator << ( return stream; } - } // namespace mesos {
