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 ;
1415import java .util .ArrayList ;
1516import java .util .Arrays ;
1617import java .util .Collections ;
17- import java .util .HashMap ;
1818import java .util .List ;
1919import java .util .Locale ;
2020import java .util .Map ;
@@ -45,7 +45,9 @@ protected DecimalFormat initialValue() {
4545 private static final DecimalFormatterThreadLocal decimalFormatter =
4646 new DecimalFormatterThreadLocal ();
4747
48- private final @ NotNull Map <String , String > keyValues ;
48+ private final @ NotNull ConcurrentHashMap <String , String > keyValues ;
49+ private final @ NotNull AutoClosableReentrantLock keyValuesLock = new AutoClosableReentrantLock ();
50+
4951 private @ Nullable Double sampleRate ;
5052 private @ Nullable Double sampleRand ;
5153
@@ -100,7 +102,9 @@ public static Baggage fromHeader(
100102 final @ Nullable String headerValue ,
101103 final boolean includeThirdPartyValues ,
102104 final @ NotNull ILogger logger ) {
103- final @ NotNull Map <String , String > keyValues = new HashMap <>();
105+
106+ final @ NotNull ConcurrentHashMap <String , String > keyValues = new ConcurrentHashMap <>();
107+
104108 final @ NotNull List <String > thirdPartyKeyValueStrings = new ArrayList <>();
105109 boolean shouldFreeze = false ;
106110
@@ -197,7 +201,7 @@ public static Baggage fromEvent(
197201
198202 @ ApiStatus .Internal
199203 public Baggage (final @ NotNull ILogger logger ) {
200- this (new HashMap <>(), null , null , null , true , false , logger );
204+ this (new ConcurrentHashMap <>(), null , null , null , true , false , logger );
201205 }
202206
203207 @ ApiStatus .Internal
@@ -214,16 +218,14 @@ public Baggage(final @NotNull Baggage baggage) {
214218
215219 @ ApiStatus .Internal
216220 public Baggage (
217- final @ NotNull Map <String , String > keyValues ,
221+ final @ NotNull ConcurrentHashMap <String , String > keyValues ,
218222 final @ Nullable Double sampleRate ,
219223 final @ Nullable Double sampleRand ,
220224 final @ Nullable String thirdPartyHeader ,
221225 final boolean isMutable ,
222226 final boolean shouldFreeze ,
223227 final @ NotNull ILogger logger ) {
224- // TODO should we deep-copy the keyValues here?
225- // if so we could optimize this by only synchronizing in case isMutable is true
226- this .keyValues = Collections .synchronizedMap (keyValues );
228+ this .keyValues = keyValues ;
227229 this .sampleRate = sampleRate ;
228230 this .sampleRand = sampleRand ;
229231 this .logger = logger ;
@@ -264,8 +266,8 @@ public String getThirdPartyHeader() {
264266 }
265267
266268 final Set <String > keys ;
267- synchronized ( keyValues ) {
268- keys = new TreeSet <>(keyValues .keySet ( ));
269+ try ( final @ NotNull ISentryLifecycleToken ignored = keyValuesLock . acquire () ) {
270+ keys = new TreeSet <>(Collections . list ( keyValues .keys () ));
269271 }
270272 keys .add (DSCKeys .SAMPLE_RATE );
271273 keys .add (DSCKeys .SAMPLE_RAND );
@@ -462,7 +464,7 @@ public void set(final @NotNull String key, final @Nullable String value) {
462464 @ ApiStatus .Internal
463465 public @ NotNull Map <String , Object > getUnknown () {
464466 final @ NotNull Map <String , Object > unknown = new ConcurrentHashMap <>();
465- synchronized ( keyValues ) {
467+ try ( final @ NotNull ISentryLifecycleToken ignored = keyValuesLock . acquire () ) {
466468 for (final Map .Entry <String , String > keyValue : keyValues .entrySet ()) {
467469 final @ NotNull String key = keyValue .getKey ();
468470 final @ Nullable String value = keyValue .getValue ();
0 commit comments