Fix potential database deadlocks

This commit is contained in:
Esophose 2020-03-13 13:09:52 -06:00
parent 80a4613725
commit 08405801b6

View file

@ -17,7 +17,6 @@ import dev.esophose.playerparticles.styles.ParticleStyle;
import dev.esophose.playerparticles.util.ParticleUtils; import dev.esophose.playerparticles.util.ParticleUtils;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -81,13 +80,10 @@ public class DataManager extends Manager {
* @return The PPlayer from cache * @return The PPlayer from cache
*/ */
public PPlayer getPPlayer(UUID playerUUID) { public PPlayer getPPlayer(UUID playerUUID) {
Collection<PPlayer> pplayers; for (PPlayer pp : this.playerParticles.getManager(ParticleManager.class).getPPlayers())
synchronized (pplayers = this.playerParticles.getManager(ParticleManager.class).getPPlayers()) { // Under rare circumstances, the PPlayers list can be changed while it's looping if (pp.getUniqueId().equals(playerUUID))
for (PPlayer pp : pplayers) return pp;
if (pp.getUniqueId().equals(playerUUID)) return null;
return pp;
return null;
}
} }
/** /**
@ -253,12 +249,8 @@ public class DataManager extends Manager {
} }
this.sync(() -> { this.sync(() -> {
synchronized (loadedPPlayer) { this.playerParticles.getManager(ParticleManager.class).addPPlayer(loadedPPlayer);
if (this.getPPlayer(playerUUID) == null) { // Make sure the PPlayer still isn't added, since this is async it's possible it got ran twice callback.accept(loadedPPlayer);
this.playerParticles.getManager(ParticleManager.class).addPPlayer(loadedPPlayer); // This will be fine now since loadedPPlayer is synchronized
callback.accept(loadedPPlayer);
}
}
}); });
}); });
}); });
@ -312,6 +304,7 @@ public class DataManager extends Manager {
this.async(() -> this.databaseConnector.connect((connection) -> { this.async(() -> this.databaseConnector.connect((connection) -> {
String groupUUID; String groupUUID;
boolean existingGroup;
String groupUUIDQuery = "SELECT uuid FROM " + this.getTablePrefix() + "group WHERE owner_uuid = ? AND name = ?"; String groupUUIDQuery = "SELECT uuid FROM " + this.getTablePrefix() + "group WHERE owner_uuid = ? AND name = ?";
try (PreparedStatement statement = connection.prepareStatement(groupUUIDQuery)) { try (PreparedStatement statement = connection.prepareStatement(groupUUIDQuery)) {
@ -321,21 +314,25 @@ public class DataManager extends Manager {
ResultSet result = statement.executeQuery(); ResultSet result = statement.executeQuery();
if (result.next()) { // Clear out particles from existing group if (result.next()) { // Clear out particles from existing group
groupUUID = result.getString("uuid"); groupUUID = result.getString("uuid");
existingGroup = true;
String particlesDeleteQuery = "DELETE FROM " + this.getTablePrefix() + "particle WHERE group_uuid = ?";
PreparedStatement particlesDeleteStatement = connection.prepareStatement(particlesDeleteQuery);
particlesDeleteStatement.setString(1, result.getString("uuid"));
particlesDeleteStatement.executeUpdate();
} else { // Create new group } else { // Create new group
groupUUID = UUID.randomUUID().toString(); groupUUID = UUID.randomUUID().toString();
existingGroup = false;
}
}
String groupCreateQuery = "INSERT INTO " + this.getTablePrefix() + "group (uuid, owner_uuid, name) VALUES (?, ?, ?)"; if (existingGroup) {
PreparedStatement groupCreateStatement = connection.prepareStatement(groupCreateQuery); String particlesDeleteQuery = "DELETE FROM " + this.getTablePrefix() + "particle WHERE group_uuid = ?";
try (PreparedStatement particlesDeleteStatement = connection.prepareStatement(particlesDeleteQuery)) {
particlesDeleteStatement.setString(1, groupUUID);
particlesDeleteStatement.executeUpdate();
}
} else {
String groupCreateQuery = "INSERT INTO " + this.getTablePrefix() + "group (uuid, owner_uuid, name) VALUES (?, ?, ?)";
try (PreparedStatement groupCreateStatement = connection.prepareStatement(groupCreateQuery)) {
groupCreateStatement.setString(1, groupUUID); groupCreateStatement.setString(1, groupUUID);
groupCreateStatement.setString(2, playerUUID.toString()); groupCreateStatement.setString(2, playerUUID.toString());
groupCreateStatement.setString(3, group.getName()); groupCreateStatement.setString(3, group.getName());
groupCreateStatement.executeUpdate(); groupCreateStatement.executeUpdate();
} }
} }
@ -527,11 +524,7 @@ public class DataManager extends Manager {
* @param asyncCallback The callback to run on a separate thread * @param asyncCallback The callback to run on a separate thread
*/ */
private void async(Runnable asyncCallback) { private void async(Runnable asyncCallback) {
if (Bukkit.isPrimaryThread()) { Bukkit.getScheduler().runTaskAsynchronously(this.playerParticles, asyncCallback);
Bukkit.getScheduler().runTaskAsynchronously(this.playerParticles, asyncCallback);
} else {
asyncCallback.run();
}
} }
/** /**