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;
}