| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef __RESOURCES_HPP__ |
| #define __RESOURCES_HPP__ |
| |
| #include <iterator> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <mesos/mesos.hpp> |
| #include <mesos/values.hpp> |
| |
| #include <stout/bytes.hpp> |
| #include <stout/foreach.hpp> |
| #include <stout/none.hpp> |
| #include <stout/option.hpp> |
| |
| |
| /** |
| * Resources come in three types: scalar, ranges, and sets. These are |
| * represented using protocol buffers. To make manipulation of |
| * resources easier within the Mesos core and for scheduler writers, |
| * we provide generic overloaded opertors (see below) as well as a |
| * general Resources class that encapsulates a collection of protocol |
| * buffer Resource objects. The Resources class also provides a few |
| * static routines to allow parsing resources (e.g., from the command |
| * line), as well as determining whether or not a Resource object is |
| * valid or allocatable. Note that many of these operations have not |
| * been optimized but instead just written for correct semantics. |
| * |
| * Note! A resource is described by a tuple (name, type, role). Doing |
| * "arithmetic" operations (those defined below) on two resources of |
| * the same name but different type, or the same name and type but |
| * different roles, doesn't make sense, so it's semantics are as |
| * though the second operand was actually just an empty resource |
| * (as though you didn't do the operation at all). In addition, |
| * doing operations on two resources of the same type but different |
| * 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 -= (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); |
| |
| |
| class Resources |
| { |
| public: |
| Resources() {} |
| |
| Resources(const google::protobuf::RepeatedPtrField<Resource>& _resources) |
| { |
| resources.MergeFrom(_resources); |
| } |
| |
| Resources(const Resources& that) |
| { |
| resources.MergeFrom(that.resources); |
| } |
| |
| Resources& operator = (const Resources& that) |
| { |
| if (this != &that) { |
| resources.Clear(); |
| resources.MergeFrom(that.resources); |
| } |
| |
| return *this; |
| } |
| |
| /** |
| * Returns a Resources object with only the allocatable resources. |
| */ |
| Resources allocatable() const |
| { |
| Resources result; |
| |
| foreach (const Resource& resource, resources) { |
| if (isAllocatable(resource)) { |
| result.resources.Add()->MergeFrom(resource); |
| } |
| } |
| |
| return result; |
| } |
| |
| size_t size() const |
| { |
| return resources.size(); |
| } |
| |
| /** |
| * Using this operator makes it easy to copy a resources object into |
| * a protocol buffer field. |
| */ |
| operator const google::protobuf::RepeatedPtrField<Resource>& () const |
| { |
| return resources; |
| } |
| |
| bool 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 true; |
| } |
| |
| bool operator != (const Resources& that) const |
| { |
| return !(*this == that); |
| } |
| |
| bool operator <= (const Resources& that) const |
| { |
| foreach (const Resource& resource, resources) { |
| Option<Resource> option = that.get(resource); |
| if (option.isNone()) { |
| return false; |
| } else { |
| if (!(resource <= option.get())) { |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| Resources operator + (const Resources& that) const |
| { |
| Resources result(*this); |
| |
| foreach (const Resource& resource, that.resources) { |
| result += resource; |
| } |
| |
| return result; |
| } |
| |
| Resources operator - (const Resources& that) const |
| { |
| Resources result(*this); |
| |
| foreach (const Resource& resource, that.resources) { |
| result -= resource; |
| } |
| |
| return result; |
| } |
| |
| Resources& operator += (const Resources& that) |
| { |
| foreach (const Resource& resource, that.resources) { |
| *this += resource; |
| } |
| |
| return *this; |
| } |
| |
| Resources& operator -= (const Resources& that) |
| { |
| foreach (const Resource& resource, that.resources) { |
| *this -= resource; |
| } |
| |
| return *this; |
| } |
| |
| 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 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& operator += (const Resource& that) |
| { |
| *this = *this + that; |
| return *this; |
| } |
| |
| Resources& operator -= (const Resource& that) |
| { |
| *this = *this - that; |
| return *this; |
| } |
| |
| /** |
| * Returns a Resources object with the same amount of each resource |
| * type as these Resources, but with only one Resource object per |
| * type and all Resource object marked as the specified role. |
| */ |
| 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 |
| * from '*', then from any other role. |
| */ |
| Option<Resources> find( |
| const Resources& toFind, |
| const std::string& role = "*") const; |
| |
| /** |
| * Returns the Resource from these Resources that matches the argument |
| * in name, type, and role, if it exists. |
| */ |
| Option<Resource> get(const Resource& r) const; |
| |
| /** |
| * Returns all Resources from these Resources that match the argument |
| * in name and type, regardless of role. |
| */ |
| Option<Resources> getAll(const Resource& r) const; |
| |
| template <typename T> |
| T get(const std::string& name, const T& t) const; |
| |
| // Helpers to get known resource types. |
| // TODO(vinod): Fix this when we make these types as first class protobufs. |
| Option<double> cpus() const; |
| Option<Bytes> mem() const; |
| Option<Bytes> disk() const; |
| Option<Value::Ranges> ports() const; // TODO(vinod): Provide a Ranges abstraction. |
| |
| typedef google::protobuf::RepeatedPtrField<Resource>::iterator |
| iterator; |
| |
| typedef google::protobuf::RepeatedPtrField<Resource>::const_iterator |
| const_iterator; |
| |
| iterator begin() { return resources.begin(); } |
| iterator end() { return resources.end(); } |
| |
| const_iterator begin() const { return resources.begin(); } |
| const_iterator end() const { return resources.end(); } |
| |
| /** |
| * 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); |
| |
| private: |
| google::protobuf::RepeatedPtrField<Resource> resources; |
| }; |
| |
| |
| template <> |
| inline Value::Scalar Resources::get( |
| const std::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 <> |
| inline Value::Ranges Resources::get( |
| const std::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 <> |
| inline Value::Set Resources::get( |
| const std::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; |
| } |
| |
| |
| inline std::ostream& operator << ( |
| std::ostream& stream, |
| const Resources& resources) |
| { |
| mesos::Resources::const_iterator it = resources.begin(); |
| |
| while (it != resources.end()) { |
| stream << *it; |
| if (++it != resources.end()) { |
| stream << "; "; |
| } |
| } |
| |
| return stream; |
| } |
| |
| |
| inline std::ostream& operator << ( |
| std::ostream& stream, |
| const google::protobuf::RepeatedPtrField<Resource>& resources) |
| { |
| return stream << Resources(resources); |
| } |
| |
| |
| inline Resources operator + ( |
| const google::protobuf::RepeatedPtrField<Resource>& left, |
| const Resources& right) |
| { |
| return Resources(left) + right; |
| } |
| |
| |
| inline Resources operator - ( |
| const google::protobuf::RepeatedPtrField<Resource>& left, |
| const Resources& right) |
| { |
| return Resources(left) - right; |
| } |
| |
| |
| inline bool operator == ( |
| const google::protobuf::RepeatedPtrField<Resource>& left, |
| const Resources& right) |
| { |
| return Resources(left) == right; |
| } |
| |
| } // namespace mesos { |
| |
| #endif // __RESOURCES_HPP__ |