From 4181f7cda8cdf5022244e6c14bfe313112f0b730 Mon Sep 17 00:00:00 2001 From: rodric rabbah Date: Mon, 18 Jun 2018 14:14:00 -0400 Subject: [PATCH] Allow invoker pools to overlap for small N. (#3751) For small N, allow the managed invokers to overlap with blackbox invokers. As an example, for a blackbox fraction of 10%, and two invokers, the blackbox pool will have size 1, but the managed pool will utilize both invokers. --- .../ShardingContainerPoolBalancer.scala | 8 +++--- .../ShardingContainerPoolBalancerTests.scala | 27 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/core/controller/src/main/scala/whisk/core/loadBalancer/ShardingContainerPoolBalancer.scala b/core/controller/src/main/scala/whisk/core/loadBalancer/ShardingContainerPoolBalancer.scala index eb95936460f..bad384288ba 100644 --- a/core/controller/src/main/scala/whisk/core/loadBalancer/ShardingContainerPoolBalancer.scala +++ b/core/controller/src/main/scala/whisk/core/loadBalancer/ShardingContainerPoolBalancer.scala @@ -424,12 +424,14 @@ case class ShardingContainerPoolBalancerState( val oldSize = _invokers.size val newSize = newInvokers.size - val blackboxes = Math.max(1, (newSize.toDouble * blackboxFraction).toInt) - val managed = Math.max(1, newSize - blackboxes) + // for small N, allow the managed invokers to overlap with blackbox invokers, and + // further assume that blackbox invokers << managed invokers + val managed = Math.max(1, Math.ceil(newSize.toDouble * (1 - blackboxFraction)).toInt) + val blackboxes = Math.max(1, Math.floor(newSize.toDouble * blackboxFraction).toInt) _invokers = newInvokers - _blackboxInvokers = _invokers.takeRight(blackboxes) _managedInvokers = _invokers.take(managed) + _blackboxInvokers = _invokers.takeRight(blackboxes) if (oldSize != newSize) { _managedStepSizes = ShardingContainerPoolBalancer.pairwiseCoprimeNumbersUntil(managed) diff --git a/tests/src/test/scala/whisk/core/loadBalancer/test/ShardingContainerPoolBalancerTests.scala b/tests/src/test/scala/whisk/core/loadBalancer/test/ShardingContainerPoolBalancerTests.scala index 49712c237e2..2f8ce9639e5 100644 --- a/tests/src/test/scala/whisk/core/loadBalancer/test/ShardingContainerPoolBalancerTests.scala +++ b/tests/src/test/scala/whisk/core/loadBalancer/test/ShardingContainerPoolBalancerTests.scala @@ -83,6 +83,33 @@ class ShardingContainerPoolBalancerTests extends FlatSpec with Matchers with Str state.blackboxStepSizes shouldBe Seq(1) } + it should "allow managed partition to overlap with blackbox for small N" in { + Seq(0.1, 0.2, 0.3, 0.4, 0.5).foreach { bf => + val state = ShardingContainerPoolBalancerState()(ShardingContainerPoolBalancerConfig(bf, 1)) + + (1 to 100).toSeq.foreach { i => + state.updateInvokers((1 to i).map(_ => healthy(1))) + + withClue(s"invoker count $bf $i:") { + state.managedInvokers.length should be <= i + state.blackboxInvokers should have size Math.max(1, (bf * i).toInt) + + val m = state.managedInvokers.length + val b = state.blackboxInvokers.length + bf match { + // written out explicitly for clarity + case 0.1 if i < 10 => m + b shouldBe i + 1 + case 0.2 if i < 5 => m + b shouldBe i + 1 + case 0.3 if i < 4 => m + b shouldBe i + 1 + case 0.4 if i < 3 => m + b shouldBe i + 1 + case 0.5 if i < 2 => m + b shouldBe i + 1 + case _ => m + b shouldBe i + } + } + } + } + } + it should "update the cluster size, adjusting the invoker slots accordingly" in { val slots = 10 val state = ShardingContainerPoolBalancerState()(ShardingContainerPoolBalancerConfig(0.5, slots))