blob: bc5b96df366f2e077e17a4dead7fdb87bc65f2df [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 __COMMON_RESOURCE_QUANTITIES_HPP__
#define __COMMON_RESOURCE_QUANTITIES_HPP__
#include <string>
#include <utility>
#include <vector>
#include <mesos/mesos.hpp>
#include <mesos/resources.hpp>
#include <stout/try.hpp>
namespace mesos {
namespace internal {
// An efficient collection of resource quantities. All values are guaranteed
// to be positive and finite.
//
// E.g. [("cpus", 4.5), ("gpus", 0.1), ("ports", 1000)]
//
// Absent resource entries imply there is no (zero) such resources.
//
// Notes on handling negativity and arithmetic operations: values are guaranteed
// to be positive. This is achieved by construction validation and no public
// mutation interfaces. During construction, `Value::Scalar` arguments must be
// non-negative and finite, and entries with zero quantities will be dropped
// silently. Invalid arguments will result in an error where `Try`
// is returned. For arithmetic operations, non-positive values are silently
// dropped--this is consist with `class Resources`.
//
// Note for posterity, the status quo prior to this class
// was to use stripped-down `Resources` objects for storing
// quantities, however this approach:
//
// (1) did not support quantities of non-scalar resources;
// (2) was error prone, the caller must ensure that no
// `Resource` metatdata (e.g. `DiskInfo`) is present;
// (3) had poor performance, given the `Resources` storage
// model and arithmetic implementation have to operate
// on broader invariants.
class ResourceQuantities
{
public:
// Parse an input string of semicolon separated "name:number" pairs.
// Duplicate names are allowed in the input and will be merged into one entry.
// Entries with zero values will be silently dropped.
//
// Example: "cpus:10;mem:1024;ports:3"
// "cpus:10; mem:1024; ports:3"
// NOTE: we will trim the whitespace around the pair and in the number.
// However, whitespace in "c p us:10" are preserved and will be parsed to
// {"c p us", 10}. This is consistent with `Resources::fromSimpleString()`.
//
// Numbers must be non-negative and finite, otherwise an `Error`
// will be returned.
static Try<ResourceQuantities> fromString(const std::string& text);
// Take scalar `Resources` and combine them into `ResourceQuantities`.
// Only the resource name and its scalar value are used and the rest of the
// meta-data is ignored. It is caller's responsibility to ensure all
// `Resource` entries are of scalar type. Otherwise a `CHECK` error will
// be triggered.
static ResourceQuantities fromScalarResources(const Resources& resources);
// Take `Resources` and combine them into `ResourceQuantities`. This function
// assumes that the provided resources have already been validated; for
// example, it assumes that ranges do not overlap and that sets do not contain
// duplicate items.
static ResourceQuantities fromResources(const Resources& resources);
// Returns the summed up `ResourceQuantities` given a
// `hashmap<Key, ResourceQuantities>`.
template <typename Key>
static ResourceQuantities sum(const hashmap<Key, ResourceQuantities>& map)
{
ResourceQuantities result;
foreachvalue (const ResourceQuantities& quantities, map) {
result += quantities;
}
return result;
}
ResourceQuantities();
explicit ResourceQuantities(
const google::protobuf::Map<std::string, Value::Scalar>& map);
ResourceQuantities(const ResourceQuantities& that) = default;
ResourceQuantities(ResourceQuantities&& that) = default;
ResourceQuantities& operator=(const ResourceQuantities& that) = default;
ResourceQuantities& operator=(ResourceQuantities&& that) = default;
typedef std::vector<std::pair<std::string, Value::Scalar>>::const_iterator
iterator;
typedef std::vector<std::pair<std::string, Value::Scalar>>::const_iterator
const_iterator;
// NOTE: Non-`const` `iterator`, `begin()` and `end()` are __intentionally__
// defined with `const` semantics in order to prevent mutation during
// iteration. Mutation is allowed with the `[]` operator.
const_iterator begin();
const_iterator end();
const_iterator begin() const { return quantities.begin(); }
const_iterator end() const { return quantities.end(); }
size_t size() const { return quantities.size(); };
bool empty() const { return quantities.empty(); }
// Returns the quantity scalar value if a quantity with the given name.
// If the given name is absent, return zero.
Value::Scalar get(const std::string& name) const;
bool contains(const ResourceQuantities& quantities) const;
bool operator==(const ResourceQuantities& quantities) const;
bool operator!=(const ResourceQuantities& quantities) const;
ResourceQuantities& operator+=(const ResourceQuantities& quantities);
ResourceQuantities& operator-=(const ResourceQuantities& quantities);
ResourceQuantities operator+(const ResourceQuantities& quantities) const;
ResourceQuantities operator-(const ResourceQuantities& quantities) const;
private:
void add(const std::string& name, const Value::Scalar& scalar);
void add(const std::string& name, double value);
// List of name quantity pairs sorted by name.
// Arithmetic and comparison operations benefit from this sorting.
std::vector<std::pair<std::string, Value::Scalar>> quantities;
};
std::ostream& operator<<(std::ostream& stream, const ResourceQuantities& q);
// An efficient collection of resource limits. All values are guaranteed
// to be non-negative and finite.
//
// E.g. [("cpus", 4.5), ("gpus", 0.1), ("ports", 1000)]
//
// Difference with `class ResourceQuantities`:
// The main difference resides in the semantics of absent entries and, in turn,
// whether zero values are preserved.
//
// (1) Absent entry in `ResourceQuantities` implies zero quantity. While in
// `ResourceLimits`, absence implies no limit (i.e. infinite amount). This
// affects the semantics of the contains operation.
//
// (2) Zero value preservation: `ResourceLimits` keeps zero value entries
// while `ResourceQuantities` silently drops them. This is in accordance with
// the absence semantic. Zero value and absence are equivalent in
// `ResourceQuantities`. While in `ResourceLimits`, they are not.
class ResourceLimits
{
public:
// Parse an input string of semicolon separated "name:number" pairs.
// Entries with zero values will be preserved (unlike `ResourceQuantities`).
// Duplicate names are NOT allowed in the input, otherwise an `Error` will
// be returned.
//
// Example: "cpus:10;mem:1024;ports:0"
// "cpus:10; mem:1024; ports:0"
// NOTE: we will trim the whitespace around the pair and in the number.
// However, whitespace in "c p us:10" are preserved and will be parsed to
// {"c p us", 10}. This is consistent with `Resources::fromSimpleString()`.
//
// Numbers must be non-negative and finite, otherwise an `Error`
// will be returned.
static Try<ResourceLimits> fromString(const std::string& text);
ResourceLimits();
explicit ResourceLimits(
const google::protobuf::Map<std::string, Value::Scalar>& map);
ResourceLimits(const ResourceLimits& that) = default;
ResourceLimits(ResourceLimits&& that) = default;
ResourceLimits& operator=(const ResourceLimits& that) = default;
ResourceLimits& operator=(ResourceLimits&& that) = default;
typedef std::vector<std::pair<std::string, Value::Scalar>>::const_iterator
iterator;
typedef std::vector<std::pair<std::string, Value::Scalar>>::const_iterator
const_iterator;
// NOTE: Non-`const` `iterator`, `begin()` and `end()` are __intentionally__
// defined with `const` semantics in order to prevent mutation during
// iteration. Mutation is allowed with the `[]` operator.
const_iterator begin();
const_iterator end();
const_iterator begin() const { return limits.begin(); }
const_iterator end() const { return limits.end(); }
size_t size() const { return limits.size(); };
// Returns the limit of the resource with the given name.
// If there is no explicit limit for the resource, return `None()`.
// Note, `None()` implies that the limit of the resource is infinite.
Option<Value::Scalar> get(const std::string& name) const;
// Due to the absence-means-infinite semantic of limits, absent entries,
// intuitively, are considered to contain entries with finite scalar values.
// For example:
// `[ ]`` will always contain any other `ResourceLimits`.
// `[("cpu":1)]` contains `[("mem":1)]` and vice versa.
// `[("cpu":1)]` will not contain `[("cpu":2)]`.
bool contains(const ResourceLimits& right) const;
bool contains(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.
void set(const std::string& name, const Value::Scalar& scalar);
// List of name limit pairs sorted by name.
// Arithmetic and comparison operations benefit from this sorting.
std::vector<std::pair<std::string, Value::Scalar>> limits;
};
} // namespace internal {
} // namespace mesos {
#endif // __COMMON_RESOURCE_QUANTITIES_HPP__