Apache Mesos
resource_quantities.hpp
Go to the documentation of this file.
1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #ifndef __COMMON_RESOURCE_QUANTITIES_HPP__
18 #define __COMMON_RESOURCE_QUANTITIES_HPP__
19 
20 #include <string>
21 #include <utility>
22 
23 #include <boost/container/small_vector.hpp>
24 
25 #include <mesos/mesos.hpp>
26 
27 #include <stout/hashmap.hpp>
28 #include <stout/try.hpp>
29 
30 namespace mesos {
31 
32 // Forward declaration.
33 class Resources;
34 
35 class ResourceLimits;
36 
37 
38 // An efficient collection of resource quantities. All values are guaranteed
39 // to be positive and finite.
40 //
41 // E.g. [("cpus", 4.5), ("gpus", 0.1), ("ports", 1000)]
42 //
43 // Absent resource entries imply there is no (zero) such resources.
44 //
45 // Notes on handling negativity and arithmetic operations: values are guaranteed
46 // to be positive. This is achieved by construction validation and no public
47 // mutation interfaces. During construction, `Value::Scalar` arguments must be
48 // non-negative and finite, and entries with zero quantities will be dropped
49 // silently. Invalid arguments will result in an error where `Try`
50 // is returned. For arithmetic operations, non-positive values are silently
51 // dropped--this is consist with `class Resources`.
52 //
53 // Note for posterity, the status quo prior to this class
54 // was to use stripped-down `Resources` objects for storing
55 // quantities, however this approach:
56 //
57 // (1) did not support quantities of non-scalar resources;
58 // (2) was error prone, the caller must ensure that no
59 // `Resource` metatdata (e.g. `DiskInfo`) is present;
60 // (3) had poor performance, given the `Resources` storage
61 // model and arithmetic implementation have to operate
62 // on broader invariants.
64 {
65 public:
66  // Parse an input string of semicolon separated "name:number" pairs.
67  // Duplicate names are allowed in the input and will be merged into one entry.
68  // Entries with zero values will be silently dropped.
69  //
70  // Example: "cpus:10;mem:1024;ports:3"
71  // "cpus:10; mem:1024; ports:3"
72  // NOTE: we will trim the whitespace around the pair and in the number.
73  // However, whitespace in "c p us:10" are preserved and will be parsed to
74  // {"c p us", 10}. This is consistent with `Resources::fromSimpleString()`.
75  //
76  // Numbers must be non-negative and finite, otherwise an `Error`
77  // will be returned.
78  static Try<ResourceQuantities> fromString(const std::string& text);
79 
80  // Take scalar `Resources` and combine them into `ResourceQuantities`.
81  // Only the resource name and its scalar value are used and the rest of the
82  // meta-data is ignored. It is caller's responsibility to ensure all
83  // `Resource` entries are of scalar type. Otherwise a `CHECK` error will
84  // be triggered.
85  static ResourceQuantities fromScalarResources(const Resources& resources);
86 
87  // Same as above, but takes a single Resource that must be valid
88  // and of scalar type.
89  static ResourceQuantities fromScalarResource(const Resource& resource);
90 
91  // Take `Resources` and combine them into `ResourceQuantities`. This function
92  // assumes that the provided resources have already been validated; for
93  // example, it assumes that ranges do not overlap and that sets do not contain
94  // duplicate items.
95  static ResourceQuantities fromResources(const Resources& resources);
96 
97  // Returns the summed up `ResourceQuantities` given a
98  // `hashmap<Key, ResourceQuantities>`.
99  template <typename Key>
101  {
102  ResourceQuantities result;
103 
104  foreachvalue (const ResourceQuantities& quantities, map) {
105  result += quantities;
106  }
107 
108  return result;
109  }
110 
112 
113  explicit ResourceQuantities(
114  const google::protobuf::Map<std::string, Value::Scalar>& map);
115 
116  ResourceQuantities(const ResourceQuantities& that) = default;
117  ResourceQuantities(ResourceQuantities&& that) = default;
118 
119  ResourceQuantities& operator=(const ResourceQuantities& that) = default;
121 
122  typedef boost::container::small_vector_base<
123  std::pair<std::string, Value::Scalar> >::const_iterator iterator;
124  typedef boost::container::small_vector_base<
125  std::pair<std::string, Value::Scalar> >::const_iterator const_iterator;
126 
127  // NOTE: Non-`const` `iterator`, `begin()` and `end()` are __intentionally__
128  // defined with `const` semantics in order to prevent mutation during
129  // iteration. Mutation is allowed with the `[]` operator.
130  const_iterator begin();
131  const_iterator end();
132 
133  const_iterator begin() const { return quantities.begin(); }
134  const_iterator end() const { return quantities.end(); }
135 
136  size_t size() const { return quantities.size(); };
137 
138  bool empty() const { return quantities.empty(); }
139 
140  // Returns the quantity scalar value if a quantity with the given name.
141  // If the given name is absent, return zero.
142  Value::Scalar get(const std::string& name) const;
143 
144  bool contains(const ResourceQuantities& quantities) const;
145 
146  bool operator==(const ResourceQuantities& quantities) const;
147  bool operator!=(const ResourceQuantities& quantities) const;
148 
151 
152  ResourceQuantities operator+(const ResourceQuantities& quantities) const;
153  ResourceQuantities operator-(const ResourceQuantities& quantities) const;
154 
155 private:
156  friend class ResourceLimits;
157 
158  void add(const std::string& name, const Value::Scalar& scalar);
159  void add(const std::string& name, double value);
160 
161  // List of name quantity pairs sorted by name.
162  // Arithmetic and comparison operations benefit from this sorting.
163  //
164  // Pre-allocate space for first-class resources, plus some margins.
165  // This needs to be updated as introduce more first-class resources.
166  // [cpus, disk, gpus, mem, ports]
167  boost::container::small_vector<std::pair<std::string, Value::Scalar>, 7>
168  quantities;
169 };
170 
171 
172 std::ostream& operator<<(std::ostream& stream, const ResourceQuantities& q);
173 
174 
175 // An efficient collection of resource limits. All values are guaranteed
176 // to be non-negative and finite.
177 //
178 // E.g. [("cpus", 4.5), ("gpus", 0.1), ("ports", 1000)]
179 //
180 // Difference with `class ResourceQuantities`:
181 // The main difference resides in the semantics of absent entries and, in turn,
182 // whether zero values are preserved.
183 //
184 // (1) Absent entry in `ResourceQuantities` implies zero quantity. While in
185 // `ResourceLimits`, absence implies no limit (i.e. infinite amount). This
186 // affects the semantics of the contains operation.
187 //
188 // (2) Zero value preservation: `ResourceLimits` keeps zero value entries
189 // while `ResourceQuantities` silently drops them. This is in accordance with
190 // the absence semantic. Zero value and absence are equivalent in
191 // `ResourceQuantities`. While in `ResourceLimits`, they are not.
193 {
194 public:
195  // Parse an input string of semicolon separated "name:number" pairs.
196  // Entries with zero values will be preserved (unlike `ResourceQuantities`).
197  // Duplicate names are NOT allowed in the input, otherwise an `Error` will
198  // be returned.
199  //
200  // Example: "cpus:10;mem:1024;ports:0"
201  // "cpus:10; mem:1024; ports:0"
202  // NOTE: we will trim the whitespace around the pair and in the number.
203  // However, whitespace in "c p us:10" are preserved and will be parsed to
204  // {"c p us", 10}. This is consistent with `Resources::fromSimpleString()`.
205  //
206  // Numbers must be non-negative and finite, otherwise an `Error`
207  // will be returned.
208  static Try<ResourceLimits> fromString(const std::string& text);
209 
210  ResourceLimits();
211 
212  explicit ResourceLimits(
213  const google::protobuf::Map<std::string, Value::Scalar>& map);
214 
215  ResourceLimits(const ResourceLimits& that) = default;
216  ResourceLimits(ResourceLimits&& that) = default;
217 
218  ResourceLimits& operator=(const ResourceLimits& that) = default;
219  ResourceLimits& operator=(ResourceLimits&& that) = default;
220 
221  typedef boost::container::small_vector_base<
222  std::pair<std::string, Value::Scalar> >::const_iterator iterator;
223  typedef boost::container::small_vector_base<
224  std::pair<std::string, Value::Scalar> >::const_iterator const_iterator;
225 
226  // NOTE: Non-`const` `iterator`, `begin()` and `end()` are __intentionally__
227  // defined with `const` semantics in order to prevent mutation during
228  // iteration. Mutation is allowed with the `[]` operator.
229  const_iterator begin();
230  const_iterator end();
231 
232  const_iterator begin() const { return limits.begin(); }
233  const_iterator end() const { return limits.end(); }
234 
235  size_t size() const { return limits.size(); };
236 
237  bool empty() const { return limits.empty(); }
238 
239  // Returns the limit of the resource with the given name.
240  // If there is no explicit limit for the resource, return `None()`.
241  // Note, `None()` implies that the limit of the resource is infinite.
242  Option<Value::Scalar> get(const std::string& name) const;
243 
244  // Due to the absence-means-infinite semantic of limits, absent entries,
245  // intuitively, are considered to contain entries with finite scalar values.
246  // For example:
247  // `[ ]`` will always contain any other `ResourceLimits`.
248  // `[("cpu":1)]` contains `[("mem":1)]` and vice versa.
249  // `[("cpu":1)]` will not contain `[("cpu":2)]`.
250  bool contains(const ResourceLimits& right) const;
251 
252  bool operator==(const ResourceLimits& limits) const;
253  bool operator!=(const ResourceLimits& limits) const;
254 
255  bool contains(const ResourceQuantities& quantities) const;
256 
257  ResourceLimits& operator-=(const ResourceQuantities& quantities);
258  ResourceLimits operator-(const ResourceQuantities& quantities) const;
259 
260 private:
261  // Set the limit of the resource with `name` to `scalar`.
262  // Note, the existing limit of the resource will be overwritten.
263  void set(const std::string& name, const Value::Scalar& scalar);
264 
265  // List of name limit pairs sorted by name.
266  // Arithmetic and comparison operations benefit from this sorting.
267  //
268  // Pre-allocate space for first-class resources, plus some margins.
269  // This needs to be updated as introduce more first-class resources.
270  // [cpus, disk, gpus, mem, ports]
271  boost::container::small_vector<std::pair<std::string, Value::Scalar>, 7>
272  limits;
273 };
274 
275 
276 std::ostream& operator<<(std::ostream& stream, const ResourceLimits& limits);
277 
278 
279 } // namespace mesos {
280 
281 #endif // __COMMON_RESOURCE_QUANTITIES_HPP__
std::ostream & operator<<(std::ostream &stream, const Attribute &attribute)
bool operator!=(const ResourceQuantities &quantities) const
bool contains(const ResourceQuantities &quantities) const
bool empty() const
Definition: resource_quantities.hpp:138
Definition: option.hpp:29
size_t size() const
Definition: resource_quantities.hpp:136
Definition: resource_quantities.hpp:192
ResourceQuantities operator-(const ResourceQuantities &quantities) const
size_t size() const
Definition: resource_quantities.hpp:235
Definition: check.hpp:33
static ResourceQuantities fromResources(const Resources &resources)
boost::container::small_vector_base< std::pair< std::string, Value::Scalar > >::const_iterator const_iterator
Definition: resource_quantities.hpp:224
Definition: resource_quantities.hpp:63
bool empty() const
Definition: resource_quantities.hpp:237
Definition: resources.hpp:83
const_iterator begin() const
Definition: resource_quantities.hpp:133
ResourceQuantities & operator-=(const ResourceQuantities &quantities)
Future< Nothing > add(const T &metric)
Definition: metrics.hpp:95
Definition: hashmap.hpp:38
ResourceQuantities operator+(const ResourceQuantities &quantities) const
boost::container::small_vector_base< std::pair< std::string, Value::Scalar > >::const_iterator const_iterator
Definition: resource_quantities.hpp:125
static ResourceQuantities fromScalarResources(const Resources &resources)
static ResourceQuantities fromScalarResource(const Resource &resource)
Definition: agent.hpp:25
const_iterator end()
friend class ResourceLimits
Definition: resource_quantities.hpp:156
boost::container::small_vector_base< std::pair< std::string, Value::Scalar > >::const_iterator iterator
Definition: resource_quantities.hpp:123
#define foreachvalue(VALUE, ELEMS)
Definition: foreach.hpp:77
static Try< ResourceQuantities > fromString(const std::string &text)
const_iterator begin()
const_iterator end() const
Definition: resource_quantities.hpp:134
ResourceQuantities & operator=(const ResourceQuantities &that)=default
Iterable< V > map(F &&f, const Iterable< U, Us... > &input)
Definition: lambda.hpp:46
bool operator==(const ResourceQuantities &quantities) const
boost::container::small_vector_base< std::pair< std::string, Value::Scalar > >::const_iterator iterator
Definition: resource_quantities.hpp:222
ResourceQuantities & operator+=(const ResourceQuantities &quantities)
static ResourceQuantities sum(const hashmap< Key, ResourceQuantities > &map)
Definition: resource_quantities.hpp:100
const_iterator begin() const
Definition: resource_quantities.hpp:232
constexpr const char * name
Definition: shell.hpp:41
const_iterator end() const
Definition: resource_quantities.hpp:233