From 97f79732665cba9457e07ea64bf881b00f43292b Mon Sep 17 00:00:00 2001 From: Carter Kozak Date: Tue, 13 Apr 2021 15:53:35 -0400 Subject: [PATCH] Fix #370: Logger instances are lazily initialized Default java loggers are no longer initialized when custom ExceptionHandler instances are provided. This allows logging frameworks to delegate to disruptor without risking deadlocks. --- .../lmax/disruptor/BatchEventProcessor.java | 43 ++++++++++++++++--- .../com/lmax/disruptor/ExceptionHandlers.java | 43 +++++++++++++++++++ .../dsl/ExceptionHandlerWrapper.java | 16 ++++--- 3 files changed, 92 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/lmax/disruptor/ExceptionHandlers.java diff --git a/src/main/java/com/lmax/disruptor/BatchEventProcessor.java b/src/main/java/com/lmax/disruptor/BatchEventProcessor.java index c2381389a..210f90089 100644 --- a/src/main/java/com/lmax/disruptor/BatchEventProcessor.java +++ b/src/main/java/com/lmax/disruptor/BatchEventProcessor.java @@ -35,7 +35,7 @@ public final class BatchEventProcessor private static final int RUNNING = HALTED + 1; private final AtomicInteger running = new AtomicInteger(IDLE); - private ExceptionHandler exceptionHandler = new FatalExceptionHandler(); + private ExceptionHandler exceptionHandler; private final DataProvider dataProvider; private final SequenceBarrier sequenceBarrier; private final EventHandler eventHandler; @@ -184,7 +184,7 @@ private void processEvents() } catch (final Throwable ex) { - exceptionHandler.handleEventException(ex, nextSequence, event); + handleEventException(ex, nextSequence, event); sequence.set(nextSequence); nextSequence++; } @@ -208,7 +208,7 @@ private void notifyTimeout(final long availableSequence) } catch (Throwable e) { - exceptionHandler.handleEventException(e, availableSequence, null); + handleEventException(e, availableSequence, null); } } @@ -225,7 +225,7 @@ private void notifyStart() } catch (final Throwable ex) { - exceptionHandler.handleOnStartException(ex); + handleOnStartException(ex); } } } @@ -243,8 +243,41 @@ private void notifyShutdown() } catch (final Throwable ex) { - exceptionHandler.handleOnShutdownException(ex); + handleOnShutdownException(ex); } } } + + /** + * Delegate to {@link ExceptionHandler#handleEventException(Throwable, long, Object)} on the delegate or + * the default {@link ExceptionHandler} if one has not been configured. + */ + private void handleEventException(final Throwable ex, final long sequence, final T event) + { + getExceptionHandler().handleEventException(ex, sequence, event); + } + + /** + * Delegate to {@link ExceptionHandler#handleOnStartException(Throwable)} on the delegate or + * the default {@link ExceptionHandler} if one has not been configured. + */ + private void handleOnStartException(final Throwable ex) + { + getExceptionHandler().handleOnStartException(ex); + } + + /** + * Delegate to {@link ExceptionHandler#handleOnShutdownException(Throwable)} on the delegate or + * the default {@link ExceptionHandler} if one has not been configured. + */ + private void handleOnShutdownException(final Throwable ex) + { + getExceptionHandler().handleOnShutdownException(ex); + } + + private ExceptionHandler getExceptionHandler() + { + ExceptionHandler handler = exceptionHandler; + return handler == null ? ExceptionHandlers.defaultHandler() : handler; + } } \ No newline at end of file diff --git a/src/main/java/com/lmax/disruptor/ExceptionHandlers.java b/src/main/java/com/lmax/disruptor/ExceptionHandlers.java new file mode 100644 index 000000000..8c3488c63 --- /dev/null +++ b/src/main/java/com/lmax/disruptor/ExceptionHandlers.java @@ -0,0 +1,43 @@ +/* + * Copyright 2021 LMAX Ltd. + * + * Licensed 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 com.lmax.disruptor; + +/** Provides static methods for accessing a default {@link ExceptionHandler} object. */ +public final class ExceptionHandlers +{ + + /** + * Get a reference to the default {@link ExceptionHandler} instance. + * + * @return a reference to the default {@link ExceptionHandler} instance + */ + public static ExceptionHandler defaultHandler() + { + return DefaultExceptionHandlerHolder.HANDLER; + } + + private ExceptionHandlers() + { + } + + // lazily initialize the default exception handler. + // This nested object isn't strictly necessary unless additional utility functionality is + // added to ExceptionHandlers, but it exists to ensure the code remains obvious. + private static final class DefaultExceptionHandlerHolder + { + private static final ExceptionHandler HANDLER = new FatalExceptionHandler(); + } +} diff --git a/src/main/java/com/lmax/disruptor/dsl/ExceptionHandlerWrapper.java b/src/main/java/com/lmax/disruptor/dsl/ExceptionHandlerWrapper.java index 4c31af140..81f72019a 100644 --- a/src/main/java/com/lmax/disruptor/dsl/ExceptionHandlerWrapper.java +++ b/src/main/java/com/lmax/disruptor/dsl/ExceptionHandlerWrapper.java @@ -1,11 +1,11 @@ package com.lmax.disruptor.dsl; import com.lmax.disruptor.ExceptionHandler; -import com.lmax.disruptor.FatalExceptionHandler; +import com.lmax.disruptor.ExceptionHandlers; public class ExceptionHandlerWrapper implements ExceptionHandler { - private ExceptionHandler delegate = new FatalExceptionHandler(); + private ExceptionHandler delegate; public void switchTo(final ExceptionHandler exceptionHandler) { @@ -15,18 +15,24 @@ public void switchTo(final ExceptionHandler exceptionHandler) @Override public void handleEventException(final Throwable ex, final long sequence, final T event) { - delegate.handleEventException(ex, sequence, event); + getExceptionHandler().handleEventException(ex, sequence, event); } @Override public void handleOnStartException(final Throwable ex) { - delegate.handleOnStartException(ex); + getExceptionHandler().handleOnStartException(ex); } @Override public void handleOnShutdownException(final Throwable ex) { - delegate.handleOnShutdownException(ex); + getExceptionHandler() .handleOnShutdownException(ex); + } + + private ExceptionHandler getExceptionHandler() + { + ExceptionHandler handler = delegate; + return handler == null ? ExceptionHandlers.defaultHandler() : handler; } }