use of org.jivesoftware.openfire.cluster.NodeID in project Openfire by igniterealtime.
the class IQDiscoInfoHandler method restoreCacheContent.
private void restoreCacheContent() {
for (String feature : localServerFeatures) {
Lock lock = CacheFactory.getLock(feature, serverFeatures);
try {
lock.lock();
Set<NodeID> nodeIDs = serverFeatures.get(feature);
if (nodeIDs == null) {
nodeIDs = new HashSet<>();
}
nodeIDs.add(XMPPServer.getInstance().getNodeID());
serverFeatures.put(feature, nodeIDs);
} finally {
lock.unlock();
}
}
}
use of org.jivesoftware.openfire.cluster.NodeID in project Openfire by igniterealtime.
the class ClusterListener method memberLeft.
public void memberLeft(MemberEvent memberEvent) {
byte[] nodeID = memberEvent.getMember().getUid().toByteArray();
if (memberEvent.isLocal()) {
Log.info("Leaving cluster");
// This node may have realized that it got kicked out of the cluster
seniorClusterMember = false;
// Clean up all traces. This will set all remote sessions as unavailable
List<NodeID> nodeIDs = new ArrayList<NodeID>(nodeSessions.keySet());
// Trigger event. Wait until the listeners have processed the event. Caches will be populated
// again with local content.
ClusterManager.fireLeftCluster();
if (!XMPPServer.getInstance().isShuttingDown()) {
for (NodeID key : nodeIDs) {
// Clean up directed presences sent from entites hosted in the leaving node to local entities
// Clean up directed presences sent to entites hosted in the leaving node from local entities
cleanupDirectedPresences(key);
// Clean up no longer valid sessions
cleanupPresences(key);
}
// Remove traces of directed presences sent from local entities to handlers that no longer exist
// At this point c2s sessions are gone from the routing table so we can identify expired sessions
XMPPServer.getInstance().getPresenceUpdateHandler().removedExpiredPresences();
}
// Mark that we are done with the clean up
done = true;
} else {
// Trigger event that a node left the cluster
ClusterManager.fireLeftCluster(nodeID);
// Clean up directed presences sent from entites hosted in the leaving node to local entities
// Clean up directed presences sent to entites hosted in the leaving node from local entities
cleanupDirectedPresences(NodeID.getInstance(nodeID));
if (!seniorClusterMember && CacheFactory.isSeniorClusterMember()) {
seniorClusterMember = true;
ClusterManager.fireMarkedAsSeniorClusterMember();
}
if (CacheFactory.isSeniorClusterMember()) {
cleanupNode(NodeID.getInstance(nodeID));
}
// Remove traces of directed presences sent from local entities to handlers that no longer exist.
// At this point c2s sessions are gone from the routing table so we can identify expired sessions
XMPPServer.getInstance().getPresenceUpdateHandler().removedExpiredPresences();
}
// Delete nodeID instance (release from memory)
NodeID.deleteInstance(nodeID);
}
use of org.jivesoftware.openfire.cluster.NodeID in project Openfire by igniterealtime.
the class ClusterListener method cleanupNode.
/**
* Executes close logic for each session hosted in the remote node that is
* no longer available. This logic is similar to the close listeners used by
* the {@link SessionManager}.<p>
*
* If the node that went down performed its own clean up logic then the other
* cluster nodes will have the correct state. That means that this method
* will not find any sessions to remove.<p>
*
* If this operation is too big and we are still in a cluster then we can
* distribute the work in the cluster to go faster.
*
* @param key the key that identifies the node that is no longer available.
*/
private void cleanupNode(NodeID key) {
// TODO Fork in another process and even ask other nodes to process work
RoutingTable routingTable = XMPPServer.getInstance().getRoutingTable();
RemoteSessionLocator sessionLocator = XMPPServer.getInstance().getRemoteSessionLocator();
SessionManager manager = XMPPServer.getInstance().getSessionManager();
// TODO Consider removing each cached entry once processed instead of all at the end. Could be more error-prove.
Set<String> registeredUsers = lookupJIDList(key, C2SCache.getName());
if (!registeredUsers.isEmpty()) {
for (String fullJID : new ArrayList<String>(registeredUsers)) {
JID offlineJID = new JID(fullJID);
manager.removeSession(null, offlineJID, false, true);
}
}
Set<String> anonymousUsers = lookupJIDList(key, anonymousC2SCache.getName());
if (!anonymousUsers.isEmpty()) {
for (String fullJID : new ArrayList<String>(anonymousUsers)) {
JID offlineJID = new JID(fullJID);
manager.removeSession(null, offlineJID, true, true);
}
}
// Remove outgoing server sessions hosted in node that left the cluster
Set<String> remoteServers = lookupJIDList(key, S2SCache.getName());
if (!remoteServers.isEmpty()) {
for (String fullJID : new ArrayList<String>(remoteServers)) {
JID serverJID = new JID(fullJID);
routingTable.removeServerRoute(serverJID);
}
}
Set<String> components = lookupJIDList(key, componentsCache.getName());
if (!components.isEmpty()) {
for (String address : new ArrayList<String>(components)) {
Lock lock = CacheFactory.getLock(address, componentsCache);
try {
lock.lock();
Set<NodeID> nodes = (Set<NodeID>) componentsCache.get(address);
if (nodes != null) {
nodes.remove(key);
if (nodes.isEmpty()) {
componentsCache.remove(address);
} else {
componentsCache.put(address, nodes);
}
}
} finally {
lock.unlock();
}
}
}
Set<String> componentSessions = lookupJIDList(key, componentSessionsCache.getName());
if (!componentSessions.isEmpty()) {
for (String domain : new ArrayList<String>(componentSessions)) {
componentSessionsCache.remove(domain);
// Registered subdomains of external component will be removed
// by the clean up of the component cache
}
}
Set<String> multiplexers = lookupJIDList(key, multiplexerSessionsCache.getName());
if (!multiplexers.isEmpty()) {
for (String fullJID : new ArrayList<String>(multiplexers)) {
multiplexerSessionsCache.remove(fullJID);
// c2s connections connected to node that went down will be cleaned up
// by the c2s logic above. If the CM went down and the node is up then
// connections will be cleaned up as usual
}
}
Set<String> incomingSessions = lookupJIDList(key, incomingServerSessionsCache.getName());
if (!incomingSessions.isEmpty()) {
for (String streamIDValue : new ArrayList<>(incomingSessions)) {
StreamID streamID = BasicStreamIDFactory.createStreamID(streamIDValue);
IncomingServerSession session = sessionLocator.getIncomingServerSession(key.toByteArray(), streamID);
// Remove all the hostnames that were registered for this server session
for (String hostname : session.getValidatedDomains()) {
manager.unregisterIncomingServerSession(hostname, session);
}
}
}
nodeSessions.remove(key);
// TODO Make sure that routing table has no entry referring to node that is gone
}
use of org.jivesoftware.openfire.cluster.NodeID in project Openfire by igniterealtime.
the class RoutingTableImpl method removeComponentRoute.
@Override
public boolean removeComponentRoute(JID route) {
String address = route.getDomain();
boolean removed = false;
Lock lock = CacheFactory.getLock(address, componentsCache);
try {
lock.lock();
Set<NodeID> nodes = componentsCache.get(address);
if (nodes != null) {
removed = nodes.remove(server.getNodeID());
if (nodes.isEmpty()) {
componentsCache.remove(address);
} else {
componentsCache.put(address, nodes);
}
}
} finally {
lock.unlock();
}
localRoutingTable.removeRoute(address);
return removed;
}
use of org.jivesoftware.openfire.cluster.NodeID in project Openfire by igniterealtime.
the class RoutingTableImpl method routeToComponent.
/**
* Routes packets that are sent to components of the XMPP domain (which are
* subdomains of the XMPP domain)
*
* @param jid
* the recipient of the packet to route.
* @param packet
* the packet to route.
* @throws PacketException
* thrown if the packet is malformed (results in the sender's
* session being shutdown).
* @return <tt>true</tt> if the packet was routed successfully,
* <tt>false</tt> otherwise.
*/
private boolean routeToComponent(JID jid, Packet packet, boolean routed) {
if (!hasComponentRoute(jid) && !ExternalComponentManager.hasConfiguration(jid.getDomain())) {
return false;
}
// First check if the component is being hosted in this JVM
RoutableChannelHandler route = localRoutingTable.getRoute(jid.getDomain());
if (route != null) {
try {
route.process(packet);
routed = true;
} catch (UnauthorizedException e) {
Log.error("Unable to route packet " + packet.toXML(), e);
}
} else {
// Check if other cluster nodes are hosting this component
Set<NodeID> nodes = componentsCache.get(jid.getDomain());
if (nodes != null) {
for (NodeID nodeID : nodes) {
if (server.getNodeID().equals(nodeID)) {
// could have been added after our previous check)
try {
RoutableChannelHandler localRoute = localRoutingTable.getRoute(jid.getDomain());
if (localRoute != null) {
localRoute.process(packet);
routed = true;
break;
}
} catch (UnauthorizedException e) {
Log.error("Unable to route packet " + packet.toXML(), e);
}
} else {
// This is a route to a local component hosted in other node
if (remotePacketRouter != null) {
routed = remotePacketRouter.routePacket(nodeID.toByteArray(), jid, packet);
if (routed) {
break;
}
}
}
}
}
}
return routed;
}
Aggregations