Publish clean state when joining (PublishStart), see #2871

* The failure in JoinTwoClustersSpec was due to missing publishing
  of cluster events when clearing current state when joining
* This fix is in the right direction, but joining clusters like this
  will need some design thought, creating ticket 2873 for that
This commit is contained in:
Patrik Nordwall 2013-01-04 16:39:48 +01:00
parent 5d53ec0c52
commit 943c438d5e
5 changed files with 31 additions and 11 deletions

View file

@ -191,7 +191,7 @@ private[cluster] final class ClusterCoreDaemon(publisher: ActorRef) extends Acto
// note that self is not initially member,
// and the Gossip is not versioned for this 'Node' yet
var latestGossip: Gossip = Gossip()
var latestGossip: Gossip = Gossip.empty
var stats = ClusterStats()
@ -283,7 +283,7 @@ private[cluster] final class ClusterCoreDaemon(publisher: ActorRef) extends Acto
def join(address: Address): Unit = {
if (!latestGossip.members.exists(_.address == address)) {
// wipe our state since a node that joins a cluster must be empty
latestGossip = Gossip()
latestGossip = Gossip.empty
// wipe the failure detector since we are starting fresh and shouldn't care about the past
failureDetector.reset()
// wipe the publisher since we are starting fresh
@ -377,7 +377,7 @@ private[cluster] final class ClusterCoreDaemon(publisher: ActorRef) extends Acto
def removing(address: Address): Unit = {
log.info("Cluster Node [{}] - Node has been REMOVED by the leader - shutting down...", selfAddress)
// just cleaning up the gossip state
latestGossip = Gossip()
latestGossip = Gossip.empty
publish(latestGossip)
context.become(removed)
// make sure the final (removed) state is published

View file

@ -238,8 +238,8 @@ object ClusterEvent {
private[cluster] final class ClusterDomainEventPublisher extends Actor with ActorLogging {
import InternalClusterAction._
var latestGossip: Gossip = Gossip()
var latestConvergedGossip: Gossip = Gossip()
var latestGossip: Gossip = Gossip.empty
var latestConvergedGossip: Gossip = Gossip.empty
var memberEvents: immutable.Seq[MemberEvent] = immutable.Seq.empty
def receive = {
@ -313,7 +313,11 @@ private[cluster] final class ClusterDomainEventPublisher extends Actor with Acto
def publish(event: AnyRef): Unit = eventStream publish event
def publishStart(): Unit = clearState()
def publishStart(): Unit =
if ((latestGossip ne Gossip.empty) || (latestConvergedGossip ne Gossip.empty)) {
clearState()
publishCurrentClusterState(None)
}
def publishDone(receiver: ActorRef): Unit = {
clearState()
@ -321,7 +325,7 @@ private[cluster] final class ClusterDomainEventPublisher extends Actor with Acto
}
def clearState(): Unit = {
latestGossip = Gossip()
latestConvergedGossip = Gossip()
latestGossip = Gossip.empty
latestConvergedGossip = Gossip.empty
}
}

View file

@ -13,6 +13,10 @@ import MemberStatus._
*/
private[cluster] object Gossip {
val emptyMembers: immutable.SortedSet[Member] = immutable.SortedSet.empty
val empty: Gossip = new Gossip(Gossip.emptyMembers)
def apply(members: immutable.SortedSet[Member]) =
if (members.isEmpty) empty else empty.copy(members = members)
}
/**
@ -49,8 +53,8 @@ private[cluster] object Gossip {
* removed node telling it to shut itself down.
*/
private[cluster] case class Gossip(
members: immutable.SortedSet[Member], // sorted set of members with their status, sorted by address
overview: GossipOverview = GossipOverview(),
members: immutable.SortedSet[Member] = Gossip.emptyMembers, // sorted set of members with their status, sorted by address
version: VectorClock = VectorClock()) // vector clock version
extends ClusterMessage // is a serializable cluster message
with Versioned[Gossip] {
@ -128,7 +132,7 @@ private[cluster] case class Gossip(
// 4. fresh seen table
val mergedSeen = Map.empty[Address, VectorClock]
Gossip(GossipOverview(mergedSeen, mergedUnreachable), mergedMembers, mergedVClock)
Gossip(mergedMembers, GossipOverview(mergedSeen, mergedUnreachable), mergedVClock)
}
/**

View file

@ -134,5 +134,17 @@ class ClusterDomainEventPublisherSpec extends AkkaSpec
expectMsg(MemberUp(c2))
expectMsgType[SeenChanged]
}
"publish clean state when PublishStart" in {
publisher ! PublishChanges(g3)
expectMsg(MemberUp(b1))
expectMsg(MemberUp(c2))
expectMsgType[SeenChanged]
publisher ! PublishStart
expectMsgType[CurrentClusterState] must be(CurrentClusterState())
}
}
}

View file

@ -29,7 +29,7 @@ class GossipSpec extends WordSpec with MustMatchers {
"A Gossip" must {
"reach convergence when it's empty" in {
Gossip().convergence must be(true)
Gossip.empty.convergence must be(true)
}
"merge members by status priority" in {