mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-11-16 15:45:16 +01:00
Fix user_id reference error on ShutdownDataPreservationTransaction
This commit is contained in:
parent
f3a5e27d8d
commit
17d39f518d
@ -22,8 +22,7 @@ import com.djrapitops.plan.gathering.domain.FinishedSession;
|
|||||||
import com.djrapitops.plan.settings.locale.Locale;
|
import com.djrapitops.plan.settings.locale.Locale;
|
||||||
import com.djrapitops.plan.settings.locale.lang.PluginLang;
|
import com.djrapitops.plan.settings.locale.lang.PluginLang;
|
||||||
import com.djrapitops.plan.storage.database.DBSystem;
|
import com.djrapitops.plan.storage.database.DBSystem;
|
||||||
import com.djrapitops.plan.storage.database.queries.LargeStoreQueries;
|
import com.djrapitops.plan.storage.database.transactions.events.ShutdownDataPreservationTransaction;
|
||||||
import com.djrapitops.plan.storage.database.transactions.Transaction;
|
|
||||||
import com.djrapitops.plan.storage.file.PlanFiles;
|
import com.djrapitops.plan.storage.file.PlanFiles;
|
||||||
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
import com.djrapitops.plan.utilities.logging.ErrorContext;
|
||||||
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
import com.djrapitops.plan.utilities.logging.ErrorLogger;
|
||||||
@ -87,12 +86,7 @@ public class ShutdownDataPreservation extends TaskSystem.Task {
|
|||||||
private void storeInDB(List<FinishedSession> finishedSessions) {
|
private void storeInDB(List<FinishedSession> finishedSessions) {
|
||||||
if (!finishedSessions.isEmpty()) {
|
if (!finishedSessions.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
dbSystem.getDatabase().executeTransaction(new Transaction() {
|
dbSystem.getDatabase().executeTransaction(new ShutdownDataPreservationTransaction(finishedSessions)).get();
|
||||||
@Override
|
|
||||||
protected void performOperations() {
|
|
||||||
execute(LargeStoreQueries.storeAllSessionsWithKillAndWorldData(finishedSessions));
|
|
||||||
}
|
|
||||||
}).get();
|
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package com.djrapitops.plan.gathering.domain;
|
package com.djrapitops.plan.gathering.domain;
|
||||||
|
|
||||||
import com.djrapitops.plan.delivery.domain.DateHolder;
|
import com.djrapitops.plan.delivery.domain.DateHolder;
|
||||||
|
import com.djrapitops.plan.delivery.domain.PlayerName;
|
||||||
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
import com.djrapitops.plan.gathering.domain.event.JoinAddress;
|
||||||
import com.djrapitops.plan.identification.ServerUUID;
|
import com.djrapitops.plan.identification.ServerUUID;
|
||||||
import com.djrapitops.plan.storage.database.sql.tables.JoinAddressTable;
|
import com.djrapitops.plan.storage.database.sql.tables.JoinAddressTable;
|
||||||
@ -143,6 +144,7 @@ public class FinishedSession implements DateHolder {
|
|||||||
asOptionals.get(7).ifPresent(value -> extraData.put(MobKillCounter.class, gson.fromJson(value, MobKillCounter.class)));
|
asOptionals.get(7).ifPresent(value -> extraData.put(MobKillCounter.class, gson.fromJson(value, MobKillCounter.class)));
|
||||||
asOptionals.get(8).ifPresent(value -> extraData.put(DeathCounter.class, gson.fromJson(value, DeathCounter.class)));
|
asOptionals.get(8).ifPresent(value -> extraData.put(DeathCounter.class, gson.fromJson(value, DeathCounter.class)));
|
||||||
asOptionals.get(9).ifPresent(value -> extraData.put(JoinAddress.class, new JoinAddress(value)));
|
asOptionals.get(9).ifPresent(value -> extraData.put(JoinAddress.class, new JoinAddress(value)));
|
||||||
|
asOptionals.get(10).ifPresent(value -> extraData.put(PlayerName.class, new PlayerName(value)));
|
||||||
return Optional.of(new FinishedSession(playerUUID, serverUUID, start, end, afkTime, extraData));
|
return Optional.of(new FinishedSession(playerUUID, serverUUID, start, end, afkTime, extraData));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +196,8 @@ public class FinishedSession implements DateHolder {
|
|||||||
getExtraData(PlayerKills.class).orElseGet(PlayerKills::new).toJson() + ';' +
|
getExtraData(PlayerKills.class).orElseGet(PlayerKills::new).toJson() + ';' +
|
||||||
getExtraData(MobKillCounter.class).orElseGet(MobKillCounter::new).toJson() + ';' +
|
getExtraData(MobKillCounter.class).orElseGet(MobKillCounter::new).toJson() + ';' +
|
||||||
getExtraData(DeathCounter.class).orElseGet(DeathCounter::new).toJson() + ';' +
|
getExtraData(DeathCounter.class).orElseGet(DeathCounter::new).toJson() + ';' +
|
||||||
getExtraData(JoinAddress.class).orElseGet(() -> new JoinAddress(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP)).getAddress();
|
getExtraData(JoinAddress.class).map(JoinAddress::getAddress).orElse(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP) + ';' +
|
||||||
|
getExtraData(PlayerName.class).map(PlayerName::get).orElseGet(playerUUID::toString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Id {
|
public static class Id {
|
||||||
|
@ -23,6 +23,7 @@ import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
|
|||||||
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
import com.djrapitops.plan.storage.database.queries.QueryStatement;
|
||||||
import com.djrapitops.plan.storage.database.sql.building.Select;
|
import com.djrapitops.plan.storage.database.sql.building.Select;
|
||||||
import com.djrapitops.plan.storage.database.sql.tables.UsersTable;
|
import com.djrapitops.plan.storage.database.sql.tables.UsersTable;
|
||||||
|
import org.apache.commons.text.TextStringBuilder;
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
@ -160,4 +161,21 @@ public class BaseUserQueries {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Query<Set<UUID>> fetchExistingUUIDs(Set<UUID> outOfPlayerUUIDs) {
|
||||||
|
String sql = SELECT + UsersTable.USER_UUID +
|
||||||
|
FROM + UsersTable.TABLE_NAME +
|
||||||
|
WHERE + UsersTable.USER_UUID + " IN ('" + new TextStringBuilder().appendWithSeparators(outOfPlayerUUIDs, "','").build() + "')";
|
||||||
|
|
||||||
|
return new QueryAllStatement<Set<UUID>>(sql) {
|
||||||
|
@Override
|
||||||
|
public Set<UUID> processResults(ResultSet set) throws SQLException {
|
||||||
|
Set<UUID> uuids = new HashSet<>();
|
||||||
|
while (set.next()) {
|
||||||
|
uuids.add(UUID.fromString(set.getString(UsersTable.USER_UUID)));
|
||||||
|
}
|
||||||
|
return uuids;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Player Analytics (Plan).
|
||||||
|
*
|
||||||
|
* Plan is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Plan is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package com.djrapitops.plan.storage.database.transactions.events;
|
||||||
|
|
||||||
|
import com.djrapitops.plan.delivery.domain.PlayerName;
|
||||||
|
import com.djrapitops.plan.gathering.domain.FinishedSession;
|
||||||
|
import com.djrapitops.plan.gathering.domain.PlayerKill;
|
||||||
|
import com.djrapitops.plan.gathering.domain.PlayerKills;
|
||||||
|
import com.djrapitops.plan.storage.database.queries.LargeStoreQueries;
|
||||||
|
import com.djrapitops.plan.storage.database.queries.objects.BaseUserQueries;
|
||||||
|
import com.djrapitops.plan.storage.database.transactions.Transaction;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.LongSupplier;
|
||||||
|
|
||||||
|
public class ShutdownDataPreservationTransaction extends Transaction {
|
||||||
|
|
||||||
|
private final List<FinishedSession> finishedSessions;
|
||||||
|
|
||||||
|
public ShutdownDataPreservationTransaction(List<FinishedSession> finishedSessions) {
|
||||||
|
this.finishedSessions = finishedSessions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void performOperations() {
|
||||||
|
ensureAllPlayersAreRegistered();
|
||||||
|
|
||||||
|
execute(LargeStoreQueries.storeAllSessionsWithKillAndWorldData(finishedSessions));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureAllPlayersAreRegistered() {
|
||||||
|
Set<UUID> playerUUIDs = new HashSet<>();
|
||||||
|
Map<UUID, String> playerNames = new HashMap<>();
|
||||||
|
Map<UUID, Long> earliestDates = new HashMap<>();
|
||||||
|
for (FinishedSession finishedSession : finishedSessions) {
|
||||||
|
UUID playerUUID = finishedSession.getPlayerUUID();
|
||||||
|
playerUUIDs.add(playerUUID);
|
||||||
|
finishedSession.getExtraData(PlayerKills.class)
|
||||||
|
.map(PlayerKills::asList)
|
||||||
|
.ifPresent(kills -> {
|
||||||
|
for (PlayerKill kill : kills) {
|
||||||
|
playerUUIDs.add(kill.getKiller().getUuid());
|
||||||
|
playerUUIDs.add(kill.getVictim().getUuid());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
finishedSession.getExtraData(PlayerName.class)
|
||||||
|
.map(PlayerName::get)
|
||||||
|
.ifPresent(playerName -> playerNames.put(playerUUID, playerName));
|
||||||
|
long start = finishedSession.getStart();
|
||||||
|
Long previous = earliestDates.get(playerUUID);
|
||||||
|
if (previous == null || start < previous) {
|
||||||
|
earliestDates.put(playerUUID, start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<UUID> existingUUIDs = query(BaseUserQueries.fetchExistingUUIDs(playerUUIDs));
|
||||||
|
|
||||||
|
for (UUID playerUUID : playerUUIDs) {
|
||||||
|
if (!existingUUIDs.contains(playerUUID)) {
|
||||||
|
LongSupplier registerDate = () -> Optional.ofNullable(earliestDates.get(playerUUID))
|
||||||
|
.orElseGet(System::currentTimeMillis);
|
||||||
|
String playerName = Optional.ofNullable(playerNames.get(playerUUID))
|
||||||
|
.orElseGet(playerUUID::toString);
|
||||||
|
executeOther(new PlayerRegisterTransaction(playerUUID, registerDate, playerName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -34,10 +34,7 @@ import com.djrapitops.plan.storage.database.transactions.ExecStatement;
|
|||||||
import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction;
|
import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction;
|
||||||
import com.djrapitops.plan.storage.database.transactions.Transaction;
|
import com.djrapitops.plan.storage.database.transactions.Transaction;
|
||||||
import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction;
|
import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction;
|
||||||
import com.djrapitops.plan.storage.database.transactions.events.PlayerRegisterTransaction;
|
import com.djrapitops.plan.storage.database.transactions.events.*;
|
||||||
import com.djrapitops.plan.storage.database.transactions.events.PlayerServerRegisterTransaction;
|
|
||||||
import com.djrapitops.plan.storage.database.transactions.events.SessionEndTransaction;
|
|
||||||
import com.djrapitops.plan.storage.database.transactions.events.WorldNameStoreTransaction;
|
|
||||||
import com.djrapitops.plan.utilities.java.Maps;
|
import com.djrapitops.plan.utilities.java.Maps;
|
||||||
import net.playeranalytics.plugin.scheduling.TimeAmount;
|
import net.playeranalytics.plugin.scheduling.TimeAmount;
|
||||||
import org.junit.jupiter.api.RepeatedTest;
|
import org.junit.jupiter.api.RepeatedTest;
|
||||||
@ -97,6 +94,45 @@ public interface SessionQueriesTest extends DatabaseTestPreparer {
|
|||||||
assertEquals(session, savedSessions.get(0));
|
assertEquals(session, savedSessions.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
default void shutdownDataPreservationTransactionOutOfOrderDoesNotFailDueToMissingMainUser() {
|
||||||
|
db().executeTransaction(new WorldNameStoreTransaction(serverUUID(), worlds[0]));
|
||||||
|
db().executeTransaction(new WorldNameStoreTransaction(serverUUID(), worlds[1]));
|
||||||
|
db().executeTransaction(new PlayerServerRegisterTransaction(player2UUID, RandomData::randomTime,
|
||||||
|
TestConstants.PLAYER_TWO_NAME, serverUUID(), TestConstants.GET_PLAYER_HOSTNAME));
|
||||||
|
|
||||||
|
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID, player2UUID);
|
||||||
|
|
||||||
|
db().executeTransaction(new ShutdownDataPreservationTransaction(List.of(session)));
|
||||||
|
|
||||||
|
Map<ServerUUID, List<FinishedSession>> sessions = db().query(SessionQueries.fetchSessionsOfPlayer(playerUUID));
|
||||||
|
List<FinishedSession> savedSessions = sessions.get(serverUUID());
|
||||||
|
|
||||||
|
assertNotNull(savedSessions);
|
||||||
|
assertEquals(1, savedSessions.size());
|
||||||
|
|
||||||
|
assertEquals(session, savedSessions.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
default void shutdownDataPreservationTransactionOutOfOrderDoesNotFailDueToMissingKilledUser() {
|
||||||
|
db().executeTransaction(new WorldNameStoreTransaction(serverUUID(), worlds[0]));
|
||||||
|
db().executeTransaction(new WorldNameStoreTransaction(serverUUID(), worlds[1]));
|
||||||
|
db().executeTransaction(new PlayerServerRegisterTransaction(playerUUID, RandomData::randomTime,
|
||||||
|
TestConstants.PLAYER_ONE_NAME, serverUUID(), TestConstants.GET_PLAYER_HOSTNAME));
|
||||||
|
|
||||||
|
FinishedSession session = RandomData.randomSession(serverUUID(), worlds, playerUUID, player2UUID);
|
||||||
|
db().executeTransaction(new ShutdownDataPreservationTransaction(List.of(session)));
|
||||||
|
|
||||||
|
Map<ServerUUID, List<FinishedSession>> sessions = db().query(SessionQueries.fetchSessionsOfPlayer(playerUUID));
|
||||||
|
List<FinishedSession> savedSessions = sessions.get(serverUUID());
|
||||||
|
|
||||||
|
assertNotNull(savedSessions);
|
||||||
|
assertEquals(1, savedSessions.size());
|
||||||
|
|
||||||
|
assertEquals(session, savedSessions.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
default void killsAreAvailableAfter2ndUserRegisterEvenIfOutOfOrder() {
|
default void killsAreAvailableAfter2ndUserRegisterEvenIfOutOfOrder() {
|
||||||
db().executeTransaction(new WorldNameStoreTransaction(serverUUID(), worlds[0]));
|
db().executeTransaction(new WorldNameStoreTransaction(serverUUID(), worlds[0]));
|
||||||
|
Loading…
Reference in New Issue
Block a user