You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by me...@apache.org on 2016/03/09 09:51:11 UTC

[3/4] mesos git commit: Addressed comments of 41672.

Addressed comments of 41672.

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


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

Branch: refs/heads/master
Commit: 17ed0eeadeddd7df6d83e825efc37525c8b8453b
Parents: feef247
Author: Yongqiao Wang <yq...@cn.ibm.com>
Authored: Tue Mar 8 23:47:46 2016 -0800
Committer: Adam B <ad...@mesosphere.io>
Committed: Tue Mar 8 23:49:49 2016 -0800

----------------------------------------------------------------------
 src/tests/hierarchical_allocator_tests.cpp | 421 +++++++++++++-----------
 1 file changed, 224 insertions(+), 197 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/17ed0eea/src/tests/hierarchical_allocator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/hierarchical_allocator_tests.cpp b/src/tests/hierarchical_allocator_tests.cpp
index 3e4ad31..7ff227d 100644
--- a/src/tests/hierarchical_allocator_tests.cpp
+++ b/src/tests/hierarchical_allocator_tests.cpp
@@ -230,6 +230,35 @@ protected:
     return weightInfo;
   }
 
+  void handleAllocationsAndRecoverResources(
+      Resources& totalAllocatedResources,
+      hashmap<FrameworkID, Allocation>& frameworkAllocations,
+      int allocationsCount,
+      bool recoverResources)
+  {
+    for (unsigned i = 0; i < allocationsCount; i++) {
+      Future<Allocation> allocation = allocations.get();
+      AWAIT_READY(allocation);
+
+      frameworkAllocations[allocation.get().frameworkId] = allocation.get();
+      totalAllocatedResources += Resources::sum(allocation.get().resources);
+
+      if (recoverResources) {
+        // Recover the allocated resources so they can be offered again
+        // next time.
+        foreachpair (const SlaveID& slaveId,
+                     const Resources& resources,
+                     allocation.get().resources) {
+          allocator->recoverResources(
+              allocation.get().frameworkId,
+              slaveId,
+              resources,
+              None());
+        }
+      }
+    }
+  }
+
 protected:
   master::Flags flags;
 
@@ -2377,6 +2406,201 @@ TEST_F(HierarchicalAllocatorTest, DeactivateAndReactivateFramework)
 }
 
 
+// This test ensures that resource allocation is done according to each role's
+// weight. This is done by having six agents and three frameworks and making
+// sure each framework gets the appropriate number of resources.
+TEST_F(HierarchicalAllocatorTest, UpdateWeight)
+{
+  // Pausing the clock is not necessary, but ensures that the test
+  // doesn't rely on the batch allocation in the allocator, which
+  // would slow down the test.
+  Clock::pause();
+
+  initialize();
+
+  // Define some constants to make the code read easily.
+  const string SINGLE_RESOURCE = "cpus:2;mem:1024";
+  const string DOUBLE_RESOURCES = "cpus:4;mem:2048";
+  const string TRIPLE_RESOURCES = "cpus:6;mem:3072";
+  const string FOURFOLD_RESOURCES = "cpus:8;mem:4096";
+  const string TOTAL_RESOURCES = "cpus:12;mem:6144";
+
+  // Register six agents with the same resources (cpus:2;mem:1024).
+  vector<SlaveInfo> agents;
+  for (unsigned i = 0; i < 6; i++) {
+    SlaveInfo agent = createSlaveInfo(SINGLE_RESOURCE);
+    agents.push_back(agent);
+    allocator->addSlave(agent.id(), agent, None(), agent.resources(), {});
+  }
+
+  // Total cluster resources (6 agents): cpus=12, mem=6144.
+
+  // Framework1 registers with 'role1' which uses the default weight (1.0),
+  // and all resources will be offered to this framework since it is the only
+  // framework running so far.
+  FrameworkInfo framework1 = createFrameworkInfo("role1");
+  allocator->addFramework(framework1.id(), framework1, {});
+
+  // Framework2 registers with 'role2' which also uses the default weight.
+  // It will not get any offers due to all resources having outstanding offers
+  // to framework1 when it registered.
+  FrameworkInfo framework2 = createFrameworkInfo("role2");
+  allocator->addFramework(framework2.id(), framework2, {});
+
+  Future<Allocation> allocation = allocations.get();
+  AWAIT_READY(allocation);
+
+  // role1 share = 1 (cpus=12, mem=6144)
+  //   framework1 share = 1
+  // role2 share = 0
+  //   framework2 share = 0
+
+  ASSERT_EQ(allocation.get().frameworkId, framework1.id());
+  ASSERT_EQ(6u, allocation.get().resources.size());
+  EXPECT_EQ(Resources::parse(TOTAL_RESOURCES).get(),
+            Resources::sum(allocation.get().resources));
+
+  // Recover all resources so they can be offered again next time.
+  foreachpair (const SlaveID& slaveId,
+               const Resources& resources,
+               allocation.get().resources) {
+    allocator->recoverResources(
+        allocation.get().frameworkId,
+        slaveId,
+        resources,
+        None());
+  }
+
+  // Tests whether `framework1` and `framework2` each get half of the resources
+  // when their roles' weights are 1:1.
+  {
+    // Advance the clock and trigger a batch allocation.
+    Clock::advance(flags.allocation_interval);
+    Clock::settle();
+
+    // role1 share = 0.5 (cpus=6, mem=3072)
+    //   framework1 share = 1
+    // role2 share = 0.5 (cpus=6, mem=3072)
+    //   framework2 share = 1
+
+    // Ensure that all resources are offered equally between both frameworks,
+    // since each framework's role has a weight of 1.0 by default.
+    hashmap<FrameworkID, Allocation> frameworkAllocations;
+    Resources totalAllocatedResources;
+    handleAllocationsAndRecoverResources(totalAllocatedResources,
+        frameworkAllocations, 2, true);
+
+    // Framework1 should get one allocation with three agents.
+    ASSERT_EQ(3u, frameworkAllocations[framework1.id()].resources.size());
+    EXPECT_EQ(Resources::parse(TRIPLE_RESOURCES).get(),
+        Resources::sum(frameworkAllocations[framework1.id()].resources));
+
+    // Framework2 should also get one allocation with three agents.
+    ASSERT_EQ(3u, frameworkAllocations[framework2.id()].resources.size());
+    EXPECT_EQ(Resources::parse(TRIPLE_RESOURCES).get(),
+        Resources::sum(frameworkAllocations[framework2.id()].resources));
+
+    // Check to ensure that these two allocations sum to the total resources;
+    // this check can ensure there are only two allocations in this case.
+    EXPECT_EQ(Resources::parse(TOTAL_RESOURCES).get(), totalAllocatedResources);
+  }
+
+  // Tests whether `framework1` gets 1/3 of the resources and `framework2` gets
+  // 2/3 of the resources when their roles' weights are 1:2.
+  {
+    // Update the weight of framework2's role to 2.0.
+    vector<WeightInfo> weightInfos;
+    weightInfos.push_back(createWeightInfo(framework2.role(), 2.0));
+    allocator->updateWeights(weightInfos);
+
+    // 'updateWeights' will trigger the allocation immediately, so it does not
+    // need to manually advance the clock here.
+    Clock::settle();
+
+    // role1 share = 0.33 (cpus=4, mem=2048)
+    //   framework1 share = 1
+    // role2 share = 0.66 (cpus=8, mem=4096)
+    //   framework2 share = 1
+
+    // Now that the frameworks's weights are 1:2, ensure that all
+    // resources are offered with a ratio of 1:2 between both frameworks.
+    hashmap<FrameworkID, Allocation> frameworkAllocations;
+    Resources totalAllocatedResources;
+    handleAllocationsAndRecoverResources(totalAllocatedResources,
+        frameworkAllocations, 2, true);
+
+    // Framework1 should get one allocation with two agents.
+    ASSERT_EQ(2u, frameworkAllocations[framework1.id()].resources.size());
+    EXPECT_EQ(Resources::parse(DOUBLE_RESOURCES).get(),
+        Resources::sum(frameworkAllocations[framework1.id()].resources));
+
+    // Framework2 should get one allocation with four agents.
+    ASSERT_EQ(4u, frameworkAllocations[framework2.id()].resources.size());
+    EXPECT_EQ(Resources::parse(FOURFOLD_RESOURCES).get(),
+        Resources::sum(frameworkAllocations[framework2.id()].resources));
+
+    // Check to ensure that these two allocations sum to the total resources;
+    // this check can ensure there are only two allocations in this case.
+    EXPECT_EQ(Resources::parse(TOTAL_RESOURCES).get(), totalAllocatedResources);
+  }
+
+  // Tests whether `framework1` gets 1/6 of the resources, `framework2` gets
+  // 2/6 of the resources and `framework3` gets 3/6 of the resources when their
+  // roles' weights are 1:2:3.
+  {
+    // Add a new role with a weight of 3.0.
+    vector<WeightInfo> weightInfos;
+    weightInfos.push_back(createWeightInfo("role3", 3.0));
+    allocator->updateWeights(weightInfos);
+
+    // 'updateWeights' will not trigger the allocation immediately because no
+    // framework exists in 'role3' yet.
+
+    // Framework3 registers with 'role3'.
+    FrameworkInfo framework3 = createFrameworkInfo("role3");
+    allocator->addFramework(framework3.id(), framework3, {});
+
+    // 'addFramework' will trigger the allocation immediately, so it does not
+    // need to manually advance the clock here.
+    Clock::settle();
+
+    // role1 share = 0.166 (cpus=2, mem=1024)
+    //   framework1 share = 1
+    // role2 share = 0.333 (cpus=4, mem=2048)
+    //   framework2 share = 1
+    // role3 share = 0.50 (cpus=6, mem=3072)
+    //   framework3 share = 1
+
+    // Currently, there are three frameworks and six agents in this cluster,
+    // and the weight ratio of these frameworks is 1:2:3, therefore frameworks
+    // will get the proper resource ratio of 1:2:3.
+    hashmap<FrameworkID, Allocation> frameworkAllocations;
+    Resources totalAllocatedResources;
+    handleAllocationsAndRecoverResources(totalAllocatedResources,
+        frameworkAllocations, 3, false);
+
+    // Framework1 should get one allocation with one agent.
+    ASSERT_EQ(1u, frameworkAllocations[framework1.id()].resources.size());
+    EXPECT_EQ(Resources::parse(SINGLE_RESOURCE).get(),
+        Resources::sum(frameworkAllocations[framework1.id()].resources));
+
+    // Framework2 should get one allocation with two agents.
+    ASSERT_EQ(2u, frameworkAllocations[framework2.id()].resources.size());
+    EXPECT_EQ(Resources::parse(DOUBLE_RESOURCES).get(),
+        Resources::sum(frameworkAllocations[framework2.id()].resources));
+
+    // Framework3 should get one allocation with three agents.
+    ASSERT_EQ(3u, frameworkAllocations[framework3.id()].resources.size());
+    EXPECT_EQ(Resources::parse(TRIPLE_RESOURCES).get(),
+        Resources::sum(frameworkAllocations[framework3.id()].resources));
+
+    // Check to ensure that these three allocations sum to the total resources;
+    // this check can ensure there are only three allocations in this case.
+    EXPECT_EQ(Resources::parse(TOTAL_RESOURCES).get(), totalAllocatedResources);
+  }
+}
+
+
 class HierarchicalAllocator_BENCHMARK_Test
   : public HierarchicalAllocatorTestBase,
     public WithParamInterface<std::tr1::tuple<size_t, size_t>> {};
@@ -2765,203 +2989,6 @@ TEST_F(HierarchicalAllocator_BENCHMARK_Test, ResourceLabels)
   Clock::resume();
 }
 
-
-// This test ensures that resource allocation is done per role's weight.
-// This is done by having six slaves and three frameworks and making sure each
-// framework gets the number of resources by their role's weight.
-TEST_F(HierarchicalAllocatorTest, UpdateWeight)
-{
-  // Pausing the clock is not necessary, but ensures that the test
-  // doesn't rely on the periodic allocation in the allocator, which
-  // would slow down the test.
-  Clock::pause();
-
-  initialize();
-
-  // Register six slaves with the same resources (cpus:2;mem:1024).
-  vector<SlaveInfo> slaves;
-  const string SINGLE_RESOURCE = "cpus:2;mem:1024";
-  const string DOUBLE_RESOURCES = "cpus:4;mem:2048";
-  const string TRIPLE_RESOURCES = "cpus:6;mem:3072";
-  const string FOURFOLD_RESOURCES = "cpus:8;mem:4096";
-  const string TOTAL_RESOURCES = "cpus:12;mem:6144";
-  for (unsigned i = 0; i < 6; i++) {
-    slaves.push_back(createSlaveInfo(SINGLE_RESOURCE));
-  }
-
-  foreach (const SlaveInfo& slave, slaves) {
-    allocator->addSlave(
-        slave.id(),
-        slave,
-        None(),
-        slave.resources(),
-        hashmap<FrameworkID, Resources>());
-  }
-
-  // Framework1 registers with 'role1' which uses the default
-  // weight (1.0), and all resources will be offered to this framework.
-  FrameworkInfo framework1 = createFrameworkInfo("role1");
-  allocator->addFramework(
-      framework1.id(), framework1, hashmap<SlaveID, Resources>());
-
-  // Framework2 registers with 'role2' which also uses the
-  // default weight (1.0).
-  FrameworkInfo framework2 = createFrameworkInfo("role2");
-  allocator->addFramework(
-      framework2.id(), framework2, hashmap<SlaveID, Resources>());
-
-  // Framework1 gets one allocation with all resources, and Framework2
-  // does not get any offers due to all resources having outstanding
-  // offers to framework1 when it registered.
-  // Recover all resources owned by framework1 so they can be offered
-  // again next time.
-  Future<Allocation> allocation = allocations.get();
-  AWAIT_READY(allocation);
-  ASSERT_EQ(allocation.get().frameworkId, framework1.id());
-  ASSERT_EQ(6u, allocation.get().resources.size());
-  EXPECT_EQ(Resources::parse(TOTAL_RESOURCES).get(),
-            Resources::sum(allocation.get().resources));
-  foreachpair (const SlaveID& slaveId,
-               const Resources& resources,
-               allocation.get().resources) {
-    allocator->recoverResources(
-        allocation.get().frameworkId,
-        slaveId,
-        resources,
-        None());
-  }
-
-  // Because each framework's role has a weight of 1.0 by default, test to
-  // ensure that all resources are offered equally between both frameworks.
-  hashmap<FrameworkID, size_t> counts;
-  Clock::advance(flags.allocation_interval);
-  Resources totalAllocatedResources1;
-  for (unsigned i = 0; i < 2; i++) {
-    Future<Allocation> allocation = allocations.get();
-    AWAIT_READY(allocation);
-    counts[allocation.get().frameworkId]++;
-    totalAllocatedResources1 += Resources::sum(allocation.get().resources);
-
-    // Each framework will get one allocation with three slaves.
-    ASSERT_EQ(3u, allocation.get().resources.size());
-    EXPECT_EQ(Resources::parse(TRIPLE_RESOURCES).get(),
-              Resources::sum(allocation.get().resources));
-
-    // Recover the offered resources so they can be offered again next time.
-    foreachpair (const SlaveID& slaveId,
-                 const Resources& resources,
-                 allocation.get().resources) {
-      allocator->recoverResources(
-          allocation.get().frameworkId,
-          slaveId,
-          resources,
-          None());
-    }
-  }
-
-  // Check to ensure that these two allocations sum to the total resources,
-  // this check can ensure there are only two allocations in this case.
-  EXPECT_EQ(Resources::parse(TOTAL_RESOURCES).get(), totalAllocatedResources1);
-  EXPECT_EQ(1u, counts[framework1.id()]);
-  EXPECT_EQ(1u, counts[framework2.id()]);
-
-  // Update the weight of framework2's role to 2.0, then their
-  // weights should be 1:2.
-  vector<WeightInfo> weightInfos1;
-  weightInfos1.push_back(createWeightInfo(framework2.role(), 2.0));
-  allocator->updateWeights(weightInfos1);
-
-  // Now that the frameworks's weights are 1:2, test to ensure that all
-  // resources are offered with a ratio of 1:2 between both frameworks.
-  counts.clear();
-  Resources totalAllocatedResources2;
-  Clock::advance(flags.allocation_interval);
-  for (unsigned i = 0; i < 2; i++) {
-    Future<Allocation> allocation = allocations.get();
-    AWAIT_READY(allocation);
-    counts[allocation.get().frameworkId]++;
-    totalAllocatedResources2 += Resources::sum(allocation.get().resources);
-
-    // Framework1 should get one allocation with two slaves.
-    if (allocation.get().frameworkId == framework1.id()) {
-      ASSERT_EQ(2u, allocation.get().resources.size());
-      EXPECT_EQ(Resources::parse(DOUBLE_RESOURCES).get(),
-                Resources::sum(allocation.get().resources));
-    } else {
-      // Framework2 should get one allocation with four slaves.
-      ASSERT_EQ(allocation.get().frameworkId, framework2.id());
-      ASSERT_EQ(4u, allocation.get().resources.size());
-      EXPECT_EQ(Resources::parse(FOURFOLD_RESOURCES).get(),
-                Resources::sum(allocation.get().resources));
-    }
-
-    // Recover the allocated resources so they can be offered again next time.
-    foreachpair (const SlaveID& slaveId,
-                 const Resources& resources,
-                 allocation.get().resources) {
-      allocator->recoverResources(
-          allocation.get().frameworkId,
-          slaveId,
-          resources,
-          None());
-    }
-  }
-  // Check to ensure that these two allocations sum to the total resources,
-  // this check can ensure there are only two allocations in this case.
-  EXPECT_EQ(Resources::parse(TOTAL_RESOURCES).get(), totalAllocatedResources2);
-  EXPECT_EQ(1u, counts[framework1.id()]);
-  EXPECT_EQ(1u, counts[framework2.id()]);
-
-  // Add a new role with a weight of 3.0.
-  vector<WeightInfo> weightInfos2;
-  weightInfos2.push_back(createWeightInfo("role3", 3.0));
-  allocator->updateWeights(weightInfos2);
-
-  // Framework3 registers with 'role3'.
-  FrameworkInfo framework3 = createFrameworkInfo("role3");
-  allocator->addFramework(
-      framework3.id(), framework3, hashmap<SlaveID, Resources>());
-
-  // Currently, there are three frameworks and six slaves in this cluster,
-  // and the weight ratio of these frameworks is 1:2:3, therefore frameworks
-  // will get the proper resource ratio of 1:2:3.
-  counts.clear();
-  Resources totalAllocatedResources3;
-  for (unsigned i = 0; i < 3; i++) {
-    Future<Allocation> allocation = allocations.get();
-    AWAIT_READY(allocation);
-    counts[allocation.get().frameworkId]++;
-    totalAllocatedResources3 += Resources::sum(allocation.get().resources);
-
-    // Framework1 should get one allocation with one slave.
-    if (allocation.get().frameworkId == framework1.id()) {
-      ASSERT_EQ(1u, allocation.get().resources.size());
-      EXPECT_EQ(Resources::parse(SINGLE_RESOURCE).get(),
-                Resources::sum(allocation.get().resources));
-    } else if (allocation.get().frameworkId == framework2.id()) {
-      // Framework2 should get one allocation with two slaves.
-      ASSERT_EQ(2u, allocation.get().resources.size());
-      EXPECT_EQ(Resources::parse(DOUBLE_RESOURCES).get(),
-                Resources::sum(allocation.get().resources));
-    } else {
-      // Framework3 should get one allocation with three slaves.
-      ASSERT_EQ(allocation.get().frameworkId, framework3.id());
-      ASSERT_EQ(3u, allocation.get().resources.size());
-      EXPECT_EQ(Resources::parse(TRIPLE_RESOURCES).get(),
-                Resources::sum(allocation.get().resources));
-    }
-  }
-
-  // Check to ensure that these three allocations sum to the total resources,
-  // this check can ensure there are only three allocations in this case.
-  EXPECT_EQ(Resources::parse(TOTAL_RESOURCES).get(), totalAllocatedResources3);
-  EXPECT_EQ(1u, counts[framework1.id()]);
-  EXPECT_EQ(1u, counts[framework2.id()]);
-  EXPECT_EQ(1u, counts[framework3.id()]);
-
-  Clock::resume();
-}
-
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {