#2377 - Wrong order in batch save, fix transaction depth

The guts of this fix is in DefaultPersister.saveAssocOne() with the change to use the new transaction.depthDecrement() method. For our failing test cases this changes the depth from -1, 0 to be 0, 1.

We can see the impact of this change in the batch ordering via the logging of:
 io.ebean.SUM - txn[1001] BatchControl flush ...
This commit is contained in:
rbygrave
2021-09-17 17:58:20 +12:00
parent b38a21f8c4
commit f51f2269fb
10 changed files with 134 additions and 59 deletions
@@ -130,7 +130,7 @@ public interface SpiTransaction extends Transaction {
Boolean getBatchGetGeneratedKeys();
/**
* Modify and return the current 'depth' of the transaction.
* Modify the current 'depth' of the transaction.
* <p>
* As we cascade save or delete we traverse the object graph tree. Going up
* to Assoc Ones the depth decreases and going down to Assoc Manys the depth
@@ -139,12 +139,31 @@ public interface SpiTransaction extends Transaction {
* The depth is used for ordering batching statements. The lowest depth get
* executed first during save.
*/
void depth(int diff);
default void depth(int diff) {
// do nothing
}
/**
* Decrement the depth BUT only if depth is greater than 0.
* Return the amount that depth should be incremented by (0 or 1).
*/
default void depthDecrement() {
// do nothing
}
/**
* Reset the depth back to 0 - done at the end of top level insert and update.
*/
default void depthReset() {
// do nothing
}
/**
* Return the current depth.
*/
int depth();
default int depth() {
return 0;
}
/**
* Return true if dirty beans are automatically persisted.
@@ -342,6 +342,16 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
transaction.depth(diff);
}
@Override
public void depthDecrement() {
transaction.depthDecrement();
}
@Override
public void depthReset() {
transaction.depthReset();
}
@Override
public int depth() {
return transaction.depth();
@@ -50,6 +50,13 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
this.label = label;
}
/**
* Reset the transaction depth back to 0.
*/
public void resetDepth() {
transaction.depthReset();
}
@Override
public void addTimingBatch(long startNanos, int size) {
// nothing by default
@@ -251,6 +251,7 @@ public final class DefaultPersister implements Persister {
} else {
update(request);
}
request.resetDepth();
}
draftHandler.updateDrafts(transaction, mgr);
@@ -417,7 +418,7 @@ public final class DefaultPersister implements Persister {
} else {
update(req);
}
req.resetDepth();
req.commitTransIfRequired();
req.flushBatchOnCascade();
@@ -455,6 +456,7 @@ public final class DefaultPersister implements Persister {
try {
req.initTransIfRequiredWithBatchCascade();
insert(req);
req.resetDepth();
req.commitTransIfRequired();
req.flushBatchOnCascade();
@@ -1123,7 +1125,7 @@ public final class DefaultPersister implements Persister {
&& !prop.isReference(detailBean)
&& !request.isParent(detailBean)) {
SpiTransaction t = request.transaction();
t.depth(-1);
t.depthDecrement();
saveRecurse(detailBean, t, null, request.flags());
t.depth(+1);
}
@@ -232,18 +232,6 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve
throw new IllegalStateException(notExpectedMessage);
}
@Override
public void depth(int diff) {
}
/**
* Return the current depth.
*/
@Override
public int depth() {
return 0;
}
@Override
public void markNotQueryOnly() {
}
@@ -484,34 +484,28 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
return existingBean.equals(beanName);
}
/**
* Return the depth of the current persist request plus the diff. This has the
* effect of changing the current depth and returning the new value. Pass
* diff=0 to return the current depth.
* <p>
* The depth of 0 is for the initial persist request. It is modified as the
* cascading of the save or delete traverses to the the associated Ones (-1)
* and associated Manys (+1).
* </p>
* <p>
* The depth is used to help the ordering of batched statements.
* </p>
*
* @param diff the amount to add or subtract from the depth.
*/
@Override
public final void depth(int diff) {
depth += diff;
}
/**
* Return the current depth.
*/
@Override
public final int depth() {
return depth;
}
@Override
public final void depthDecrement() {
if (depth != 0) {
depth += -1;
}
}
@Override
public final void depthReset() {
depth = 0;
}
@Override
public final void markNotQueryOnly() {
this.queryOnly = false;
@@ -310,15 +310,6 @@ final class NoTransaction implements SpiTransaction {
return null;
}
@Override
public void depth(int diff) {
}
@Override
public int depth() {
return 0;
}
@Override
public boolean isExplicit() {
return false;