-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Fix concurrency issues with StubServiceEmitter #18249
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,21 +24,24 @@ | |
| import org.apache.druid.java.util.emitter.service.ServiceEmitter; | ||
| import org.apache.druid.java.util.emitter.service.ServiceMetricEvent; | ||
|
|
||
| import java.util.ArrayDeque; | ||
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Queue; | ||
| import java.util.concurrent.ConcurrentHashMap; | ||
| import java.util.concurrent.ConcurrentLinkedDeque; | ||
|
|
||
| /** | ||
| * Test implementation of {@link ServiceEmitter} that collects emitted metrics | ||
| * and alerts in lists. | ||
| */ | ||
| public class StubServiceEmitter extends ServiceEmitter implements MetricsVerifier | ||
| { | ||
| private final List<Event> events = new ArrayList<>(); | ||
| private final List<AlertEvent> alertEvents = new ArrayList<>(); | ||
| private final ConcurrentHashMap<String, List<ServiceMetricEventSnapshot>> metricEvents = new ConcurrentHashMap<>(); | ||
| private final Queue<Event> events = new ConcurrentLinkedDeque<>(); | ||
| private final Queue<AlertEvent> alertEvents = new ConcurrentLinkedDeque<>(); | ||
| private final ConcurrentHashMap<String, Queue<ServiceMetricEventSnapshot>> metricEvents = new ConcurrentHashMap<>(); | ||
|
|
||
| public StubServiceEmitter() | ||
| { | ||
|
|
@@ -55,7 +58,7 @@ public void emit(Event event) | |
| { | ||
| if (event instanceof ServiceMetricEvent) { | ||
| ServiceMetricEvent metricEvent = (ServiceMetricEvent) event; | ||
| metricEvents.computeIfAbsent(metricEvent.getMetric(), name -> new ArrayList<>()) | ||
| metricEvents.computeIfAbsent(metricEvent.getMetric(), name -> new ConcurrentLinkedDeque<>()) | ||
| .add(new ServiceMetricEventSnapshot(metricEvent)); | ||
| } else if (event instanceof AlertEvent) { | ||
| alertEvents.add((AlertEvent) event); | ||
|
|
@@ -68,15 +71,15 @@ public void emit(Event event) | |
| */ | ||
| public List<Event> getEvents() | ||
| { | ||
| return events; | ||
| return new ArrayList<>(events); | ||
| } | ||
|
|
||
| /** | ||
| * Gets all the metric events emitted since the previous {@link #flush()}. | ||
| * | ||
| * @return Map from metric name to list of events emitted for that metric. | ||
| */ | ||
| public Map<String, List<ServiceMetricEventSnapshot>> getMetricEvents() | ||
| public Map<String, Queue<ServiceMetricEventSnapshot>> getMetricEvents() | ||
| { | ||
| return metricEvents; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: I guess we can later update this method to also return a map containing read-only lists rather than the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes; some enhancements could be made there - actually in the latchingemitter even after this patch an assimptotically I already had to undo a jfr fix in this patch as it was causing some other issues - and I'm afraid this won't fully solve the problem ; sometimes I could still reproduce the issue...with a lower probability....but its still there. seems like recently it happens on apache/master more frequently - I have to collect more details
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
What is the n^2 computation, is it the evaluation of events against a given WaitCondition?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Must be a bug then, because every
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it's a good pattern to expose internals. I don't think it should need this readuntil pattern
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, it is just for tests and not really exposed outside the class, only for use by the sub-class. The read until is actually very useful to process only the stuff that we need to process. Otherwise, we would need to pipe every new event through each existing condition either sync or async. But all of that just seems overkill for a simple testing use case. Please let me know if you have some other suggestions to improve this flow.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. reading pre-existing events registrations seems dodgy to me; I feel like that's an artifact of the fact that the usage pattern is like: which could have trouble if it should be more like or possibly with some try-with-resources sugar so that the contract of
not sure if this would apply to all existing use cases - but I hope so...
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I would have liked it to be something like that. But it would make the embedded tests (where the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The original flow actually feels more intuitive to me. (now that the |
||
| } | ||
|
|
@@ -86,7 +89,7 @@ public Map<String, List<ServiceMetricEventSnapshot>> getMetricEvents() | |
| */ | ||
| public List<AlertEvent> getAlerts() | ||
| { | ||
| return alertEvents; | ||
| return new ArrayList<>(alertEvents); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -96,8 +99,8 @@ public List<Number> getMetricValues( | |
| ) | ||
| { | ||
| final List<Number> values = new ArrayList<>(); | ||
| final List<ServiceMetricEventSnapshot> events = | ||
| metricEvents.getOrDefault(metricName, Collections.emptyList()); | ||
| final Queue<ServiceMetricEventSnapshot> events = | ||
| metricEvents.getOrDefault(metricName, new ArrayDeque<>()); | ||
| final Map<String, Object> filters = | ||
| dimensionFilters == null ? Collections.emptyMap() : dimensionFilters; | ||
| for (ServiceMetricEventSnapshot event : events) { | ||
|
|
||
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.
is this related to anything or just opportunistic?
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.
not closely related; just in an earlier version I've tried out a junit 5.12.x feature....then undone it - but retained the bom upgrade as it might still be usefull later (didn't made things worse)