* Session locking - Fixed some problems with the reentrant lock.

This commit is contained in:
LevelX2 2014-12-01 17:00:26 +01:00
parent 2af52cfd3a
commit 896793b93d
4 changed files with 92 additions and 47 deletions

View file

@ -63,6 +63,7 @@ import java.net.InetAddress;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static mage.server.Session.getBasicCause;
import org.jboss.remoting.transport.bisocket.BisocketServerInvoker; import org.jboss.remoting.transport.bisocket.BisocketServerInvoker;
@ -213,18 +214,16 @@ public class Main {
//SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.Disconnected); //SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.Disconnected);
SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.LostConnection); SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.LostConnection);
logger.info("CLIENT DISCONNECTED - " + sessionInfo, throwable); logger.info("CLIENT DISCONNECTED - " + sessionInfo, throwable);
if (logger.isDebugEnabled()) { logger.debug("Stack Trace", throwable);
throwable.printStackTrace();
}
} }
else { else {
SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.LostConnection); SessionManager.getInstance().disconnect(client.getSessionId(), DisconnectReason.LostConnection);
logger.info("CONNECTION LOST - " + sessionInfo, throwable); logger.info("LOST CONNECTION - " + sessionInfo);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
if (throwable == null) { if (throwable == null) {
logger.debug("Lease expired"); logger.debug("- cause: Lease expired");
} else { } else {
throwable.printStackTrace(); logger.debug(" - cause: " + Session.getBasicCause(throwable).toString());
} }
} }
} }

View file

@ -33,7 +33,6 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -213,8 +212,10 @@ public class Session {
// because different threads can activate this // because different threads can activate this
public void userLostConnection() { public void userLostConnection() {
boolean lockSet = false;
try { try {
if(lock.tryLock(5, TimeUnit.SECONDS)) { if(lock.tryLock(500, TimeUnit.MILLISECONDS)) {
lockSet = true;
User user = UserManager.getInstance().getUser(userId); User user = UserManager.getInstance().getUser(userId);
if (user == null || !user.isConnected()) { if (user == null || !user.isConnected()) {
return; //user was already disconnected by other thread return; //user was already disconnected by other thread
@ -224,46 +225,70 @@ public class Session {
logger.info("OLD SESSION IGNORED - " + user.getName()); logger.info("OLD SESSION IGNORED - " + user.getName());
return; return;
} }
logger.info("LOST CONNECTION - " + user.getName()); logger.info("LOST CONNECTION - " + user.getName() + " id: " + userId);
UserManager.getInstance().disconnect(userId, DisconnectReason.LostConnection); UserManager.getInstance().disconnect(userId, DisconnectReason.LostConnection);
} else { } else {
logger.error("SESSION LOCK - userId " + userId); logger.error("SESSION LOCK lost connection - userId: " + userId);
} }
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
logger.error("SESSION LOCK - userId " + userId, ex); logger.error("SESSION LOCK lost connection - userId: " + userId, ex);
} }
finally { finally {
lock.unlock(); if (lockSet) {
lock.unlock();
}
} }
} }
public void kill(DisconnectReason reason) { public void kill(DisconnectReason reason) {
UserManager.getInstance().removeUser(userId, reason); boolean lockSet = false;
try {
if(lock.tryLock(500, TimeUnit.MILLISECONDS)) {
lockSet = true;
UserManager.getInstance().removeUser(userId, reason);
} else {
logger.error("SESSION LOCK - kill: userId " + userId);
}
} catch (InterruptedException ex) {
logger.error("SESSION LOCK - kill: userId " + userId, ex);
}
finally {
if (lockSet) {
lock.unlock();
}
}
} }
public void fireCallback(final ClientCallback call) { public void fireCallback(final ClientCallback call) {
boolean lockSet = false;
try { try {
boolean tryLock; if (lock.tryLock(500, TimeUnit.MILLISECONDS)) {
if (lock.tryLock(5, TimeUnit.SECONDS)) { lockSet = true;
call.setMessageId(messageId++); call.setMessageId(messageId++);
callbackHandler.handleCallbackOneway(new Callback(call)); callbackHandler.handleCallbackOneway(new Callback(call));
} else { } else {
logger.error("CALLBACK LOCK - userId " + userId); logger.error("SESSION LOCK callback: userId " + userId);
logger.error(" - method: " + call.getMethod()); logger.error(" - method: " + call.getMethod());
} }
} catch (HandleCallbackException ex) { } catch (HandleCallbackException ex) {
logger.info("CALLBACK EXCEPTION - userId " + userId, ex); User user = UserManager.getInstance().getUser(userId);
if (logger.isDebugEnabled()) { logger.warn("SESSION CALLBACK EXCEPTION - " + (user != null ? user.getName():"") + " userId " + userId);
ex.printStackTrace(); logger.warn(" - method: " + call.getMethod());
} logger.warn(" - cause: " + getBasicCause(ex).toString());
logger.trace("Stack trace:", ex);
userLostConnection(); userLostConnection();
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
logger.error("CALLBACK LOCK EXCEPTION - userId " + userId, ex); logger.error("SESSION LOCK callback -userId: " + userId);
logger.error(" - method: " + call.getMethod()); logger.error(" - method: " + call.getMethod());
logger.error(" - cause: " + getBasicCause(ex).toString());
logger.trace("Stack trace:", ex);
} }
finally { finally {
lock.unlock(); if (lockSet) {
lock.unlock();
}
} }
} }
@ -293,4 +318,15 @@ public class Session {
messageData.add(message); messageData.add(message);
fireCallback(new ClientCallback("showUserMessage", null, messageData)); fireCallback(new ClientCallback("showUserMessage", null, messageData));
} }
public static Throwable getBasicCause(Throwable cause) {
Throwable t = cause;
while (t.getCause() != null) {
t = t.getCause();
if (t == cause) {
throw new IllegalArgumentException("Infinite cycle detected in causal chain");
}
}
return t;
}
} }

View file

@ -115,28 +115,26 @@ public class SessionManager {
Session session = sessions.get(sessionId); Session session = sessions.get(sessionId);
if (session != null) { if (session != null) {
if (!reason.equals(DisconnectReason.AdminDisconnect)) { if (!reason.equals(DisconnectReason.AdminDisconnect)) {
synchronized (session) { if (!sessions.containsKey(sessionId)) {
if (!sessions.containsKey(sessionId)) { // session was removed meanwhile by another thread so we can return
// session was removed meanwhile by another thread so we can return return;
return; }
} sessions.remove(sessionId);
sessions.remove(sessionId); switch (reason) {
switch (reason) { case Disconnected:
case Disconnected: session.kill(reason);
session.kill(reason); LogServiceImpl.instance.log(LogKeys.KEY_SESSION_KILLED, sessionId);
LogServiceImpl.instance.log(LogKeys.KEY_SESSION_KILLED, sessionId); break;
break; case SessionExpired:
case SessionExpired: session.kill(reason);
session.kill(reason); LogServiceImpl.instance.log(LogKeys.KEY_SESSION_EXPIRED, sessionId);
LogServiceImpl.instance.log(LogKeys.KEY_SESSION_EXPIRED, sessionId); break;
break; case LostConnection:
case LostConnection: session.userLostConnection();
session.userLostConnection(); LogServiceImpl.instance.log(LogKeys.KEY_SESSION_DISCONNECTED, sessionId);
LogServiceImpl.instance.log(LogKeys.KEY_SESSION_DISCONNECTED, sessionId); break;
break; default:
default: logger.error("endSession: unexpected reason " + reason.toString() + " - sessionId: "+ sessionId);
logger.error("endSession: unexpected reason " + reason.toString() + " - sessionId: "+ sessionId);
}
} }
} else { } else {
sessions.remove(sessionId); sessions.remove(sessionId);

View file

@ -29,6 +29,7 @@ package mage.server;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -123,14 +124,25 @@ public class User {
this.sessionId = sessionId; this.sessionId = sessionId;
if (sessionId.isEmpty()) { if (sessionId.isEmpty()) {
userState = UserState.Disconnected; userState = UserState.Disconnected;
logger.debug("Disconnected User " + userName + " id: " + userId); lostConnection();
logger.debug("USER - lost connection: " + userName + " id: " + userId);
} else if (userState == UserState.Created) { } else if (userState == UserState.Created) {
userState = UserState.Connected; userState = UserState.Connected;
logger.debug("Created user " + userName + " id: " + userId); logger.debug("USER - created: " + userName + " id: " + userId);
} else { } else {
userState = UserState.Reconnected; userState = UserState.Reconnected;
reconnect(); reconnect();
logger.info("Reconnected user " + userName + " id: " + userId); logger.info("USER - reconnected: " + userName + " id: " + userId);
}
}
public void lostConnection() {
// Because watched games don't get restored after reconnection call stop watching
for (Iterator<UUID> iterator = watchedGames.iterator(); iterator.hasNext();) {
UUID gameId = iterator.next();
GameManager.getInstance().stopWatching(gameId, userId);
iterator.remove();
} }
} }