Commit 914ead40 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

cluster_optimization

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@10216 b35dd754-fafc-0310-a699-88a17e54d16e
parent 2bb4252f
...@@ -53,6 +53,7 @@ public class SessionManager extends BasicModule implements ClusterEventListener ...@@ -53,6 +53,7 @@ public class SessionManager extends BasicModule implements ClusterEventListener
public static final String COMPONENT_SESSION_CACHE_NAME = "Components Sessions"; public static final String COMPONENT_SESSION_CACHE_NAME = "Components Sessions";
public static final String CM_CACHE_NAME = "Connection Managers Sessions"; public static final String CM_CACHE_NAME = "Connection Managers Sessions";
public static final String ISS_CACHE_NAME = "Incoming Server Sessions"; public static final String ISS_CACHE_NAME = "Incoming Server Sessions";
public static final String C2S_INFO_CACHE_NAME = "Client Session Info Cache";
public static final int NEVER_KICK = -1; public static final int NEVER_KICK = -1;
...@@ -71,6 +72,14 @@ public class SessionManager extends BasicModule implements ClusterEventListener ...@@ -71,6 +72,14 @@ public class SessionManager extends BasicModule implements ClusterEventListener
*/ */
private final AtomicInteger connectionsCounter = new AtomicInteger(0); private final AtomicInteger connectionsCounter = new AtomicInteger(0);
/**
* Cache (unlimited, never expire) that holds information about client sessions (as soon as
* a resource has been bound). The cache is used by Remote sessions to avoid generating big
* number of remote calls.
* Key: full JID, Value: ClientSessionInfo
*/
private Cache<String, ClientSessionInfo> sessionInfoCache;
/** /**
* Cache (unlimited, never expire) that holds external component sessions. * Cache (unlimited, never expire) that holds external component sessions.
* Key: component address, Value: nodeID * Key: component address, Value: nodeID
...@@ -517,6 +526,10 @@ public class SessionManager extends BasicModule implements ClusterEventListener ...@@ -517,6 +526,10 @@ public class SessionManager extends BasicModule implements ClusterEventListener
SessionEventDispatcher.EventType.session_created; SessionEventDispatcher.EventType.session_created;
// Fire session created event. // Fire session created event.
SessionEventDispatcher.dispatchEvent(session, event); SessionEventDispatcher.dispatchEvent(session, event);
if (ClusterManager.isClusteringStarted()) {
// Track information about the session and share it with other cluster nodes
sessionInfoCache.put(session.getAddress().toString(), new ClientSessionInfo(session));
}
} }
/** /**
...@@ -1056,6 +1069,10 @@ public class SessionManager extends BasicModule implements ClusterEventListener ...@@ -1056,6 +1069,10 @@ public class SessionManager extends BasicModule implements ClusterEventListener
offline.setType(Presence.Type.unavailable); offline.setType(Presence.Type.unavailable);
router.route(offline); router.route(offline);
} }
// Stop tracking information about the session and share it with other cluster nodes
sessionInfoCache.remove(fullJID.toString());
if (removed || preauth_removed) { if (removed || preauth_removed) {
// Decrement the counter of user sessions // Decrement the counter of user sessions
connectionsCounter.decrementAndGet(); connectionsCounter.decrementAndGet();
...@@ -1249,6 +1266,7 @@ public class SessionManager extends BasicModule implements ClusterEventListener ...@@ -1249,6 +1266,7 @@ public class SessionManager extends BasicModule implements ClusterEventListener
incomingServerSessionsCache = CacheFactory.createCache(ISS_CACHE_NAME); incomingServerSessionsCache = CacheFactory.createCache(ISS_CACHE_NAME);
hostnameSessionsCache = CacheFactory.createCache("Sessions by Hostname"); hostnameSessionsCache = CacheFactory.createCache("Sessions by Hostname");
validatedDomainsCache = CacheFactory.createCache("Validated Domains"); validatedDomainsCache = CacheFactory.createCache("Validated Domains");
sessionInfoCache = CacheFactory.createCache(C2S_INFO_CACHE_NAME);
// Listen to cluster events // Listen to cluster events
ClusterManager.addListener(this); ClusterManager.addListener(this);
} }
...@@ -1397,8 +1415,16 @@ public class SessionManager extends BasicModule implements ClusterEventListener ...@@ -1397,8 +1415,16 @@ public class SessionManager extends BasicModule implements ClusterEventListener
return JiveGlobals.getIntProperty("xmpp.server.session.idle", 10 * 60 * 1000); return JiveGlobals.getIntProperty("xmpp.server.session.idle", 10 * 60 * 1000);
} }
public Cache<String, ClientSessionInfo> getSessionInfoCache() {
return sessionInfoCache;
}
public void joinedCluster() { public void joinedCluster() {
restoreCacheContent(); restoreCacheContent();
// Track information about local sessions and share it with other cluster nodes
for (ClientSession session : routingTable.getClientsRoutes(true)) {
sessionInfoCache.put(session.getAddress().toString(), new ClientSessionInfo((LocalClientSession)session));
}
} }
public void joinedCluster(byte[] nodeID) { public void joinedCluster(byte[] nodeID) {
......
/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2005-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.session;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.util.cache.ExternalizableUtil;
import org.xmpp.packet.Presence;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/**
* Client session information to be used when running in a cluster. The session
* information is shared between cluster nodes and is meant to be used by remote
* sessions to avoid invocation remote calls and instead use cached information.
* This optimization should give an important boost to the application specifically
* while users are logging in.<p>
*
* Session information is stored after a user authenticated and bound a resource.
*
* @author Gaston Dombiak
*/
public class ClientSessionInfo implements Externalizable {
private Presence presence;
private String defaultList;
private String activeList;
public ClientSessionInfo() {
}
public ClientSessionInfo(LocalClientSession session) {
presence = session.getPresence();
defaultList = session.getDefaultList() != null ? session.getDefaultList().getName() : null;
activeList = session.getActiveList() != null ? session.getActiveList().getName() : null;
}
public Presence getPresence() {
return presence;
}
public String getDefaultList() {
return defaultList;
}
public String getActiveList() {
return activeList;
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeSerializable(out, (DefaultElement) presence.getElement());
ExternalizableUtil.getInstance().writeBoolean(out, defaultList != null);
if (defaultList != null) {
ExternalizableUtil.getInstance().writeSafeUTF(out, defaultList);
}
ExternalizableUtil.getInstance().writeBoolean(out, activeList != null);
if (activeList != null) {
ExternalizableUtil.getInstance().writeSafeUTF(out, activeList);
}
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
Element packetElement = (Element) ExternalizableUtil.getInstance().readSerializable(in);
presence = new Presence(packetElement, true);
if (ExternalizableUtil.getInstance().readBoolean(in)) {
defaultList = ExternalizableUtil.getInstance().readSafeUTF(in);
}
if (ExternalizableUtil.getInstance().readBoolean(in)) {
activeList = ExternalizableUtil.getInstance().readSafeUTF(in);
}
}
}
...@@ -18,6 +18,7 @@ import org.jivesoftware.openfire.StreamID; ...@@ -18,6 +18,7 @@ import org.jivesoftware.openfire.StreamID;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.auth.AuthToken; import org.jivesoftware.openfire.auth.AuthToken;
import org.jivesoftware.openfire.auth.UnauthorizedException; import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.cluster.ClusterManager;
import org.jivesoftware.openfire.net.SASLAuthentication; import org.jivesoftware.openfire.net.SASLAuthentication;
import org.jivesoftware.openfire.net.SSLConfig; import org.jivesoftware.openfire.net.SSLConfig;
import org.jivesoftware.openfire.net.SocketConnection; import org.jivesoftware.openfire.net.SocketConnection;
...@@ -28,6 +29,7 @@ import org.jivesoftware.openfire.user.UserNotFoundException; ...@@ -28,6 +29,7 @@ import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.LocaleUtils; import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.Cache;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
...@@ -421,6 +423,11 @@ public class LocalClientSession extends LocalSession implements ClientSession { ...@@ -421,6 +423,11 @@ public class LocalClientSession extends LocalSession implements ClientSession {
*/ */
public void setActiveList(PrivacyList activeList) { public void setActiveList(PrivacyList activeList) {
this.activeList = activeList != null ? activeList.getName() : null; this.activeList = activeList != null ? activeList.getName() : null;
if (ClusterManager.isClusteringStarted()) {
// Track information about the session and share it with other cluster nodes
Cache<String,ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache();
cache.put(getAddress().toString(), new ClientSessionInfo(this));
}
} }
/** /**
...@@ -447,7 +454,17 @@ public class LocalClientSession extends LocalSession implements ClientSession { ...@@ -447,7 +454,17 @@ public class LocalClientSession extends LocalSession implements ClientSession {
* @param defaultList the default Privacy list used for the session's user. * @param defaultList the default Privacy list used for the session's user.
*/ */
public void setDefaultList(PrivacyList defaultList) { public void setDefaultList(PrivacyList defaultList) {
// Do nothing if nothing has changed
if ((this.defaultList == null && defaultList == null) ||
(defaultList != null && defaultList.getName().equals(this.defaultList))) {
return;
}
this.defaultList = defaultList != null ? defaultList.getName() : null; this.defaultList = defaultList != null ? defaultList.getName() : null;
if (ClusterManager.isClusteringStarted()) {
// Track information about the session and share it with other cluster nodes
Cache<String,ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache();
cache.put(getAddress().toString(), new ClientSessionInfo(this));
}
} }
/** /**
...@@ -670,6 +687,11 @@ public class LocalClientSession extends LocalSession implements ClientSession { ...@@ -670,6 +687,11 @@ public class LocalClientSession extends LocalSession implements ClientSession {
// Notify listeners that the show or status value of the presence has changed // Notify listeners that the show or status value of the presence has changed
PresenceEventDispatcher.presenceChanged(this, presence); PresenceEventDispatcher.presenceChanged(this, presence);
} }
if (ClusterManager.isClusteringStarted()) {
// Track information about the session and share it with other cluster nodes
Cache<String,ClientSessionInfo> cache = SessionManager.getInstance().getSessionInfoCache();
cache.put(getAddress().toString(), new ClientSessionInfo(this));
}
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment