public void LeastShardAllocationStrategy_should_allocate_to_region_with_least_number_of_shards()
        {
            var allocations = new Dictionary <IActorRef, IImmutableList <string> >
            {
                { _regionA, new [] { "shard1" }.ToImmutableList() },
                { _regionB, new [] { "shard2" }.ToImmutableList() },
                { _regionC, ImmutableList <string> .Empty }
            }.ToImmutableDictionary();

            var result = _allocationStrategy.AllocateShard(_regionA, "shard3", allocations).Result;

            Assert.Equal(result, _regionC);
        }
        private void HandleGetShardHome(GetShardHome getShardHome)
        {
            var shard = getShardHome.Shard;

            if (_rebalanceInProgress.Contains(shard))
            {
                Log.Debug("GetShardHome [{0}] request ignored, because rebalance is in progress for this shard.", shard);
            }
            else if (!HasAllRegionsRegistered())
            {
                Log.Debug("GetShardHome [{0}] request ignored, because not all regions have registered yet.", shard);
            }
            else
            {
                if (_currentState.Shards.TryGetValue(shard, out var region))
                {
                    if (_regionTerminationInProgress.Contains(region))
                    {
                        Log.Debug("GetShardHome [{0}] request ignored, due to region [{1}] termination in progress.", shard, region);
                    }
                    else
                    {
                        Sender.Tell(new ShardHome(shard, region));
                    }
                }
                else
                {
                    var activeRegions = _currentState.Regions.RemoveRange(_gracefullShutdownInProgress);
                    if (activeRegions.Count != 0)
                    {
                        var getShardHomeSender = Sender;
                        var regionTask         = AllocationStrategy.AllocateShard(getShardHomeSender, shard, activeRegions);

                        // if task completed immediately, just continue
                        if (regionTask.IsCompleted && !regionTask.IsFaulted)
                        {
                            ContinueGetShardHome(shard, regionTask.Result, getShardHomeSender);
                        }
                        else
                        {
                            regionTask.ContinueWith(t => !(t.IsFaulted || t.IsCanceled)
                                ? new AllocateShardResult(shard, t.Result, getShardHomeSender)
                                : new AllocateShardResult(shard, null, getShardHomeSender), TaskContinuationOptions.ExecuteSynchronously)
                            .PipeTo(Self);
                        }
                    }
                }
            }
        }
        internal static IImmutableDictionary <IActorRef, IImmutableList <string> > AfterRebalance(
            IShardAllocationStrategy allocationStrategy,
            IImmutableDictionary <IActorRef, IImmutableList <string> > allocations,
            IImmutableSet <string> rebalance)
        {
            var allocationsAfterRemoval = allocations.SetItems(allocations.Select(i => new KeyValuePair <IActorRef, IImmutableList <string> >(i.Key, i.Value.ToImmutableHashSet().Except(rebalance).OrderBy(j => j).ToImmutableList())));

            IImmutableDictionary <IActorRef, IImmutableList <string> > acc = allocationsAfterRemoval;

            foreach (var shard in rebalance.OrderBy(i => i))
            {
                var region = allocationStrategy.AllocateShard(new DummyActorRef(), shard, acc).Result;
                acc = acc.SetItem(region, acc[region].Add(shard));
            }
            return(acc);
        }