You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bm...@apache.org on 2018/07/25 23:20:01 UTC

[1/2] mesos git commit: Updated `Slave::getAvailable()` to return all shared resources.

Repository: mesos
Updated Branches:
  refs/heads/master 56d421d4d -> eeb74c036


Updated `Slave::getAvailable()` to return all shared resources.

Currently, `HierarchicalAllocatorProcess::Slave::getAvailable()`
only exposes the unallocated portion of shared resources. However,
we currently always consider a copy of shared resources to be
available for allocation.

This helps us acheive some cleanup of one-off shared resources logic
in the allocation loop.

Review: https://reviews.apache.org/r/67826/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/a9d50efd
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/a9d50efd
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/a9d50efd

Branch: refs/heads/master
Commit: a9d50efd63bf4cc47a49ffe3feaef87dfc0ffa7a
Parents: 56d421d
Author: Meng Zhu <mz...@mesosphere.io>
Authored: Wed Jul 25 15:57:47 2018 -0700
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Wed Jul 25 16:15:30 2018 -0700

----------------------------------------------------------------------
 src/master/allocator/mesos/hierarchical.hpp | 41 +++++++++++++++++-------
 1 file changed, 30 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/a9d50efd/src/master/allocator/mesos/hierarchical.hpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/mesos/hierarchical.hpp b/src/master/allocator/mesos/hierarchical.hpp
index c1a6789..02c63b1 100644
--- a/src/master/allocator/mesos/hierarchical.hpp
+++ b/src/master/allocator/mesos/hierarchical.hpp
@@ -372,14 +372,10 @@ protected:
         capabilities(_capabilities),
         activated(_activated),
         total(_total),
-        allocated(_allocated)
+        allocated(_allocated),
+        shared(_total.shared())
     {
-      // In order to subtract from the total,
-      // we strip the allocation information.
-      Resources allocated_ = allocated;
-      allocated_.unallocate();
-
-      available = total - allocated_;
+      updateAvailable();
     }
 
     const Resources& getTotal() const { return total; }
@@ -390,6 +386,7 @@ protected:
 
     void updateTotal(const Resources& newTotal) {
       total = newTotal;
+      shared = total.shared();
 
       updateAvailable();
     }
@@ -461,7 +458,21 @@ protected:
       Resources allocated_ = allocated;
       allocated_.unallocate();
 
-      available = total - allocated_;
+      // Calling `nonShared()` currently copies the underlying resources
+      // and is therefore rather expensive. We avoid it in the common
+      // case that there are no shared resources.
+      //
+      // TODO(mzhu): Ideally there would be a single logical path here.
+      // One solution is to have `Resources` be copy-on-write such that
+      // `nonShared()` performs no copying and instead points to a
+      // subset of the original `Resource` objects.
+      if (shared.empty()) {
+        available = total - allocated_;
+      } else {
+        // Since shared resources are offerable even when they are in use, we
+        // always include them as part of available resources.
+        available = (total.nonShared() - allocated_.nonShared()) + shared;
+      }
     }
 
     // Total amount of regular *and* oversubscribed resources.
@@ -480,14 +491,22 @@ protected:
     // hasn't reregistered. See MESOS-2919 for details.
     Resources allocated;
 
-    // We track the total and allocated resources on the slave, the
-    // available resources are computed as follows:
+    // We track the total and allocated resources on the slave to
+    // avoid calculating it in place every time.
     //
-    //   available = total - allocated
+    // Note that `available` always contains all the shared resources on the
+    // agent regardless whether they have ever been allocated or not.
+    // NOTE, however, we currently only offer a shared resource only if it has
+    // not been offered in an allocation cycle to a framework. We do this mainly
+    // to preserve the normal offer behavior. This may change in the future
+    // depending on use cases.
     //
     // Note that it's possible for the slave to be over-allocated!
     // In this case, allocated > total.
     Resources available;
+
+    // We keep a copy of the shared resources to avoid unnecessary copying.
+    Resources shared;
   };
 
   hashmap<SlaveID, Slave> slaves;


[2/2] mesos git commit: Added a `stripIncapableResources` helper in the allocator.

Posted by bm...@apache.org.
Added a `stripIncapableResources` helper in the allocator.

This helper removes any resources that the framework is not
capable of receiving based on the given framework capability.

Review: https://reviews.apache.org/r/67827/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/eeb74c03
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/eeb74c03
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/eeb74c03

Branch: refs/heads/master
Commit: eeb74c03695a8311a9c3bf2d2f895c6c25f86266
Parents: a9d50ef
Author: Meng Zhu <mz...@mesosphere.io>
Authored: Wed Jul 25 16:15:48 2018 -0700
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Wed Jul 25 16:15:48 2018 -0700

----------------------------------------------------------------------
 src/master/allocator/mesos/hierarchical.cpp | 115 ++++++++++-------------
 src/master/allocator/mesos/hierarchical.hpp |   9 ++
 2 files changed, 59 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/eeb74c03/src/master/allocator/mesos/hierarchical.cpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/mesos/hierarchical.cpp b/src/master/allocator/mesos/hierarchical.cpp
index 7b4e9db..3599247 100644
--- a/src/master/allocator/mesos/hierarchical.cpp
+++ b/src/master/allocator/mesos/hierarchical.cpp
@@ -1803,21 +1803,14 @@ void HierarchicalAllocatorProcess::__allocate()
           continue;
         }
 
-        // Calculate the currently available resources on the slave, which
-        // is the difference in non-shared resources between total and
-        // allocated, plus all shared resources on the agent (if applicable).
-        Resources available = slave.getAvailable().nonShared();
-
-        // Since shared resources are offerable even when they are in use, we
-        // make one copy of the shared resources available regardless of the
-        // past allocations. Offer a shared resource only if it has not been
-        // offered in this offer cycle to a framework.
-        if (framework.capabilities.sharedResources) {
-          available += slave.getTotal().shared();
-          if (offeredSharedResources.contains(slaveId)) {
-            available -= offeredSharedResources[slaveId];
-          }
-        }
+        // Get the currently available resources on the agent and strip
+        // resources that are incompatible with the framework capabilities.
+        Resources available =
+          stripIncapableResources(slave.getAvailable(), framework.capabilities);
+
+        // Offer a shared resource only if it has not been offered in this
+        // offer cycle to a framework.
+        available -= offeredSharedResources.get(slaveId).getOrElse(Resources());
 
         // In this first stage, we allocate the role's reservations as well as
         // any unreserved resources while ensuring the role stays within its
@@ -1947,21 +1940,6 @@ void HierarchicalAllocatorProcess::__allocate()
           break;
         }
 
-        // When reservation refinements are present, old frameworks without the
-        // RESERVATION_REFINEMENT capability won't be able to understand the
-        // new format. While it's possible to translate the refined reservations
-        // into the old format by "hiding" the intermediate reservations in the
-        // "stack", this leads to ambiguity when processing RESERVE / UNRESERVE
-        // operations. This is due to the loss of information when we drop the
-        // intermediate reservations. Therefore, for now we simply filter out
-        // resources with refined reservations if the framework does not have
-        // the capability.
-        if (!framework.capabilities.reservationRefinement) {
-          toAllocate = toAllocate.filter([](const Resource& resource) {
-            return !Resources::hasRefinedReservations(resource);
-          });
-        }
-
         // If the framework filters these resources, ignore.
         if (isFiltered(frameworkId, role, slaveId, toAllocate)) {
           continue;
@@ -2036,21 +2014,14 @@ void HierarchicalAllocatorProcess::__allocate()
           continue;
         }
 
-        // Calculate the currently available resources on the slave, which
-        // is the difference in non-shared resources between total and
-        // allocated, plus all shared resources on the agent (if applicable).
-        Resources available = slave.getAvailable().nonShared();
-
-        // Since shared resources are offerable even when they are in use, we
-        // make one copy of the shared resources available regardless of the
-        // past allocations. Offer a shared resource only if it has not been
-        // offered in this offer cycle to a framework.
-        if (framework.capabilities.sharedResources) {
-          available += slave.getTotal().shared();
-          if (offeredSharedResources.contains(slaveId)) {
-            available -= offeredSharedResources[slaveId];
-          }
-        }
+        // Get the currently available resources on the agent and strip
+        // resources that are incompatible with the framework capabilities.
+        Resources available =
+          stripIncapableResources(slave.getAvailable(), framework.capabilities);
+
+        // Offer a shared resource only if it has not been offered in this offer
+        // cycle to a framework.
+        available -= offeredSharedResources.get(slaveId).getOrElse(Resources());
 
         // The resources we offer are the unreserved resources as well as the
         // reserved resources for this particular role and all its ancestors
@@ -2076,26 +2047,6 @@ void HierarchicalAllocatorProcess::__allocate()
           break;
         }
 
-        // Remove revocable resources if the framework has not opted for them.
-        if (!framework.capabilities.revocableResources) {
-          toAllocate = toAllocate.nonRevocable();
-        }
-
-        // When reservation refinements are present, old frameworks without the
-        // RESERVATION_REFINEMENT capability won't be able to understand the
-        // new format. While it's possible to translate the refined reservations
-        // into the old format by "hiding" the intermediate reservations in the
-        // "stack", this leads to ambiguity when processing RESERVE / UNRESERVE
-        // operations. This is due to the loss of information when we drop the
-        // intermediate reservations. Therefore, for now we simply filter out
-        // resources with refined reservations if the framework does not have
-        // the capability.
-        if (!framework.capabilities.reservationRefinement) {
-          toAllocate = toAllocate.filter([](const Resource& resource) {
-            return !Resources::hasRefinedReservations(resource);
-          });
-        }
-
         // If allocating these resources would reduce the headroom
         // below what is required, we will hold them back.
         const Resources headroomToAllocate = toAllocate
@@ -2730,6 +2681,40 @@ bool HierarchicalAllocatorProcess::isCapableOfReceivingAgent(
 }
 
 
+Resources HierarchicalAllocatorProcess::stripIncapableResources(
+    const Resources& resources,
+    const protobuf::framework::Capabilities& frameworkCapabilities) const
+{
+  return resources.filter([&](const Resource& resource) {
+    if (!frameworkCapabilities.sharedResources &&
+        Resources::isShared(resource)) {
+      return false;
+    }
+
+    if (!frameworkCapabilities.revocableResources &&
+        Resources::isRevocable(resource)) {
+      return false;
+    }
+
+    // When reservation refinements are present, old frameworks without the
+    // RESERVATION_REFINEMENT capability won't be able to understand the
+    // new format. While it's possible to translate the refined reservations
+    // into the old format by "hiding" the intermediate reservations in the
+    // "stack", this leads to ambiguity when processing RESERVE / UNRESERVE
+    // operations. This is due to the loss of information when we drop the
+    // intermediate reservations. Therefore, for now we simply filter out
+    // resources with refined reservations if the framework does not have
+    // the capability.
+    if (!frameworkCapabilities.reservationRefinement &&
+        Resources::hasRefinedReservations(resource)) {
+      return false;
+    }
+
+    return true;
+  });
+}
+
+
 void HierarchicalAllocatorProcess::trackAllocatedResources(
     const SlaveID& slaveId,
     const FrameworkID& frameworkId,

http://git-wip-us.apache.org/repos/asf/mesos/blob/eeb74c03/src/master/allocator/mesos/hierarchical.hpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/mesos/hierarchical.hpp b/src/master/allocator/mesos/hierarchical.hpp
index 02c63b1..0cd2fac 100644
--- a/src/master/allocator/mesos/hierarchical.hpp
+++ b/src/master/allocator/mesos/hierarchical.hpp
@@ -674,6 +674,15 @@ private:
       const protobuf::framework::Capabilities& frameworkCapabilities,
       const Slave& slave) const;
 
+  // Helper function that removes any resources that the framework is not
+  // capable of receiving based on the given framework capability.
+  //
+  // TODO(mzhu): Make this a `Framework` member function once we pull
+  // `struct Framework` out from being nested.
+  Resources stripIncapableResources(
+      const Resources& resources,
+      const protobuf::framework::Capabilities& frameworkCapabilities) const;
+
   // Helper to track allocated resources on an agent.
   void trackAllocatedResources(
       const SlaveID& slaveId,