Objects: don't run tx commit hooks inside the same transaction

This commit is contained in:
2025-03-17 23:29:10 +01:00
parent f260bb0491
commit 97c0f002fb
3 changed files with 59 additions and 22 deletions

View File

@@ -54,7 +54,7 @@ public class JObjectManager {
return tx;
}
public TransactionHandle commit(TransactionPrivate tx) {
public Pair<Collection<Runnable>, TransactionHandle> commit(TransactionPrivate tx) {
verifyReady();
var writes = new LinkedHashMap<JObjectKey, TxRecord.TxObjectRecord<?>>();
var dependenciesLocked = new LinkedHashMap<JObjectKey, Optional<JDataVersionedWrapper>>();
@@ -173,16 +173,17 @@ public class JObjectManager {
if (writes.isEmpty()) {
Log.trace("Committing transaction - no changes");
for (var callback : tx.getOnCommit()) {
callback.run();
}
return new TransactionHandle() {
@Override
public void onFlush(Runnable runnable) {
runnable.run();
}
};
return Pair.of(
Stream.concat(
tx.getOnCommit().stream(),
tx.getOnFlush().stream()
).toList(),
new TransactionHandle() {
@Override
public void onFlush(Runnable runnable) {
runnable.run();
}
});
}
Log.trace("Committing transaction start");
@@ -224,20 +225,18 @@ public class JObjectManager {
return true;
}).toList());
for (var callback : tx.getOnCommit()) {
callback.run();
}
for (var callback : tx.getOnFlush()) {
addFlushCallback.accept(callback);
}
return new TransactionHandle() {
@Override
public void onFlush(Runnable runnable) {
addFlushCallback.accept(runnable);
}
};
return Pair.of(
List.copyOf(tx.getOnCommit()),
new TransactionHandle() {
@Override
public void onFlush(Runnable runnable) {
addFlushCallback.accept(runnable);
}
});
} catch (Throwable t) {
Log.trace("Error when committing transaction", t);
throw new TxCommitException(t.getMessage(), t);

View File

@@ -3,6 +3,9 @@ package com.usatiuk.dhfs.objects.transaction;
import io.quarkus.logging.Log;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.apache.commons.lang3.tuple.Pair;
import java.util.Collection;
@ApplicationScoped
public class TransactionManagerImpl implements TransactionManager {
@@ -28,8 +31,10 @@ public class TransactionManagerImpl implements TransactionManager {
}
Log.trace("Committing transaction");
Pair<Collection<Runnable>, TransactionHandle> ret;
try {
return jObjectManager.commit(_currentTransaction.get());
ret = jObjectManager.commit(_currentTransaction.get());
} catch (Throwable e) {
Log.trace("Transaction commit failed", e);
throw e;
@@ -37,6 +42,15 @@ public class TransactionManagerImpl implements TransactionManager {
_currentTransaction.get().close();
_currentTransaction.remove();
}
for (var r : ret.getLeft()) {
try {
r.run();
} catch (Throwable e) {
Log.error("Transaction commit hook error: ", e);
}
}
return ret.getRight();
}
@Override

View File

@@ -69,6 +69,30 @@ public abstract class ObjectsTestImpl {
});
}
@Test
void onCommitHookTest() {
txm.run(() -> {
var newParent = new Parent(JObjectKey.of("ParentOnCommitHook"), "John");
curTx.put(newParent);
curTx.onCommit(() -> txm.run(() -> {
curTx.put(new Parent(JObjectKey.of("ParentOnCommitHook2"), "John2"));
}));
});
txm.run(() -> {
curTx.onCommit(() -> txm.run(() -> {
curTx.put(new Parent(JObjectKey.of("ParentOnCommitHook3"), "John3"));
}));
});
txm.run(() -> {
var parent = curTx.get(Parent.class, new JObjectKey("ParentOnCommitHook")).orElse(null);
Assertions.assertEquals("John", parent.name());
var parent2 = curTx.get(Parent.class, new JObjectKey("ParentOnCommitHook2")).orElse(null);
Assertions.assertEquals("John2", parent2.name());
var parent3 = curTx.get(Parent.class, new JObjectKey("ParentOnCommitHook3")).orElse(null);
Assertions.assertEquals("John3", parent3.name());
});
}
@Test
void createGetObject() {
txm.run(() -> {