Skip to content

Commit f0276a6

Browse files
authored
Merge pull request #5599 from getsentry/perf/sdk-overhead-reduction-contexts-key-array
perf(core): [SDK Overhead Reduction 8] Reduce context serialization allocations
2 parents b070303 + 507d84e commit f0276a6

6 files changed

Lines changed: 46 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@
44

55
### Internal
66

7-
<<<<<<< perf/sdk-overhead-reduction-breadcrumb-lazy-data
7+
- Reduce context serialization overhead by sorting key snapshots with arrays instead of temporary lists. ([#5599](https://github.com/getsentry/sentry-java/pull/5599))
88
- Reduce breadcrumb allocation overhead by creating the `Breadcrumb` data map only when data is added. ([#5598](https://github.com/getsentry/sentry-java/pull/5598))
9-
=======
109
- Reduce JSON serialization overhead by lowering the initial `JsonWriter` nesting stack size while preserving on-demand growth. ([#5591](https://github.com/getsentry/sentry-java/pull/5591))
1110
- Reduce timestamp helper overhead by replacing unnecessary `Calendar` usage in `DateUtils` with direct `Date` creation. ([#5589](https://github.com/getsentry/sentry-java/pull/5589))
1211
- Reduce Android startup overhead by using the default timezone directly on older devices or when no timezone info is available in the locale. ([#5587](https://github.com/getsentry/sentry-java/pull/5587))
13-
>>>>>>> perf/sdk-overhead-reduction
1412

1513
## 8.45.0
1614

sentry/api/sentry.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7619,6 +7619,7 @@ public final class io/sentry/util/CollectionUtils {
76197619
public static fun newHashMap (Ljava/util/Map;)Ljava/util/Map;
76207620
public static fun reverseListIterator (Ljava/util/concurrent/CopyOnWriteArrayList;)Ljava/util/ListIterator;
76217621
public static fun size (Ljava/lang/Iterable;)I
7622+
public static fun toSortedStringArray (Ljava/util/Enumeration;I)[Ljava/lang/String;
76227623
}
76237624

76247625
public abstract interface class io/sentry/util/CollectionUtils$Mapper {

sentry/src/main/java/io/sentry/MonitorContexts.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package io.sentry;
22

3+
import io.sentry.util.CollectionUtils;
34
import io.sentry.util.Objects;
45
import io.sentry.vendor.gson.stream.JsonToken;
56
import java.io.IOException;
6-
import java.util.Collections;
7-
import java.util.List;
87
import java.util.concurrent.ConcurrentHashMap;
98
import org.jetbrains.annotations.NotNull;
109
import org.jetbrains.annotations.Nullable;
@@ -49,8 +48,7 @@ public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger
4948
throws IOException {
5049
writer.beginObject();
5150
// Serialize in alphabetical order to keep determinism.
52-
final List<String> sortedKeys = Collections.list(keys());
53-
Collections.sort(sortedKeys);
51+
final String[] sortedKeys = CollectionUtils.toSortedStringArray(keys(), size());
5452
for (final String key : sortedKeys) {
5553
final Object value = get(key);
5654
if (value != null) {

sentry/src/main/java/io/sentry/protocol/Contexts.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,13 @@
1010
import io.sentry.ProfileContext;
1111
import io.sentry.SpanContext;
1212
import io.sentry.util.AutoClosableReentrantLock;
13+
import io.sentry.util.CollectionUtils;
1314
import io.sentry.util.HintUtils;
1415
import io.sentry.util.Objects;
1516
import io.sentry.vendor.gson.stream.JsonToken;
1617
import java.io.IOException;
17-
import java.util.Collections;
1818
import java.util.Enumeration;
1919
import java.util.HashMap;
20-
import java.util.List;
2120
import java.util.Map;
2221
import java.util.Set;
2322
import java.util.concurrent.ConcurrentHashMap;
@@ -302,8 +301,7 @@ public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger
302301
throws IOException {
303302
writer.beginObject();
304303
// Serialize in alphabetical order to keep determinism.
305-
final List<String> sortedKeys = Collections.list(keys());
306-
Collections.sort(sortedKeys);
304+
final String[] sortedKeys = CollectionUtils.toSortedStringArray(keys(), internalStorage.size());
307305
for (final String key : sortedKeys) {
308306
final Object value = get(key);
309307
if (value != null) {

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

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

33
import java.util.ArrayList;
4+
import java.util.Arrays;
45
import java.util.Collection;
6+
import java.util.Enumeration;
57
import java.util.HashMap;
68
import java.util.List;
79
import java.util.ListIterator;
@@ -15,9 +17,28 @@
1517
/** Util class for Collections */
1618
@ApiStatus.Internal
1719
public final class CollectionUtils {
20+
private static final String[] EMPTY_STRINGS = new String[0];
1821

1922
private CollectionUtils() {}
2023

24+
public static @NotNull String[] toSortedStringArray(
25+
final @NotNull Enumeration<String> source, final int size) {
26+
String[] sorted = size == 0 ? EMPTY_STRINGS : new String[size];
27+
int index = 0;
28+
while (source.hasMoreElements()) {
29+
if (index == sorted.length) {
30+
sorted = Arrays.copyOf(sorted, sorted.length + 1);
31+
}
32+
sorted[index] = source.nextElement();
33+
index++;
34+
}
35+
if (index != sorted.length) {
36+
sorted = Arrays.copyOf(sorted, index);
37+
}
38+
Arrays.sort(sorted);
39+
return sorted;
40+
}
41+
2142
/**
2243
* Returns an Iterator size
2344
*
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.sentry
2+
3+
import io.sentry.protocol.SerializationUtils
4+
import kotlin.test.Test
5+
import kotlin.test.assertEquals
6+
import org.mockito.kotlin.mock
7+
8+
class MonitorContextsTest {
9+
@Test
10+
fun `serializes entries in alphabetical order`() {
11+
val contexts =
12+
MonitorContexts().apply {
13+
put("b", 2)
14+
put("a", 1)
15+
}
16+
17+
assertEquals("{\"a\":1,\"b\":2}", SerializationUtils.serializeToString(contexts, mock()))
18+
}
19+
}

0 commit comments

Comments
 (0)