Skip to content

Commit 3ae85d7

Browse files
authored
[JENKINS-75081] Avoid heap allocation when rendering large logs (#10515)
1 parent b452ffd commit 3ae85d7

6 files changed

Lines changed: 50 additions & 13 deletions

File tree

bom/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ THE SOFTWARE.
4141
<commons-fileupload2.version>2.0.0-M2</commons-fileupload2.version>
4242
<groovy.version>2.4.21</groovy.version>
4343
<jelly.version>1.1-jenkins-20250108</jelly.version>
44-
<stapler.version>1971.vf47a_d79853d7</stapler.version>
44+
<stapler.version>1979.v5048d87384d7</stapler.version>
4545
</properties>
4646

4747
<dependencyManagement>

core/src/main/java/hudson/console/AnnotatedLargeText.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,10 @@ public void doProgressiveText(StaplerRequest req, StaplerResponse rsp) throws IO
141141
* and use this request attribute to differentiate.
142142
*/
143143
private boolean isHtml() {
144-
StaplerRequest2 req = Stapler.getCurrentRequest2();
144+
return isHtml(Stapler.getCurrentRequest2());
145+
}
146+
147+
private boolean isHtml(StaplerRequest2 req) {
145148
return req != null && req.getAttribute("html") != null;
146149
}
147150

@@ -207,6 +210,11 @@ public long writeLogTo(long start, Writer w) throws IOException {
207210
return super.writeLogTo(start, w);
208211
}
209212

213+
@Override
214+
protected boolean delegateToWriteLogTo(StaplerRequest2 req, StaplerResponse2 rsp) {
215+
return isHtml(req);
216+
}
217+
210218
/**
211219
* Strips annotations using a {@link PlainTextConsoleOutputStream}.
212220
* {@inheritDoc}

core/src/main/java/hudson/console/ConsoleAnnotator.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ public ConsoleAnnotator annotate(T context, MarkupText text) {
118118
default: return this;
119119
}
120120
}
121+
122+
@Override
123+
public String toString() {
124+
return "ConsoleAnnotatorAggregator" + list;
125+
}
121126
}
122127

123128
/**

core/src/main/java/hudson/model/Run.java

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@
7272
import io.jenkins.servlet.ServletExceptionWrapper;
7373
import jakarta.servlet.ServletException;
7474
import jakarta.servlet.http.HttpServletResponse;
75-
import java.io.BufferedInputStream;
7675
import java.io.ByteArrayInputStream;
7776
import java.io.File;
7877
import java.io.IOException;
@@ -1466,19 +1465,34 @@ public Collection<Fingerprint> getBuildFingerprints() {
14661465
*/
14671466
@SuppressFBWarnings(value = "RV_RETURN_VALUE_IGNORED", justification = "method signature does not permit plumbing through the return value")
14681467
public void writeLogTo(long offset, @NonNull XMLOutput out) throws IOException {
1469-
long start = offset;
1468+
AnnotatedLargeText<?> logText = getLogText();
14701469
if (offset > 0) {
1471-
try (BufferedInputStream bufferedInputStream = new BufferedInputStream(getLogInputStream())) {
1472-
if (offset == bufferedInputStream.skip(offset)) {
1473-
int r;
1474-
do {
1475-
r = bufferedInputStream.read();
1476-
start = r == -1 ? 0 : start + 1;
1477-
} while (r != -1 && r != '\n');
1478-
}
1470+
long _offset = offset;
1471+
try {
1472+
logText.writeRawLogTo(offset - 1, new OutputStream() {
1473+
long pos = _offset;
1474+
@Override
1475+
public void write(int b) throws IOException {
1476+
if (b == '\n') {
1477+
throw new Halt(pos);
1478+
} else {
1479+
pos++;
1480+
}
1481+
}
1482+
});
1483+
} catch (Halt halt) {
1484+
offset = halt.offset;
14791485
}
14801486
}
1481-
getLogText().writeHtmlTo(start, out.asWriter());
1487+
logText.writeHtmlTo(offset, out.asWriter());
1488+
}
1489+
1490+
private static final class Halt extends IOException {
1491+
final long offset;
1492+
1493+
Halt(long offset) {
1494+
this.offset = offset;
1495+
}
14821496
}
14831497

14841498
/**

core/src/test/java/hudson/model/RunTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,11 @@ public void wontPushOffsetOnRenderingFromBeginning() throws Exception {
280280
assertWriteLogToEquals(new String(new char[5]).replace("\0", SAMPLE_BUILD_OUTPUT) + "Finished: SUCCESS.\n", 0);
281281
}
282282

283+
@Test
284+
public void wontPushOffsetOnRenderingFromBeginningOfLine() throws Exception {
285+
assertWriteLogToEquals(new String(new char[3]).replace("\0", SAMPLE_BUILD_OUTPUT) + "Finished: SUCCESS.\n", 2 * SAMPLE_BUILD_OUTPUT.length());
286+
}
287+
283288
@Test
284289
public void willRenderNothingIfOffsetSetOnLastLine() throws Exception {
285290
assertWriteLogToEquals("", 5 * SAMPLE_BUILD_OUTPUT.length() + 6);

test/src/test/java/hudson/console/ConsoleAnnotatorTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,11 @@ public ConsoleAnnotator annotate(Object build, MarkupText text) {
224224
text.addMarkup(0, 5, "<b tag=" + n++ + ">", "</b>");
225225
return this;
226226
}
227+
228+
@Override
229+
public String toString() {
230+
return "StatefulAnnotator:" + n + " @" + System.identityHashCode(this);
231+
}
227232
}
228233

229234

0 commit comments

Comments
 (0)