From 604bf7e29caf788a34083348cf0e3896688f7504 Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Sun, 3 Sep 2017 14:35:02 +0300 Subject: [PATCH] Batch Operations for Session and WorldTimesTables --- .../plan/database/tables/KillsTable.java | 8 + .../plan/database/tables/SessionsTable.java | 166 ++++++++++++++++-- .../plan/database/tables/WorldTimesTable.java | 141 +++++++++++++-- 3 files changed, 288 insertions(+), 27 deletions(-) diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/KillsTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/KillsTable.java index 476890945..a340a5571 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/KillsTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/KillsTable.java @@ -182,4 +182,12 @@ public class KillsTable extends UserIDTable { close(set, statement); } } + + public void addKillsToSessions(Map>> map) { + // TODO + } + + public void savePlayerKills(Map>> allSessions) { + // TODO + } } diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/SessionsTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/SessionsTable.java index 830a44f57..933f98ad6 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/SessionsTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/SessionsTable.java @@ -1,5 +1,6 @@ package main.java.com.djrapitops.plan.database.tables; +import com.djrapitops.plugin.utilities.Verify; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.api.exceptions.DBCreateTableException; import main.java.com.djrapitops.plan.data.Session; @@ -28,6 +29,7 @@ public class SessionsTable extends UserIDTable { private final String columnDeaths = "deaths"; private final ServerTable serverTable; + private String insertStatement; /** * @param db @@ -36,6 +38,17 @@ public class SessionsTable extends UserIDTable { public SessionsTable(SQLDB db, boolean usingMySQL) { super("plan_sessions", db, usingMySQL); serverTable = db.getServerTable(); + insertStatement = "INSERT INTO " + tableName + " (" + + columnUserID + ", " + + columnSessionStart + ", " + + columnSessionEnd + ", " + + columnDeaths + ", " + + columnMobKills + ", " + + columnServerID + + ") VALUES (" + + usersTable.statementSelectID + ", " + + "?, ?, ?, ?, " + + serverTable.statementSelectServerID + ")"; } /** @@ -90,17 +103,7 @@ public class SessionsTable extends UserIDTable { private void saveSessionInformation(UUID uuid, Session session) throws SQLException { PreparedStatement statement = null; try { - statement = prepareStatement("INSERT INTO " + tableName + " (" - + columnUserID + ", " - + columnSessionStart + ", " - + columnSessionEnd + ", " - + columnDeaths + ", " - + columnMobKills + ", " - + columnServerID - + ") VALUES (" - + usersTable.statementSelectID + ", " - + "?, ?, ?, ?, " - + serverTable.statementSelectServerID + ")"); + statement = prepareStatement(insertStatement); statement.setString(1, uuid.toString()); statement.setLong(2, session.getSessionStart()); @@ -543,4 +546,145 @@ public class SessionsTable extends UserIDTable { close(set, statement); } } + + public Map>> getAllSessions(boolean includeExtraData) throws SQLException { + PreparedStatement statement = null; + ResultSet set = null; + try { + String usersIDColumn = usersTable + "." + usersTable.getColumnID(); + String usersUUIDColumn = usersTable + "." + usersTable.getColumnUUID() + " as uuid"; + String serverIDColumn = serverTable + "." + serverTable.getColumnID(); + String serverUUIDColumn = serverTable + "." + serverTable.getColumnUUID() + " as s_uuid"; + + statement = prepareStatement("SELECT " + + columnID + ", " + + columnSessionStart + ", " + + columnSessionEnd + ", " + + columnDeaths + ", " + + columnMobKills + ", " + + usersUUIDColumn + ", " + + serverUUIDColumn + + " FROM " + tableName + + " JOIN " + usersTable + " on " + usersIDColumn + "=" + columnUserID + + " JOIN " + serverTable + " on " + serverIDColumn + "=" + columnServerID + ); + statement.setFetchSize(20000); + set = statement.executeQuery(); + + Map>> map = new HashMap<>(); + while (set.next()) { + UUID serverUUID = UUID.fromString(set.getString("s_uuid")); + UUID uuid = UUID.fromString(set.getString("uuid")); + + Map> sessionsByUser = map.getOrDefault(serverUUID, new HashMap<>()); + List sessions = sessionsByUser.getOrDefault(uuid, new ArrayList<>()); + + long start = set.getLong(columnSessionStart); + long end = set.getLong(columnSessionEnd); + + int deaths = set.getInt(columnDeaths); + int mobKills = set.getInt(columnMobKills); + int id = set.getInt(columnID); + + Session session = new Session(id, start, end, mobKills, deaths); + sessions.add(session); + + sessionsByUser.put(uuid, sessions); + map.put(serverUUID, sessionsByUser); + } + if (includeExtraData) { + db.getKillsTable().addKillsToSessions(map); + db.getWorldTimesTable().addWorldTimesToSessions(map); + } + return map; + } finally { + endTransaction(statement); + close(set, statement); + } + } + + public void insertSessions(Map>> allSessions, boolean containsExtraData) throws SQLException { + if (Verify.isEmpty(allSessions)) { + return; + } + PreparedStatement statement = null; + try { + statement = prepareStatement(insertStatement); + for (UUID serverUUID : allSessions.keySet()) { + for (Map.Entry> entry : allSessions.get(serverUUID).entrySet()) { + UUID uuid = entry.getKey(); + List sessions = entry.getValue(); + + for (Session session : sessions) { + statement.setString(1, uuid.toString()); + statement.setLong(2, session.getSessionStart()); + statement.setLong(3, session.getSessionEnd()); + statement.setInt(4, session.getDeaths()); + statement.setInt(5, session.getMobKills()); + statement.setString(6, serverUUID.toString()); + statement.addBatch(); + } + } + } + + statement.executeBatch(); + commit(statement.getConnection()); + } finally { + close(statement); + } + if (containsExtraData) { + Map>> savedSessions = getAllSessions(false); + matchSessionIDs(allSessions, savedSessions); + db.getKillsTable().savePlayerKills(allSessions); + db.getWorldTimesTable().saveWorldTimes(allSessions); + } + } + + /** + * Sessions should be saved before calling this method. + * + * @param allSessions Sessions to match IDs to (contain extra data) + * @param allSavedSessions Sessions in the Database. + */ + private void matchSessionIDs(Map>> allSessions, Map>> allSavedSessions) { + for (UUID serverUUID : allSessions.keySet()) { + Map> serverSessions = allSessions.get(serverUUID); + Map> savedServerSessions = allSavedSessions.get(serverUUID); + + for (Map.Entry> entry : serverSessions.entrySet()) { + UUID uuid = entry.getKey(); + List sessions = entry.getValue(); + + List savedSessions = savedServerSessions.get(uuid); + if (savedSessions == null) { + throw new IllegalStateException("Some of the sessions being matched were not saved."); + } + + matchSessions(sessions, savedSessions); + } + } + } + + /** + * Used by matchSessionIDs method. + *

+ * Matches IDs of Sessions with by sessionStart. + * Assumes that both lists are from the same user and server. + * + * @param sessions Sessions of Player in a Server. + * @param savedSessions Sessions of Player in a Server in the db. + */ + private void matchSessions(List sessions, List savedSessions) { + Map sessionsByStart = sessions.stream().collect(Collectors.toMap(Session::getSessionStart, Function.identity())); + Map savedSessionsByStart = savedSessions.stream().collect(Collectors.toMap(Session::getSessionStart, Function.identity())); + for (Map.Entry sessionEntry : sessionsByStart.entrySet()) { + long start = sessionEntry.getKey(); + Session savedSession = savedSessionsByStart.get(start); + if (savedSession == null) { + throw new IllegalStateException("Some of the sessions being matched were not saved."); + } + Session session = sessionEntry.getValue(); + session.setSessionID(savedSession.getSessionID()); + } + } } \ No newline at end of file diff --git a/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTimesTable.java b/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTimesTable.java index 8bf265a79..161e327a2 100644 --- a/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTimesTable.java +++ b/Plan/src/main/java/com/djrapitops/plan/database/tables/WorldTimesTable.java @@ -13,10 +13,8 @@ import main.java.com.djrapitops.plan.database.sql.TableSqlParser; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; +import java.util.stream.Collectors; /** * Table class representing database table plan_world_times. @@ -35,6 +33,7 @@ public class WorldTimesTable extends UserIDTable { private final WorldTable worldTable; private final SessionsTable sessionsTable; + private String insertStatement; /** * Constructor. @@ -46,6 +45,18 @@ public class WorldTimesTable extends UserIDTable { super("plan_world_times", db, usingMySQL); worldTable = db.getWorldTable(); sessionsTable = db.getSessionsTable(); + insertStatement = "INSERT INTO " + tableName + " (" + + columnUserID + ", " + + columnWorldId + ", " + + columnSessionID + ", " + + columnSurvival + ", " + + columnCreative + ", " + + columnAdventure + ", " + + columnSpectator + + ") VALUES (" + + usersTable.statementSelectID + ", " + + worldTable.statementSelectID + ", " + + "?, ?, ?, ?, ?)"; } @Override @@ -76,18 +87,7 @@ public class WorldTimesTable extends UserIDTable { PreparedStatement statement = null; try { - statement = prepareStatement("INSERT INTO " + tableName + " (" + - columnUserID + ", " + - columnWorldId + ", " + - columnSessionID + ", " + - columnSurvival + ", " + - columnCreative + ", " + - columnAdventure + ", " + - columnSpectator + - ") VALUES (" + - usersTable.statementSelectID + ", " + - worldTable.statementSelectID + ", " + - "?, ?, ?, ?, ?)"); + statement = prepareStatement(insertStatement); for (Map.Entry entry : worldTimesMap.entrySet()) { String worldName = entry.getKey(); @@ -244,4 +244,113 @@ public class WorldTimesTable extends UserIDTable { close(set, statement); } } + + public void addWorldTimesToSessions(Map>> map) throws SQLException { + Map worldTimesBySessionID = getAllWorldTimesBySessionID(); + + for (UUID serverUUID : map.keySet()) { + for (List sessions : map.get(serverUUID).values()) { + for (Session session : sessions) { + WorldTimes worldTimes = worldTimesBySessionID.get(session.getSessionID()); + if (worldTimes != null) { + session.setWorldTimes(worldTimes); + } + } + } + } + } + + public void saveWorldTimes(Map>> allSessions) throws SQLException { + if (Verify.isEmpty(allSessions)) { + return; + } + List worldNames = allSessions.values().stream() + .map(Map::values) + .flatMap(Collection::stream) + .flatMap(Collection::stream) + .map(Session::getWorldTimes) + .map(WorldTimes::getWorldTimes) + .map(Map::keySet) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + db.getWorldTable().saveWorlds(worldNames); + + PreparedStatement statement = null; + try { + statement = prepareStatement(insertStatement); + String[] gms = GMTimes.getGMKeyArray(); + for (UUID serverUUID : allSessions.keySet()) { + for (Map.Entry> entry : allSessions.get(serverUUID).entrySet()) { + UUID uuid = entry.getKey(); + List sessions = entry.getValue(); + + for (Session session : sessions) { + int sessionID = session.getSessionID(); + for (Map.Entry worldTimesEntry : session.getWorldTimes().getWorldTimes().entrySet()) { + String worldName = worldTimesEntry.getKey(); + GMTimes gmTimes = worldTimesEntry.getValue(); + statement.setString(1, uuid.toString()); + statement.setString(2, worldName); + statement.setInt(3, sessionID); + + statement.setLong(4, gmTimes.getTime(gms[0])); + statement.setLong(5, gmTimes.getTime(gms[1])); + statement.setLong(6, gmTimes.getTime(gms[2])); + statement.setLong(7, gmTimes.getTime(gms[3])); + statement.addBatch(); + } + } + } + } + statement.executeBatch(); + commit(statement.getConnection()); + } finally { + close(statement); + } + } + + public Map getAllWorldTimesBySessionID() throws SQLException { + PreparedStatement statement = null; + ResultSet set = null; + try { + String worldIDColumn = worldTable + "." + worldTable.getColumnID(); + String worldNameColumn = worldTable + "." + worldTable.getColumnWorldName() + " as world_name"; + statement = prepareStatement("SELECT " + + columnSessionID + ", " + + columnSurvival + ", " + + columnCreative + ", " + + columnAdventure + ", " + + columnSpectator + ", " + + worldNameColumn + + " FROM " + tableName + + " JOIN " + worldTable + " on " + worldIDColumn + "=" + columnWorldId + ); + statement.setFetchSize(10000); + set = statement.executeQuery(); + String[] gms = GMTimes.getGMKeyArray(); + + Map worldTimes = new HashMap<>(); + while (set.next()) { + int sessionID = set.getInt(columnSessionID); + + String worldName = set.getString("world_name"); + + Map gmMap = new HashMap<>(); + gmMap.put(gms[0], set.getLong(columnSurvival)); + gmMap.put(gms[1], set.getLong(columnCreative)); + gmMap.put(gms[2], set.getLong(columnAdventure)); + gmMap.put(gms[3], set.getLong(columnSpectator)); + GMTimes gmTimes = new GMTimes(gmMap); + + WorldTimes worldTOfSession = worldTimes.getOrDefault(sessionID, new WorldTimes(new HashMap<>())); + worldTOfSession.setGMTimesForWorld(worldName, gmTimes); + worldTimes.put(sessionID, worldTOfSession); + } + return worldTimes; + } finally { + endTransaction(statement); + close(set, statement); + } + } }