Skip to content

Commit de8e075

Browse files
committed
Increasing default buffer size, and making tuning parameters configurable via system property.
1 parent 4e8faa4 commit de8e075

File tree

2 files changed

+25
-10
lines changed

2 files changed

+25
-10
lines changed

src/main/java/org/jenkinsci/plugins/workflow/log/BufferedBuildListener.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,14 @@ private static final class Replacement implements SerializableOnlyOverRemoting {
6767
private static final long serialVersionUID = 1;
6868

6969
private final RemoteOutputStream ros;
70+
private final DelayBufferedOutputStream.Tuning tuning = DelayBufferedOutputStream.Tuning.DEFAULT; // load defaults on master
7071

7172
Replacement(BufferedBuildListener cbl) {
7273
this.ros = new RemoteOutputStream(new CloseProofOutputStream(cbl.out));
7374
}
7475

7576
private Object readResolve() throws IOException {
76-
return new BufferedBuildListener(new DelayBufferedOutputStream(ros));
77+
return new BufferedBuildListener(new DelayBufferedOutputStream(ros, tuning));
7778
}
7879

7980
}

src/main/java/org/jenkinsci/plugins/workflow/log/DelayBufferedOutputStream.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.logging.Level;
3535
import java.util.logging.Logger;
3636
import jenkins.util.Timer;
37+
import org.jenkinsci.remoting.SerializableOnlyOverRemoting;
3738

3839
/**
3940
* Buffered output stream which is guaranteed to deliver content after some time even if idle and the buffer does not fill up.
@@ -43,21 +44,33 @@ final class DelayBufferedOutputStream extends BufferedOutputStream {
4344

4445
private static final Logger LOGGER = Logger.getLogger(DelayBufferedOutputStream.class.getName());
4546

46-
// TODO make these customizable (not trivial since this system properties would need to be loaded on the master side and then remoted)
47-
private static final long MIN_RECURRENCE_PERIOD = 250; // ¼s
48-
private static final long MAX_RECURRENCE_PERIOD = 10_000; // 10s
49-
private static final float RECURRENCE_PERIOD_BACKOFF = 1.05f;
47+
static final class Tuning implements SerializableOnlyOverRemoting {
48+
private Tuning() {}
49+
// nonfinal for Groovy scripting:
50+
long minRecurrencePeriod = Long.getLong(DelayBufferedOutputStream.class.getName() + ".minRecurrencePeriod", 250); // ¼s
51+
long maxRecurrencePeriod = Long.getLong(DelayBufferedOutputStream.class.getName() + ".maxRecurrencePeriod", 10_000); // 10s
52+
float recurrencePeriodBackoff = Float.parseFloat(System.getProperty(DelayBufferedOutputStream.class.getName() + ".recurrencePeriodBackoff", "1.05"));
53+
int bufferSize = Integer.getInteger(DelayBufferedOutputStream.class.getName() + ".bufferSize", 1 << 16); // 64Kib
54+
static final Tuning DEFAULT = new Tuning();
55+
}
5056

51-
private long recurrencePeriod = MIN_RECURRENCE_PERIOD;
57+
private final Tuning tuning;
58+
private long recurrencePeriod;
5259

5360
DelayBufferedOutputStream(OutputStream out) {
54-
super(new FlushControlledOutputStream(out)); // default buffer size: 8Kib
61+
this(out, Tuning.DEFAULT);
62+
}
63+
64+
DelayBufferedOutputStream(OutputStream out, Tuning tuning) {
65+
super(new FlushControlledOutputStream(out), tuning.bufferSize);
66+
this.tuning = tuning;
67+
recurrencePeriod = tuning.minRecurrencePeriod;
5568
reschedule();
5669
}
5770

5871
private void reschedule() {
5972
Timer.get().schedule(new Flush(this), recurrencePeriod, TimeUnit.MILLISECONDS);
60-
recurrencePeriod = Math.min((long) (recurrencePeriod * RECURRENCE_PERIOD_BACKOFF), MAX_RECURRENCE_PERIOD);
73+
recurrencePeriod = Math.min((long) (recurrencePeriod * tuning.recurrencePeriodBackoff), tuning.maxRecurrencePeriod);
6174
}
6275

6376
/** We can only call {@link BufferedOutputStream#flushBuffer} via {@link #flush}, but we do not wish to flush the underlying stream, only write out the buffer. */
@@ -72,7 +85,8 @@ private void flushBuffer() throws IOException {
7285
}
7386
}
7487

75-
void run() {
88+
void flushAndReschedule() {
89+
// TODO as an optimization, avoid flushing the buffer if it was recently flushed anyway due to filling up
7690
try {
7791
flushBuffer();
7892
} catch (IOException x) {
@@ -100,7 +114,7 @@ private static final class Flush implements Runnable {
100114
@Override public void run() {
101115
DelayBufferedOutputStream os = osr.get();
102116
if (os != null) {
103-
os.run();
117+
os.flushAndReschedule();
104118
}
105119
}
106120

0 commit comments

Comments
 (0)