From 86d02161595b6ac6a1d5ef28ceea40af5cd91c2b Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 4 Mar 2019 12:42:08 +1300 Subject: [PATCH] #1644 - ENH: Improve batch flush when multiple "top level" (unrelated) types are persisted --- .../server/persist/BatchControl.java | 8 +-- .../transaction/TestBatchModelFlush.java | 64 +++++++++++++++++++ 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/persist/BatchControl.java b/src/main/java/io/ebeaninternal/server/persist/BatchControl.java index 4a3cafa8b..0b6fd3a66 100644 --- a/src/main/java/io/ebeaninternal/server/persist/BatchControl.java +++ b/src/main/java/io/ebeaninternal/server/persist/BatchControl.java @@ -69,6 +69,7 @@ public final class BatchControl { * Size of the largest buffer. */ private int bufferMax; + private int topCounter; private Queue earlyQueue; private Queue lateQueue; @@ -246,6 +247,7 @@ public final class BatchControl { pstmtHolder.clear(); beanHoldMap.clear(); maxDepth = 0; + topCounter = 0; } private void flushBuffer(boolean resetTop) throws BatchedSqlException { @@ -319,10 +321,8 @@ public final class BatchControl { if (maybe != -1) { beanDepth = maybe; } else { - // we can't be certain of the relative ordering for this type so - // flush and reset the batch as we are changing the type of our top level - // bean so just keep it simple and flush and reset the top - flushReset(); + // additional "top level" bean type ordered by save() order + beanDepth += ++topCounter; } } diff --git a/src/test/java/org/tests/transaction/TestBatchModelFlush.java b/src/test/java/org/tests/transaction/TestBatchModelFlush.java index c176392a1..a8195ec96 100644 --- a/src/test/java/org/tests/transaction/TestBatchModelFlush.java +++ b/src/test/java/org/tests/transaction/TestBatchModelFlush.java @@ -1,10 +1,19 @@ package org.tests.transaction; import io.ebean.BaseTestCase; +import io.ebean.DB; import io.ebean.Ebean; +import io.ebean.Transaction; import io.ebean.annotation.Transactional; +import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import org.tests.model.m2m.MnyB; +import org.tests.model.m2m.MnyTopic; +import org.tests.model.m2m.Role; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; public class TestBatchModelFlush extends BaseTestCase { @@ -30,4 +39,59 @@ public class TestBatchModelFlush extends BaseTestCase { // the rest is flushed on commit new MnyB("TestBatchModelFlush_5").save(); } + + @Test + public void multipleTopLevel_expect_singleFlush() { + + LoggedSqlCollector.start(); + + // 2 unrelated "top level" beans being persisted + MnyB m0 = new MnyB("BatchMultipleTop_0"); + MnyB m1 = new MnyB("BatchMultipleTop_1"); + Role r0 = new Role("Role_0"); + Role r1 = new Role("Role_1"); + + MnyTopic t0 = new MnyTopic("MnyTopic_0"); + MnyTopic t1 = new MnyTopic("MnyTopic_1"); + + try (Transaction transaction = DB.beginTransaction()) { + transaction.setBatchMode(true); + + m0.save(); + DB.save(r0); + DB.save(t0); + DB.save(t1); + + m1.save(); + DB.save(r1); + + transaction.commit(); + } + + List sql = LoggedSqlCollector.stop(); + + // DEBUG io.ebean.SUM - txn[1001] BatchControl flush [MnyB:100 i:2, Role:101 i:2, MnyTopic:102 i:2] + + assertThat(sql).hasSize(9); + + // first saved to batch - (depth 100) + assertThat(sql.get(0)).contains("insert into mny_b"); + assertThat(sql.get(1)).contains(" -- bind(BatchMultipleTop_0"); + assertThat(sql.get(2)).contains(" -- bind(BatchMultipleTop_1"); + // second saved to batch - (depth 101) + assertThat(sql.get(3)).contains("insert into mt_role"); + assertThat(sql.get(4)).contains(" -- bind("); + assertThat(sql.get(5)).contains(" -- bind("); + // third saved to batch - (depth 102) + assertThat(sql.get(6)).contains("insert into mny_topic"); + assertThat(sql.get(7)).contains(" -- bind(MnyTopic_0"); + assertThat(sql.get(8)).contains(" -- bind(MnyTopic_1"); + + DB.delete(t0); + DB.delete(t1); + DB.delete(r0); + DB.delete(r1); + DB.delete(m0); + DB.delete(m1); + } }