Skip to content

Trim console output before processing it console document#2462

Open
trancexpress wants to merge 1 commit intoeclipse-platform:masterfrom
trancexpress:gh2283
Open

Trim console output before processing it console document#2462
trancexpress wants to merge 1 commit intoeclipse-platform:masterfrom
trancexpress:gh2283

Conversation

@trancexpress
Copy link
Contributor

When processing large amounts of console output of a process, its possible that the Eclipse UI will freeze.
E.g. on Linux, very long lines (> 1 million symbols) result in such freezes.

Using the console limit preference doesn't help preventing this freeze, despite limitting the contents seen in the console.

This change adjusts IOConsolePartitioner.QueueProcessingJob.processPendingPartitions() to trim pending console output before setting this output in the console document, if a console limit is set in the Eclipse preferences.

See: #2283

applyStreamOutput(pendingCopy, sizeHint);
}
checkFinished();
checkBufferSize(); // needs partitions synchronized
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proper trimming is done here. The above change just reduces the output that will be processed by the document / underlying widget.

}
sizeHint = 0;
int index = 0;
for (int i = copy.size() - 1; i >= 0; --i) {
Copy link
Contributor Author

@trancexpress trancexpress Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will need to write this better, current state is not good.

But generally this is what Copilot advised to do. With this change, at least the user is able to set a console limit to avoid the UI hangs.

It will still be good to fix the problem even without the console limit... But the change is something and its simple.

Note that with my snippet, #2283 (comment), the console contents are unusable if I use the console limit (with and without this change). Probably we want to open another bug for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think another problem we see here is that the console character limit is not applied, if the output is only a single line.

Likely we can do this here as well... If there is only one pending change after the initial trim, trim the text in it as well, if its length is above the character limit.

And maybe we look into the trimming algorithm below, for continuous output on the same line... But likely we want to do this in a separate ticket.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to prevent Eclipse UI freezes when processing extremely large console output by trimming pending console output in IOConsolePartitioner.QueueProcessingJob.processPendingPartitions() before applying it to the console document, when a console limit (water marks) is configured.

Changes:

  • Adds logic in processPendingPartitions() to trim pending partitions based on the console highWaterMark before calling applyStreamOutput(...).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 809 to 832
List<PendingPartition> copy = new ArrayList<>();
List<PendingPartition> trimmedCopy = new ArrayList<>();
for (PendingPartition p : pendingCopy) {
if (p.stream != stream) {
break;
}
copy.add(p);
}
sizeHint = 0;
int index = 0;
for (int i = copy.size() - 1; i >= 0; --i) {
PendingPartition p = copy.get(i);
sizeHint += p.text.length();
index = i;
if (sizeHint > hwm) {
break;
}
}
for (int i = index; i < copy.size(); ++i) {
PendingPartition p = copy.get(i);
trimmedCopy.add(p);
}
pendingCopy = trimmedCopy;
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trimming block replaces pendingCopy with trimmedCopy, which is built only from the first contiguous stream (copy stops at the first p.stream != stream). If pendingCopy contained additional partitions from other streams after that boundary, they were already drained from pendingPartitions and will be silently dropped (lost console output). Consider preserving the remainder of the original pendingCopy (after the first-stream segment) and only trimming that first segment, or re-queueing the discarded partitions so ordering/data isn’t lost.

Copilot uses AI. Check for mistakes.
Comment on lines 818 to 832
int index = 0;
for (int i = copy.size() - 1; i >= 0; --i) {
PendingPartition p = copy.get(i);
sizeHint += p.text.length();
index = i;
if (sizeHint > hwm) {
break;
}
}
for (int i = index; i < copy.size(); ++i) {
PendingPartition p = copy.get(i);
trimmedCopy.add(p);
}
pendingCopy = trimmedCopy;
}
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trimming logic still allows an oversized batch to be passed to SWT: the backward scan breaks when sizeHint > hwm and then keeps partitions starting at index, so the retained content length remains > hwm. Also, if a single PendingPartition.text is itself very large (e.g., a 1M-char line), this code won’t trim within that partition, so a huge string can still be applied to the document and trigger the UI freeze this PR targets. Consider enforcing a hard upper bound (<= hwm or another safe chunk size) and truncating/splitting a too-large partition so the inserted text cannot exceed that bound.

Suggested change
int index = 0;
for (int i = copy.size() - 1; i >= 0; --i) {
PendingPartition p = copy.get(i);
sizeHint += p.text.length();
index = i;
if (sizeHint > hwm) {
break;
}
}
for (int i = index; i < copy.size(); ++i) {
PendingPartition p = copy.get(i);
trimmedCopy.add(p);
}
pendingCopy = trimmedCopy;
}
int index = copy.size();
// walk backwards and only include partitions while the total stays within hwm
for (int i = copy.size() - 1; i >= 0; --i) {
PendingPartition p = copy.get(i);
int len = p.text.length();
if (sizeHint + len > hwm) {
break;
}
sizeHint += len;
index = i;
}
if (index < copy.size()) {
for (int i = index; i < copy.size(); ++i) {
PendingPartition p = copy.get(i);
trimmedCopy.add(p);
}
}
// if index == copy.size() no partition could be included without exceeding hwm;
// in that case we drop this oversized batch for the stream
pendingCopy = trimmedCopy;
}
// ensure sizeHint matches the actual content we are about to apply
sizeHint = 0;
for (PendingPartition p : pendingCopy) {
sizeHint += p.text.length();
}

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Contributor

github-actions bot commented Feb 24, 2026

Test Results

 1 950 files  ±0   1 950 suites  ±0   1h 36m 49s ⏱️ + 6m 46s
 4 743 tests ±0   4 718 ✅ ±0   24 💤 ±0  0 ❌  - 1  1 🔥 +1 
14 076 runs  ±0  13 893 ✅ ±0  182 💤 ±0  0 ❌  - 1  1 🔥 +1 

For more details on these errors, see this check.

Results for commit 9b230a8. ± Comparison against base commit 8594fad.

♻️ This comment has been updated with latest results.

@trancexpress
Copy link
Contributor Author

Fails on Linux:

 org.eclipse.debug.tests.console.IOConsoleTests.testTrim -- Time elapsed: 0.180 s <<< FAILURE!
org.opentest4j.AssertionFailedError: 
Expected string not found in console document. ==> expected: <0123456789> but was: <
012345678>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
	at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1156)
	at org.eclipse.debug.tests.console.IOConsoleTestUtil.verifyContentByOffset(IOConsoleTestUtil.java:572)
	at org.eclipse.debug.tests.console.IOConsoleTests.testTrim(IOConsoleTests.java:718)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
 org.eclipse.debug.tests.console.IOConsoleFixedWidthTests.testTrim -- Time elapsed: 0.233 s <<< FAILURE!
org.opentest4j.AssertionFailedError: 
Expected string not found in console document. ==> expected: <0123456789> but was: <
012345678>
	at org.eclipse.debug.tests.console.IOConsoleTestUtil.verifyContentByOffset(IOConsoleTestUtil.java:572)
	at org.eclipse.debug.tests.console.IOConsoleTests.testTrim(IOConsoleTests.java:718)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
 org.eclipse.debug.tests.console.ProcessConsoleManagerTests.testProcessConsoleLifecycle(TestInfo) -- Time elapsed: 0.084 s <<< FAILURE!
java.lang.AssertionError: 
[console has been added] 
Expected size: 1 but was: 3 in:
[org.eclipse.ui.console.IOConsole@2548368f,
    org.eclipse.ui.console.IOConsole@2a858f05,
    org.eclipse.debug.internal.ui.views.console.ProcessConsole@3946284c]
	at org.eclipse.debug.tests.console.ProcessConsoleManagerTests.testProcessConsoleLifecycle(ProcessConsoleManagerTests.java:88)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)

@trancexpress
Copy link
Contributor Author

Lets apply this one in a separate issue, its causing fails:

@@ -1203,6 +1240,8 @@ public class IOConsolePartitioner
                                        if (truncateToOffsetLineStart) {
                                                int cutoffLine = document.getLineOfOffset(truncateOffset);
                                                cutOffset = document.getLineOffset(cutoffLine);
+                                               // deal with case of one long line
+                                               cutOffset = Math.max(cutOffset, truncateOffset);
                                        }
                                        if (cutOffset >= length) {
                                                updateType = DocUpdateType.TRIM;

When processing large amounts of console output of a process,
its possible that the Eclipse UI will freeze.
E.g. on Linux, very long lines (> 1 million symbols) result in such freezes.

Using the console limit preference doesn't help preventing this freeze,
despite limitting the contents seen in the console.

This change adjusts IOConsolePartitioner.QueueProcessingJob.processPendingPartitions()
to trim pending console output before setting this output in the console document,
if a console limit is set in the Eclipse preferences.

See: eclipse-platform#2283
@trancexpress trancexpress marked this pull request as ready for review February 24, 2026 15:22
@trancexpress
Copy link
Contributor Author

Fail on Linux is:

 org.eclipse.core.tests.resources.NatureTest.testBug297871 -- Time elapsed: 0.006 s <<< ERROR!
java.nio.file.FileAlreadyExistsException: /home/runner/work/eclipse.platform/eclipse.platform/resources/tests/org.eclipse.core.tests.resources/target/work/data/40050a949511001114069a35697b81a0/.project
	at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:94)
	at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106)
	at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
	at java.base/sun.nio.fs.UnixFileSystem.copyFile(UnixFileSystem.java:668)
	at java.base/sun.nio.fs.UnixFileSystem.copy(UnixFileSystem.java:1075)
	at java.base/sun.nio.fs.UnixFileSystemProvider.copy(UnixFileSystemProvider.java:300)
	at java.base/java.nio.file.Files.copy(Files.java:1305)
	at org.eclipse.core.tests.resources.NatureTest.testBug297871(NatureTest.java:303)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants