From 50f8af651fa7fb91f288823e3b862a415eadd311 Mon Sep 17 00:00:00 2001 From: "jakub.salavec" Date: Thu, 17 Apr 2025 12:05:51 +0200 Subject: [PATCH 1/4] Performance - reduced number of active tournament db queries --- .../async/handler/AdminRequestHandler.java | 1 - .../handler/TableDraftRequestHandler.java | 7 ------ .../com/gempukku/lotro/hall/TableHolder.java | 14 +++++------ .../lotro/tournament/TournamentService.java | 25 +++++++++++++------ 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/AdminRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/AdminRequestHandler.java index 35b181e40..636c747e3 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/AdminRequestHandler.java +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/AdminRequestHandler.java @@ -1183,7 +1183,6 @@ public class AdminRequestHandler extends LotroServerRequestHandler implements Ur private void clearCacheInternal() throws SQLException, IOException { _leagueService.clearCache(); - _tournamentService.clearCache(); _cacheManager.clearCaches(); _hallServer.cleanup(true); } diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/TableDraftRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/TableDraftRequestHandler.java index d2c727d94..10de2f695 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/TableDraftRequestHandler.java +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/TableDraftRequestHandler.java @@ -8,10 +8,8 @@ import com.gempukku.lotro.draft2.SoloDraftDefinitions; import com.gempukku.lotro.draft3.DraftPlayer; import com.gempukku.lotro.draft3.TableDraft; import com.gempukku.lotro.draft3.TableDraftDefinitions; -import com.gempukku.lotro.game.CardCollection; import com.gempukku.lotro.game.LotroCardBlueprintLibrary; import com.gempukku.lotro.game.Player; -import com.gempukku.lotro.game.SortAndFilterCards; import com.gempukku.lotro.game.formats.LotroFormatLibrary; import com.gempukku.lotro.league.LeagueService; import com.gempukku.lotro.packs.ProductLibrary; @@ -25,15 +23,10 @@ import io.netty.handler.codec.http.QueryStringDecoder; import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.lang.reflect.Type; import java.util.HashMap; -import java.util.List; import java.util.Map; public class TableDraftRequestHandler extends LotroServerRequestHandler implements UriRequestHandler { diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/TableHolder.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/TableHolder.java index 33a05e161..1edfb4f39 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/TableHolder.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/TableHolder.java @@ -268,18 +268,16 @@ public class TableHolder { private String getTournamentName(GameTable table) { final League league = table.getGameSettings().league(); - final Tournament tournament = null; //tournamentService.getLiveTournaments().stream().filter(tournament1 -> tournament1.getTournamentId().equals(table.getGameSettings().tournamentId())).findFirst().orElse(null); if (league != null) { return league.getName() + " - " + table.getGameSettings().leagueSerie().getName(); - } else if (tournament != null) { - String tournamentTableDescription = tournament.getTableDescription(); - if (tournamentTableDescription == null || tournamentTableDescription.isEmpty()) { - return "Casual - " + table.getGameSettings().timeSettings().name(); + } else if (table.getGameSettings().tournamentId() != null) { + final String tournamentTableDescription = tournamentService.getActiveTournamentTableDescription(table.getGameSettings().tournamentId()); + if (tournamentTableDescription != null) { + return tournamentTableDescription; } - return tournamentTableDescription; - } else { - return "Casual - " + table.getGameSettings().timeSettings().name(); } + + return "Casual - " + table.getGameSettings().timeSettings().name(); } public List getTournamentTables(String tournamentId) { diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentService.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentService.java index db990bda9..469e3cc0d 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentService.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/TournamentService.java @@ -179,10 +179,8 @@ public class TournamentService { public void reloadTournaments(TableHolder tables) { _tables = tables; - clearCache(); reloadQueues(); - - getLiveTournaments(); + reloadLiveTournamentsFromDb(); } public void reloadQueues() { @@ -234,10 +232,6 @@ public class TournamentService { addImmediateRecurringSealed("th_sealed_queue", casual + "Hunters Block Sealed", "thSealedQueue-", "single_th_block_sealed"); } - public void clearCache() { - _activeTournaments.clear(); - } - public void cancelAllTournamentQueues() throws SQLException, IOException { for (TournamentQueue tournamentQueue : _tournamentQueues.values()) tournamentQueue.leaveAllPlayers(); @@ -474,7 +468,9 @@ public class TournamentService { return result; } - public List getLiveTournaments() { + private List reloadLiveTournamentsFromDb() { + _activeTournaments.clear(); + List result = new ArrayList<>(); for (var dbinfo : _tournamentDao.getUnfinishedTournaments()) { var tournament = upsertTournamentInCache(dbinfo); @@ -483,6 +479,10 @@ public class TournamentService { return result; } + public List getLiveTournaments() { + return new ArrayList<>(_activeTournaments.values()); + } + public Tournament getTournamentById(String tournamentId) { Tournament tournament = _activeTournaments.get(tournamentId); if (tournament == null) { @@ -495,6 +495,15 @@ public class TournamentService { return tournament; } + public String getActiveTournamentTableDescription(String tournamentId) { + Tournament tournament = _activeTournaments.get(tournamentId); + if (tournament == null) { + return null; + } else { + return tournament.getTableDescription(); + } + } + public synchronized CollectionType getCollectionTypeByCode(String collectionTypeCode) { for (var tourney : getLiveTournaments()) { var collection = tourney.getInfo().Collection; From 46f98fd144bd1709d28edb96c7e4edc74cdbd74d Mon Sep 17 00:00:00 2001 From: "jakub.salavec" Date: Thu, 17 Apr 2025 12:35:08 +0200 Subject: [PATCH 2/4] Performance - reduced number of db queries if draft with the same id starts again (ie. after server restart if one was in progress) --- .../lotro/collection/CollectionsManager.java | 14 ++++++++++---- .../gempukku/lotro/draft3/TableDraftClassic.java | 6 +----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/collection/CollectionsManager.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/collection/CollectionsManager.java index db61bcbe4..9cc412e7b 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/collection/CollectionsManager.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/collection/CollectionsManager.java @@ -135,6 +135,16 @@ public class CollectionsManager { } } + + public void removeFromPlayerCollection(String player, String collectionType, CardCollection cardCollection, String reason) throws SQLException, IOException { + _readWriteLock.writeLock().lock(); + try { + removeFromPlayerCollection(_playerDAO.getPlayer(player), collectionType, cardCollection, reason); + } finally { + _readWriteLock.writeLock().unlock(); + } + } + private void removeFromPlayerCollection(Player player, String collectionType, CardCollection cardCollection, String reason) { if (collectionType.contains("+")) throw new IllegalArgumentException("Invalid collection type: " + collectionType); @@ -308,10 +318,6 @@ public class CollectionsManager { } } - public boolean sellCardInPlayerCollection(String player, CollectionType collectionType, String blueprintId, int currency) throws SQLException, IOException { - return sellCardInPlayerCollection(_playerDAO.getPlayer(player), collectionType, blueprintId, currency); - } - public boolean sellCardInPlayerCollection(Player player, CollectionType collectionType, String blueprintId, int currency) throws SQLException, IOException { _readWriteLock.writeLock().lock(); try { diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/TableDraftClassic.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/TableDraftClassic.java index a8e5ce795..b6ba15b0c 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/TableDraftClassic.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft3/TableDraftClassic.java @@ -164,11 +164,7 @@ public class TableDraftClassic implements TableDraft{ if (draftPlayer instanceof DraftBot) { botCollections.remove(draftPlayer); } else { - for (CardCollection.Item item : collection.getAll()) { - for (int i = 0; i < item.getCount(); i++) { - collectionsManager.sellCardInPlayerCollection(draftPlayer.getName(), collectionType, item.getBlueprintId(), 0); - } - } + collectionsManager.removeFromPlayerCollection(draftPlayer.getName(), collectionType.getCode(), collection, "Duplicate tournament collection"); } } } catch (SQLException | IOException ignore) { From a27889f058f911be68b31575e9c92da5ce1384da Mon Sep 17 00:00:00 2001 From: "jakub.salavec" Date: Thu, 17 Apr 2025 13:27:11 +0200 Subject: [PATCH 3/4] Fixed - sealed tournament no longer depends on (removed) db query to issue starting material --- .../gempukku/lotro/tournament/SealedTournament.java | 12 +++++++++++- .../lotro/tournament/SoloDraftTournament.java | 8 ++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SealedTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SealedTournament.java index 9dcc466be..c9e7fd361 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SealedTournament.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SealedTournament.java @@ -25,6 +25,8 @@ public class SealedTournament extends BaseTournament implements Tournament { private SealedTournamentInfo _sealedInfo; private ZonedDateTime nextRoundStart = null; + private boolean collectionsCreated = false; + public SealedTournament(TournamentService tournamentService, CollectionsManager collectionsManager, ProductLibrary productLibrary, LotroFormatLibrary formatLibrary, SoloDraftDefinitions soloDraftDefinitions, TableDraftDefinitions tableDraftDefinitions, TableHolder tables, String tournamentId) { super(tournamentService, collectionsManager, productLibrary, formatLibrary, soloDraftDefinitions, tableDraftDefinitions, tables, tournamentId); @@ -90,7 +92,11 @@ public class SealedTournament extends BaseTournament implements Tournament { _collectionsManager.addPlayerCollection(true, "Sealed tournament product", player, collDef, newCollection); } - public void createAndPopulateCollections() { + private void createAndPopulateCollections() { + if (collectionsCreated) { + return; + } + var collDef = _sealedInfo.generateCollectionInfo(); var collections = _collectionsManager.getPlayersCollection(collDef.getCode()); var sealedDef = _sealedInfo.SealedDefinition; @@ -107,6 +113,8 @@ public class SealedTournament extends BaseTournament implements Tournament { _collectionsManager.addPlayerCollection(true, "Sealed tournament product", playerName, collDef, newCollection); } + + collectionsCreated = true; } public void disqualifyUnregisteredPlayers() { @@ -170,6 +178,8 @@ public class SealedTournament extends BaseTournament implements Tournament { _tournamentInfo.Stage = Stage.DECK_BUILDING; _tournamentService.recordTournamentStage(_tournamentId, getTournamentStage()); + createAndPopulateCollections(); + String duration = DateUtils.HumanDuration(_sealedInfo.DeckbuildingDuration); result.add(new BroadcastAction("Sealed product has been issued for tournament " + getTournamentName() + ". Players now have " + duration + " to open packs and build a deck with the cards you open. " diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloDraftTournament.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloDraftTournament.java index 321e6a796..2186379da 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloDraftTournament.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/tournament/SoloDraftTournament.java @@ -28,6 +28,8 @@ public class SoloDraftTournament extends BaseTournament implements Tournament { private SoloDraftTournamentInfo _soloDraftInfo; private ZonedDateTime nextRoundStart = null; + private boolean collectionsCreated = false; + public SoloDraftTournament(TournamentService tournamentService, CollectionsManager collectionsManager, ProductLibrary productLibrary, LotroFormatLibrary formatLibrary, SoloDraftDefinitions soloDraftDefinitions, TableDraftDefinitions tableDraftDefinitions, TableHolder tables, String tournamentId) { super(tournamentService, collectionsManager, productLibrary, formatLibrary, soloDraftDefinitions, tableDraftDefinitions, tables, tournamentId); @@ -112,6 +114,10 @@ public class SoloDraftTournament extends BaseTournament implements Tournament { } private void createStartingCollections() { + if (collectionsCreated) { + return; + } + var collDef = _soloDraftInfo.generateCollectionInfo(); var collections = _collectionsManager.getPlayersCollection(collDef.getCode()); @@ -134,6 +140,8 @@ public class SoloDraftTournament extends BaseTournament implements Tournament { _collectionsManager.addPlayerCollection(false, "Draft tournament product", playerName, collDef, startingCollection); } + + collectionsCreated = true; } private long getSeed(String playerName, CollectionType collectionType) { From ee3ca08f0ef20d990893700e77ceab53669ca9d3 Mon Sep 17 00:00:00 2001 From: "jakub.salavec" Date: Thu, 17 Apr 2025 17:24:17 +0200 Subject: [PATCH 4/4] Added - warning that clearing server cache can break live tournaments --- .../src/main/web/includes/admin/generalAdmin.html | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/includes/admin/generalAdmin.html b/gemp-lotr/gemp-lotr-async/src/main/web/includes/admin/generalAdmin.html index 9df1279f6..35e7d930f 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/includes/admin/generalAdmin.html +++ b/gemp-lotr/gemp-lotr-async/src/main/web/includes/admin/generalAdmin.html @@ -24,7 +24,18 @@ $("#shutdown-response").html(string); }); }); - + + hall.comm.getLiveTournaments( + function (xml) { + var root = xml.documentElement; + if (root.tagName == 'tournaments') { + var tournaments = root.getElementsByTagName("tournament"); + if (tournaments.length > 0) { + $("#cache-response").html("Ready.
Live tournaments: " + tournaments.length + "
THE ABOVE TOURNAMENTS WILL BE INTERRUPTED AND MAY NOT BE ABLE TO BE RESUMED"); + } + } + }); + $("#clear-cache-button").button().click( function () { $("#cache-response").html("Processing...");