diff --git a/src/main/java/org/jenkinsci/plugins/workflow/log/BufferedBuildListener.java b/src/main/java/org/jenkinsci/plugins/workflow/log/BufferedBuildListener.java index 9d0dd81f..43375ddb 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/log/BufferedBuildListener.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/log/BufferedBuildListener.java @@ -114,7 +114,7 @@ private static final class Replacement implements SerializableOnlyOverRemoting { } private Object readResolve() { - return new BufferedBuildListener(new CloseableOutputStream(new GCFlushedOutputStream(new DelayBufferedOutputStream(ros, tuning)))); + return new BufferedBuildListener(new CloseableOutputStream(new DelayBufferedOutputStream(ros, tuning))); } } diff --git a/src/main/java/org/jenkinsci/plugins/workflow/log/GCFlushedOutputStream.java b/src/main/java/org/jenkinsci/plugins/workflow/log/GCFlushedOutputStream.java deleted file mode 100644 index 0123213c..00000000 --- a/src/main/java/org/jenkinsci/plugins/workflow/log/GCFlushedOutputStream.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * The MIT License - * - * Copyright 2018 CloudBees, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package org.jenkinsci.plugins.workflow.log; - -import java.io.BufferedOutputStream; -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.lang.ref.PhantomReference; -import java.lang.ref.ReferenceQueue; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; - -import edu.umd.cs.findbugs.annotations.NonNull; -import hudson.remoting.ChannelClosedException; -import java.io.EOFException; -import java.nio.channels.ClosedChannelException; -import java.util.stream.Stream; -import jenkins.util.Timer; - -/** - * A stream which will be flushed before garbage collection. - * {@link BufferedOutputStream} does not do this automatically. - */ -final class GCFlushedOutputStream extends FilterOutputStream { - - private static final Logger LOGGER = Logger.getLogger(GCFlushedOutputStream.class.getName()); - - GCFlushedOutputStream(OutputStream out) { - super(out); - FlushRef.register(this, out); - } - - @Override public void write(@NonNull byte[] b, int off, int len) throws IOException { - out.write(b, off, len); // super method is surprising - } - - @Override public String toString() { - return "GCFlushedOutputStream[" + out + "]"; - } - - // TODO https://github.com/jenkinsci/remoting/pull/657 - private static boolean isClosedChannelException(Throwable t) { - if (t instanceof ClosedChannelException) { - return true; - } else if (t instanceof ChannelClosedException) { - return true; - } else if (t instanceof EOFException) { - return true; - } else if (t == null) { - return false; - } else { - return isClosedChannelException(t.getCause()) || Stream.of(t.getSuppressed()).anyMatch(GCFlushedOutputStream::isClosedChannelException); - } - } - - /** - * Flushes streams prior to garbage collection. - * ({@link BufferedOutputStream} does not do this automatically.) - * TODO Java 9+ could use java.util.Cleaner - */ - private static final class FlushRef extends PhantomReference { - - private static final ReferenceQueue rq = new ReferenceQueue<>(); - - static { - Timer.get().scheduleWithFixedDelay(() -> { - while (true) { - FlushRef ref = (FlushRef) rq.poll(); - if (ref == null) { - break; - } - LOGGER.log(Level.FINE, "flushing {0}", ref.out); - try { - ref.out.flush(); - } catch (IOException x) { - LOGGER.log(isClosedChannelException(x) ? Level.FINE : Level.WARNING, null, x); - } - } - }, 0, 10, TimeUnit.SECONDS); - } - - static void register(GCFlushedOutputStream fos, OutputStream out) { - new FlushRef(fos, out, rq).enqueue(); - } - - private final OutputStream out; - - private FlushRef(GCFlushedOutputStream fos, OutputStream out, ReferenceQueue rq) { - super(fos, rq); - this.out = out; - } - - } - -} diff --git a/src/main/java/org/jenkinsci/plugins/workflow/log/LogStorage.java b/src/main/java/org/jenkinsci/plugins/workflow/log/LogStorage.java index 0b0707b8..7cd75886 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/log/LogStorage.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/log/LogStorage.java @@ -186,7 +186,7 @@ public interface LogStorage { * Wraps the specified {@link OutputStream} with a buffer that flushes automatically as needed. */ static @NonNull OutputStream wrapWithAutoFlushingBuffer(@NonNull OutputStream os) throws IOException { - return new GCFlushedOutputStream(new DelayBufferedOutputStream(os)); + return new DelayBufferedOutputStream(os); } }