diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java index d4869459fc..54c2a2b477 100644 --- a/Mage.Server/src/main/java/mage/server/Main.java +++ b/Mage.Server/src/main/java/mage/server/Main.java @@ -32,20 +32,10 @@ import java.io.FilenameFilter; import java.net.InetAddress; import java.net.MalformedURLException; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; import javax.management.MBeanServer; import mage.cards.repository.CardScanner; import mage.game.match.MatchType; -import mage.game.result.ResultProtos.MatchPlayerProto; -import mage.game.result.ResultProtos.MatchProto; -import mage.game.result.ResultProtos.TableProto; -import mage.game.result.ResultProtos.TourneyPlayerProto; -import mage.game.result.ResultProtos.TourneyProto; -import mage.game.result.ResultProtos.UserStatsProto; import mage.game.tournament.TournamentType; import mage.interfaces.MageServer; import mage.remote.Connection; @@ -53,9 +43,6 @@ import mage.server.draft.CubeFactory; import mage.server.game.DeckValidatorFactory; import mage.server.game.GameFactory; import mage.server.game.PlayerFactory; -import mage.server.record.TableRecord; -import mage.server.record.TableRecordRepository; -import mage.server.record.UserStats; import mage.server.record.UserStatsRepository; import mage.server.tournament.TournamentFactory; import mage.server.util.ConfigSettings; @@ -102,8 +89,6 @@ public class Main { protected static boolean testMode; protected static boolean fastDbMode; - private static final ScheduledExecutorService updateUserStatsTaskExecutor = Executors.newSingleThreadScheduledExecutor(); - /** * @param args the command line arguments */ @@ -132,6 +117,10 @@ public class Main { } logger.info("Done."); + logger.info("Updating user stats DB..."); + UserStatsRepository.instance.updateUserStats(); + logger.info("Done."); + deleteSavedGames(); ConfigSettings config = ConfigSettings.getInstance(); for (GamePlugin plugin : config.getGameTypes()) { @@ -195,13 +184,6 @@ public class Main { } catch (Exception ex) { logger.fatal("Failed to start server - " + connection.toString(), ex); } - - updateUserStatsTaskExecutor.scheduleAtFixedRate(new Runnable() { - @Override - public void run() { - updateUserStats(); - } - }, 60, 60, TimeUnit.SECONDS); } static void initStatistics() { @@ -396,78 +378,4 @@ public class Main { public static boolean isTestMode() { return testMode; } - - private static void updateUserStats() { - long latestEndTimeMs = UserStatsRepository.instance.getLatestEndTimeMs(); - List records = TableRecordRepository.instance.getAfter(latestEndTimeMs); - for (TableRecord record : records) { - TableProto table = record.getProto(); - if (table.getControllerName().equals("System")) { - // This is a sub table within a tournament, so it's already handled by the main - // tournament table. - continue; - } - if (table.hasMatch()) { - MatchProto match = table.getMatch(); - for (MatchPlayerProto player : match.getPlayersList()) { - UserStats userStats = UserStatsRepository.instance.getUser(player.getName()); - UserStatsProto proto = userStats != null ? userStats.getProto() - : UserStatsProto.newBuilder().setName(player.getName()).build(); - UserStatsProto.Builder builder = UserStatsProto.newBuilder(proto) - .setMatches(proto.getMatches() + 1); - switch (player.getQuit()) { - case IDLE_TIMEOUT: - builder.setMatchesIdleTimeout(proto.getMatchesIdleTimeout() + 1); - break; - case TIMER_TIMEOUT: - builder.setMatchesTimerTimeout(proto.getMatchesTimerTimeout() + 1); - break; - case QUIT: - builder.setMatchesQuit(proto.getMatchesQuit() + 1); - break; - } - if (userStats == null) { - UserStatsRepository.instance.add(new UserStats(builder.build(), table.getEndTimeMs())); - } else { - UserStatsRepository.instance.update(new UserStats(builder.build(), table.getEndTimeMs())); - } - // UserStats for this player is updated, so refresh it. - User user = UserManager.getInstance().getUserByName(player.getName()); - if (user != null) { - user.resetUserStats(); - } - } - } else if (table.hasTourney()) { - TourneyProto tourney = table.getTourney(); - for (TourneyPlayerProto player : tourney.getPlayersList()) { - UserStats userStats = UserStatsRepository.instance.getUser(player.getName()); - UserStatsProto proto = userStats != null ? userStats.getProto() - : UserStatsProto.newBuilder().setName(player.getName()).build(); - UserStatsProto.Builder builder = UserStatsProto.newBuilder(proto) - .setTourneys(proto.getTourneys() + 1); - switch (player.getQuit()) { - case DURING_ROUND: - builder.setTourneysQuitDuringRound(proto.getTourneysQuitDuringRound() + 1); - break; - case DURING_DRAFTING: - builder.setTourneysQuitDuringDrafting(proto.getTourneysQuitDuringDrafting() + 1); - break; - case DURING_CONSTRUCTION: - builder.setTourneysQuitDuringConstruction(proto.getTourneysQuitDuringConstruction() + 1); - break; - } - if (userStats == null) { - UserStatsRepository.instance.add(new UserStats(builder.build(), table.getEndTimeMs())); - } else { - UserStatsRepository.instance.update(new UserStats(builder.build(), table.getEndTimeMs())); - } - // UserStats for this player is updated, so refresh it. - User user = UserManager.getInstance().getUserByName(player.getName()); - if (user != null) { - user.resetUserStats(); - } - } - } - } - } } diff --git a/Mage.Server/src/main/java/mage/server/UserManager.java b/Mage.Server/src/main/java/mage/server/UserManager.java index 2c363b47a6..7b1b875869 100644 --- a/Mage.Server/src/main/java/mage/server/UserManager.java +++ b/Mage.Server/src/main/java/mage/server/UserManager.java @@ -209,4 +209,18 @@ public class UserManager { } return "History of user " + userName + ": " + user.getUserData().getHistory(); } + + public void updateUserHistory() { + callExecutor.execute(new Runnable() { + @Override + public void run() { + for (String updatedUser : UserStatsRepository.instance.updateUserStats()) { + User user = getUserByName(updatedUser); + if (user != null) { + user.resetUserStats(); + } + } + } + }); + } } diff --git a/Mage.Server/src/main/java/mage/server/record/TableRecorderImpl.java b/Mage.Server/src/main/java/mage/server/record/TableRecorderImpl.java index b4d16688ed..2bafdff9c1 100644 --- a/Mage.Server/src/main/java/mage/server/record/TableRecorderImpl.java +++ b/Mage.Server/src/main/java/mage/server/record/TableRecorderImpl.java @@ -3,6 +3,7 @@ package mage.server.record; import mage.game.Table; import mage.game.Table.TableRecorder; import mage.game.result.ResultProtos.TableProto; +import mage.server.UserManager; import org.apache.log4j.Logger; public class TableRecorderImpl implements TableRecorder { @@ -17,5 +18,6 @@ public class TableRecorderImpl implements TableRecorder { public void record(Table table) { TableProto proto = table.toProto(); TableRecordRepository.instance.add(new TableRecord(proto, proto.getEndTimeMs())); + UserManager.getInstance().updateUserHistory(); } } diff --git a/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java b/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java index de43a7c76b..26348de66a 100644 --- a/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java +++ b/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java @@ -9,8 +9,11 @@ import com.j256.ormlite.support.DatabaseConnection; import com.j256.ormlite.table.TableUtils; import java.io.File; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import mage.cards.repository.RepositoryUtil; +import mage.game.result.ResultProtos; import org.apache.log4j.Logger; public enum UserStatsRepository { @@ -98,6 +101,79 @@ public enum UserStatsRepository { return 0; } + // updateUserStats reads tables finished after the last DB update and reflects it to the DB. + // It returns the list of user names that are upated. + public List updateUserStats() { + HashSet updatedUsers = new HashSet(); + // Lock the DB so that no other updateUserStats runs at the same time. + synchronized(this) { + long latestEndTimeMs = this.getLatestEndTimeMs(); + List records = TableRecordRepository.instance.getAfter(latestEndTimeMs); + for (TableRecord record : records) { + ResultProtos.TableProto table = record.getProto(); + if (table.getControllerName().equals("System")) { + // This is a sub table within a tournament, so it's already handled by the main + // tournament table. + continue; + } + if (table.hasMatch()) { + ResultProtos.MatchProto match = table.getMatch(); + for (ResultProtos.MatchPlayerProto player : match.getPlayersList()) { + UserStats userStats = this.getUser(player.getName()); + ResultProtos.UserStatsProto proto = userStats != null ? userStats.getProto() + : ResultProtos.UserStatsProto.newBuilder().setName(player.getName()).build(); + ResultProtos.UserStatsProto.Builder builder = ResultProtos.UserStatsProto.newBuilder(proto) + .setMatches(proto.getMatches() + 1); + switch (player.getQuit()) { + case IDLE_TIMEOUT: + builder.setMatchesIdleTimeout(proto.getMatchesIdleTimeout() + 1); + break; + case TIMER_TIMEOUT: + builder.setMatchesTimerTimeout(proto.getMatchesTimerTimeout() + 1); + break; + case QUIT: + builder.setMatchesQuit(proto.getMatchesQuit() + 1); + break; + } + if (userStats == null) { + this.add(new UserStats(builder.build(), table.getEndTimeMs())); + } else { + this.update(new UserStats(builder.build(), table.getEndTimeMs())); + } + updatedUsers.add(player.getName()); + } + } else if (table.hasTourney()) { + ResultProtos.TourneyProto tourney = table.getTourney(); + for (ResultProtos.TourneyPlayerProto player : tourney.getPlayersList()) { + UserStats userStats = this.getUser(player.getName()); + ResultProtos.UserStatsProto proto = userStats != null ? userStats.getProto() + : ResultProtos.UserStatsProto.newBuilder().setName(player.getName()).build(); + ResultProtos.UserStatsProto.Builder builder = ResultProtos.UserStatsProto.newBuilder(proto) + .setTourneys(proto.getTourneys() + 1); + switch (player.getQuit()) { + case DURING_ROUND: + builder.setTourneysQuitDuringRound(proto.getTourneysQuitDuringRound() + 1); + break; + case DURING_DRAFTING: + builder.setTourneysQuitDuringDrafting(proto.getTourneysQuitDuringDrafting() + 1); + break; + case DURING_CONSTRUCTION: + builder.setTourneysQuitDuringConstruction(proto.getTourneysQuitDuringConstruction() + 1); + break; + } + if (userStats == null) { + this.add(new UserStats(builder.build(), table.getEndTimeMs())); + } else { + this.update(new UserStats(builder.build(), table.getEndTimeMs())); + } + updatedUsers.add(player.getName()); + } + } + } + } + return new ArrayList(updatedUsers); + } + public void closeDB() { try { if (dao != null && dao.getConnectionSource() != null) {