Update user stats DB on every table completion.

This commit is contained in:
Me Car 2016-01-24 14:55:19 +09:00
parent fb0e0d6519
commit 5029806baa
4 changed files with 96 additions and 96 deletions

View file

@ -32,20 +32,10 @@ import java.io.FilenameFilter;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.management.MBeanServer; import javax.management.MBeanServer;
import mage.cards.repository.CardScanner; import mage.cards.repository.CardScanner;
import mage.game.match.MatchType; 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.game.tournament.TournamentType;
import mage.interfaces.MageServer; import mage.interfaces.MageServer;
import mage.remote.Connection; import mage.remote.Connection;
@ -53,9 +43,6 @@ import mage.server.draft.CubeFactory;
import mage.server.game.DeckValidatorFactory; import mage.server.game.DeckValidatorFactory;
import mage.server.game.GameFactory; import mage.server.game.GameFactory;
import mage.server.game.PlayerFactory; 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.record.UserStatsRepository;
import mage.server.tournament.TournamentFactory; import mage.server.tournament.TournamentFactory;
import mage.server.util.ConfigSettings; import mage.server.util.ConfigSettings;
@ -102,8 +89,6 @@ public class Main {
protected static boolean testMode; protected static boolean testMode;
protected static boolean fastDbMode; protected static boolean fastDbMode;
private static final ScheduledExecutorService updateUserStatsTaskExecutor = Executors.newSingleThreadScheduledExecutor();
/** /**
* @param args the command line arguments * @param args the command line arguments
*/ */
@ -132,6 +117,10 @@ public class Main {
} }
logger.info("Done."); logger.info("Done.");
logger.info("Updating user stats DB...");
UserStatsRepository.instance.updateUserStats();
logger.info("Done.");
deleteSavedGames(); deleteSavedGames();
ConfigSettings config = ConfigSettings.getInstance(); ConfigSettings config = ConfigSettings.getInstance();
for (GamePlugin plugin : config.getGameTypes()) { for (GamePlugin plugin : config.getGameTypes()) {
@ -195,13 +184,6 @@ public class Main {
} catch (Exception ex) { } catch (Exception ex) {
logger.fatal("Failed to start server - " + connection.toString(), 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() { static void initStatistics() {
@ -396,78 +378,4 @@ public class Main {
public static boolean isTestMode() { public static boolean isTestMode() {
return testMode; return testMode;
} }
private static void updateUserStats() {
long latestEndTimeMs = UserStatsRepository.instance.getLatestEndTimeMs();
List<TableRecord> 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();
}
}
}
}
}
} }

View file

@ -209,4 +209,18 @@ public class UserManager {
} }
return "History of user " + userName + ": " + user.getUserData().getHistory(); 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();
}
}
}
});
}
} }

View file

@ -3,6 +3,7 @@ package mage.server.record;
import mage.game.Table; import mage.game.Table;
import mage.game.Table.TableRecorder; import mage.game.Table.TableRecorder;
import mage.game.result.ResultProtos.TableProto; import mage.game.result.ResultProtos.TableProto;
import mage.server.UserManager;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
public class TableRecorderImpl implements TableRecorder { public class TableRecorderImpl implements TableRecorder {
@ -17,5 +18,6 @@ public class TableRecorderImpl implements TableRecorder {
public void record(Table table) { public void record(Table table) {
TableProto proto = table.toProto(); TableProto proto = table.toProto();
TableRecordRepository.instance.add(new TableRecord(proto, proto.getEndTimeMs())); TableRecordRepository.instance.add(new TableRecord(proto, proto.getEndTimeMs()));
UserManager.getInstance().updateUserHistory();
} }
} }

View file

@ -9,8 +9,11 @@ import com.j256.ormlite.support.DatabaseConnection;
import com.j256.ormlite.table.TableUtils; import com.j256.ormlite.table.TableUtils;
import java.io.File; import java.io.File;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import mage.cards.repository.RepositoryUtil; import mage.cards.repository.RepositoryUtil;
import mage.game.result.ResultProtos;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
public enum UserStatsRepository { public enum UserStatsRepository {
@ -98,6 +101,79 @@ public enum UserStatsRepository {
return 0; 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<String> updateUserStats() {
HashSet<String> updatedUsers = new HashSet();
// Lock the DB so that no other updateUserStats runs at the same time.
synchronized(this) {
long latestEndTimeMs = this.getLatestEndTimeMs();
List<TableRecord> 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() { public void closeDB() {
try { try {
if (dao != null && dao.getConnectionSource() != null) { if (dao != null && dao.getConnectionSource() != null) {