Skip to content

Commit b4466a3

Browse files
Gopal Vsteveloughran
authored andcommitted
HADOOP-16341. ShutDownHookManager: Regressed performance on Hook removals after HADOOP-15679
Contributed by Gopal V and Atilla Magyar. Change-Id: I066d5eece332a1673594de0f9b484443f95530ec
1 parent 19a0018 commit b4466a3

File tree

2 files changed

+32
-18
lines changed

2 files changed

+32
-18
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/ShutdownHookManager.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public void run() {
9292
return;
9393
}
9494
long started = System.currentTimeMillis();
95-
int timeoutCount = executeShutdown();
95+
int timeoutCount = MGR.executeShutdown();
9696
long ended = System.currentTimeMillis();
9797
LOG.debug(String.format(
9898
"Completed shutdown in %.3f seconds; Timeouts: %d",
@@ -116,9 +116,9 @@ public void run() {
116116
*/
117117
@InterfaceAudience.Private
118118
@VisibleForTesting
119-
static int executeShutdown() {
119+
int executeShutdown() {
120120
int timeouts = 0;
121-
for (HookEntry entry: MGR.getShutdownHooksInOrder()) {
121+
for (HookEntry entry: getShutdownHooksInOrder()) {
122122
Future<?> future = EXECUTOR.submit(entry.getHook());
123123
try {
124124
future.get(entry.getTimeout(), entry.getTimeUnit());
@@ -254,7 +254,9 @@ TimeUnit getTimeUnit() {
254254
private AtomicBoolean shutdownInProgress = new AtomicBoolean(false);
255255

256256
//private to constructor to ensure singularity
257-
private ShutdownHookManager() {
257+
@VisibleForTesting
258+
@InterfaceAudience.Private
259+
ShutdownHookManager() {
258260
}
259261

260262
/**
@@ -267,8 +269,8 @@ private ShutdownHookManager() {
267269
@VisibleForTesting
268270
List<HookEntry> getShutdownHooksInOrder() {
269271
List<HookEntry> list;
270-
synchronized (MGR.hooks) {
271-
list = new ArrayList<>(MGR.hooks);
272+
synchronized (hooks) {
273+
list = new ArrayList<>(hooks);
272274
}
273275
Collections.sort(list, new Comparator<HookEntry>() {
274276

@@ -342,7 +344,9 @@ public boolean removeShutdownHook(Runnable shutdownHook) {
342344
throw new IllegalStateException("Shutdown in progress, cannot remove a " +
343345
"shutdownHook");
344346
}
345-
return hooks.remove(new HookEntry(shutdownHook, 0));
347+
// hooks are only == by runnable
348+
return hooks.remove(new HookEntry(shutdownHook, 0, TIMEOUT_MINIMUM,
349+
TIME_UNIT_DEFAULT));
346350
}
347351

348352
/**
@@ -354,7 +358,8 @@ public boolean removeShutdownHook(Runnable shutdownHook) {
354358
@InterfaceAudience.Public
355359
@InterfaceStability.Stable
356360
public boolean hasShutdownHook(Runnable shutdownHook) {
357-
return hooks.contains(new HookEntry(shutdownHook, 0));
361+
return hooks.contains(new HookEntry(shutdownHook, 0, TIMEOUT_MINIMUM,
362+
TIME_UNIT_DEFAULT));
358363
}
359364

360365
/**

hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestShutdownHookManager.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import java.util.concurrent.TimeUnit;
2222
import java.util.concurrent.atomic.AtomicInteger;
2323

24-
import org.junit.After;
2524
import org.junit.Test;
2625
import org.slf4j.Logger;
2726
import org.slf4j.LoggerFactory;
@@ -43,13 +42,10 @@ public class TestShutdownHookManager {
4342
LoggerFactory.getLogger(TestShutdownHookManager.class.getName());
4443

4544
/**
46-
* remove all the shutdown hooks so that they never get invoked later
47-
* on in this test process.
45+
* A new instance of ShutdownHookManager to ensure parallel tests
46+
* don't have shared context.
4847
*/
49-
@After
50-
public void clearShutdownHooks() {
51-
ShutdownHookManager.get().clearShutdownHooks();
52-
}
48+
private final ShutdownHookManager mgr = new ShutdownHookManager();
5349

5450
/**
5551
* Verify hook registration, then execute the hook callback stage
@@ -58,7 +54,6 @@ public void clearShutdownHooks() {
5854
*/
5955
@Test
6056
public void shutdownHookManager() {
61-
ShutdownHookManager mgr = ShutdownHookManager.get();
6257
assertNotNull("No ShutdownHookManager", mgr);
6358
assertEquals(0, mgr.getShutdownHooksInOrder().size());
6459
Hook hook1 = new Hook("hook1", 0, false);
@@ -119,7 +114,7 @@ public void shutdownHookManager() {
119114
// now execute the hook shutdown sequence
120115
INVOCATION_COUNT.set(0);
121116
LOG.info("invoking executeShutdown()");
122-
int timeouts = ShutdownHookManager.executeShutdown();
117+
int timeouts = mgr.executeShutdown();
123118
LOG.info("Shutdown completed");
124119
assertEquals("Number of timed out hooks", 1, timeouts);
125120

@@ -193,7 +188,6 @@ public void testShutdownTimeoutBadConfiguration() throws Throwable {
193188
*/
194189
@Test
195190
public void testDuplicateRegistration() throws Throwable {
196-
ShutdownHookManager mgr = ShutdownHookManager.get();
197191
Hook hook = new Hook("hook1", 0, false);
198192

199193
// add the hook
@@ -222,6 +216,21 @@ public void testDuplicateRegistration() throws Throwable {
222216

223217
}
224218

219+
@Test
220+
public void testShutdownRemove() throws Throwable {
221+
assertNotNull("No ShutdownHookManager", mgr);
222+
assertEquals(0, mgr.getShutdownHooksInOrder().size());
223+
Hook hook1 = new Hook("hook1", 0, false);
224+
Hook hook2 = new Hook("hook2", 0, false);
225+
mgr.addShutdownHook(hook1, 9); // create Hook1 with priority 9
226+
assertTrue("No hook1", mgr.hasShutdownHook(hook1)); // hook1 lookup works
227+
assertEquals(1, mgr.getShutdownHooksInOrder().size()); // 1 hook
228+
assertFalse("Delete hook2 should not be allowed",
229+
mgr.removeShutdownHook(hook2));
230+
assertTrue("Can't delete hook1", mgr.removeShutdownHook(hook1));
231+
assertEquals(0, mgr.getShutdownHooksInOrder().size());
232+
}
233+
225234
private static final AtomicInteger INVOCATION_COUNT = new AtomicInteger();
226235

227236
/**

0 commit comments

Comments
 (0)