Commit ae54ffc6 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

1) More optimization work

2) Fixed s2s problem in routing table that was causing endless loop --> high CPU problem

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@8692 b35dd754-fafc-0310-a699-88a17e54d16e
parent 5e7b3384
...@@ -804,7 +804,7 @@ public class SessionManager extends BasicModule implements ClusterEventListener ...@@ -804,7 +804,7 @@ public class SessionManager extends BasicModule implements ClusterEventListener
* @return a session that was originated from this server to a remote server. * @return a session that was originated from this server to a remote server.
*/ */
public OutgoingServerSession getOutgoingServerSession(String hostname) { public OutgoingServerSession getOutgoingServerSession(String hostname) {
return routingTable.getServerRoute(new JID(null, hostname, null)); return routingTable.getServerRoute(new JID(null, hostname, null, true));
} }
public Collection<ClientSession> getSessions(String username) { public Collection<ClientSession> getSessions(String username) {
......
...@@ -208,6 +208,9 @@ public class OutgoingSessionPromise implements RoutableChannelHandler { ...@@ -208,6 +208,9 @@ public class OutgoingSessionPromise implements RoutableChannelHandler {
lock.unlock(); lock.unlock();
} }
if (created) { if (created) {
if (!routingTable.hasServerRoute(packet.getTo())) {
throw new Exception("Route created but not found!!!");
}
// A connection to the remote server was created so get the route and send the packet // A connection to the remote server was created so get the route and send the packet
routingTable.routePacket(packet.getTo(), packet, false); routingTable.routePacket(packet.getTo(), packet, false);
} }
......
package org.jivesoftware.openfire.server; package org.jivesoftware.openfire.server;
import org.jivesoftware.util.cache.CacheSizes;
import org.jivesoftware.util.cache.Cacheable;
import org.jivesoftware.util.cache.ExternalizableUtil;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
/** /**
* Holds the configuration when connecting to/from a remote server. The configuration specifies * Holds the configuration when connecting to/from a remote server. The configuration specifies
* if incoming or outgoing connections are allowed to the remote server and the port to use * if incoming or outgoing connections are allowed to the remote server and the port to use
...@@ -7,7 +16,7 @@ package org.jivesoftware.openfire.server; ...@@ -7,7 +16,7 @@ package org.jivesoftware.openfire.server;
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class RemoteServerConfiguration { public class RemoteServerConfiguration implements Cacheable, Externalizable {
private String domain; private String domain;
...@@ -39,6 +48,33 @@ public class RemoteServerConfiguration { ...@@ -39,6 +48,33 @@ public class RemoteServerConfiguration {
this.remotePort = remotePort; this.remotePort = remotePort;
} }
public int getCachedSize() {
// Approximate the size of the object in bytes by calculating the size
// of each field.
int size = 0;
size += CacheSizes.sizeOfObject(); // overhead of object
size += CacheSizes.sizeOfString(domain); // domain
size += CacheSizes.sizeOfInt(); // remotePort
return size;
}
public void writeExternal(ObjectOutput out) throws IOException {
ExternalizableUtil.getInstance().writeSafeUTF(out, domain);
ExternalizableUtil.getInstance().writeBoolean(out, permission != null);
if (permission != null) {
ExternalizableUtil.getInstance().writeInt(out, permission.ordinal());
}
ExternalizableUtil.getInstance().writeInt(out, remotePort);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
domain = ExternalizableUtil.getInstance().readSafeUTF(in);
if (ExternalizableUtil.getInstance().readBoolean(in)) {
permission = Permission.values()[ExternalizableUtil.getInstance().readInt(in)];
}
remotePort = ExternalizableUtil.getInstance().readInt(in);
}
public enum Permission { public enum Permission {
/** /**
* The XMPP entity is allowed to connect to the server. * The XMPP entity is allowed to connect to the server.
......
...@@ -17,6 +17,8 @@ import org.jivesoftware.openfire.server.RemoteServerConfiguration.Permission; ...@@ -17,6 +17,8 @@ import org.jivesoftware.openfire.server.RemoteServerConfiguration.Permission;
import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheFactory;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
...@@ -42,6 +44,12 @@ public class RemoteServerManager { ...@@ -42,6 +44,12 @@ public class RemoteServerManager {
private static final String LOAD_CONFIGURATIONS = private static final String LOAD_CONFIGURATIONS =
"SELECT domain,remotePort FROM jiveRemoteServerConf where permission=?"; "SELECT domain,remotePort FROM jiveRemoteServerConf where permission=?";
private static Cache configurationsCache;
static {
configurationsCache = CacheFactory.createCache("Remote Server Configurations");
}
/** /**
* Allows a remote server to connect to the local server with the specified configuration. * Allows a remote server to connect to the local server with the specified configuration.
* *
...@@ -152,6 +160,8 @@ public class RemoteServerManager { ...@@ -152,6 +160,8 @@ public class RemoteServerManager {
* @param domain the domain of the remote server. * @param domain the domain of the remote server.
*/ */
public static void deleteConfiguration(String domain) { public static void deleteConfiguration(String domain) {
// Remove configuration from cache
configurationsCache.remove(domain);
// Remove the permission for the entity from the database // Remove the permission for the entity from the database
java.sql.Connection con = null; java.sql.Connection con = null;
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
...@@ -174,8 +184,12 @@ public class RemoteServerManager { ...@@ -174,8 +184,12 @@ public class RemoteServerManager {
/** /**
* Adds a new permission for the specified remote server. * Adds a new permission for the specified remote server.
*
* @param configuration the new configuration for a remote server
*/ */
private static void addConfiguration(RemoteServerConfiguration configuration) { private static void addConfiguration(RemoteServerConfiguration configuration) {
// Remove configuration from cache
configurationsCache.put(configuration.getDomain(), configuration);
// Remove the permission for the entity from the database // Remove the permission for the entity from the database
java.sql.Connection con = null; java.sql.Connection con = null;
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
...@@ -205,30 +219,42 @@ public class RemoteServerManager { ...@@ -205,30 +219,42 @@ public class RemoteServerManager {
* @return the configuration for a remote server or <tt>null</tt> if none was found. * @return the configuration for a remote server or <tt>null</tt> if none was found.
*/ */
public static RemoteServerConfiguration getConfiguration(String domain) { public static RemoteServerConfiguration getConfiguration(String domain) {
RemoteServerConfiguration configuration = null; Object value = configurationsCache.get(domain);
java.sql.Connection con = null; if ("null".equals(value)) {
PreparedStatement pstmt = null; return null;
try { }
con = DbConnectionManager.getConnection(); RemoteServerConfiguration configuration = (RemoteServerConfiguration) value;
pstmt = con.prepareStatement(LOAD_CONFIGURATION); if (configuration == null) {
pstmt.setString(1, domain); java.sql.Connection con = null;
ResultSet rs = pstmt.executeQuery(); PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOAD_CONFIGURATION);
pstmt.setString(1, domain);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) { while (rs.next()) {
configuration = new RemoteServerConfiguration(domain); configuration = new RemoteServerConfiguration(domain);
configuration.setRemotePort(rs.getInt(1)); configuration.setRemotePort(rs.getInt(1));
configuration.setPermission(Permission.valueOf(rs.getString(2))); configuration.setPermission(Permission.valueOf(rs.getString(2)));
}
rs.close();
}
catch (SQLException sqle) {
Log.error(sqle);
}
finally {
try { if (pstmt != null) pstmt.close(); }
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
}
if (configuration != null) {
configurationsCache.put(domain, configuration);
}
else {
configurationsCache.put(domain, "null");
} }
rs.close();
}
catch (SQLException sqle) {
Log.error(sqle);
}
finally {
try { if (pstmt != null) pstmt.close(); }
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
} }
return configuration; return configuration;
} }
......
...@@ -38,7 +38,10 @@ import java.io.IOException; ...@@ -38,7 +38,10 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.util.*; import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
...@@ -69,7 +72,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -69,7 +72,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
*/ */
private static Pattern pattern = Pattern.compile("[a-zA-Z]"); private static Pattern pattern = Pattern.compile("[a-zA-Z]");
private Collection<String> authenticatedDomains = new ArrayList<String>(); private Collection<String> authenticatedDomains = new HashSet<String>();
private final Collection<String> hostnames = new HashSet<String>(); private final Collection<String> hostnames = new HashSet<String>();
private OutgoingServerSocketReader socketReader; private OutgoingServerSocketReader socketReader;
/** /**
...@@ -119,9 +122,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -119,9 +122,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
if (session != null) { if (session != null) {
if (session.isUsingServerDialback()) { if (session.isUsingServerDialback()) {
// A session to the same remote server but with different hostname // A session to the same remote server but with different hostname
// was found. Use this session and add the new hostname to the // was found. Use this session.
// session
session.addHostname(hostname);
break; break;
} else { } else {
session = null; session = null;
...@@ -137,10 +138,10 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -137,10 +138,10 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
if (session == null) { if (session == null) {
session = createOutgoingSession(domain, hostname, port); session = createOutgoingSession(domain, hostname, port);
if (session != null) { if (session != null) {
// Add the new hostname to the list of names that the server may have
session.addHostname(hostname);
// Add the validated domain as an authenticated domain // Add the validated domain as an authenticated domain
session.addAuthenticatedDomain(domain); session.addAuthenticatedDomain(domain);
// Add the new hostname to the list of names that the server may have
session.addHostname(hostname);
// Notify the SessionManager that a new session has been created // Notify the SessionManager that a new session has been created
sessionManager.outgoingServerSessionCreated((LocalOutgoingServerSession) session); sessionManager.outgoingServerSessionCreated((LocalOutgoingServerSession) session);
return true; return true;
...@@ -178,14 +179,14 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -178,14 +179,14 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
} }
session = createOutgoingSession(domain, newHostname, port); session = createOutgoingSession(domain, newHostname, port);
if (session != null) { if (session != null) {
// Add the new hostname to the list of names that the server may have
session.addHostname(hostname);
// Add the validated domain as an authenticated domain // Add the validated domain as an authenticated domain
session.addAuthenticatedDomain(domain); session.addAuthenticatedDomain(domain);
// Notify the SessionManager that a new session has been created // Add the new hostname to the list of names that the server may have
sessionManager.outgoingServerSessionCreated((LocalOutgoingServerSession) session); session.addHostname(hostname);
// Add the new hostname to the found session // Add the new hostname to the found session
session.addHostname(newHostname); session.addHostname(newHostname);
// Notify the SessionManager that a new session has been created
sessionManager.outgoingServerSessionCreated((LocalOutgoingServerSession) session);
return true; return true;
} else { } else {
index = hostname.indexOf('.', index + 1); index = hostname.indexOf('.', index + 1);
...@@ -197,7 +198,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -197,7 +198,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
} }
// A session already exists. The session was established using server dialback so // A session already exists. The session was established using server dialback so
// it is possible to do piggybacking to authenticate more domains // it is possible to do piggybacking to authenticate more domains
if (session.getAuthenticatedDomains().contains(domain)) { if (session.getAuthenticatedDomains().contains(domain) && session.getHostnames().contains(hostname)) {
// Do nothing since the domain has already been authenticated // Do nothing since the domain has already been authenticated
return true; return true;
} }
...@@ -531,12 +532,14 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -531,12 +532,14 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
// Using SASL so just assume that the domain was validated // Using SASL so just assume that the domain was validated
// (note: this may not be correct) // (note: this may not be correct)
addAuthenticatedDomain(domain); addAuthenticatedDomain(domain);
addHostname(hostname);
return true; return true;
} }
ServerDialback method = new ServerDialback(getConnection(), domain); ServerDialback method = new ServerDialback(getConnection(), domain);
if (method.authenticateDomain(socketReader, domain, hostname, getStreamID().getID())) { if (method.authenticateDomain(socketReader, domain, hostname, getStreamID().getID())) {
// Add the validated domain as an authenticated domain // Add the validated domain as an authenticated domain
addAuthenticatedDomain(domain); addAuthenticatedDomain(domain);
addHostname(hostname);
return true; return true;
} }
return false; return false;
...@@ -593,14 +596,11 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -593,14 +596,11 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
} }
public void addHostname(String hostname) { public void addHostname(String hostname) {
boolean added;
synchronized (hostnames) { synchronized (hostnames) {
added = hostnames.add(hostname); hostnames.add(hostname);
}
if (added) {
// Add a new route for this new session
XMPPServer.getInstance().getRoutingTable().addServerRoute(new JID(hostname), this);
} }
// Add a new route for this new session
XMPPServer.getInstance().getRoutingTable().addServerRoute(new JID(null, hostname, null, true), this);
} }
public String getAvailableStreamFeatures() { public String getAvailableStreamFeatures() {
......
...@@ -100,13 +100,13 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust ...@@ -100,13 +100,13 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust
} }
public void addServerRoute(JID route, LocalOutgoingServerSession destination) { public void addServerRoute(JID route, LocalOutgoingServerSession destination) {
String address = destination.getAddress().getDomain(); String address = route.getDomain();
localRoutingTable.addRoute(address, destination); localRoutingTable.addRoute(address, destination);
serversCache.put(address, server.getNodeID().toByteArray()); serversCache.put(address, server.getNodeID().toByteArray());
} }
public void addComponentRoute(JID route, RoutableChannelHandler destination) { public void addComponentRoute(JID route, RoutableChannelHandler destination) {
String address = destination.getAddress().getDomain(); String address = route.getDomain();
localRoutingTable.addRoute(address, destination); localRoutingTable.addRoute(address, destination);
Lock lock = LockManager.getLock(address + "rt"); Lock lock = LockManager.getLock(address + "rt");
try { try {
...@@ -123,11 +123,10 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust ...@@ -123,11 +123,10 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust
} }
public boolean addClientRoute(JID route, LocalClientSession destination) { public boolean addClientRoute(JID route, LocalClientSession destination) {
String address = destination.getAddress().toString();
boolean available = destination.getPresence().isAvailable(); boolean available = destination.getPresence().isAvailable();
boolean added = localRoutingTable.addRoute(address, destination); boolean added = localRoutingTable.addRoute(route.toString(), destination);
if (destination.getAuthToken().isAnonymous()) { if (destination.getAuthToken().isAnonymous()) {
anonymousUsersCache.put(address, new ClientRoute(server.getNodeID(), available)); anonymousUsersCache.put(route.toString(), new ClientRoute(server.getNodeID(), available));
// Add the session to the list of user sessions // Add the session to the list of user sessions
if (route.getResource() != null && !available) { if (route.getResource() != null && !available) {
Lock lock = LockManager.getLock(route.toBareJID()); Lock lock = LockManager.getLock(route.toBareJID());
...@@ -141,7 +140,7 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust ...@@ -141,7 +140,7 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust
} }
} }
else { else {
usersCache.put(address, new ClientRoute(server.getNodeID(), available)); usersCache.put(route.toString(), new ClientRoute(server.getNodeID(), available));
// Add the session to the list of user sessions // Add the session to the list of user sessions
if (route.getResource() != null && !available) { if (route.getResource() != null && !available) {
Lock lock = LockManager.getLock(route.toBareJID()); Lock lock = LockManager.getLock(route.toBareJID());
......
...@@ -77,6 +77,7 @@ public class DefaultLocalCacheStrategy implements CacheFactoryStrategy { ...@@ -77,6 +77,7 @@ public class DefaultLocalCacheStrategy implements CacheFactoryStrategy {
cacheNames.put("Directed Presences", "directedPresences"); cacheNames.put("Directed Presences", "directedPresences");
cacheNames.put("Disco Server Features", "serverFeatures"); cacheNames.put("Disco Server Features", "serverFeatures");
cacheNames.put("Disco Server Items", "serverItems"); cacheNames.put("Disco Server Items", "serverItems");
cacheNames.put("Remote Server Configurations", "serversConfigurations");
cacheProps.put("cache.fileTransfer.size", 128 * 1024l); cacheProps.put("cache.fileTransfer.size", 128 * 1024l);
cacheProps.put("cache.fileTransfer.maxLifetime", 1000 * 60 * 10l); cacheProps.put("cache.fileTransfer.maxLifetime", 1000 * 60 * 10l);
...@@ -134,6 +135,8 @@ public class DefaultLocalCacheStrategy implements CacheFactoryStrategy { ...@@ -134,6 +135,8 @@ public class DefaultLocalCacheStrategy implements CacheFactoryStrategy {
cacheProps.put("cache.serverFeatures.maxLifetime", -1l); cacheProps.put("cache.serverFeatures.maxLifetime", -1l);
cacheProps.put("cache.serverItems.size", -1l); cacheProps.put("cache.serverItems.size", -1l);
cacheProps.put("cache.serverItems.maxLifetime", -1l); cacheProps.put("cache.serverItems.maxLifetime", -1l);
cacheProps.put("cache.serversConfigurations.size", 128 * 1024l);
cacheProps.put("cache.serversConfigurations.maxLifetime", JiveConstants.MINUTE * 30);
} }
......
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