leventov commented on a change in pull request #6402: Thread-safe QueryMetrics
URL: https://github.com/apache/incubator-druid/pull/6402#discussion_r223758381
 
 

 ##########
 File path: 
processing/src/main/java/org/apache/druid/query/DefaultQueryMetrics.java
 ##########
 @@ -23,51 +23,64 @@
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.ImmutableMap;
 import org.apache.druid.collections.bitmap.BitmapFactory;
+import org.apache.druid.java.util.common.ISE;
 import org.apache.druid.java.util.common.StringUtils;
 import org.apache.druid.java.util.emitter.service.ServiceEmitter;
 import org.apache.druid.java.util.emitter.service.ServiceMetricEvent;
 import org.apache.druid.query.filter.Filter;
 import org.joda.time.Interval;
 
+import javax.annotation.concurrent.GuardedBy;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
-/**
- * DefaultQueryMetrics is unsafe for use from multiple threads. It fails with 
RuntimeException on access not from the
- * thread where it was constructed. To "transfer" DefaultQueryMetrics from one 
thread to another {@link #ownerThread}
- * field should be updated.
- */
 public class DefaultQueryMetrics<QueryType extends Query<?>> implements 
QueryMetrics<QueryType>
 {
   protected final ObjectMapper jsonMapper;
-  protected final ServiceMetricEvent.Builder builder = new 
ServiceMetricEvent.Builder();
-  protected final Map<String, Number> metrics = new HashMap<>();
+  protected final Object lock = new Object();
+  @GuardedBy("lock") private final Map<String, String> singleValueDims = new 
HashMap<>();
+  @GuardedBy("lock") private final Map<String, String[]> multiValueDims = new 
HashMap<>();
+  @GuardedBy("lock") private final Map<String, Number> metrics = new 
HashMap<>();
+  @GuardedBy("lock") private Thread ownerThread;
 
-  /** Non final to give subclasses ability to reassign it. */
-  protected Thread ownerThread = Thread.currentThread();
 
   public DefaultQueryMetrics(ObjectMapper jsonMapper)
   {
     this.jsonMapper = jsonMapper;
   }
 
-  protected void checkModifiedFromOwnerThread()
+  protected void setDimension(String dimension, String value)
   {
-    if (Thread.currentThread() != ownerThread) {
-      throw new IllegalStateException(
-          "DefaultQueryMetrics must not be modified from multiple threads. If 
it is needed to gather dimension or "
-          + "metric information from multiple threads or from an async thread, 
this information should explicitly be "
-          + "passed between threads (e. g. using Futures), or this 
DefaultQueryMetrics's ownerThread should be "
-          + "reassigned explicitly");
+    synchronized (lock) {
+      String oldValue = singleValueDims.put(dimension, value);
+      if (oldValue != null && !oldValue.equals(value)) {
+        throw new ISE("Changing dimension values in QueryMetrics is not 
allowed: %s", dimension);
+      }
     }
   }
 
-  protected void setDimension(String dimension, String value)
+  protected void setDimensions(String dimension, String[] values)
   {
-    checkModifiedFromOwnerThread();
-    builder.setDimension(dimension, value);
+    synchronized (lock) {
+      String[] oldValues = multiValueDims.put(dimension, values);
+      if (oldValues != null && !Arrays.equals(oldValues, values)) {
+        throw new ISE("Changing dimension values in QueryMetrics is not 
allowed: %s", dimension);
+      }
+    }
+  }
+
+  protected QueryMetrics<QueryType> reportMetric(String metricName, Number 
value)
+  {
+    synchronized (lock) {
+      if (metrics.put(metricName, value) != null) {
 
 Review comment:
   putIfAbsent()

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to