9
0
mirror of https://github.com/WiIIiam278/HuskSync.git synced 2025-12-19 14:59:21 +00:00

refactor: optimize rotateSnapshots

Don't pull all snapshots when rotating!
This commit is contained in:
William278
2025-03-30 14:48:19 +01:00
parent c419587933
commit dc880bc37f
4 changed files with 81 additions and 21 deletions

View File

@@ -24,6 +24,7 @@ import net.william278.husksync.HuskSync;
import net.william278.husksync.config.Settings;
import net.william278.husksync.data.DataSnapshot;
import net.william278.husksync.user.User;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.Blocking;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -68,7 +69,7 @@ public abstract class Database {
* @return the formatted statement, with table placeholders replaced with the correct names
*/
@NotNull
protected final String formatStatementTables(@NotNull String sql) {
protected final String formatStatementTables(@NotNull @Language("SQL") String sql) {
final Settings.DatabaseSettings settings = plugin.getSettings().getDatabase();
return sql.replaceAll("%users_table%", settings.getTableName(TableName.USERS))
.replaceAll("%user_data_table%", settings.getTableName(TableName.USER_DATA))
@@ -138,6 +139,16 @@ public abstract class Database {
@NotNull
public abstract List<DataSnapshot.Packed> getAllSnapshots(@NotNull User user);
/**
* Get the number of {@link DataSnapshot}s a user has
*
* @param user the user to count snapshots for
* @param includePinned whether to include pinned snapshots in the search
* @return the number of snapshots this user has saved
*/
@Blocking
public abstract int getSnapshotCount(@NotNull User user, boolean includePinned);
/**
* Gets a specific {@link DataSnapshot} entry for a user from the database, by its UUID.
*
@@ -264,7 +275,7 @@ public abstract class Database {
*
* @param serverName Name of the server the map originates from
* @param mapId Original map ID
* @return Map.Entry (key: map data, value: is from current world)
* @return Map.Entry (key: map data, value: is from current world)
*/
@Blocking
public abstract @Nullable Map.Entry<byte[], Boolean> getMapData(@NotNull String serverName, int mapId);
@@ -274,7 +285,7 @@ public abstract class Database {
*
* @param serverName Name of the server the map originates from
* @param mapId Original map ID
* @return Map.Entry (key: server name, value: map ID)
* @return Map.Entry (key: server name, value: map ID)
*/
@Blocking
public abstract @Nullable Map.Entry<String, Integer> getMapBinding(@NotNull String serverName, int mapId);
@@ -296,7 +307,7 @@ public abstract class Database {
* @param fromServerName Name of the server the map originates from
* @param fromMapId Original map ID
* @param toServerName Name of the new server
* @return New map ID or -1 if not found
* @return New map ID or -1 if not found
*/
@Blocking
public abstract int getBoundMapId(@NotNull String fromServerName, int fromMapId, @NotNull String toServerName);

View File

@@ -234,6 +234,20 @@ public class MongoDbDatabase extends Database {
}
}
@Override
public int getSnapshotCount(@NotNull User user, boolean includePinned) {
try {
Document filter = new Document("player_uuid", user.getUuid());
if (!includePinned) {
filter = filter.append("pinned", false);
}
return (int) mongoCollectionHelper.getCollection(userDataTable).countDocuments(filter);
} catch (MongoException e) {
plugin.log(Level.SEVERE, "Failed to fetch a user's current snapshot count", e);
}
return 0;
}
@Blocking
@Override
public Optional<DataSnapshot.Packed> getSnapshot(@NotNull User user, @NotNull UUID versionUuid) {
@@ -259,17 +273,14 @@ public class MongoDbDatabase extends Database {
@Override
protected void rotateSnapshots(@NotNull User user) {
try {
final List<DataSnapshot.Packed> unpinnedUserData = getAllSnapshots(user).stream()
.filter(dataSnapshot -> !dataSnapshot.isPinned()).toList();
final int unpinnedSnapshots = getSnapshotCount(user, false);
final int maxSnapshots = plugin.getSettings().getSynchronization().getMaxUserDataSnapshots();
if (unpinnedUserData.size() > maxSnapshots) {
if (unpinnedSnapshots > maxSnapshots) {
Document filter = new Document("player_uuid", user.getUuid()).append("pinned", false);
Document sort = new Document("timestamp", 1); // 1 = Ascending
FindIterable<Document> iterable = mongoCollectionHelper.getCollection(userDataTable)
.find(filter)
.sort(sort)
.limit(unpinnedUserData.size() - maxSnapshots);
.find(filter).sort(sort)
.limit(unpinnedSnapshots - maxSnapshots);
for (Document doc : iterable) {
mongoCollectionHelper.deleteDocument(userDataTable, doc);

View File

@@ -299,11 +299,31 @@ public class MySqlDatabase extends Database {
return retrievedData;
}
} catch (SQLException | DataAdapter.AdaptionException e) {
plugin.log(Level.SEVERE, "Failed to fetch a user's current user data from the database", e);
plugin.log(Level.SEVERE, "Failed to fetch a user's list of snapshots from the database", e);
}
return retrievedData;
}
@Override
public int getSnapshotCount(@NotNull User user, boolean includePinned) {
try (Connection connection = getConnection()) {
try (PreparedStatement statement = connection.prepareStatement(formatStatementTables("""
SELECT COUNT(`version_uuid`)
FROM `%user_data_table%` AND `pinned`=false OR `pinned`=?
WHERE `player_uuid`=?;"""))) {
statement.setString(1, user.getUuid().toString());
statement.setBoolean(2, includePinned);
final ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
return resultSet.getInt(1);
}
}
} catch (SQLException e) {
plugin.log(Level.SEVERE, "Failed to fetch a user's current snapshot count", e);
}
return 0;
}
@Blocking
@Override
public Optional<DataSnapshot.Packed> getSnapshot(@NotNull User user, @NotNull UUID versionUuid) {
@@ -336,10 +356,9 @@ public class MySqlDatabase extends Database {
@Blocking
@Override
protected void rotateSnapshots(@NotNull User user) {
final List<DataSnapshot.Packed> unpinnedUserData = getAllSnapshots(user).stream()
.filter(dataSnapshot -> !dataSnapshot.isPinned()).toList();
final int unpinnedSnapshots = getSnapshotCount(user, false);
final int maxSnapshots = plugin.getSettings().getSynchronization().getMaxUserDataSnapshots();
if (unpinnedUserData.size() > maxSnapshots) {
if (unpinnedSnapshots > maxSnapshots) {
try (Connection connection = getConnection()) {
try (PreparedStatement statement = connection.prepareStatement(formatStatementTables("""
DELETE FROM `%user_data_table%`
@@ -347,7 +366,7 @@ public class MySqlDatabase extends Database {
AND `pinned` IS FALSE
ORDER BY `timestamp` ASC
LIMIT %entry_count%;""".replace("%entry_count%",
Integer.toString(unpinnedUserData.size() - maxSnapshots))))) {
Integer.toString(unpinnedSnapshots - maxSnapshots))))) {
statement.setString(1, user.getUuid().toString());
statement.executeUpdate();
}

View File

@@ -288,11 +288,31 @@ public class PostgresDatabase extends Database {
return retrievedData;
}
} catch (SQLException | DataAdapter.AdaptionException e) {
plugin.log(Level.SEVERE, "Failed to fetch a user's current user data from the database", e);
plugin.log(Level.SEVERE, "Failed to fetch a user's list of snapshots from the database", e);
}
return retrievedData;
}
@Override
public int getSnapshotCount(@NotNull User user, boolean includePinned) {
try (Connection connection = getConnection()) {
try (PreparedStatement statement = connection.prepareStatement(formatStatementTables("""
SELECT COUNT(`version_uuid`)
FROM `%user_data_table%` AND `pinned`=false OR `pinned`=?
WHERE `player_uuid`=?;"""))) {
statement.setString(1, user.getUuid().toString());
statement.setBoolean(2, includePinned);
final ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
return resultSet.getInt(1);
}
}
} catch (SQLException e) {
plugin.log(Level.SEVERE, "Failed to fetch a user's current snapshot count", e);
}
return 0;
}
@Blocking
@Override
public Optional<DataSnapshot.Packed> getSnapshot(@NotNull User user, @NotNull UUID versionUuid) {
@@ -323,10 +343,9 @@ public class PostgresDatabase extends Database {
@Blocking
@Override
protected void rotateSnapshots(@NotNull User user) {
final List<DataSnapshot.Packed> unpinnedUserData = getAllSnapshots(user).stream()
.filter(dataSnapshot -> !dataSnapshot.isPinned()).toList();
final int unpinnedSnapshots = getSnapshotCount(user, false);
final int maxSnapshots = plugin.getSettings().getSynchronization().getMaxUserDataSnapshots();
if (unpinnedUserData.size() > maxSnapshots) {
if (unpinnedSnapshots > maxSnapshots) {
try (Connection connection = getConnection()) {
try (PreparedStatement statement = connection.prepareStatement(formatStatementTables("""
WITH cte AS (
@@ -339,7 +358,7 @@ public class PostgresDatabase extends Database {
)
DELETE FROM %user_data_table%
WHERE version_uuid IN (SELECT version_uuid FROM cte);""".replace("%entry_count%",
Integer.toString(unpinnedUserData.size() - maxSnapshots))))) {
Integer.toString(unpinnedSnapshots - maxSnapshots))))) {
statement.setObject(1, user.getUuid());
statement.executeUpdate();
}