diff --git a/Mage.Server/src/main/java/mage/server/draft/DraftController.java b/Mage.Server/src/main/java/mage/server/draft/DraftController.java index 13558eb7c4f..38af257d528 100644 --- a/Mage.Server/src/main/java/mage/server/draft/DraftController.java +++ b/Mage.Server/src/main/java/mage/server/draft/DraftController.java @@ -119,11 +119,12 @@ public class DraftController { private synchronized void checkStart() { if (!draft.isStarted() && allJoined()) { draft.setStarted(); - managerFactory.threadExecutor().getCallExecutor().execute(this::startDraft); + managerFactory.threadExecutor().getTourneyExecutor().execute(this::startDraft); } } private void startDraft() { + Thread.currentThread().setName("TOURNEY DRAFT " + tableId); for (final Entry entry : draftSessions.entrySet()) { if (!entry.getValue().init()) { logger.fatal("Unable to initialize client for playerId " + entry.getKey()); diff --git a/Mage.Server/src/main/java/mage/server/managers/ThreadExecutor.java b/Mage.Server/src/main/java/mage/server/managers/ThreadExecutor.java index 79c1c3e1f22..936122c2281 100644 --- a/Mage.Server/src/main/java/mage/server/managers/ThreadExecutor.java +++ b/Mage.Server/src/main/java/mage/server/managers/ThreadExecutor.java @@ -15,6 +15,11 @@ public interface ThreadExecutor { */ ExecutorService getGameExecutor(); + /** + * Tourney thread + */ + ExecutorService getTourneyExecutor(); + /** * Helper threads to execute async commands for game and server related tasks (example: process income command from a client) */ diff --git a/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java b/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java index 4069b81c4b2..4e914513102 100644 --- a/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java +++ b/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java @@ -174,7 +174,7 @@ public class TournamentController { private void checkStart() { if (!started && allJoined()) { - managerFactory.threadExecutor().getCallExecutor().execute(this::startTournament); + managerFactory.threadExecutor().getTourneyExecutor().execute(this::startTournament); } } @@ -191,6 +191,7 @@ public class TournamentController { } private synchronized void startTournament() { + Thread.currentThread().setName("TOURNEY " + tableId); for (final TournamentSession tournamentSession : tournamentSessions.values()) { if (!tournamentSession.init()) { logger.fatal("Unable to initialize client userId: " + tournamentSession.userId + " tournamentId " + tournament.getId()); diff --git a/Mage.Server/src/main/java/mage/server/util/ThreadExecutorImpl.java b/Mage.Server/src/main/java/mage/server/util/ThreadExecutorImpl.java index bf83aedba10..0ce8aa2bb9e 100644 --- a/Mage.Server/src/main/java/mage/server/util/ThreadExecutorImpl.java +++ b/Mage.Server/src/main/java/mage/server/util/ThreadExecutorImpl.java @@ -14,8 +14,13 @@ public class ThreadExecutorImpl implements ThreadExecutor { private static final Logger logger = Logger.getLogger(ThreadExecutorImpl.class); + // used for max tourney limit, but without new config setting + // example: server can have 100 games and 10 tourney at a time + private final int GAMES_PER_TOURNEY_RATIO = 100 / 10; + private final ExecutorService callExecutor; // shareable threads to run single task (example: save new game settings from a user, send chat message, etc) private final ExecutorService gameExecutor; // game threads to run long tasks, one per game (example: run game and wait user's feedback) + private final ExecutorService tourneyExecutor; // tourney threads (example: make draft, construction, build and run other game threads) private final ScheduledExecutorService timeoutExecutor; private final ScheduledExecutorService timeoutIdleExecutor; private final ScheduledExecutorService serverHealthExecutor; @@ -44,15 +49,21 @@ public class ThreadExecutorImpl implements ThreadExecutor { ((ThreadPoolExecutor) gameExecutor).allowCoreThreadTimeOut(true); ((ThreadPoolExecutor) gameExecutor).setThreadFactory(new XMageThreadFactory("GAME")); + //tourney = Executors.newFixedThreadPool(config.getMaxGameThreads() / GAMES_PER_TOURNEY_RATIO); + tourneyExecutor = new FixedThreadPoolWithException(config.getMaxGameThreads() / GAMES_PER_TOURNEY_RATIO); + ((ThreadPoolExecutor) tourneyExecutor).setKeepAliveTime(60, TimeUnit.SECONDS); + ((ThreadPoolExecutor) tourneyExecutor).allowCoreThreadTimeOut(true); + ((ThreadPoolExecutor) tourneyExecutor).setThreadFactory(new XMageThreadFactory("TOURNEY")); + timeoutExecutor = Executors.newScheduledThreadPool(4); ((ThreadPoolExecutor) timeoutExecutor).setKeepAliveTime(60, TimeUnit.SECONDS); ((ThreadPoolExecutor) timeoutExecutor).allowCoreThreadTimeOut(true); - ((ThreadPoolExecutor) timeoutExecutor).setThreadFactory(new XMageThreadFactory("TIMEOUT")); + ((ThreadPoolExecutor) timeoutExecutor).setThreadFactory(new XMageThreadFactory("XMAGE TIMEOUT")); timeoutIdleExecutor = Executors.newScheduledThreadPool(4); ((ThreadPoolExecutor) timeoutIdleExecutor).setKeepAliveTime(60, TimeUnit.SECONDS); ((ThreadPoolExecutor) timeoutIdleExecutor).allowCoreThreadTimeOut(true); - ((ThreadPoolExecutor) timeoutIdleExecutor).setThreadFactory(new XMageThreadFactory("TIMEOUT_IDLE")); + ((ThreadPoolExecutor) timeoutIdleExecutor).setThreadFactory(new XMageThreadFactory("XMAGE TIMEOUT_IDLE")); serverHealthExecutor = Executors.newSingleThreadScheduledExecutor(new XMageThreadFactory("HEALTH")); } @@ -109,6 +120,11 @@ public class ThreadExecutorImpl implements ThreadExecutor { return callExecutor; } + @Override + public ExecutorService getTourneyExecutor() { + return tourneyExecutor; + } + @Override public ExecutorService getGameExecutor() { return gameExecutor;