Commit f90eb5c2 authored by Matt Tucker's avatar Matt Tucker Committed by matt

Eliminated locks. The new logic should be fine due to...

Eliminated locks. The new logic should be fine due to synchronized(username.intern()) as well as use of ConcurrentHashMap. However, we will need to test further.


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@815 b35dd754-fafc-0310-a699-88a17e54d16e
parent 7abf5583
...@@ -22,8 +22,6 @@ import java.util.LinkedList; ...@@ -22,8 +22,6 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.jivesoftware.messenger.audit.AuditStreamIDFactory; import org.jivesoftware.messenger.audit.AuditStreamIDFactory;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.container.BasicModule; import org.jivesoftware.messenger.container.BasicModule;
...@@ -38,7 +36,6 @@ import org.xmpp.packet.JID; ...@@ -38,7 +36,6 @@ import org.xmpp.packet.JID;
import org.xmpp.packet.Message; import org.xmpp.packet.Message;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence; import org.xmpp.packet.Presence;
import org.xmlpull.v1.XmlPullParserException;
/** /**
* Manages the sessions associated with an account. The information * Manages the sessions associated with an account. The information
...@@ -94,12 +91,6 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -94,12 +91,6 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
} }
} }
/**
* The standard Jive reader/writer lock to synchronize access to
* the session set.
*/
private ReadWriteLock sessionLock = new ReentrantReadWriteLock();
/** /**
* Map of priority ordered SessionMap objects with username (toLowerCase) as key. * Map of priority ordered SessionMap objects with username (toLowerCase) as key.
* The map and its contents should NOT be persisted to disk. * The map and its contents should NOT be persisted to disk.
...@@ -112,18 +103,12 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -112,18 +103,12 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
*/ */
private RoutingTable routingTable; private RoutingTable routingTable;
/**
* The standard Jive reader/writer lock to synchronize access to
* the anonymous session set.
*/
private ReadWriteLock anonymousSessionLock = new ReentrantReadWriteLock();
/** /**
* Map of anonymous server sessions. They need to be treated separately as they * Map of anonymous server sessions. They need to be treated separately as they
* have no associated user, and don't follow the normal routing rules for * have no associated user, and don't follow the normal routing rules for
* priority based fall over. * priority based fall over.
*/ */
private Map<String, Session> anonymousSessions = new HashMap<String, Session>(); private Map<String, Session> anonymousSessions = new ConcurrentHashMap<String, Session>();
/** /**
* Simple data structure to track sessions for a single user (tracked by resource * Simple data structure to track sessions for a single user (tracked by resource
...@@ -297,28 +282,27 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -297,28 +282,27 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
boolean success = false; boolean success = false;
String username = session.getAddress().getNode().toLowerCase(); String username = session.getAddress().getNode().toLowerCase();
SessionMap resources = null; SessionMap resources = null;
sessionLock.writeLock().lock();
try { synchronized(username.intern()) {
resources = sessions.get(username); try {
if (resources == null) { resources = sessions.get(username);
resources = new SessionMap(); if (resources == null) {
sessions.put(username, resources); resources = new SessionMap();
sessions.put(username, resources);
}
resources.addSession(session);
// Register to recieve close notification on this session so we can
// remove its route from the sessions set. We hand the session back
// to ourselves in the message.
session.getConnection().registerCloseListener(this, session);
// Remove the pre-Authenticated session but remember to use the temporary JID as the key
preAuthenticatedSessions.remove(new JID(null, session.getAddress().getDomain(),
session.getStreamID().toString()).toString());
success = true;
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
} }
resources.addSession(session);
// Register to recieve close notification on this session so we can
// remove its route from the sessions set. We hand the session back
// to ourselves in the message.
session.getConnection().registerCloseListener(this, session);
// Remove the pre-Authenticated session but remember to use the temporary JID as the key
preAuthenticatedSessions.remove(new JID(null, session.getAddress().getDomain(),
session.getStreamID().toString()).toString());
success = true;
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
finally {
sessionLock.writeLock().unlock();
} }
if (success) { if (success) {
Session defaultSession = resources.getDefaultSession(); Session defaultSession = resources.getDefaultSession();
...@@ -339,8 +323,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -339,8 +323,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
*/ */
public void changePriority(JID sender, int priority) { public void changePriority(JID sender, int priority) {
String username = sender.getNode().toLowerCase(); String username = sender.getNode().toLowerCase();
sessionLock.writeLock().lock(); synchronized (username.intern()) {
try {
SessionMap resources = sessions.get(username); SessionMap resources = sessions.get(username);
if (resources == null) { if (resources == null) {
return; return;
...@@ -353,9 +336,6 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -353,9 +336,6 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
routingTable.addRoute(new JID(defaultSession.getAddress().getNode(), defaultSession.getAddress().getDomain(), ""), routingTable.addRoute(new JID(defaultSession.getAddress().getNode(), defaultSession.getAddress().getDomain(), ""),
defaultSession); defaultSession);
} }
finally {
sessionLock.writeLock().unlock();
}
} }
...@@ -376,22 +356,17 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -376,22 +356,17 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
String username = recipient.getNode(); String username = recipient.getNode();
if (username == null || "".equals(username)) { if (username == null || "".equals(username)) {
if (resource != null) { if (resource != null) {
anonymousSessionLock.readLock().lock(); synchronized (username.intern()) {
try {
session = anonymousSessions.get(resource); session = anonymousSessions.get(resource);
if(session == null){ if (session == null){
session = getSession(recipient); session = getSession(recipient);
} }
} }
finally {
anonymousSessionLock.readLock().unlock();
}
} }
} }
else { else {
username = username.toLowerCase(); username = username.toLowerCase();
sessionLock.readLock().lock(); synchronized (username.intern()) {
try {
SessionMap sessionMap = sessions.get(username); SessionMap sessionMap = sessions.get(username);
if (sessionMap != null) { if (sessionMap != null) {
if (resource == null) { if (resource == null) {
...@@ -405,9 +380,6 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -405,9 +380,6 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
} }
} }
} }
finally {
sessionLock.readLock().unlock();
}
} }
return session; return session;
} }
...@@ -419,20 +391,13 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -419,20 +391,13 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
if (username == null || "".equals(username)) { if (username == null || "".equals(username)) {
if (resource != null) { if (resource != null) {
anonymousSessionLock.readLock().lock(); hasRoute = anonymousSessions.containsKey(resource);
try {
hasRoute = anonymousSessions.containsKey(resource);
}
finally {
anonymousSessionLock.readLock().unlock();
}
} }
} }
else { else {
username = username.toLowerCase(); username = username.toLowerCase();
Session session = null; Session session = null;
sessionLock.readLock().lock(); synchronized (username.intern()) {
try {
SessionMap sessionMap = sessions.get(username); SessionMap sessionMap = sessions.get(username);
if (sessionMap != null) { if (sessionMap != null) {
if (resource == null) { if (resource == null) {
...@@ -445,9 +410,6 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -445,9 +410,6 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
} }
} }
} }
finally {
sessionLock.readLock().unlock();
}
// Makes sure the session is still active // Makes sure the session is still active
// Must occur outside of the lock since validation can cause // Must occur outside of the lock since validation can cause
// the socket to close - deadlocking on session removal // the socket to close - deadlocking on session removal
...@@ -482,26 +444,16 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -482,26 +444,16 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
} }
String username = from.getNode(); String username = from.getNode();
if (username == null || "".equals(username)) { if (username == null || "".equals(username)) {
anonymousSessionLock.readLock().lock(); session = anonymousSessions.get(resource);
try {
session = anonymousSessions.get(resource);
}
finally {
anonymousSessionLock.readLock().unlock();
}
} }
else { else {
username = username.toLowerCase(); username = username.toLowerCase();
sessionLock.readLock().lock(); synchronized (username.intern()) {
try {
SessionMap sessionMap = sessions.get(username); SessionMap sessionMap = sessions.get(username);
if (sessionMap != null) { if (sessionMap != null) {
session = sessionMap.getSession(resource); session = sessionMap.getSession(resource);
} }
} }
finally {
sessionLock.readLock().unlock();
}
} }
if (session == null) { if (session == null) {
return null; return null;
...@@ -653,49 +605,31 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -653,49 +605,31 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
private void copyAnonSessions(List sessions) { private void copyAnonSessions(List sessions) {
// Add anonymous sessions // Add anonymous sessions
anonymousSessionLock.readLock().lock(); for (Session session : anonymousSessions.values()) {
try { sessions.add(session);
for (Session session : anonymousSessions.values()) {
sessions.add(session);
}
}
finally {
anonymousSessionLock.readLock().unlock();
} }
} }
private void copyUserSessions(List sessions) { private void copyUserSessions(List sessions) {
// Get a copy of the sessions from all users // Get a copy of the sessions from all users
sessionLock.readLock().lock(); Iterator users = getSessionUsers();
try { while (users.hasNext()) {
Iterator users = getSessionUsers(); Collection<Session> usrSessions = getSessions((String)users.next());
while (users.hasNext()) { for (Session session : usrSessions) {
Collection<Session> usrSessions = getSessions((String)users.next()); sessions.add(session);
for (Session session : usrSessions) {
sessions.add(session);
}
} }
} }
finally {
sessionLock.readLock().unlock();
}
} }
private void copyUserSessions(String username, List sessionList) { private void copyUserSessions(String username, List sessionList) {
// Get a copy of the sessions from all users // Get a copy of the sessions from all users
sessionLock.readLock().lock(); SessionMap sessionMap = sessions.get(username);
try { if (sessionMap != null) {
SessionMap sessionMap = sessions.get(username); Iterator sessionItr = sessionMap.getSessions();
if (sessionMap != null) { while (sessionItr.hasNext()) {
Iterator sessionItr = sessionMap.getSessions(); sessionList.add(sessionItr.next());
while (sessionItr.hasNext()) {
sessionList.add(sessionItr.next());
}
} }
} }
finally {
sessionLock.readLock().unlock();
}
} }
public Iterator getAnonymousSessions() { public Iterator getAnonymousSessions() {
...@@ -730,15 +664,9 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -730,15 +664,9 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
public int getSessionCount(String username) throws UnauthorizedException { public int getSessionCount(String username) throws UnauthorizedException {
int sessionCount = 0; int sessionCount = 0;
sessionLock.readLock().lock(); SessionMap sessionMap = sessions.get(username);
try { if (sessionMap != null) {
SessionMap sessionMap = sessions.get(username); sessionCount = sessionMap.resources.size();
if (sessionMap != null) {
sessionCount = sessionMap.resources.size();
}
}
finally {
sessionLock.readLock().unlock();
} }
return sessionCount; return sessionCount;
} }
...@@ -753,25 +681,14 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -753,25 +681,14 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
* *
* @param packet The packet to be broadcast * @param packet The packet to be broadcast
*/ */
public void broadcast(Packet packet) throws UnauthorizedException, PacketException, XmlPullParserException { public void broadcast(Packet packet) throws UnauthorizedException {
sessionLock.readLock().lock(); Iterator values = sessions.values().iterator();
try { while (values.hasNext()) {
Iterator values = sessions.values().iterator(); ((SessionMap)values.next()).broadcast(packet);
while (values.hasNext()) {
((SessionMap)values.next()).broadcast(packet);
}
} }
finally {
sessionLock.readLock().unlock(); for (Session session : anonymousSessions.values()) {
} session.getConnection().deliver(packet);
anonymousSessionLock.readLock().lock();
try {
for (Session session : anonymousSessions.values()) {
session.getConnection().deliver(packet);
}
}
finally {
anonymousSessionLock.readLock().unlock();
} }
} }
...@@ -783,15 +700,9 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -783,15 +700,9 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
* @param packet The packet to be broadcast * @param packet The packet to be broadcast
*/ */
public void userBroadcast(String username, Packet packet) throws UnauthorizedException, PacketException { public void userBroadcast(String username, Packet packet) throws UnauthorizedException, PacketException {
sessionLock.readLock().lock(); SessionMap sessionMap = sessions.get(username);
try { if (sessionMap != null) {
SessionMap sessionMap = sessions.get(username); sessionMap.broadcast(packet);
if (sessionMap != null) {
sessionMap.broadcast(packet);
}
}
finally {
sessionLock.readLock().unlock();
} }
} }
...@@ -807,20 +718,13 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -807,20 +718,13 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
} }
SessionMap sessionMap = null; SessionMap sessionMap = null;
if (anonymousSessions.containsValue(session)) { if (anonymousSessions.containsValue(session)) {
anonymousSessionLock.writeLock().lock(); anonymousSessions.remove(session.getAddress().getResource());
try { sessionCount--;
anonymousSessions.remove(session.getAddress().getResource());
sessionCount--;
}
finally {
anonymousSessionLock.writeLock().unlock();
}
} }
else { else {
if (session.getAddress() != null && session.getAddress().getNode() != null) { if (session.getAddress() != null && session.getAddress().getNode() != null) {
String username = session.getAddress().getNode().toLowerCase(); String username = session.getAddress().getNode().toLowerCase();
sessionLock.writeLock().lock(); synchronized (username.intern()) {
try {
sessionMap = sessions.get(username); sessionMap = sessions.get(username);
if (sessionMap != null) { if (sessionMap != null) {
sessionMap.removeSession(session); sessionMap.removeSession(session);
...@@ -830,9 +734,6 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -830,9 +734,6 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
} }
} }
} }
finally {
sessionLock.writeLock().unlock();
}
} }
} }
...@@ -865,16 +766,10 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -865,16 +766,10 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
public void addAnonymousSession(Session session) { public void addAnonymousSession(Session session) {
try { try {
anonymousSessionLock.writeLock().lock(); anonymousSessions.put(session.getAddress().getResource(), session);
try { session.getConnection().registerCloseListener(this, session);
anonymousSessions.put(session.getAddress().getResource(), session); // Remove the session from the pre-Authenticated sessions list
session.getConnection().registerCloseListener(this, session); preAuthenticatedSessions.remove(session.getAddress().toString());
// Remove the session from the pre-Authenticated sessions list
preAuthenticatedSessions.remove(session.getAddress().toString());
}
finally {
anonymousSessionLock.writeLock().unlock();
}
// Anonymous session always have resources so we only need to add one route. That is // Anonymous session always have resources so we only need to add one route. That is
// the route to the anonymous session // the route to the anonymous session
routingTable.addRoute(session.getAddress(), session); routingTable.addRoute(session.getAddress(), session);
......
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