diff --git a/src/core/Akka.Cluster/ClusterHeartbeat.cs b/src/core/Akka.Cluster/ClusterHeartbeat.cs index 035cffc3ace..0ed134262fa 100644 --- a/src/core/Akka.Cluster/ClusterHeartbeat.cs +++ b/src/core/Akka.Cluster/ClusterHeartbeat.cs @@ -552,7 +552,7 @@ public ClusterHeartbeatSenderState HeartbeatRsp(UniqueAddress from) /// TBD /// TBD /// TBD - public ClusterHeartbeatSenderState Copy(HeartbeatNodeRing ring = null, ImmutableHashSet oldReceiversNowUnreachable = null, IFailureDetectorRegistry
failureDetector = null) + public ClusterHeartbeatSenderState Copy(HeartbeatNodeRing? ring = null, ImmutableHashSet oldReceiversNowUnreachable = null, IFailureDetectorRegistry
failureDetector = null) { return new ClusterHeartbeatSenderState(ring ?? Ring, oldReceiversNowUnreachable ?? OldReceiversNowUnreachable, failureDetector ?? FailureDetector); } @@ -566,7 +566,7 @@ public ClusterHeartbeatSenderState Copy(HeartbeatNodeRing ring = null, Immutable /// /// It is immutable, i.e. the methods all return new instances. /// - internal sealed class HeartbeatNodeRing + internal struct HeartbeatNodeRing { private readonly bool _useAllAsReceivers; private Option> _myReceivers; @@ -656,37 +656,40 @@ public IImmutableSet Receivers(UniqueAddress sender) // The reason for not limiting it to strictly monitoredByNrOfMembers is that the leader must // be able to continue its duties (e.g. removal of downed nodes) when many nodes are shutdown // at the same time and nobody in the remaining cluster is monitoring some of the shutdown nodes. - (int, ImmutableSortedSet) Take(int n, IEnumerator iter, ImmutableSortedSet acc) + (int, ImmutableSortedSet) Take(int n, IEnumerator iter, ImmutableSortedSet acc, ImmutableHashSet unreachable, int monitoredByNumberOfNodes) { - if (iter.MoveNext() == false || n == 0) + while (true) { - iter.Dispose(); // dispose enumerator - return (n, acc); - } - else - { - var next = iter.Current; - var isUnreachable = Unreachable.Contains(next); - if (isUnreachable && acc.Count >= MonitoredByNumberOfNodes) - { - return Take(n, iter, acc); // skip the unreachable, since we have already picked `MonitoredByNumberOfNodes` - } - else if (isUnreachable) + if (iter.MoveNext() == false || n == 0) { - return Take(n, iter, acc.Add(next)); // include the unreachable, but don't count it + iter.Dispose(); // dispose enumerator + return (n, acc); } else { - return Take(n - 1, iter, acc.Add(next)); // include the reachable + var next = iter.Current; + var isUnreachable = unreachable.Contains(next); + if (isUnreachable && acc.Count >= monitoredByNumberOfNodes) + { + } + else if (isUnreachable) + { + acc = acc.Add(next); + } + else + { + n = n - 1; + acc = acc.Add(next); + } } } } - var (remaining, slice1) = Take(MonitoredByNumberOfNodes, NodeRing.From(sender).Skip(1).GetEnumerator(), ImmutableSortedSet.Empty); + var (remaining, slice1) = Take(MonitoredByNumberOfNodes, NodeRing.From(sender).Skip(1).GetEnumerator(), ImmutableSortedSet.Empty, Unreachable, MonitoredByNumberOfNodes); IImmutableSet slice = remaining == 0 ? slice1 // or, wrap-around - : Take(remaining, NodeRing.TakeWhile(x => x != sender).GetEnumerator(), slice1).Item2; + : Take(remaining, NodeRing.TakeWhile(x => x != sender).GetEnumerator(), slice1, Unreachable, MonitoredByNumberOfNodes).Item2; return slice; }