This is an automated email from the ASF dual-hosted git repository. clebertsuconic pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git
The following commit(s) were added to refs/heads/master by this push: new b1835fa ARTEMIS-3037 JournalImpl#checkKnownRecordID() implementation can leave a thread hanging in WAITING state new 1db088e This closes #3385 b1835fa is described below commit b1835fa2d8bf2c54d1e2d5a3f2f1e0cb075adcb3 Author: Tomas Hofman <thof...@redhat.com> AuthorDate: Thu Dec 17 11:52:25 2020 +0100 ARTEMIS-3037 JournalImpl#checkKnownRecordID() implementation can leave a thread hanging in WAITING state --- .../artemis/core/journal/impl/JournalImpl.java | 17 +++-- .../extras/byteman/JournalImplConcurrencyTest.java | 73 ++++++++++++++++++++++ 2 files changed, 84 insertions(+), 6 deletions(-) diff --git a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalImpl.java b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalImpl.java index e91b76b..8418174 100644 --- a/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalImpl.java +++ b/artemis-journal/src/main/java/org/apache/activemq/artemis/core/journal/impl/JournalImpl.java @@ -1135,14 +1135,19 @@ public class JournalImpl extends JournalBase implements TestableJournal, Journal appendExecutor.execute(new Runnable() { @Override public void run() { - journalLock.readLock().lock(); try { + journalLock.readLock().lock(); + try { - known.set(records.containsKey(id) - || pendingRecords.contains(id) - || (compactor != null && compactor.containsRecord(id))); - } finally { - journalLock.readLock().unlock(); + known.set(records.containsKey(id) + || pendingRecords.contains(id) + || (compactor != null && compactor.containsRecord(id))); + } finally { + journalLock.readLock().unlock(); + } + } catch (Throwable t) { + known.fail(t); + throw t; } } }); diff --git a/tests/extra-tests/src/test/java/org/apache/activemq/artemis/tests/extras/byteman/JournalImplConcurrencyTest.java b/tests/extra-tests/src/test/java/org/apache/activemq/artemis/tests/extras/byteman/JournalImplConcurrencyTest.java new file mode 100644 index 0000000..5df1afa --- /dev/null +++ b/tests/extra-tests/src/test/java/org/apache/activemq/artemis/tests/extras/byteman/JournalImplConcurrencyTest.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.artemis.tests.extras.byteman; + +import org.apache.activemq.artemis.core.io.SequentialFileFactory; +import org.apache.activemq.artemis.tests.unit.core.journal.impl.JournalImplTestBase; +import org.apache.activemq.artemis.tests.unit.core.journal.impl.fakes.FakeSequentialFileFactory; +import org.jboss.byteman.contrib.bmunit.BMRule; +import org.jboss.byteman.contrib.bmunit.BMRules; +import org.jboss.byteman.contrib.bmunit.BMUnitRunner; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.ExecutionException; + +@RunWith(BMUnitRunner.class) +public class JournalImplConcurrencyTest extends JournalImplTestBase { + + @Override + protected SequentialFileFactory getFileFactory() { + return new FakeSequentialFileFactory(); + } + + + /** + * Tests that JournalImpl#checkKnownRecordID() doesn't hang when the executor thread fails with + * an exception before setting the future value. + */ + @Test(timeout = 2000) + @BMRules(rules = { + @BMRule( + name = "BlockOnFinalLargeMessagePacket", + targetClass = "java.util.concurrent.locks.ReentrantReadWriteLock", + targetMethod = "readLock()", + targetLocation = "EXIT", + condition = "Thread.currentThread().getName().contains(\"ArtemisIOThread\")", + action = "throw RuntimeException(\"Injected exception\");" + ) + }) + public void testTryDelete() throws Exception { + setup(10, 10 * 1024, true); + createJournal(); + startJournal(); + load(); + addTx(1, 1, 2, 3); + + try { + tryDelete(1); + Assert.fail("Expected to throw exception injected by a byteman rule"); + } catch (ExecutionException e) { + Assert.assertTrue(e.getCause() instanceof RuntimeException); + Assert.assertEquals("Injected exception", e.getCause().getMessage()); + } + + stopJournal(); + } + +}