HDFS-9347. Invariant assumption in TestQuorumJournalManager.shutdown() is wrong. Contributed by Wei-Chiu Chuang.

Change-Id: Idde8522e11c77f82b376e0c90a9bf33d163d5cb9
This commit is contained in:
Zhe Zhang 2015-12-18 16:04:47 -08:00
parent 1147b086d9
commit 223b47b398
3 changed files with 56 additions and 14 deletions

View File

@ -417,6 +417,26 @@ public static void assertValueWithinRange(long expectedMin, long expectedMax,
+ expectedMax + ")", expectedMin <= actual && actual <= expectedMax); + expectedMax + ")", expectedMin <= actual && actual <= expectedMax);
} }
/**
* Determine if there are any threads whose name matches the regex.
* @param pattern a Pattern object used to match thread names
* @return true if there is any thread that matches the pattern
*/
public static boolean anyThreadMatching(Pattern pattern) {
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] infos =
threadBean.getThreadInfo(threadBean.getAllThreadIds(), 20);
for (ThreadInfo info : infos) {
if (info == null)
continue;
if (pattern.matcher(info.getThreadName()).matches()) {
return true;
}
}
return false;
}
/** /**
* Assert that there are no threads running whose name matches the * Assert that there are no threads running whose name matches the
* given regular expression. * given regular expression.
@ -424,18 +444,34 @@ public static void assertValueWithinRange(long expectedMin, long expectedMax,
*/ */
public static void assertNoThreadsMatching(String regex) { public static void assertNoThreadsMatching(String regex) {
Pattern pattern = Pattern.compile(regex); Pattern pattern = Pattern.compile(regex);
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); if (anyThreadMatching(pattern)) {
Assert.fail("Leaked thread matches " + regex);
ThreadInfo[] infos = threadBean.getThreadInfo(threadBean.getAllThreadIds(), 20);
for (ThreadInfo info : infos) {
if (info == null) continue;
if (pattern.matcher(info.getThreadName()).matches()) {
Assert.fail("Leaked thread: " + info + "\n" +
Joiner.on("\n").join(info.getStackTrace()));
}
} }
} }
/**
* Periodically check and wait for any threads whose name match the
* given regular expression.
*
* @param regex the regex to match against.
* @param checkEveryMillis time (in milliseconds) between checks.
* @param waitForMillis total time (in milliseconds) to wait before throwing
* a time out exception.
* @throws TimeoutException
* @throws InterruptedException
*/
public static void waitForThreadTermination(String regex,
int checkEveryMillis, final int waitForMillis) throws TimeoutException,
InterruptedException {
final Pattern pattern = Pattern.compile(regex);
waitFor(new Supplier<Boolean>() {
@Override public Boolean get() {
return !anyThreadMatching(pattern);
}
}, checkEveryMillis, waitForMillis);
}
/** /**
* Skip test if native build profile of Maven is not activated. * Skip test if native build profile of Maven is not activated.
* Sub-project using this must set 'runningWithNative' property to true * Sub-project using this must set 'runningWithNative' property to true

View File

@ -1664,6 +1664,9 @@ Release 2.8.0 - UNRELEASED
replicas should go through BlockPlacementPolicy replicas should go through BlockPlacementPolicy
(J.Andreina via vinayakumarb) (J.Andreina via vinayakumarb)
HDFS-9347. Invariant assumption in TestQuorumJournalManager.shutdown()
is wrong. (Wei-Chiu Chuang via zhz)
Release 2.7.3 - UNRELEASED Release 2.7.3 - UNRELEASED
INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES

View File

@ -38,6 +38,7 @@
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeoutException;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -103,21 +104,23 @@ public void setup() throws Exception {
qjm.recoverUnfinalizedSegments(); qjm.recoverUnfinalizedSegments();
assertEquals(1, qjm.getLoggerSetForTests().getEpoch()); assertEquals(1, qjm.getLoggerSetForTests().getEpoch());
} }
@After @After
public void shutdown() throws IOException { public void shutdown() throws IOException, InterruptedException,
TimeoutException {
IOUtils.cleanup(LOG, toClose.toArray(new Closeable[0])); IOUtils.cleanup(LOG, toClose.toArray(new Closeable[0]));
// Should not leak clients between tests -- this can cause flaky tests. // Should not leak clients between tests -- this can cause flaky tests.
// (See HDFS-4643) // (See HDFS-4643)
GenericTestUtils.assertNoThreadsMatching(".*IPC Client.*"); // Wait for IPC clients to terminate to avoid flaky tests
GenericTestUtils.waitForThreadTermination(".*IPC Client.*", 100, 1000);
if (cluster != null) { if (cluster != null) {
cluster.shutdown(); cluster.shutdown();
cluster = null; cluster = null;
} }
} }
/** /**
* Enqueue a QJM for closing during shutdown. This makes the code a little * Enqueue a QJM for closing during shutdown. This makes the code a little
* easier to follow, with fewer try..finally clauses necessary. * easier to follow, with fewer try..finally clauses necessary.