📄 clustermanager.java
字号:
/**
* $RCSfile: $
* $Revision: $
* $Date: $
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution, or a commercial license
* agreement with Jive.
*/
package org.jivesoftware.openfire.cluster;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.JiveProperties;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.CacheFactory;
import java.util.Collection;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* A cluster manager is responsible for triggering events related to clustering.
* A future version will also provide statistics about the cluster.
*
* @author Gaston Dombiak
*/
public class ClusterManager {
public static String CLUSTER_PROPERTY_NAME = "clustering.enabled";
private static Queue<ClusterEventListener> listeners = new ConcurrentLinkedQueue<ClusterEventListener>();
private static BlockingQueue<Event> events = new LinkedBlockingQueue<Event>();
static {
Thread thread = new Thread("ClusterManager events dispatcher") {
public void run() {
for (; ;) {
try {
Event event = events.take();
EventType eventType = event.getType();
// Make sure that CacheFactory is getting this events first (to update cache structure)
if (eventType == EventType.joined_cluster && event.getNodeID() == null) {
// Replace standalone caches with clustered caches. Local cached data is not moved.
CacheFactory.joinedCluster();
}
// Now notify rest of the listeners
for (ClusterEventListener listener : listeners) {
try {
switch (eventType) {
case joined_cluster: {
if (event.getNodeID() == null) {
listener.joinedCluster();
}
else {
listener.joinedCluster(event.getNodeID());
}
break;
}
case left_cluster: {
if (event.getNodeID() == null) {
listener.leftCluster();
}
else {
listener.leftCluster(event.getNodeID());
}
break;
}
case marked_senior_cluster_member: {
listener.markedAsSeniorClusterMember();
break;
}
default:
break;
}
}
catch (Exception e) {
Log.error(e);
}
}
// Mark event as processed
event.setProcessed(true);
} catch (InterruptedException e) {
Log.warn(e);
} catch (Exception e) {
Log.error(e);
}
}
}
};
thread.setDaemon(true);
thread.start();
}
/**
* Registers a listener to receive events.
*
* @param listener the listener.
*/
public static void addListener(ClusterEventListener listener) {
if (listener == null) {
throw new NullPointerException();
}
listeners.add(listener);
}
/**
* Unregisters a listener to receive events.
*
* @param listener the listener.
*/
public static void removeListener(ClusterEventListener listener) {
listeners.remove(listener);
}
/**
* Triggers event indicating that this JVM is now part of a cluster. At this point the
* {@link org.jivesoftware.openfire.XMPPServer#getNodeID()} holds the new nodeID value and
* the old nodeID value is passed in case the listener needs it.<p>
* <p/>
* When joining the cluster as the senior cluster member the {@link #fireMarkedAsSeniorClusterMember()}
* event will be sent right after this event.<p>
* <p/>
* This event will be triggered in another thread. This will avoid potential deadlocks
* in Coherence.
*
* @param asynchronous true if event will be triggered in background
*/
public static void fireJoinedCluster(boolean asynchronous) {
try {
Event event = new Event(EventType.joined_cluster, null);
events.put(event);
if (!asynchronous) {
while (!event.isProcessed()) {
Thread.sleep(50);
}
}
} catch (InterruptedException e) {
// Should never happen
Log.error(e);
}
}
/**
* Triggers event indicating that another JVM is now part of a cluster.<p>
*
* This event will be triggered in another thread. This will avoid potential deadlocks
* in Coherence.
*
* @param nodeID nodeID assigned to the JVM when joining the cluster.
* @param asynchronous true if event will be triggered in background
*/
public static void fireJoinedCluster(byte[] nodeID, boolean asynchronous) {
try {
Event event = new Event(EventType.joined_cluster, nodeID);
events.put(event);
if (!asynchronous) {
while (!event.isProcessed()) {
Thread.sleep(50);
}
}
} catch (InterruptedException e) {
// Should never happen
Log.error(e);
}
}
/**
* Triggers event indicating that this JVM is no longer part of the cluster. This could
* happen when disabling clustering support or removing the enterprise plugin that provides
* clustering support.<p>
*
* Moreover, if we were in a "split brain" scenario (ie. separated cluster islands) and the
* island were this JVM belonged was marked as "old" then all nodes of that island will
* get the <tt>left cluster event</tt> and <tt>joined cluster events</tt>. That means that
* caches will be reset and thus will need to be repopulated again with fresh data from this JVM.
* This also includes the case where this JVM was the senior cluster member and when the islands
* met again then this JVM stopped being the senior member.
*/
public static void fireLeftCluster() {
// Now notify rest of the listeners
for (ClusterEventListener listener : listeners) {
try {
listener.leftCluster();
}
catch (Exception e) {
Log.error(e);
}
}
}
/**
* Triggers event indicating that another JVM is no longer part of the cluster. This could
* happen when disabling clustering support or removing the enterprise plugin that provides
* clustering support.
*
* @param nodeID nodeID assigned to the JVM when joining the cluster.
*/
public static void fireLeftCluster(byte[] nodeID) {
try {
Event event = new Event(EventType.left_cluster, nodeID);
events.put(event);
} catch (InterruptedException e) {
// Should never happen
Log.error(e);
}
}
/**
* Triggers event indicating that this JVM is now the senior cluster member. This
* could either happen when initially joining the cluster or when the senior cluster
* member node left the cluster and this JVM was marked as the new senior cluster member.<p>
* <p/>
* Moreover, in the case of a "split brain" scenario (ie. separated cluster islands) each
* island will have its own senior cluster member. However, when the islands meet again there
* could only be one senior cluster member so one of the senior cluster members will stop playing
* that role. When that happens the JVM no longer playing that role will receive the
* {@link #fireLeftCluster()} and {@link #fireJoinedCluster(boolean)} events.<p>
* <p/>
* This event will be triggered in another thread. This will avoid potential deadlocks
* in Coherence.
*/
public static void fireMarkedAsSeniorClusterMember() {
try {
events.put(new Event(EventType.marked_senior_cluster_member, null));
} catch (InterruptedException e) {
// Should never happen
}
}
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -