Avoid publication of duplicate UnreachableDataCenter, #24955

* see scenario in added test, extracted from debug logs "New gossip published"
  from MultiDcSplitBrainSpec
* it publised UnreachableDataCenter even though it had already published that,
  when a new cross link is added as unreachable in the reachability table
* don't know why the implementation of diffUnreachableDataCenter/isReachable was
  so complicated, but no tests are failing for the changed implementation
This commit is contained in:
Patrik Nordwall 2019-09-10 10:23:41 +02:00
parent 9a9e21a62b
commit cf4c954009
3 changed files with 81 additions and 11 deletions

View file

@ -437,14 +437,13 @@ object ClusterEvent {
/**
* Internal API
*/
private[cluster] def isReachable(state: MembershipState, oldUnreachableNodes: Set[UniqueAddress])(
otherDc: DataCenter): Boolean = {
private[cluster] def isDataCenterReachable(state: MembershipState)(otherDc: DataCenter): Boolean = {
val unrelatedDcNodes = state.latestGossip.members.collect {
case m if m.dataCenter != otherDc && m.dataCenter != state.selfDc => m.uniqueAddress
}
val reachabilityForOtherDc = state.dcReachabilityWithoutObservationsWithin.remove(unrelatedDcNodes)
reachabilityForOtherDc.allUnreachable.filterNot(oldUnreachableNodes).isEmpty
reachabilityForOtherDc.allUnreachable.isEmpty
}
/**
@ -457,11 +456,11 @@ object ClusterEvent {
else {
val otherDcs = (oldState.latestGossip.allDataCenters
.union(newState.latestGossip.allDataCenters)) - newState.selfDc
otherDcs
.filterNot(isReachable(newState, oldState.dcReachability.allUnreachableOrTerminated))
.iterator
.map(UnreachableDataCenter)
.to(immutable.IndexedSeq)
val oldUnreachableDcs = otherDcs.filterNot(isDataCenterReachable(oldState))
val currentUnreachableDcs = otherDcs.filterNot(isDataCenterReachable(newState))
currentUnreachableDcs.diff(oldUnreachableDcs).iterator.map(UnreachableDataCenter).to(immutable.IndexedSeq)
}
}
@ -476,8 +475,8 @@ object ClusterEvent {
val otherDcs = (oldState.latestGossip.allDataCenters
.union(newState.latestGossip.allDataCenters)) - newState.selfDc
val oldUnreachableDcs = otherDcs.filterNot(isReachable(oldState, Set()))
val currentUnreachableDcs = otherDcs.filterNot(isReachable(newState, Set()))
val oldUnreachableDcs = otherDcs.filterNot(isDataCenterReachable(oldState))
val currentUnreachableDcs = otherDcs.filterNot(isDataCenterReachable(newState))
oldUnreachableDcs.diff(currentUnreachableDcs).iterator.map(ReachableDataCenter).to(immutable.IndexedSeq)
}
@ -620,7 +619,7 @@ private[cluster] final class ClusterDomainEventPublisher
val unreachableDataCenters: Set[DataCenter] =
if (!membershipState.latestGossip.isMultiDc) Set.empty
else membershipState.latestGossip.allDataCenters.filterNot(isReachable(membershipState, Set.empty))
else membershipState.latestGossip.allDataCenters.filterNot(isDataCenterReachable(membershipState))
val state = new CurrentClusterState(
members = membershipState.latestGossip.members,