Skip to content

Commit 04c2e16

Browse files
committed
improve
1 parent 05bfb83 commit 04c2e16

5 files changed

Lines changed: 65 additions & 8 deletions

File tree

sentry/api/sentry.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6087,6 +6087,7 @@ public final class io/sentry/util/CollectionUtils {
60876087
public static fun newArrayList (Ljava/util/List;)Ljava/util/List;
60886088
public static fun newConcurrentHashMap (Ljava/util/Map;)Ljava/util/Map;
60896089
public static fun newHashMap (Ljava/util/Map;)Ljava/util/Map;
6090+
public static fun reverseListIterator (Ljava/util/concurrent/CopyOnWriteArrayList;)Ljava/util/ListIterator;
60906091
public static fun size (Ljava/lang/Iterable;)I
60916092
}
60926093

sentry/src/main/java/io/sentry/SentryTracer.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.sentry;
22

3+
import static io.sentry.util.CollectionUtils.reverseListIterator;
4+
35
import io.sentry.protocol.Contexts;
46
import io.sentry.protocol.SentryId;
57
import io.sentry.protocol.SentryTransaction;
@@ -154,10 +156,9 @@ private void onDeadlineTimeoutReached() {
154156
// abort all child-spans first, this ensures the transaction can be finished,
155157
// even if waitForChildren is true
156158
// iterate in reverse order to ensure leaf spans are processed before their parents
157-
@NotNull final ListIterator<Span> iterator = this.children.listIterator();
158-
while (iterator.hasNext()) {
159-
iterator.next();
160-
}
159+
@NotNull
160+
final ListIterator<Span> iterator =
161+
reverseListIterator((CopyOnWriteArrayList<Span>) this.children);
161162
while (iterator.hasPrevious()) {
162163
@NotNull final Span span = iterator.previous();
163164
span.setSpanFinishedCallback(null);
@@ -910,10 +911,9 @@ public void setName(@NotNull String name, @NotNull TransactionNameSource transac
910911

911912
@Override
912913
public @Nullable ISpan getLatestActiveSpan() {
913-
@NotNull final ListIterator<Span> iterator = this.children.listIterator();
914-
while (iterator.hasNext()) {
915-
iterator.next();
916-
}
914+
@NotNull
915+
final ListIterator<Span> iterator =
916+
reverseListIterator((CopyOnWriteArrayList<Span>) this.children);
917917
while (iterator.hasPrevious()) {
918918
@NotNull final Span span = iterator.previous();
919919
if (!span.isFinished()) {

sentry/src/main/java/io/sentry/util/CollectionUtils.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
import java.util.Collection;
55
import java.util.HashMap;
66
import java.util.List;
7+
import java.util.ListIterator;
78
import java.util.Map;
89
import java.util.concurrent.ConcurrentHashMap;
10+
import java.util.concurrent.CopyOnWriteArrayList;
911
import org.jetbrains.annotations.ApiStatus;
1012
import org.jetbrains.annotations.NotNull;
1113
import org.jetbrains.annotations.Nullable;
@@ -179,4 +181,23 @@ public interface Predicate<T> {
179181
public interface Mapper<T, R> {
180182
R map(T t);
181183
}
184+
185+
/**
186+
* Returns a reverse iterator, where the first (resp. last) valid call to `prev` returns the last
187+
* (resp. first) element that would be returned when iterating forwards. Note that this differs
188+
* from the behavior of e.g. `org.apache.commons.collections4.iterators.ReverseListIterator`,
189+
* where you need to iterate using `next` instead. We use the concrete type `CopyOnWriteArrayList`
190+
* here as we are relying on the fact that its copy constructor only copies the reference to an
191+
* internal array. We don't want to use this for other `List` implementations, as it could lead to
192+
* an unnecessary copy of the elements instead.
193+
*
194+
* @param list the `CopyOnWriteArrayList` to get the reverse iterator for
195+
* @param <T> the type
196+
* @return a reverse iterator over `list`
197+
*/
198+
public static @NotNull <T> ListIterator<T> reverseListIterator(
199+
final @NotNull CopyOnWriteArrayList<T> list) {
200+
final @NotNull CopyOnWriteArrayList<T> copy = new CopyOnWriteArrayList<>(list);
201+
return copy.listIterator(copy.size());
202+
}
182203
}

sentry/src/test/java/io/sentry/ScopeTest.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,18 @@ class ScopeTest {
906906
assertTrue(cloned.attachments is CopyOnWriteArrayList)
907907
}
908908

909+
@Test
910+
fun `getAttachments returns new instance`() {
911+
val scope = Scope(SentryOptions())
912+
scope.addAttachment(Attachment(""))
913+
914+
assertNotSame(
915+
scope.attachments,
916+
scope.attachments,
917+
"Scope.attachments must return a new instance on each call."
918+
)
919+
}
920+
909921
@Test
910922
fun `clearAttachments clears all attachments`() {
911923
val scope = Scope(SentryOptions())

sentry/src/test/java/io/sentry/util/CollectionUtilsTest.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package io.sentry.util
22

33
import io.sentry.JsonObjectReader
44
import java.io.StringReader
5+
import java.util.concurrent.CopyOnWriteArrayList
56
import kotlin.test.Test
67
import kotlin.test.assertEquals
78
import kotlin.test.assertFalse
@@ -79,4 +80,26 @@ class CollectionUtilsTest {
7980
fun `contains returns false if element is not present`() {
8081
assertFalse(CollectionUtils.contains(arrayOf("one", "two", "three"), "four"))
8182
}
83+
84+
@Test
85+
fun `reverseListIterator returns empty iterator if list is empty`() {
86+
val list = CopyOnWriteArrayList<String>()
87+
val iterator = CollectionUtils.reverseListIterator(list)
88+
assertFalse(iterator.hasNext())
89+
assertFalse(iterator.hasPrevious())
90+
}
91+
92+
@Test
93+
fun `reverseListIterator returns reversed iterator if list is not empty`() {
94+
val elements = listOf("one", "two", "three")
95+
val list = CopyOnWriteArrayList(elements)
96+
val iterator = CollectionUtils.reverseListIterator(list)
97+
assertFalse(iterator.hasNext())
98+
assertTrue(iterator.hasPrevious())
99+
val reversedElements = mutableListOf<String>()
100+
while (iterator.hasPrevious()) {
101+
reversedElements.add(iterator.previous())
102+
}
103+
assertEquals(elements.reversed(), reversedElements)
104+
}
82105
}

0 commit comments

Comments
 (0)