Optimized CleanTransaction inactive player query

- Removed SessionsTable#getLastSeenForAllPlayers
- Made a test to ensure that the clean transaction does not delete all
  players
- Fixed Peak player count fetch statement
This commit is contained in:
Rsl1122 2019-02-14 18:54:30 +02:00
parent 6f474d2aea
commit 18cc7af151
7 changed files with 61 additions and 51 deletions

View File

@ -42,7 +42,8 @@ public class OptionalFetchQueries {
public static Query<Optional<DateObj<Integer>>> fetchPeakPlayerCount(UUID serverUUID, long afterDate) {
String sql = "SELECT " + TPSTable.DATE + ", MAX(" + TPSTable.PLAYERS_ONLINE + ") as max FROM " + TPSTable.TABLE_NAME +
" WHERE " + TPSTable.SERVER_ID + "=" + ServerTable.STATEMENT_SELECT_SERVER_ID +
" AND " + TPSTable.DATE + ">= ?";
" AND " + TPSTable.DATE + ">= ?" +
" GROUP BY " + TPSTable.SERVER_ID;
return new QueryStatement<Optional<DateObj<Integer>>>(sql) {
@Override

View File

@ -19,9 +19,12 @@ package com.djrapitops.plan.db.access.transactions;
import com.djrapitops.plan.data.store.objects.DateObj;
import com.djrapitops.plan.db.access.ExecStatement;
import com.djrapitops.plan.db.access.Executable;
import com.djrapitops.plan.db.access.Query;
import com.djrapitops.plan.db.access.QueryStatement;
import com.djrapitops.plan.db.access.queries.OptionalFetchQueries;
import com.djrapitops.plan.db.access.transactions.commands.RemovePlayerTransaction;
import com.djrapitops.plan.db.sql.tables.PingTable;
import com.djrapitops.plan.db.sql.tables.SessionsTable;
import com.djrapitops.plan.db.sql.tables.TPSTable;
import com.djrapitops.plan.system.locale.Locale;
import com.djrapitops.plan.system.locale.lang.PluginLang;
@ -29,12 +32,12 @@ import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.logging.console.PluginLogger;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* Transaction for cleaning up old data from the database.
@ -64,7 +67,7 @@ public class CleanTransaction extends Transaction {
@Override
protected void performOperations() {
Optional<Integer> allTimePeak = db.query(OptionalFetchQueries.fetchAllTimePeakPlayerCount(serverUUID)).map(DateObj::getValue);
Optional<Integer> allTimePeak = query(OptionalFetchQueries.fetchAllTimePeakPlayerCount(serverUUID)).map(DateObj::getValue);
execute(cleanTPSTable(allTimePeak.orElse(-1)));
execute(cleanPingTable());
@ -79,10 +82,7 @@ public class CleanTransaction extends Transaction {
long now = System.currentTimeMillis();
long keepActiveAfter = now - keepInactiveForMs;
List<UUID> inactivePlayers = db.getSessionsTable().getLastSeenForAllPlayers().entrySet().stream()
.filter(entry -> entry.getValue() < keepActiveAfter)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
List<UUID> inactivePlayers = query(fetchInactivePlayerUUIDs(keepActiveAfter));
for (UUID uuid : inactivePlayers) {
executeOther(new RemovePlayerTransaction(uuid));
}
@ -118,4 +118,28 @@ public class CleanTransaction extends Transaction {
}
};
}
private Query<List<UUID>> fetchInactivePlayerUUIDs(long keepActiveAfter) {
String sql = "SELECT uuid, last_seen FROM (SELECT" +
" MAX(" + SessionsTable.SESSION_END + ") as last_seen, " + SessionsTable.USER_UUID +
" FROM " + SessionsTable.TABLE_NAME +
" GROUP BY " + SessionsTable.USER_UUID + ") as q1" +
" WHERE last_seen < ?";
return new QueryStatement<List<UUID>>(sql, 20000) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setLong(1, keepActiveAfter);
}
@Override
public List<UUID> processResults(ResultSet set) throws SQLException {
List<UUID> inactiveUUIDs = new ArrayList<>();
while (set.next()) {
inactiveUUIDs.add(UUID.fromString(set.getString("uuid")));
}
return inactiveUUIDs;
}
};
}
}

View File

@ -36,7 +36,7 @@ import java.sql.Savepoint;
*/
public abstract class Transaction {
SQLDB db;
protected SQLDB db; // TODO Make private, this is a quick hack to access some tables while they are in use.
private Connection connection;
private Savepoint savepoint;

View File

@ -188,27 +188,6 @@ public class SessionsTable extends Table {
});
}
public Map<UUID, Long> getLastSeenForAllPlayers() {
String sql = "SELECT" +
" MAX(" + SESSION_END + ") as last_seen, " +
USER_UUID +
" FROM " + tableName +
" GROUP BY " + USER_UUID;
return query(new QueryAllStatement<Map<UUID, Long>>(sql, 20000) {
@Override
public Map<UUID, Long> processResults(ResultSet set) throws SQLException {
Map<UUID, Long> lastSeenMap = new HashMap<>();
while (set.next()) {
UUID uuid = UUID.fromString(set.getString("uuid"));
long lastSeen = set.getLong("last_seen");
lastSeenMap.put(uuid, lastSeen);
}
return lastSeenMap;
}
});
}
public Map<Integer, Integer> getIDServerIDRelation() {
String sql = "SELECT " +
ID + ", " +

View File

@ -132,6 +132,9 @@ public interface FetchOperations {
@Deprecated
Map<UUID, UserInfo> getUsers();
/**
* @deprecated Now empty map is returned.
*/
@Deprecated
Map<UUID, Long> getLastSeenForAllPlayers();

View File

@ -110,7 +110,7 @@ public class SQLFetchOps extends SQLOps implements FetchOperations {
@Override
public Map<UUID, Long> getLastSeenForAllPlayers() {
return sessionsTable.getLastSeenForAllPlayers();
return new HashMap<>();
}
@Override

View File

@ -48,11 +48,13 @@ import com.djrapitops.plan.db.sql.tables.UsersTable;
import com.djrapitops.plan.system.PlanSystem;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.info.server.Server;
import com.djrapitops.plan.system.locale.Locale;
import com.djrapitops.plan.system.settings.config.Config;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plan.system.settings.paths.WebserverSettings;
import com.djrapitops.plan.utilities.SHA256Hash;
import com.djrapitops.plan.utilities.comparators.DateHolderRecentComparator;
import com.djrapitops.plugin.logging.console.TestPluginLogger;
import org.junit.*;
import org.junit.rules.TemporaryFolder;
import org.junit.rules.Timeout;
@ -350,7 +352,7 @@ public abstract class CommonDBTest {
saveTwoWorlds();
saveUserOne();
saveUserTwo();
Session session = new Session(playerUUID, serverUUID, 12345L, "", "");
Session session = new Session(playerUUID, serverUUID, 12345L, worlds[0], "SURVIVAL");
session.endSession(22345L);
session.setWorldTimes(createWorldTimes());
session.setPlayerKills(createKills());
@ -380,12 +382,11 @@ public abstract class CommonDBTest {
saveUserOne();
saveUserTwo();
Session session = new Session(playerUUID, serverUUID, 12345L, "", "");
Session session = new Session(playerUUID, serverUUID, 12345L, worlds[0], "SURVIVAL");
session.endSession(22345L);
session.setWorldTimes(createWorldTimes());
session.setPlayerKills(createKills());
SessionsTable sessionsTable = db.getSessionsTable();
execute(DataStoreQueries.storeSession(session));
commitTest();
@ -398,11 +399,6 @@ public abstract class CommonDBTest {
assertNull(sessions.get(UUID.randomUUID()));
assertEquals(session, savedSessions.get(0));
Map<UUID, Long> lastSeen = sessionsTable.getLastSeenForAllPlayers();
assertTrue(lastSeen.containsKey(playerUUID));
assertFalse(lastSeen.containsKey(TestConstants.PLAYER_TWO_UUID));
assertEquals(22345L, (long) lastSeen.get(playerUUID));
}
@Test
@ -475,12 +471,10 @@ public abstract class CommonDBTest {
public void testRemovalSingleUser() {
saveUserTwo();
SessionsTable sessionsTable = db.getSessionsTable();
db.executeTransaction(new PlayerServerRegisterTransaction(playerUUID, () -> 223456789L, "Test_name", serverUUID));
saveTwoWorlds();
Session session = new Session(playerUUID, serverUUID, 12345L, "", "");
Session session = new Session(playerUUID, serverUUID, 12345L, worlds[0], "SURVIVAL");
session.endSession(22345L);
session.setWorldTimes(createWorldTimes());
session.setPlayerKills(createKills());
@ -529,7 +523,7 @@ public abstract class CommonDBTest {
saveTwoWorlds();
Session session = new Session(playerUUID, serverUUID, 12345L, "", "");
Session session = new Session(playerUUID, serverUUID, 12345L, worlds[0], "SURVIVAL");
session.endSession(22345L);
session.setWorldTimes(createWorldTimes());
session.setPlayerKills(createKills());
@ -580,22 +574,15 @@ public abstract class CommonDBTest {
db.executeTransaction(new GeoInfoStoreTransaction(uuid, geoInfo));
}
@Test
public void testSessionTableNPEWhenNoPlayers() {
Map<UUID, Long> lastSeen = db.getSessionsTable().getLastSeenForAllPlayers();
assertTrue(lastSeen.isEmpty());
}
@Test
public void testSessionTableGetInfoOfServer() throws DBInitException {
saveUserOne();
saveUserTwo();
Session session = new Session(playerUUID, serverUUID, 12345L, "", "");
Session session = new Session(playerUUID, serverUUID, 12345L, worlds[0], "SURVIVAL");
session.endSession(22345L);
session.setWorldTimes(createWorldTimes());
session.setPlayerKills(createKills());
execute(DataStoreQueries.storeSession(session));
commitTest();
@ -609,6 +596,22 @@ public abstract class CommonDBTest {
assertEquals(session, sSessions.get(0));
}
@Test
public void cleanTransactionDoesNotCleanActivePlayers() {
saveUserOne();
saveTwoWorlds();
long sessionStart = System.currentTimeMillis();
Session session = new Session(playerUUID, serverUUID, sessionStart, worlds[0], "SURVIVAL");
session.endSession(sessionStart + 22345L);
execute(DataStoreQueries.storeSession(session));
db.executeTransaction(new CleanTransaction(serverUUID, TimeUnit.DAYS.toMillis(1L), new TestPluginLogger(), new Locale()));
Collection<BaseUser> found = db.query(BaseUserQueries.fetchServerBaseUsers(serverUUID));
assertFalse("All users were deleted!! D:", found.isEmpty());
}
@Test
public void testKillTableGetKillsOfServer() throws DBInitException {
saveUserOne();