-
-
Notifications
You must be signed in to change notification settings - Fork 465
Synchronize Baggage keyValues #4327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
|
||
| @ApiStatus.Internal | ||
| public void set(final @NotNull String key, final @Nullable String value) { | ||
| set(key, value, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was always called with force=false, so I just merged set(key, value, force) and set(key, value).
Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 351306b | 426.36 ms | 460.65 ms | 34.29 ms |
| c529988 | 428.26 ms | 442.80 ms | 14.54 ms |
| 9ae6786 | 424.54 ms | 443.76 ms | 19.22 ms |
| 75efa54 | 401.13 ms | 456.45 ms | 55.32 ms |
| 2aa945a | 429.48 ms | 516.48 ms | 87.00 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 351306b | 1.58 MiB | 2.08 MiB | 505.74 KiB |
| c529988 | 1.58 MiB | 2.08 MiB | 505.64 KiB |
| 9ae6786 | 1.58 MiB | 2.08 MiB | 505.69 KiB |
| 75efa54 | 1.58 MiB | 2.08 MiB | 505.68 KiB |
| 2aa945a | 1.58 MiB | 2.08 MiB | 505.63 KiB |
| if (value != null) { | ||
| final @NotNull String unknownKey = key.replaceFirst(SENTRY_BAGGAGE_PREFIX, ""); | ||
| unknown.put(unknownKey, value); | ||
| synchronized (keyValues) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use AutoClosableReentrantLock over synchronized as there was problems with virtual threads and synchronized before.
|
|
||
| final Set<String> keys = new TreeSet<>(keyValues.keySet()); | ||
| final Set<String> keys; | ||
| synchronized (keyValues) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See below, replace with AutoClosableReentrantLock.
| final boolean shouldFreeze, | ||
| final @NotNull ILogger logger) { | ||
| this.keyValues = keyValues; | ||
| // TODO should we deep-copy the keyValues here? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, we sometimes want to write to a shared baggage.
| final @NotNull ILogger logger) { | ||
| this.keyValues = keyValues; | ||
| // TODO should we deep-copy the keyValues here? | ||
| // if so we could optimize this by only synchronizing in case isMutable is true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are cases where we forcefully overwrite the sample rate, even if mutable = false.
| this.keyValues = keyValues; | ||
| // TODO should we deep-copy the keyValues here? | ||
| // if so we could optimize this by only synchronizing in case isMutable is true | ||
| this.keyValues = Collections.synchronizedMap(keyValues); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of wrapping here, which will cause problems with virtual threads again due to using synchronized internally, could we revert this line and instead always use ConcurrentHashMap in place of Map in this class?
| final @NotNull Map<String, String> keyValues; | ||
| @Nullable Double sampleRate; | ||
| @Nullable Double sampleRand; | ||
| private final @NotNull Map<String, String> keyValues; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| private final @NotNull Map<String, String> keyValues; | |
| private final @NotNull ConcurrentHashMap<String, String> keyValues; |
we should also change this in all locations of this file, where we have Map as a param or create a new HashMap. e.g. ctors and fromHeader
| if (copiedUnknown != null) { | ||
| this.unknown = copiedUnknown; | ||
| } | ||
| // TODO should this be a deep copy instead? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, we need to share entries.
adinauer
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did not mean to block this PR
adinauer
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.
adinauer
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for fixing!
📜 Description
A
Baggagecan be mutable, but we don't synchronize it's internalkeyValues, thus if e.g.Baggage.setTraceId()andBaggage.toHeaderString()are called simultaneously, aConcurrentModificationmay be thrown.SpanContextseems to be holding and creating reference copies of Baggage objects, so multiple spans happening at the same time are suspect to trigger this faulty behavior.💡 Motivation and Context
Fixes #4321
💚 How did you test it?
📝 Checklist
sendDefaultPIIis enabled.🔮 Next steps