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
* @return a session that was originated from this server to a remote server.
*/
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) {
......
......@@ -208,6 +208,9 @@ public class OutgoingSessionPromise implements RoutableChannelHandler {
lock.unlock();
}
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
routingTable.routePacket(packet.getTo(), packet, false);
}
......
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
* 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;
*
* @author Gaston Dombiak
*/
public class RemoteServerConfiguration {
public class RemoteServerConfiguration implements Cacheable, Externalizable {
private String domain;
......@@ -39,6 +48,33 @@ public class RemoteServerConfiguration {
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 {
/**
* The XMPP entity is allowed to connect to the server.
......
......@@ -17,6 +17,8 @@ import org.jivesoftware.openfire.server.RemoteServerConfiguration.Permission;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.cache.Cache;
import org.jivesoftware.util.cache.CacheFactory;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
......@@ -42,6 +44,12 @@ public class RemoteServerManager {
private static final String LOAD_CONFIGURATIONS =
"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.
*
......@@ -152,6 +160,8 @@ public class RemoteServerManager {
* @param domain the domain of the remote server.
*/
public static void deleteConfiguration(String domain) {
// Remove configuration from cache
configurationsCache.remove(domain);
// Remove the permission for the entity from the database
java.sql.Connection con = null;
PreparedStatement pstmt = null;
......@@ -174,8 +184,12 @@ public class RemoteServerManager {
/**
* Adds a new permission for the specified remote server.
*
* @param configuration the new configuration for a remote server
*/
private static void addConfiguration(RemoteServerConfiguration configuration) {
// Remove configuration from cache
configurationsCache.put(configuration.getDomain(), configuration);
// Remove the permission for the entity from the database
java.sql.Connection con = null;
PreparedStatement pstmt = null;
......@@ -205,30 +219,42 @@ public class RemoteServerManager {
* @return the configuration for a remote server or <tt>null</tt> if none was found.
*/
public static RemoteServerConfiguration getConfiguration(String domain) {
RemoteServerConfiguration configuration = null;
java.sql.Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOAD_CONFIGURATION);
pstmt.setString(1, domain);
ResultSet rs = pstmt.executeQuery();
Object value = configurationsCache.get(domain);
if ("null".equals(value)) {
return null;
}
RemoteServerConfiguration configuration = (RemoteServerConfiguration) value;
if (configuration == null) {
java.sql.Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOAD_CONFIGURATION);
pstmt.setString(1, domain);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
configuration = new RemoteServerConfiguration(domain);
configuration.setRemotePort(rs.getInt(1));
configuration.setPermission(Permission.valueOf(rs.getString(2)));
while (rs.next()) {
configuration = new RemoteServerConfiguration(domain);
configuration.setRemotePort(rs.getInt(1));
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;
}
......
......@@ -38,7 +38,10 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
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;
/**
......@@ -69,7 +72,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
*/
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 OutgoingServerSocketReader socketReader;
/**
......@@ -119,9 +122,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
if (session != null) {
if (session.isUsingServerDialback()) {
// A session to the same remote server but with different hostname
// was found. Use this session and add the new hostname to the
// session
session.addHostname(hostname);
// was found. Use this session.
break;
} else {
session = null;
......@@ -137,10 +138,10 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
if (session == null) {
session = createOutgoingSession(domain, hostname, port);
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
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
sessionManager.outgoingServerSessionCreated((LocalOutgoingServerSession) session);
return true;
......@@ -178,14 +179,14 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
}
session = createOutgoingSession(domain, newHostname, port);
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
session.addAuthenticatedDomain(domain);
// Notify the SessionManager that a new session has been created
sessionManager.outgoingServerSessionCreated((LocalOutgoingServerSession) session);
// Add the new hostname to the list of names that the server may have
session.addHostname(hostname);
// Add the new hostname to the found session
session.addHostname(newHostname);
// Notify the SessionManager that a new session has been created
sessionManager.outgoingServerSessionCreated((LocalOutgoingServerSession) session);
return true;
} else {
index = hostname.indexOf('.', index + 1);
......@@ -197,7 +198,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
}
// A session already exists. The session was established using server dialback so
// 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
return true;
}
......@@ -531,12 +532,14 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
// Using SASL so just assume that the domain was validated
// (note: this may not be correct)
addAuthenticatedDomain(domain);
addHostname(hostname);
return true;
}
ServerDialback method = new ServerDialback(getConnection(), domain);
if (method.authenticateDomain(socketReader, domain, hostname, getStreamID().getID())) {
// Add the validated domain as an authenticated domain
addAuthenticatedDomain(domain);
addHostname(hostname);
return true;
}
return false;
......@@ -593,14 +596,11 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
}
public void addHostname(String hostname) {
boolean added;
synchronized (hostnames) {
added = hostnames.add(hostname);
}
if (added) {
// Add a new route for this new session
XMPPServer.getInstance().getRoutingTable().addServerRoute(new JID(hostname), this);
hostnames.add(hostname);
}
// Add a new route for this new session
XMPPServer.getInstance().getRoutingTable().addServerRoute(new JID(null, hostname, null, true), this);
}
public String getAvailableStreamFeatures() {
......
......@@ -100,13 +100,13 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust
}
public void addServerRoute(JID route, LocalOutgoingServerSession destination) {
String address = destination.getAddress().getDomain();
String address = route.getDomain();
localRoutingTable.addRoute(address, destination);
serversCache.put(address, server.getNodeID().toByteArray());
}
public void addComponentRoute(JID route, RoutableChannelHandler destination) {
String address = destination.getAddress().getDomain();
String address = route.getDomain();
localRoutingTable.addRoute(address, destination);
Lock lock = LockManager.getLock(address + "rt");
try {
......@@ -123,11 +123,10 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust
}
public boolean addClientRoute(JID route, LocalClientSession destination) {
String address = destination.getAddress().toString();
boolean available = destination.getPresence().isAvailable();
boolean added = localRoutingTable.addRoute(address, destination);
boolean added = localRoutingTable.addRoute(route.toString(), destination);
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
if (route.getResource() != null && !available) {
Lock lock = LockManager.getLock(route.toBareJID());
......@@ -141,7 +140,7 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust
}
}
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
if (route.getResource() != null && !available) {
Lock lock = LockManager.getLock(route.toBareJID());
......
......@@ -77,6 +77,7 @@ public class DefaultLocalCacheStrategy implements CacheFactoryStrategy {
cacheNames.put("Directed Presences", "directedPresences");
cacheNames.put("Disco Server Features", "serverFeatures");
cacheNames.put("Disco Server Items", "serverItems");
cacheNames.put("Remote Server Configurations", "serversConfigurations");
cacheProps.put("cache.fileTransfer.size", 128 * 1024l);
cacheProps.put("cache.fileTransfer.maxLifetime", 1000 * 60 * 10l);
......@@ -134,6 +135,8 @@ public class DefaultLocalCacheStrategy implements CacheFactoryStrategy {
cacheProps.put("cache.serverFeatures.maxLifetime", -1l);
cacheProps.put("cache.serverItems.size", -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