diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/LongList.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/LongList.java index f21eb03ac3..652448039b 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/LongList.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/LongList.java @@ -27,6 +27,7 @@ import java.util.Arrays; public class LongList { + private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; private static final int DEFAULT_CAPACITY = 16; private long[] longs; private int size; @@ -58,9 +59,20 @@ public void addAll(LongList other) { size += other.size; } - private void ensureCapacity(int size) { - if (longs.length < size) { - longs = Arrays.copyOf(longs, longs.length * 2); + private void ensureCapacity(long minCapacity) { + if (longs.length < minCapacity) { + longs = Arrays.copyOf(longs, newCapacity(minCapacity, longs.length)); + } + } + + static int newCapacity(long minCapacity, long oldCapacity) { + long growBy50Percent = oldCapacity + (oldCapacity >> 1); + if (minCapacity <= growBy50Percent) { + return (int) growBy50Percent; + } else if (minCapacity <= MAX_ARRAY_SIZE) { + return (int) minCapacity; + } else { + throw new OutOfMemoryError(); } } diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/collections/LongListTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/collections/LongListTest.java index 648bb56ecb..4d3c957878 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/collections/LongListTest.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/collections/LongListTest.java @@ -69,6 +69,28 @@ void testAddAll() { assertThat(this.longList.get(2)).isEqualTo(44); } + @Test + void testAddAllLargeList() { + longList.add(42); + LongList list2 = new LongList(); + for (int i = 0; i < 42; i++) { + list2.add(i); + } + longList.addAll(list2); + assertThat(this.longList.getSize()).isEqualTo(43); + assertThat(this.longList.get(0)).isEqualTo(42); + assertThat(this.longList.get(1)).isEqualTo(0); + assertThat(this.longList.get(2)).isEqualTo(1); + } + + @Test + void testNewCapacity() { + assertThat(LongList.newCapacity(1, 0)).isEqualTo(1); + assertThat(LongList.newCapacity(42, 4)).isEqualTo(42); + assertThat(LongList.newCapacity(5, 4)).isEqualTo(6); + assertThatThrownBy(() -> LongList.newCapacity(Integer.MAX_VALUE, 4)).isInstanceOf(OutOfMemoryError.class); + } + @Test void testOutOfBounds() { assertThatThrownBy(() -> longList.get(0)).isInstanceOf(IndexOutOfBoundsException.class);