From 87787e4ec1263079ae55f3f949ddc6ae6d93d1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sautter?= Date: Tue, 29 Aug 2023 18:05:19 +0200 Subject: [PATCH] [java] batch copy input to the circular buffer --- .../selenium/io/CircularOutputStream.java | 58 ++++++++++++++----- .../selenium/io/CircularOutputStreamTest.java | 12 ++++ 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/java/src/org/openqa/selenium/io/CircularOutputStream.java b/java/src/org/openqa/selenium/io/CircularOutputStream.java index 6c7fbf45ed08f..6bf9284baa725 100644 --- a/java/src/org/openqa/selenium/io/CircularOutputStream.java +++ b/java/src/org/openqa/selenium/io/CircularOutputStream.java @@ -23,10 +23,9 @@ /** Captures the last N bytes of output. */ public class CircularOutputStream extends OutputStream { private static final int DEFAULT_SIZE = 4096; - private int start; private int end; private boolean filled = false; - private byte[] buffer; + private final byte[] buffer; public CircularOutputStream(int maxSize) { buffer = new byte[maxSize]; @@ -36,6 +35,35 @@ public CircularOutputStream() { this(DEFAULT_SIZE); } + @Override + public void write(byte[] b) { + // overridden to get rid of the IOException + write(b, 0, b.length); + } + + @Override + public synchronized void write(byte[] b, int off, int len) { + int bufferSize = buffer.length; + + while (len > 0) { + int chunk = Math.min(bufferSize, len); + + if (bufferSize >= end + chunk) { + System.arraycopy(b, off, buffer, end, chunk); + end += chunk; + } else { + int space = bufferSize - end; + System.arraycopy(b, off, buffer, end, space); + filled = true; + end = chunk - space; + System.arraycopy(b, off + space, buffer, 0, end); + } + + off += chunk; + len -= chunk; + } + } + @Override public synchronized void write(int b) { if (end == buffer.length) { @@ -43,15 +71,21 @@ public synchronized void write(int b) { end = 0; } - if (filled && end == start) { - start = start == buffer.length - 1 ? 0 : start + 1; - } - buffer[end++] = (byte) b; } @Override - public String toString() { + public void flush() { + // overridden to get rid of the IOException + } + + @Override + public void close() { + // overridden to get rid of the IOException + } + + @Override + public synchronized String toString() { int size = filled ? buffer.length : end; byte[] toReturn = new byte[size]; @@ -61,13 +95,9 @@ public String toString() { return new String(toReturn, Charset.defaultCharset()); } - int copyStart = buffer.length - start; - if (copyStart == buffer.length) { - copyStart = 0; - } - - System.arraycopy(buffer, start, toReturn, 0, copyStart); - System.arraycopy(buffer, 0, toReturn, copyStart, end); + int n = buffer.length - end; + System.arraycopy(buffer, end, toReturn, 0, n); + System.arraycopy(buffer, 0, toReturn, n, end); return new String(toReturn, Charset.defaultCharset()); } } diff --git a/java/test/org/openqa/selenium/io/CircularOutputStreamTest.java b/java/test/org/openqa/selenium/io/CircularOutputStreamTest.java index 76852e8b19dd9..56d68f5d9a020 100644 --- a/java/test/org/openqa/selenium/io/CircularOutputStreamTest.java +++ b/java/test/org/openqa/selenium/io/CircularOutputStreamTest.java @@ -124,6 +124,18 @@ void testCircularness() { } } + @Test + void testWriteExceedsBuffer() { + CircularOutputStream os = new CircularOutputStream(5); + try (PrintWriter pw = new PrintWriter(os, true)) { + + pw.write("00"); + pw.write("000000000000012345"); + pw.flush(); + assertThat(os.toString()).isEqualTo("12345"); + } + } + @Test void testConcurrentWrites() throws InterruptedException { final int bytesToWrite = 10000;