mirror of
https://github.com/PlayPro/CoreProtect.git
synced 2026-10-28 09:44:56 +00:00
Prevent DuckDB entity interaction queue stalls (#1002)
This commit is contained in:
1 parent
9cf12ee5bf
commit
0ec76561dc
2 files changed
+92
No files matched your search
@@ -25,6 +25,7 @@ import net.coreprotect.consumer.Queue;
|
||||
import net.coreprotect.database.ConsumerEntitySpawnUpdates;
|
||||
import net.coreprotect.database.ConsumerWriteBatch;
|
||||
import net.coreprotect.database.Database;
|
||||
import net.coreprotect.database.DatabaseType;
|
||||
import net.coreprotect.database.DuckDBRecovery;
|
||||
import net.coreprotect.database.logger.EntityInteractionLogger;
|
||||
import net.coreprotect.database.rollback.EntitySpawnRollbackHandler;
|
||||
@@ -361,6 +362,12 @@ public class Process {
|
||||
});
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (shouldDiscardFailedEvent(ConfigHandler.databaseType, action, e)) {
|
||||
Database.acknowledgeRollbackOnlyTransaction();
|
||||
cancelEntityInteractionPromotion(interaction);
|
||||
ErrorReporter.report(new IllegalStateException("Dropped entity interaction after a duplicate DuckDB entity UUID prevented identity creation: " + interaction.getEntityUuid(), e));
|
||||
break;
|
||||
}
|
||||
pendingEntityInteractions.add(new PendingEntityInteraction(user, interaction, false, true));
|
||||
throw e;
|
||||
}
|
||||
@@ -1064,6 +1071,24 @@ public class Process {
|
||||
return !sqlFailure;
|
||||
}
|
||||
|
||||
static boolean shouldDiscardFailedEvent(DatabaseType databaseType, int action, Throwable failure) {
|
||||
if (!databaseType.isDuckDB() || action != ENTITY_INTERACTION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Throwable> visited = new HashSet<>();
|
||||
while (failure != null && visited.add(failure)) {
|
||||
String message = failure.getMessage();
|
||||
if (failure instanceof SQLException && message != null
|
||||
&& message.contains("Constraint Error: Duplicate key \"uuid: ")
|
||||
&& message.contains("violates unique constraint")) {
|
||||
return true;
|
||||
}
|
||||
failure = failure.getCause();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void clearConsumerData(int processId, ArrayList<Object[]> consumerData, Map<Integer, String[]> users, Map<Integer, Object> consumerObject) {
|
||||
discardProcessedConsumerData(processId, consumerData, users, consumerObject, consumerData.size());
|
||||
users.clear();
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package net.coreprotect.consumer.process;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import net.coreprotect.database.DatabaseType;
|
||||
|
||||
class ProcessTest {
|
||||
|
||||
private static final String DUPLICATE_UUID = "Constraint Error: Duplicate key \"uuid: 2114a8b0-4978-4191-a5e0-14ca05436e83\" violates unique constraint.";
|
||||
|
||||
@Test
|
||||
void discardsDuckDbEntityInteractionBlockedByDuplicateUuid() {
|
||||
SQLException failure = new SQLException(DUPLICATE_UUID);
|
||||
|
||||
assertTrue(Process.shouldDiscardFailedEvent(DatabaseType.DUCKDB, Process.ENTITY_INTERACTION, failure));
|
||||
}
|
||||
|
||||
@Test
|
||||
void findsDuplicateUuidInWrappedSqlFailure() {
|
||||
Exception failure = new Exception("Unable to log entity interaction", new SQLException(DUPLICATE_UUID));
|
||||
|
||||
assertTrue(Process.shouldDiscardFailedEvent(DatabaseType.DUCKDB, Process.ENTITY_INTERACTION, failure));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retainsTransientDuckDbEntityInteractionFailure() {
|
||||
SQLException failure = new SQLException("Connection reset while inserting entity identity");
|
||||
|
||||
assertFalse(Process.shouldDiscardFailedEvent(DatabaseType.DUCKDB, Process.ENTITY_INTERACTION, failure));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retainsDuplicateUuidFailureForOtherDatabase() {
|
||||
SQLException failure = new SQLException(DUPLICATE_UUID);
|
||||
|
||||
assertFalse(Process.shouldDiscardFailedEvent(DatabaseType.SQLITE, Process.ENTITY_INTERACTION, failure));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retainsDuplicateUuidFailureForOtherAction() {
|
||||
SQLException failure = new SQLException(DUPLICATE_UUID);
|
||||
|
||||
assertFalse(Process.shouldDiscardFailedEvent(DatabaseType.DUCKDB, Process.ENTITY_SPAWN_LOG, failure));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retainsDuckDbEntityInteractionFailureForDifferentUniqueKey() {
|
||||
SQLException failure = new SQLException("Constraint Error: Duplicate key \"kill_rowid: 42\" violates unique constraint.");
|
||||
|
||||
assertFalse(Process.shouldDiscardFailedEvent(DatabaseType.DUCKDB, Process.ENTITY_INTERACTION, failure));
|
||||
}
|
||||
|
||||
@Test
|
||||
void stopsAtCyclicExceptionCauses() {
|
||||
Exception first = new Exception("first");
|
||||
Exception second = new Exception("second");
|
||||
first.initCause(second);
|
||||
second.initCause(first);
|
||||
|
||||
assertFalse(Process.shouldDiscardFailedEvent(DatabaseType.DUCKDB, Process.ENTITY_INTERACTION, first));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user