Batch Operations for Session and WorldTimesTables

This commit is contained in:
Rsl1122 2017-09-03 14:35:02 +03:00
parent 92ae2995da
commit 604bf7e29c
3 changed files with 288 additions and 27 deletions

View File

@ -182,4 +182,12 @@ public class KillsTable extends UserIDTable {
close(set, statement);
}
}
public void addKillsToSessions(Map<UUID, Map<UUID, List<Session>>> map) {
// TODO
}
public void savePlayerKills(Map<UUID, Map<UUID, List<Session>>> allSessions) {
// TODO
}
}

View File

@ -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<UUID, Map<UUID, List<Session>>> 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<UUID, Map<UUID, List<Session>>> map = new HashMap<>();
while (set.next()) {
UUID serverUUID = UUID.fromString(set.getString("s_uuid"));
UUID uuid = UUID.fromString(set.getString("uuid"));
Map<UUID, List<Session>> sessionsByUser = map.getOrDefault(serverUUID, new HashMap<>());
List<Session> 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<UUID, Map<UUID, List<Session>>> 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<UUID, List<Session>> entry : allSessions.get(serverUUID).entrySet()) {
UUID uuid = entry.getKey();
List<Session> 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<UUID, Map<UUID, List<Session>>> 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<UUID, Map<UUID, List<Session>>> allSessions, Map<UUID, Map<UUID, List<Session>>> allSavedSessions) {
for (UUID serverUUID : allSessions.keySet()) {
Map<UUID, List<Session>> serverSessions = allSessions.get(serverUUID);
Map<UUID, List<Session>> savedServerSessions = allSavedSessions.get(serverUUID);
for (Map.Entry<UUID, List<Session>> entry : serverSessions.entrySet()) {
UUID uuid = entry.getKey();
List<Session> sessions = entry.getValue();
List<Session> 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.
* <p>
* 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<Session> sessions, List<Session> savedSessions) {
Map<Long, Session> sessionsByStart = sessions.stream().collect(Collectors.toMap(Session::getSessionStart, Function.identity()));
Map<Long, Session> savedSessionsByStart = savedSessions.stream().collect(Collectors.toMap(Session::getSessionStart, Function.identity()));
for (Map.Entry<Long, Session> 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());
}
}
}

View File

@ -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<String, GMTimes> entry : worldTimesMap.entrySet()) {
String worldName = entry.getKey();
@ -244,4 +244,113 @@ public class WorldTimesTable extends UserIDTable {
close(set, statement);
}
}
public void addWorldTimesToSessions(Map<UUID, Map<UUID, List<Session>>> map) throws SQLException {
Map<Integer, WorldTimes> worldTimesBySessionID = getAllWorldTimesBySessionID();
for (UUID serverUUID : map.keySet()) {
for (List<Session> 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<UUID, Map<UUID, List<Session>>> allSessions) throws SQLException {
if (Verify.isEmpty(allSessions)) {
return;
}
List<String> 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<UUID, List<Session>> entry : allSessions.get(serverUUID).entrySet()) {
UUID uuid = entry.getKey();
List<Session> sessions = entry.getValue();
for (Session session : sessions) {
int sessionID = session.getSessionID();
for (Map.Entry<String, GMTimes> 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<Integer, WorldTimes> 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<Integer, WorldTimes> worldTimes = new HashMap<>();
while (set.next()) {
int sessionID = set.getInt(columnSessionID);
String worldName = set.getString("world_name");
Map<String, Long> 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);
}
}
}