blob: 12adedc4429519b90f4975036f7359c20608708a [file] [log] [blame]
/**
* 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 <string>
#include <mesos/mesos.hpp>
#include <mesos/values.hpp>
#include <stout/bytes.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() {}
/*implicit*/
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;
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;
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;
}
/**
* 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;
// TODO(vinod): Provide a Ranges abstraction.
Option<Value::Ranges> ports() const;
// TODO(jieyu): Consider returning an EphemeralPorts abstraction
// which holds the ephemeral ports allocation logic.
Option<Value::Ranges> ephemeral_ports() const;
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;
};
std::ostream& operator << (std::ostream& stream, const Resources& resources);
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__