use of io.atomix.cluster.ClusterEvent in project atomix by atomix.
the class DefaultClusterService method sendHeartbeat.
/**
* Sends a heartbeat to the given peer.
*/
private void sendHeartbeat(Endpoint endpoint, byte[] payload) {
messagingService.sendAndReceive(endpoint, HEARTBEAT_MESSAGE, payload).whenComplete((response, error) -> {
if (error == null) {
Collection<StatefulNode> nodes = SERIALIZER.decode(response);
boolean sendHeartbeats = false;
for (StatefulNode node : nodes) {
if (this.nodes.putIfAbsent(node.id(), node) == null) {
post(new ClusterEvent(ClusterEvent.Type.NODE_ADDED, node));
post(new ClusterEvent(ClusterEvent.Type.NODE_ACTIVATED, node));
sendHeartbeats = true;
}
}
if (sendHeartbeats) {
sendHeartbeats();
}
} else {
LOGGER.trace("Sending heartbeat to {} failed", endpoint, error);
}
});
}
use of io.atomix.cluster.ClusterEvent in project atomix by atomix.
the class DefaultClusterService method handleMetadataEvent.
/**
* Handles a cluster metadata change event.
*/
private void handleMetadataEvent(ClusterMetadataEvent event) {
// Iterate through all bootstrap nodes and add any missing data nodes, triggering NODE_ADDED events.
// Collect the bootstrap node IDs into a set.
Set<NodeId> bootstrapNodes = event.subject().bootstrapNodes().stream().map(node -> {
StatefulNode existingNode = nodes.get(node.id());
if (existingNode == null) {
StatefulNode newNode = new StatefulNode(node.id(), node.type(), node.endpoint(), node.zone(), node.rack(), node.host());
nodes.put(newNode.id(), newNode);
post(new ClusterEvent(ClusterEvent.Type.NODE_ADDED, newNode));
}
return node.id();
}).collect(Collectors.toSet());
// Filter the set of data node IDs from the local node information.
Set<NodeId> dataNodes = nodes.entrySet().stream().filter(entry -> entry.getValue().type() == Node.Type.CORE).map(entry -> entry.getKey()).collect(Collectors.toSet());
// Compute the set of local data nodes missing in the set of bootstrap nodes.
Set<NodeId> missingNodes = Sets.difference(dataNodes, bootstrapNodes);
// For each missing data node, remove the node and trigger a NODE_REMOVED event.
for (NodeId nodeId : missingNodes) {
StatefulNode existingNode = nodes.remove(nodeId);
if (existingNode != null) {
post(new ClusterEvent(ClusterEvent.Type.NODE_REMOVED, existingNode));
}
}
}
use of io.atomix.cluster.ClusterEvent in project atomix by atomix.
the class DefaultClusterService method activateNode.
/**
* Activates the given node.
*/
private void activateNode(StatefulNode node) {
StatefulNode existingNode = nodes.get(node.id());
if (existingNode == null) {
node.setState(State.ACTIVE);
nodes.put(node.id(), node);
post(new ClusterEvent(ClusterEvent.Type.NODE_ADDED, node));
post(new ClusterEvent(ClusterEvent.Type.NODE_ACTIVATED, node));
sendHeartbeat(node.endpoint(), SERIALIZER.encode(new ClusterHeartbeat(localNode.id(), localNode.type(), localNode.zone(), localNode.rack(), localNode.host())));
} else if (existingNode.getState() == State.INACTIVE) {
existingNode.setState(State.ACTIVE);
post(new ClusterEvent(ClusterEvent.Type.NODE_ACTIVATED, existingNode));
}
}
use of io.atomix.cluster.ClusterEvent in project atomix by atomix.
the class AtomixTest method testClientJoinLeave.
/**
* Tests a client joining and leaving the cluster.
*/
@Test
public void testClientJoinLeave() throws Exception {
List<CompletableFuture<Atomix>> futures = new ArrayList<>();
futures.add(startAtomix(Node.Type.CORE, 1, 1, 2, 3));
futures.add(startAtomix(Node.Type.CORE, 2, 1, 2, 3));
futures.add(startAtomix(Node.Type.CORE, 3, 1, 2, 3));
Futures.allOf(futures).join();
TestClusterEventListener dataListener = new TestClusterEventListener();
instances.get(0).clusterService().addListener(dataListener);
Atomix client1 = startAtomix(Node.Type.CLIENT, 4, 1, 2, 3).join();
// client1 added to data node
ClusterEvent event1 = dataListener.event();
assertEquals(ClusterEvent.Type.NODE_ADDED, event1.type());
event1 = dataListener.event();
assertEquals(ClusterEvent.Type.NODE_ACTIVATED, event1.type());
Thread.sleep(1000);
TestClusterEventListener clientListener = new TestClusterEventListener();
client1.clusterService().addListener(clientListener);
Atomix client2 = startAtomix(Node.Type.CLIENT, 5, 1, 2, 3).join();
// client2 added to data node
ClusterEvent event2 = dataListener.event();
assertEquals(ClusterEvent.Type.NODE_ADDED, event2.type());
event2 = dataListener.event();
assertEquals(ClusterEvent.Type.NODE_ACTIVATED, event2.type());
// client2 added to client node
event1 = clientListener.event();
assertEquals(ClusterEvent.Type.NODE_ADDED, event1.type());
event1 = clientListener.event();
assertEquals(ClusterEvent.Type.NODE_ACTIVATED, event1.type());
client2.stop().join();
// client2 removed from data node
event1 = dataListener.event();
assertEquals(ClusterEvent.Type.NODE_DEACTIVATED, event1.type());
event1 = dataListener.event();
assertEquals(ClusterEvent.Type.NODE_REMOVED, event1.type());
// client2 removed from client node
event1 = clientListener.event();
assertEquals(ClusterEvent.Type.NODE_DEACTIVATED, event1.type());
event1 = clientListener.event();
assertEquals(ClusterEvent.Type.NODE_REMOVED, event1.type());
}
use of io.atomix.cluster.ClusterEvent in project atomix by atomix.
the class DefaultClusterService method deactivateNode.
/**
* Deactivates the given node.
*/
private void deactivateNode(StatefulNode node) {
StatefulNode existingNode = nodes.get(node.id());
if (existingNode != null && existingNode.getState() == State.ACTIVE) {
existingNode.setState(State.INACTIVE);
switch(existingNode.type()) {
case CORE:
post(new ClusterEvent(ClusterEvent.Type.NODE_DEACTIVATED, existingNode));
break;
case DATA:
case CLIENT:
post(new ClusterEvent(ClusterEvent.Type.NODE_DEACTIVATED, existingNode));
post(new ClusterEvent(ClusterEvent.Type.NODE_REMOVED, existingNode));
break;
default:
throw new AssertionError();
}
}
}
Aggregations