* Cleanup of server memory handling - removed memory leaks for Chat, Player, Match, Game etc.

This commit is contained in:
LevelX2 2014-02-21 01:13:27 +01:00
parent c7289a3810
commit 8491b5b90b
27 changed files with 255 additions and 129 deletions

View file

@ -133,16 +133,18 @@ public class GameEndDialog extends MageDialog {
// get game log
try {
GamePanel gamePanel = MageFrame.getGame(gameEndView.getMatchView().getGames().get(gameEndView.getMatchView().getGames().size()-1));
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern( "yyyyMMdd_HHmmss" );
String fileName = new StringBuilder(dir).append(File.separator)
.append(sdf.format(gameEndView.getStartTime()))
.append("_").append(gameEndView.getMatchView().getGameType())
.append("_").append(gameEndView.getMatchView().getGames().size())
.append(".txt").toString();
PrintWriter out = new PrintWriter(fileName);
out.print(gamePanel.getGameLog());
out.close();
if (gamePanel != null) {
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern( "yyyyMMdd_HHmmss" );
String fileName = new StringBuilder(dir).append(File.separator)
.append(sdf.format(gameEndView.getStartTime()))
.append("_").append(gameEndView.getMatchView().getGameType())
.append("_").append(gameEndView.getMatchView().getGames().size())
.append(".txt").toString();
PrintWriter out = new PrintWriter(fileName);
out.print(gamePanel.getGameLog());
out.close();
}
} catch (FileNotFoundException ex) {
JOptionPane.showMessageDialog(this, "Error while writing game log to file\n\n" + ex, "Error writing gamelog", JOptionPane.ERROR_MESSAGE);
}

View file

@ -245,7 +245,7 @@ public class TableWaitingDialog extends MageDialog {
private void btnStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStartActionPerformed
if (!isTournament) {
session.startGame(roomId, tableId);
session.startMatch(roomId, tableId);
}
else {
session.startTournament(roomId, tableId);

View file

@ -617,7 +617,7 @@ public class TablesPanel extends javax.swing.JPanel {
session.joinTable(roomId, table.getTableId(), "Human", "Human", 1, DeckImporterUtil.importDeck("test.dck"));
session.joinTable(roomId, table.getTableId(), "Computer", "Computer - mad", 5, DeckImporterUtil.importDeck("test.dck"));
session.startGame(roomId, table.getTableId());
session.startMatch(roomId, table.getTableId());
} catch (HeadlessException ex) {
handleError(ex);
}

View file

@ -127,7 +127,7 @@ public interface MageServer {
DraftPickView sendCardPick(UUID draftId, String sessionId, UUID cardId) throws MageException;
//challenge methods
void startChallenge(String sessionId, UUID roomId, UUID tableId, UUID challengeId) throws MageException;
// void startChallenge(String sessionId, UUID roomId, UUID tableId, UUID challengeId) throws MageException;
//replay methods
void replayGame(UUID gameId, String sessionId) throws MageException;

View file

@ -878,7 +878,7 @@ public class SessionImpl implements Session {
}
@Override
public boolean startGame(UUID roomId, UUID tableId) {
public boolean startMatch(UUID roomId, UUID tableId) {
try {
if (isConnected()) {
server.startMatch(sessionId, roomId, tableId);
@ -886,8 +886,6 @@ public class SessionImpl implements Session {
}
} catch (MageException ex) {
handleMageException(ex);
} catch (Throwable t) {
handleThrowable(t);
}
return false;
}
@ -907,20 +905,20 @@ public class SessionImpl implements Session {
return false;
}
@Override
public boolean startChallenge(UUID roomId, UUID tableId, UUID challengeId) {
try {
if (isConnected()) {
server.startChallenge(sessionId, roomId, tableId, challengeId);
return true;
}
} catch (MageException ex) {
handleMageException(ex);
} catch (Throwable t) {
handleThrowable(t);
}
return false;
}
// @Override
// public boolean startChallenge(UUID roomId, UUID tableId, UUID challengeId) {
// try {
// if (isConnected()) {
// server.startChallenge(sessionId, roomId, tableId, challengeId);
// return true;
// }
// } catch (MageException ex) {
// handleMageException(ex);
// } catch (Throwable t) {
// handleThrowable(t);
// }
// return false;
// }
@Override
public boolean submitDeck(UUID tableId, DeckCardLists deck) {

View file

@ -37,7 +37,7 @@ import java.util.UUID;
*/
public interface GamePlay {
boolean startGame(UUID roomId, UUID tableId);
boolean startMatch(UUID roomId, UUID tableId);
boolean watchGame(UUID gameId);

View file

@ -61,7 +61,7 @@ public interface PlayerActions {
boolean startTournament(UUID roomId, UUID tableId);
boolean startChallenge(UUID roomId, UUID tableId, UUID challengeId);
// boolean startChallenge(UUID roomId, UUID tableId, UUID challengeId);
boolean joinTournamentTable(UUID roomId, UUID tableId, String playerName, String playerType, int skill);

View file

@ -1370,4 +1370,12 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
}
return sb.toString();
}
@Override
public void cleanUpOnMatchEnd() {
root = null;
super.cleanUpOnMatchEnd();
}
}

View file

@ -49,7 +49,7 @@ public class ChatManager {
private ChatManager() {}
private ConcurrentHashMap<UUID, ChatSession> chatSessions = new ConcurrentHashMap<UUID, ChatSession>();
private final ConcurrentHashMap<UUID, ChatSession> chatSessions = new ConcurrentHashMap<>();
public UUID createChatSession() {
ChatSession chatSession = new ChatSession();

View file

@ -354,16 +354,16 @@ public class MageServerImpl implements MageServer {
});
}
@Override
public void startChallenge(final String sessionId, final UUID roomId, final UUID tableId, final UUID challengeId) throws MageException {
execute("startChallenge", sessionId, new Action() {
@Override
public void execute() {
UUID userId = SessionManager.getInstance().getSession(sessionId).getUserId();
TableManager.getInstance().startChallenge(userId, roomId, tableId, challengeId);
}
});
}
// @Override
// public void startChallenge(final String sessionId, final UUID roomId, final UUID tableId, final UUID challengeId) throws MageException {
// execute("startChallenge", sessionId, new Action() {
// @Override
// public void execute() {
// UUID userId = SessionManager.getInstance().getSession(sessionId).getUserId();
// TableManager.getInstance().startChallenge(userId, roomId, tableId, challengeId);
// }
// });
// }
@Override
public void startTournament(final String sessionId, final UUID roomId, final UUID tableId) throws MageException {

View file

@ -399,44 +399,50 @@ public class TableController {
}
// public synchronized void startChallenge(UUID userId, UUID challengeId) {
// if (userId.equals(this.userId)) {
// try {
// match.startMatch();
// match.startGame();
// table.initGame();
// GameOptions gameOptions = new GameOptions();
// gameOptions.testMode = true;
//// match.getGame().setGameOptions(gameOptions);
// GameManager.getInstance().createGameSession(match.getGame(), userPlayerMap, table.getId(), null);
// ChallengeManager.getInstance().prepareChallenge(getPlayerId(), match);
// for (Entry<UUID, UUID> entry: userPlayerMap.entrySet()) {
// UserManager.getInstance().getUser(entry.getKey()).gameStarted(match.getGame().getId(), entry.getValue());
// }
// } catch (GameException ex) {
// logger.fatal(null, ex);
// }
// }
// }
// private UUID getPlayerId() throws GameException {
// UUID playerId = null;
// for (Entry<UUID, UUID> entry : userPlayerMap.entrySet()) {
// playerId = entry.getValue();
// break;
// }
// if (playerId == null) {
// throw new GameException("Couldn't find a player in challenge mode.");
// }
// return playerId;
// }
/**
* Used from non tournament match to start
*
* @param userId owner of the tabel
*/
public synchronized void startMatch(UUID userId) {
if (userId.equals(this.userId)) {
if (isOwner(userId)) {
startMatch();
}
}
public synchronized void startChallenge(UUID userId, UUID challengeId) {
if (userId.equals(this.userId)) {
try {
match.startMatch();
match.startGame();
table.initGame();
GameOptions gameOptions = new GameOptions();
gameOptions.testMode = true;
// match.getGame().setGameOptions(gameOptions);
GameManager.getInstance().createGameSession(match.getGame(), userPlayerMap, table.getId(), null);
ChallengeManager.getInstance().prepareChallenge(getPlayerId(), match);
for (Entry<UUID, UUID> entry: userPlayerMap.entrySet()) {
UserManager.getInstance().getUser(entry.getKey()).gameStarted(match.getGame().getId(), entry.getValue());
}
} catch (GameException ex) {
logger.fatal(null, ex);
}
}
}
private UUID getPlayerId() throws GameException {
UUID playerId = null;
for (Entry<UUID, UUID> entry : userPlayerMap.entrySet()) {
playerId = entry.getValue();
break;
}
if (playerId == null) {
throw new GameException("Couldn't find a player in challenge mode.");
}
return playerId;
}
public synchronized void startMatch() {
if (table.getState() == TableState.STARTING) {
try {
@ -576,11 +582,16 @@ public class TableController {
return options;
}
public void endGame() {
/**
* Ends the current game and starts if neccessary the next game
*
* @return true if table can be closed
*/
public boolean endGameAndStartNextGame() {
boolean matchIsOver = false;
// get player that chooses who goes first
UUID choosingPlayerId = match.getChooser();
match.endGame();
table.endGame();
if (ConfigSettings.getInstance().isSaveGameActivated() && !match.getGame().isSimulation()) {
if (GameManager.getInstance().saveGame(match.getGame().getId())) {
match.setReplayAvailable(true);
@ -596,18 +607,30 @@ public class TableController {
if (!match.isMatchOver()) {
startGame(choosingPlayerId);
} else {
this.matchEnd();
table.endGame();
matchIsOver = true;
closeTable();
}
}
else {
// if match has only one game
this.matchEnd();
table.endGame();
matchIsOver = true;
closeTable();
}
} catch (GameException ex) {
logger.fatal(null, ex);
}
return matchIsOver;
}
/**
* Tables of normal matches or tournament sub tables are no longer
* needed, if the match ends.
*
*/
private void closeTable() {
this.matchEnd();
table.closeTable();
ChatManager.getInstance().destroyChatSession(chatId);
}
private void matchEnd() {
@ -639,9 +662,9 @@ public class TableController {
}
}
}
// free resources no longer needed
match.cleanUpOnMatchEnd(ConfigSettings.getInstance().isSaveGameActivated());
}
// free resources no longer needed
match.cleanUpOnMatchEnd(ConfigSettings.getInstance().isSaveGameActivated());
}
private synchronized void setupTimeout(int seconds) {

View file

@ -62,8 +62,8 @@ public class TableManager {
private static final TableManager INSTANCE = new TableManager();
private static final Logger logger = Logger.getLogger(TableManager.class);
private final ConcurrentHashMap<UUID, TableController> controllers = new ConcurrentHashMap<UUID, TableController>();
private final ConcurrentHashMap<UUID, Table> tables = new ConcurrentHashMap<UUID, Table>();
private final ConcurrentHashMap<UUID, TableController> controllers = new ConcurrentHashMap<>();
private final ConcurrentHashMap<UUID, Table> tables = new ConcurrentHashMap<>();
/**
* Defines how often checking process should be run on server.
@ -212,23 +212,36 @@ public class TableManager {
return null;
}
/**
* Starts the Match from a non tournament table
*
* @param userId table owner
* @param roomId
* @param tableId
*/
public void startMatch(UUID userId, UUID roomId, UUID tableId) {
if (controllers.containsKey(tableId)) {
controllers.get(tableId).startMatch(userId);
}
}
public void startMatch(UUID roomId, UUID tableId) {
/**
* Used from tournament to start the sub matches from tournament
*
* @param roomId
* @param tableId
*/
public void startTournamentSubMatch(UUID roomId, UUID tableId) {
if (controllers.containsKey(tableId)) {
controllers.get(tableId).startMatch();
}
}
public void startChallenge(UUID userId, UUID roomId, UUID tableId, UUID challengeId) {
if (controllers.containsKey(tableId)) {
controllers.get(tableId).startChallenge(userId, challengeId);
}
}
// public void startChallenge(UUID userId, UUID roomId, UUID tableId, UUID challengeId) {
// if (controllers.containsKey(tableId)) {
// controllers.get(tableId).startChallenge(userId, challengeId);
// }
// }
public void startTournament(UUID userId, UUID roomId, UUID tableId) {
if (controllers.containsKey(tableId)) {
@ -258,7 +271,9 @@ public class TableManager {
public void endGame(UUID tableId) {
if (controllers.containsKey(tableId)) {
controllers.get(tableId).endGame();
if (controllers.get(tableId).endGameAndStartNextGame()) {
removeTable(tableId);
}
}
}
@ -303,7 +318,10 @@ public class TableManager {
Table table = tables.get(tableId);
controllers.remove(tableId);
tables.remove(tableId);
GamesRoomManager.getInstance().removeTable(tableId);
// If table is not finished, the table has to removed completly (if finished it will be removed in GamesRoomImpl.Update())
if (!table.getState().equals(TableState.FINISHED)) {
GamesRoomManager.getInstance().removeTable(tableId);
}
if (table.getMatch() != null && table.getMatch().getGame() != null) {
table.getMatch().getGame().end();
}
@ -314,7 +332,7 @@ public class TableManager {
logger.debug("Table expire checking...");
Date now = new Date();
List<UUID> toRemove = new ArrayList<UUID>();
List<UUID> toRemove = new ArrayList<>();
for (Table table : tables.values()) {
if (!table.getState().equals(TableState.FINISHED)) {
// remove all not finished tables created more than expire_time ago

View file

@ -7,6 +7,8 @@ import mage.constants.Zone;
import mage.game.match.Match;
/**
* C U R R E N T L Y U N U S E D
*
* Loads challenges from scenarios.
* Configure games by initializing starting game board.
*/

View file

@ -93,9 +93,9 @@ public class GameController implements GameCallback {
private static final ExecutorService gameExecutor = ThreadExecutor.getInstance().getGameExecutor();
private static final Logger logger = Logger.getLogger(GameController.class);
private ConcurrentHashMap<UUID, GameSession> gameSessions = new ConcurrentHashMap<UUID, GameSession>();
private ConcurrentHashMap<UUID, GameWatcher> watchers = new ConcurrentHashMap<UUID, GameWatcher>();
private ConcurrentHashMap<UUID, PriorityTimer> timers = new ConcurrentHashMap<UUID, PriorityTimer>();
private ConcurrentHashMap<UUID, GameSession> gameSessions = new ConcurrentHashMap<>();
private ConcurrentHashMap<UUID, GameWatcher> watchers = new ConcurrentHashMap<>();
private ConcurrentHashMap<UUID, PriorityTimer> timers = new ConcurrentHashMap<>();
private ConcurrentHashMap<UUID, UUID> userPlayerMap;
private UUID gameSessionId;
@ -123,6 +123,10 @@ public class GameController implements GameCallback {
init();
}
public void cleanUp() {
ChatManager.getInstance().destroyChatSession(chatId);
}
private void init() {
game.addTableEventListener(
new Listener<TableEvent> () {
@ -383,7 +387,7 @@ public class GameController implements GameCallback {
CardInfo cardInfo = CardRepository.instance.findCard(cardName);
Card card = cardInfo != null ? cardInfo.getCard() : null;
if (card != null) {
Set<Card> cards = new HashSet<Card>();
Set<Card> cards = new HashSet<>();
cards.add(card);
game.loadCards(cards, playerId);
card.moveToZone(Zone.HAND, null, game, false);

View file

@ -48,7 +48,7 @@ public class GameManager {
private GameManager() {}
private ConcurrentHashMap<UUID, GameController> gameControllers = new ConcurrentHashMap<UUID, GameController>();
private final ConcurrentHashMap<UUID, GameController> gameControllers = new ConcurrentHashMap<>();
public UUID createGameSession(Game game, ConcurrentHashMap<UUID, UUID> userPlayerMap, UUID tableId, UUID choosingPlayerId) {
GameController gameController = new GameController(game, userPlayerMap, tableId, choosingPlayerId);
@ -62,9 +62,9 @@ public class GameManager {
}
}
public void destroyChatSession(UUID gameId) {
gameControllers.remove(gameId);
}
// public void destroyChatSession(UUID gameId) {
// gameControllers.remove(gameId);
// }
public UUID getChatId(UUID gameId) {
if (gameControllers.containsKey(gameId)) {
@ -145,11 +145,11 @@ public class GameManager {
}
}
public void removeSession(UUID userId) {
for (GameController controller: gameControllers.values()) {
controller.kill(userId);
}
}
// public void removeSession(UUID userId) {
// for (GameController controller: gameControllers.values()) {
// controller.kill(userId);
// }
// }
public void kill(UUID gameId, UUID userId) {
if (gameControllers.containsKey(gameId)) {
@ -177,7 +177,11 @@ public class GameManager {
}
public void removeGame(UUID gameId) {
gameControllers.remove(gameId);
GameController gameController = gameControllers.get(gameId);
if (gameController != null) {
gameController.cleanUp();
gameControllers.remove(gameId);
}
}
public boolean saveGame(UUID gameId) {

View file

@ -86,15 +86,15 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
private void update() {
ArrayList<TableView> tableList = new ArrayList<>();
ArrayList<MatchView> matchList = new ArrayList<>();
List<Table> t = new ArrayList<>(tables.values());
Collections.sort(t, new TimestampSorter());
Collections.reverse(t);
for (Table table: t) {
List<Table> allTables = new ArrayList<>(tables.values());
Collections.sort(allTables, new TimestampSorter());
Collections.reverse(allTables);
for (Table table: allTables) {
if (table.getState() != TableState.FINISHED) {
tableList.add(new TableView(table));
}
else if (matchList.size() < 50) {
if (table.isTournament()) {
else if (matchList.size() < 50) {
if (table.isTournament()) {
matchList.add(new MatchView(table));
} else {
matchList.add(new MatchView(table.getMatch()));
@ -173,9 +173,13 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
@Override
public void removeTable(UUID tableId) {
tables.remove(tableId);
if (logger.isDebugEnabled()) {
logger.debug("Table removed: " + tableId);
Table table = tables.get(tableId);
if (table != null) {
table.cleanUp();
tables.remove(tableId);
if (logger.isDebugEnabled()) {
logger.debug("Table removed: " + tableId);
}
}
}

View file

@ -68,12 +68,12 @@ public class TournamentController {
private static final Logger logger = Logger.getLogger(TournamentController.class);
private UUID chatId;
private UUID tableId;
private final UUID chatId;
private final UUID tableId;
private boolean started = false;
private Tournament tournament;
private ConcurrentHashMap<UUID, UUID> userPlayerMap = new ConcurrentHashMap<UUID, UUID>();
private ConcurrentHashMap<UUID, TournamentSession> tournamentSessions = new ConcurrentHashMap<UUID, TournamentSession>();
private final Tournament tournament;
private ConcurrentHashMap<UUID, UUID> userPlayerMap = new ConcurrentHashMap<>();
private final ConcurrentHashMap<UUID, TournamentSession> tournamentSessions = new ConcurrentHashMap<>();
private boolean abort = false;
@ -197,7 +197,9 @@ public class TournamentController {
tournamentSession.tournamentOver();
tournamentSession.removeTournament();
}
this.tournamentSessions.clear();
TableManager.getInstance().endTournament(tableId, tournament);
tournament.cleanUpOnTournamentEnd();
}
@ -211,7 +213,7 @@ public class TournamentController {
TournamentPlayer player2 = pair.getPlayer2();
tableManager.addPlayer(getPlayerSessionId(player1.getPlayer().getId()), table.getId(), player1.getPlayer(), player1.getPlayerType(), player1.getDeck());
tableManager.addPlayer(getPlayerSessionId(player2.getPlayer().getId()), table.getId(), player2.getPlayer(), player2.getPlayerType(), player2.getDeck());
tableManager.startMatch(null, table.getId());
tableManager.startTournamentSubMatch(null, table.getId());
pair.setMatch(tableManager.getMatch(table.getId()));
pair.setTableId(table.getId());
player1.setState(TournamentPlayerState.DUELING);

View file

@ -126,7 +126,7 @@ public class LoadTest {
}
/*** Start game ***/
session.startGame(roomId, table.getTableId());
session.startMatch(roomId, table.getTableId());
Thread.sleep(100);
}
@ -203,7 +203,7 @@ public class LoadTest {
}
/*** Start game ***/
session.startGame(roomId, table.getTableId());
session.startMatch(roomId, table.getTableId());
while (!mageClient.isGameOver()) {
Thread.sleep(1000);

View file

@ -125,8 +125,22 @@ public class Table implements Serializable {
state = TableState.CONSTRUCTING;
}
public void endGame() {
/**
* All activities of the table end
* (only replay of games (if active) and display tournament results)
*
*/
public void closeTable() {
state = TableState.FINISHED;
this.validator = null;
}
/**
* Complete remove of the table, release all objects
*
*/
public void cleanUp() {
match.cleanUpOnMatchEnd(isTournament);
}
public String getGameType() {

View file

@ -91,5 +91,10 @@ public interface Match {
* @param isSaveGameActivated
*/
void cleanUpOnMatchEnd(boolean isSaveGameActivated);
/**
* Free all possible resources
*/
void cleanUp();
}

View file

@ -340,5 +340,14 @@ public abstract class MatchImpl implements Match {
this.getGames().clear();
}
}
@Override
public void cleanUp() {
for (MatchPlayer matchPlayer: players) {
matchPlayer.cleanUpOnMatchEnd();
}
this.getGames().clear();
}
}

View file

@ -129,9 +129,15 @@ public class MatchPlayer {
public void cleanUpOnMatchEnd() {
// Free resources that are not needed after match end
this.deck = null;
this.player.cleanUpOnMatchEnd();
// this.player = null;
}
public void cleanUp() {
// Free resources that are not needed after match end
this.player = null;
}
public String getName() {
return name;
}

View file

@ -83,4 +83,6 @@ public interface Tournament {
void setTournamentType(TournamentType tournamentType);
int getNumberRounds();
void cleanUpOnTournamentEnd();
}

View file

@ -214,7 +214,7 @@ public abstract class TournamentImpl implements Tournament {
}
protected List<TournamentPlayer> getActivePlayers() {
List<TournamentPlayer> activePlayers = new ArrayList<TournamentPlayer>();
List<TournamentPlayer> activePlayers = new ArrayList<>();
for (TournamentPlayer player: players.values()) {
if (!player.getEliminated()) {
activePlayers.add(player);
@ -324,6 +324,7 @@ public abstract class TournamentImpl implements Tournament {
player.setConstructing();
new Thread(
new Runnable() {
@Override
public void run() {
player.getPlayer().construct(TournamentImpl.this, player.getDeck());
}
@ -410,4 +411,11 @@ public abstract class TournamentImpl implements Tournament {
}
}
@Override
public void cleanUpOnTournamentEnd() {
for(TournamentPlayer tournamentPlayer: players.values()) {
tournamentPlayer.CleanUpOnTournamentEnd();
}
}
}

View file

@ -163,5 +163,12 @@ public class TournamentPlayer {
this.doneConstructing = true;
}
/**
* Free resources no longer needed if tournament has ended
*
*/
public void CleanUpOnTournamentEnd() {
this.deck = null;
}
}

View file

@ -432,4 +432,9 @@ public interface Player extends MageItem, Copyable<Player> {
* @return true if playerToCheckId belongs to an opponent
*/
boolean hasOpponent(UUID playerToCheckId, Game game);
/**
* Free resources on match end
*/
void cleanUpOnMatchEnd();
}

View file

@ -2158,5 +2158,10 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
return game.isOpponent(this, playerToCheckId);
}
@Override
public void cleanUpOnMatchEnd() {
}
}