44
55import io .sentry .protocol .SentryId ;
66import io .sentry .protocol .TransactionNameSource ;
7+ import io .sentry .util .AutoClosableReentrantLock ;
78import io .sentry .util .SampleRateUtils ;
89import io .sentry .util .StringUtils ;
910import java .io .UnsupportedEncodingException ;
1314import java .text .DecimalFormatSymbols ;
1415import java .util .ArrayList ;
1516import java .util .Arrays ;
16- import java .util .HashMap ;
17+ import java .util .Collections ;
1718import java .util .List ;
1819import java .util .Locale ;
1920import java .util .Map ;
@@ -44,13 +45,15 @@ protected DecimalFormat initialValue() {
4445 private static final DecimalFormatterThreadLocal decimalFormatter =
4546 new DecimalFormatterThreadLocal ();
4647
47- final @ NotNull Map <String , String > keyValues ;
48- @ Nullable Double sampleRate ;
49- @ Nullable Double sampleRand ;
48+ private final @ NotNull ConcurrentHashMap <String , String > keyValues ;
49+ private final @ NotNull AutoClosableReentrantLock keyValuesLock = new AutoClosableReentrantLock ();
5050
51- final @ Nullable String thirdPartyHeader ;
51+ private @ Nullable Double sampleRate ;
52+ private @ Nullable Double sampleRand ;
53+
54+ private final @ Nullable String thirdPartyHeader ;
5255 private boolean mutable ;
53- private boolean shouldFreeze ;
56+ private final boolean shouldFreeze ;
5457 final @ NotNull ILogger logger ;
5558
5659 @ NotNull
@@ -99,7 +102,9 @@ public static Baggage fromHeader(
99102 final @ Nullable String headerValue ,
100103 final boolean includeThirdPartyValues ,
101104 final @ NotNull ILogger logger ) {
102- final @ NotNull Map <String , String > keyValues = new HashMap <>();
105+
106+ final @ NotNull ConcurrentHashMap <String , String > keyValues = new ConcurrentHashMap <>();
107+
103108 final @ NotNull List <String > thirdPartyKeyValueStrings = new ArrayList <>();
104109 boolean shouldFreeze = false ;
105110
@@ -196,7 +201,7 @@ public static Baggage fromEvent(
196201
197202 @ ApiStatus .Internal
198203 public Baggage (final @ NotNull ILogger logger ) {
199- this (new HashMap <>(), null , null , null , true , false , logger );
204+ this (new ConcurrentHashMap <>(), null , null , null , true , false , logger );
200205 }
201206
202207 @ ApiStatus .Internal
@@ -213,12 +218,12 @@ public Baggage(final @NotNull Baggage baggage) {
213218
214219 @ ApiStatus .Internal
215220 public Baggage (
216- final @ NotNull Map <String , String > keyValues ,
221+ final @ NotNull ConcurrentHashMap <String , String > keyValues ,
217222 final @ Nullable Double sampleRate ,
218223 final @ Nullable Double sampleRand ,
219224 final @ Nullable String thirdPartyHeader ,
220- boolean isMutable ,
221- boolean shouldFreeze ,
225+ final boolean isMutable ,
226+ final boolean shouldFreeze ,
222227 final @ NotNull ILogger logger ) {
223228 this .keyValues = keyValues ;
224229 this .sampleRate = sampleRate ;
@@ -260,7 +265,10 @@ public String getThirdPartyHeader() {
260265 separator = "," ;
261266 }
262267
263- final Set <String > keys = new TreeSet <>(keyValues .keySet ());
268+ final Set <String > keys ;
269+ try (final @ NotNull ISentryLifecycleToken ignored = keyValuesLock .acquire ()) {
270+ keys = new TreeSet <>(Collections .list (keyValues .keys ()));
271+ }
264272 keys .add (DSCKeys .SAMPLE_RATE );
265273 keys .add (DSCKeys .SAMPLE_RAND );
266274
@@ -440,38 +448,38 @@ public void setReplayId(final @Nullable String replayId) {
440448 set (DSCKeys .REPLAY_ID , replayId );
441449 }
442450
443- @ ApiStatus .Internal
444- public void set (final @ NotNull String key , final @ Nullable String value ) {
445- set (key , value , false );
446- }
447-
448451 /**
449- * Sets / updates a value
452+ * Sets / updates a value, but only if the baggage is still mutable.
450453 *
451454 * @param key key
452455 * @param value value to set
453- * @param force ignores mutability of this baggage and sets the value anyways
454456 */
455- private void set (final @ NotNull String key , final @ Nullable String value , final boolean force ) {
456- if (mutable || force ) {
457- this .keyValues .put (key , value );
457+ @ ApiStatus .Internal
458+ public void set (final @ NotNull String key , final @ Nullable String value ) {
459+ if (mutable ) {
460+ if (value == null ) {
461+ keyValues .remove (key );
462+ } else {
463+ keyValues .put (key , value );
464+ }
458465 }
459466 }
460467
461468 @ ApiStatus .Internal
462469 public @ NotNull Map <String , Object > getUnknown () {
463470 final @ NotNull Map <String , Object > unknown = new ConcurrentHashMap <>();
464- for (Map .Entry <String , String > keyValue : this .keyValues .entrySet ()) {
465- final @ NotNull String key = keyValue .getKey ();
466- final @ Nullable String value = keyValue .getValue ();
467- if (!DSCKeys .ALL .contains (key )) {
468- if (value != null ) {
469- final @ NotNull String unknownKey = key .replaceFirst (SENTRY_BAGGAGE_PREFIX , "" );
470- unknown .put (unknownKey , value );
471+ try (final @ NotNull ISentryLifecycleToken ignored = keyValuesLock .acquire ()) {
472+ for (final Map .Entry <String , String > keyValue : keyValues .entrySet ()) {
473+ final @ NotNull String key = keyValue .getKey ();
474+ final @ Nullable String value = keyValue .getValue ();
475+ if (!DSCKeys .ALL .contains (key )) {
476+ if (value != null ) {
477+ final @ NotNull String unknownKey = key .replaceFirst (SENTRY_BAGGAGE_PREFIX , "" );
478+ unknown .put (unknownKey , value );
479+ }
471480 }
472481 }
473482 }
474-
475483 return unknown ;
476484 }
477485
0 commit comments