denis-chudov commented on code in PR #3092:
URL: https://github.com/apache/ignite-3/pull/3092#discussion_r1474685812


##########
modules/table/src/testFixtures/java/org/apache/ignite/internal/table/TxAbstractTest.java:
##########
@@ -2151,12 +2158,178 @@ public void 
testYoungerTransactionThrowsExceptionIfKeyLockedByOlderTransactionWi
         assertThrows(TransactionException.class, () -> 
keyValueView.put(youngNormalTx, 1L, "normal"));
     }
 
+    @RepeatedTest(10)
+    public void testTransactionMultiThreadedCommit() {
+        testTransactionMultiThreadedFinish(1, false);
+    }
+
+    @RepeatedTest(10)
+    public void testTransactionMultiThreadedCommitEmpty() {
+        testTransactionMultiThreadedFinish(1, true);
+    }
+
+    @RepeatedTest(10)
+    public void testTransactionMultiThreadedRollback() {
+        testTransactionMultiThreadedFinish(0, false);
+    }
+
+    @RepeatedTest(10)
+    public void testTransactionMultiThreadedRollbackEmpty() {
+        testTransactionMultiThreadedFinish(0, true);
+    }
+
+    @RepeatedTest(10)
+    public void testTransactionMultiThreadedMixed() {
+        testTransactionMultiThreadedFinish(-1, false);
+    }
+
+    @RepeatedTest(10)
+    public void testTransactionMultiThreadedMixedEmpty() {
+        testTransactionMultiThreadedFinish(-1, true);
+    }
+
+    /**
+     * Test trying to finish a tx in multiple threads simultaneously, and 
enlist new operations right after the first finish.
+     *
+     * @param finishMode 1 is commit, 0 is rollback, otherwise random outcome.
+     * @param checkEmptyTx Whether the tx should be empty on finishing (no 
enlisted operations).
+     */
+    private void testTransactionMultiThreadedFinish(int finishMode, boolean 
checkEmptyTx) {
+        var rv = accounts.recordView();
+
+        rv.upsert(null, makeValue(1, 1.));
+
+        Transaction tx = igniteTransactions.begin();
+
+        var txId = ((ReadWriteTransactionImpl) tx).id();
+
+        log.info("Started transaction {}", txId);
+
+        if (!checkEmptyTx) {
+            rv.upsert(tx, makeValue(1, 100.));
+            rv.upsert(tx, makeValue(2, 200.));
+        }
+
+        int threadNum = Runtime.getRuntime().availableProcessors() * 5;
+
+        CyclicBarrier b = new CyclicBarrier(threadNum);
+        CountDownLatch finishLatch = new CountDownLatch(1);
+
+        List<Exception> enlistExceptions = synchronizedList(new ArrayList<>());
+
+        var futEnlists = runMultiThreadedAsync(() -> {
+            finishLatch.await();
+            var rnd = ThreadLocalRandom.current();
+
+            try {
+                if (rnd.nextBoolean()) {
+                    rv.upsert(tx, makeValue(2, 200.));
+                } else {
+                    rv.get(tx, makeKey(1));
+                }
+            } catch (Exception e) {
+                enlistExceptions.add(e);
+            }
+
+            return null;
+        }, threadNum, "txCommitTestThread");
+
+        var futFinishes = runMultiThreadedAsync(() -> {
+            b.await();
+
+            finishTx(tx, finishMode);
+
+            finishLatch.countDown();
+
+            return null;
+        }, threadNum, "txCommitTestThread");
+
+        assertThat(futFinishes, willSucceedFast());
+        assertThat(futEnlists, willSucceedFast());
+
+        assertEquals(threadNum, enlistExceptions.size());
+
+        for (var e : enlistExceptions) {
+            try {
+                assertInstanceOf(TransactionException.class, e);

Review Comment:
   assertThrowsWithCause? I think it's not what is needed, it checks a Runnable 
and doesnt have multiple acceptable messages



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@ignite.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to