You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ignite.apache.org by GitBox <gi...@apache.org> on 2020/02/18 20:17:50 UTC

[GitHub] [ignite] Vladsz83 opened a new pull request #7446: IGNITE-12464 : Service metrics

Vladsz83 opened a new pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446
 
 
   We should provide the following metrics for each deployed service:
   
   - Histogram of executions duration

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400982180
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
 
 Review comment:
   I looked at `MetricRegistry#findMetric` and `MetricRegistry#histogram` implementations  and they are thread safe. You should not synchronize over `metricRegistry` to avoid possible contention.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400438477
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
 
 Review comment:
   `ConcurrentHashMap` should be used. Otherwise, it's possible to get the exception here:
   ```
   java.lang.ClassCastException: java.util.HashMap$Node cannot be cast to java.util.HashMap$TreeNode
   	at java.util.HashMap$TreeNode.moveRootToFront(HashMap.java:1835)
   	at java.util.HashMap$TreeNode.treeify(HashMap.java:1951)
   	at java.util.HashMap.treeifyBin(HashMap.java:772)
   	at java.util.HashMap.computeIfAbsent(HashMap.java:1140)
   ```

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401141419
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
 
 Review comment:
   @ivandasch Yep, just realized we can lose value on parallel puts. Doesn’t matter. I finally remembered the reason why staying with simple HashMap without sync blocks or any other concurrency protections. Service deploying/undeploying are guided by discovery messages which are serial. Actually, all we do here we do in single thread. WDYT?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400813600
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
 
 Review comment:
   `interface A {
           void foo();
       }
   
       interface B extends A {
           @Override void foo();
       }
   
       static class C implements Service, B {
           @Override public void foo() {
               System.err.println("foo");
           }
           ...
       }
   
   @Test
       public void test() throws Exception {
           Method methodA = A.class.getMethod("foo");
           Method methodB = B.class.getMethod("foo");
           Method methodC = C.class.getMethod("foo");
   
           assertEquals(methodA, methodB);
           assertEquals(methodA, methodC);
           assertEquals(methodB, methodA);
   
           assertEquals(methodB, methodC);
           assertEquals(methodC, methodA);
           assertEquals(methodC, methodB);
       }`
   
   They are not equals. And yes, significant invocation boost. If we keep direct link to not-overloaded method, we avoid:
   
   1) Creation new Method() (`getMethod()` always create new one)
   2) Creation new Object[] when calling `Method.getParameterTypes()` to identify method.
   3) We do not search overloaded methods map at all. We get method by it name.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400813600
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
 
 Review comment:
   @NSAmelchev , the problem is:
   
   ```
       interface A {
           void foo();
       }
   
       interface B extends A {
           @Override void foo();
       }
   
       static class C implements Service, B {
           @Override public void foo() {
               System.err.println("foo");
           }
       }
   
      @Test
       public void test() throws Exception {
           Method methodA = A.class.getMethod("foo");
           Method methodB = B.class.getMethod("foo");
           Method methodC = C.class.getMethod("foo");
   
           assertEquals(methodA, methodB);
           assertEquals(methodA, methodC);
   
           assertEquals(methodB, methodA);
           assertEquals(methodB, methodC);
   
           assertEquals(methodC, methodA);
           assertEquals(methodC, methodB);
       }
   ```
   
   Same for:
   ```
       interface A {
           void foo();
       }
   
       interface B /* not extends A */ {
           void foo();
       }
   
       class C implements Service, A, B {
           @Override public void foo() {
               System.err.println("foo");
           }
       }
   ```
   
   They are not equal.
   
   And yes, significant invocation boost. If we keep direct link to not-overloaded method, we avoid:
   
   1) Creation new Method() (`getMethod()` always create new one)
   2) Creation new Object[] when calling `Method.getParameterTypes()` to identify method.
   3) We do not search overloaded methods map at all. We get method by it name.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 removed a comment on issue #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 removed a comment on issue #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#issuecomment-606761243
 
 
   @ivandasch, Hi. Thank you!
   
   >>> Also, I suppose, that we should leave to user the final conclusion to instrument methods of
   his or her service or not. I ... annotation like @Metered or @Timed, with bunch of configurable parameters. ...
   
   What if we introduce system parameter like "SERVICE_METRICS_ENABLED" with default “true” and overriding annotations @MetricsEnabled, @MetricsDisabled. This parameter might be switched through JMX. You’ll be able to disable metrics for every service but a certain one. Or to enable metrics for most of your services with an exception of couple. Or even to enable metrics for certain methods in one service.
   Why I propose system parameter is that it causes fewer code changes/recompilations. 
   
   

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385097815
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceContextImpl.java
 ##########
 @@ -56,8 +59,9 @@
     @GridToStringExclude
     private final ExecutorService exe;
 
-    /** Methods reflection cache. */
-    private final ConcurrentMap<GridServiceMethodReflectKey, Method> mtds = new ConcurrentHashMap<>();
+    /** Keeps cached data bound to service method. */
+    private final ConcurrentMap<GridServiceMethodReflectKey, IgniteBiTuple<Method, HistogramMetricImpl>> mtds =
 
 Review comment:
   I suggest make code more readable and create a separate map for metrics. `ConcurrentMap<Method, HistogramMetricImpl>`

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401115708
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -188,6 +216,9 @@
     /** Disconnected flag. */
     private volatile boolean disconnected;
 
+    /** Keeps histograms to measure durations of service methods. Guided by service name, then method name. */
+    private final Map<String, Map<String, MethodHistogramHolder>> invocationHistograms = new HashMap<>(1);
 
 Review comment:
   This is not a cached variable, not a class property. It is re-requested every time. Yes, some gap in getting histogram is possible. But why long?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r402810942
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MetricUtils.java
 ##########
 @@ -163,4 +168,66 @@ private static boolean ensureAllNamesNotEmpty(String... names) {
 
         return names;
     }
+
+    /**
+     * Abbreviates package name for metric naming purposes.
+     *
+     * @param pkgNameDepth Exhibition level of java package name. The bigger, the wider.
+     *                     Max level is {@link #MAX_ABBREVIATE_NAME_LVL}. Values:
+     *                     <pre>
+     *                         0 or negative - wont add package name;
+     *                         1 - add first and last char of each name in java package;
+     *                         2 or bigger - add full name of java package.
+     *                     </pre>
+     * @return Abbreviated name of {@code cls}.
+     */
+    public static String abbreviateName(Class<?> cls, int pkgNameDepth) {
+        if (pkgNameDepth < 1)
+            return cls.getSimpleName();
+
+        if (pkgNameDepth >= MAX_ABBREVIATE_NAME_LVL)
+            return cls.getName();
+
+        String[] pkgNameParts = cls.getName().split("\\.");
+
+        // No package like 'void' or 'int'.
+        if (pkgNameParts.length == 1)
+            return pkgNameParts[0];
+
+        StringBuilder sb = new StringBuilder();
+
+        for (int i = 0; i < pkgNameParts.length - 1; ++i) {
+            sb.append(pkgNameParts[i].charAt(0));
+
+            if (pkgNameParts[i].length() > 1)
+                sb.append(pkgNameParts[i].charAt(pkgNameParts[i].length() - 1));
+
+            sb.append(".");
+        }
+
+        // Add name to the class.
+        sb.append(pkgNameParts[pkgNameParts.length - 1]);
+
+        return sb.toString();
+    }
+
+    /**
+     * Gives proper name for service metric registry.
+     *
+     * @param srvcName Name of the service.
+     * @return registry name for service {@code srvcName}.
+     */
+    public static String serviceMetricRegistryName(String srvcName) {
+        return metricName(SERVICE_METRIC_REGISTRY, srvcName);
+    }
+
+    /**
+     * Count total of histogram values.
+     *
+     * @param histogram Histogram to traverse.
+     * @return Sum of all entries of {@code histogram} buckets.
+     */
+    public static long sumHistogramEntries(HistogramMetric histogram) {
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r402808392
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/IgniteServicesImpl.java
 ##########
 @@ -75,6 +75,30 @@ public IgniteServicesImpl(GridKernalContext ctx, ClusterGroupAdapter prj, boolea
         return prj;
     }
 
+    /** {@inheritDoc} */
+    @Override public ServiceConfiguration clusterSingletonConfiguration(String name, Service svc) {
+        return ctx.service().serviceConfiguration(name, svc, 1, 1);
+    }
+
+    /** {@inheritDoc} */
+    @Override public ServiceConfiguration nodeSingletonConfiguration(String name, Service svc) {
+        return ctx.service().serviceConfiguration(name, svc, 0, 1);
+    }
+
+    /** {@inheritDoc} */
+    @Override public ServiceConfiguration keyAffinitySingletonConfiguration(String name, Service svc, String cacheName,
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r384503495
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -976,6 +1103,39 @@ private boolean hasLocalNode(ClusterGroup prj) {
         return false;
     }
 
+    /**
+     * Creates metric for service method. If the metric exists then considers one or several argument types has same
+     * name but different packages. Then skips existing metric and tries to extend metric name with abbreviation of
+     * java package name. @see {@link #abbreviatePgkName(Class, int)}.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogramm of service method timings.
 
 Review comment:
   `Histogramm` -> `Histogram` (and in other places)

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401068478
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
 
 Review comment:
   @ivandasch , there is a gap between
   `metricRegistry.findMetric(methodMetricName)`
   and
   `metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
                           DESCRIPTION_OF_INVOCATION_METRIC)`
   
   It is important. If something creates metric after `metricRegistry.findMetric(methodMetricName)`, it would cause incorrent metric naming or NPE. 
   
   Is it ok to keep synchronized ?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400767497
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java
 ##########
 @@ -354,6 +355,37 @@ T proxy() {
         return proxy;
     }
 
+    /**
+     * Calls service method, measures and registers its performance.
+     *
+     * @param srvcProc Current service processor.
+     * @param srvc The service object.
+     * @param srvcName The service name.
+     * @param mtd Method to call.
+     * @param args Arguments for {@code mtd}.
+     */
+    private static Object callSrvcMtd(ServiceProcessorAdapter srvcProc, Service srvc, String srvcName, Method mtd,
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on issue #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on issue #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#issuecomment-606761243
 
 
   @ivandasch, Hi. Thank you!
   
   >>> Also, I suppose, that we should leave to user the final conclusion to instrument methods of
   his or her service or not. I ... annotation like @Metered or @Timed, with bunch of configurable parameters. ...
   
   What if we introduce system parameter like "SERVICE_METRICS_ENABLED" with default “true” and overriding annotations @MetricsEnabled, @MetricsDisabled. This parameter might be switched through JMX. You’ll be able to disable metrics for every service but a certain one. Or to enable metrics for most of your services with an exception of couple. Or even to enable metrics for certain methods in one service.
   Why I propose system parameter is that it causes fewer code changes/recompilations. 
   
   

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400425648
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java
 ##########
 @@ -354,6 +355,37 @@ T proxy() {
         return proxy;
     }
 
+    /**
+     * Calls service method, measures and registers its performance.
+     *
+     * @param srvcProc Current service processor.
+     * @param srvc The service object.
+     * @param srvcName The service name.
+     * @param mtd Method to call.
+     * @param args Arguments for {@code mtd}.
+     */
+    private static Object callSrvcMtd(ServiceProcessorAdapter srvcProc, Service srvc, String srvcName, Method mtd,
+        Object[] args) throws InvocationTargetException, IllegalAccessException {
+
+        long timing = System.nanoTime();
+
+        try {
+            return mtd.invoke(srvc, args);
+        }
+        finally {
+            if (srvcProc instanceof IgniteServiceProcessor) {
+                timing = System.nanoTime() - timing;
 
 Review comment:
   Let's name vars explicit: `startTime`, `duration`

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385137912
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,418 @@
+package org.apache.ignite.internal.processors.service;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICE_METRICS_ENABLED;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.METRIC_REGISTRY_INVOCATIONS;
+
+/** */
+public class GridServiceMetricsTest extends GridCommonAbstractTest {
+    /** Number of service invcations. */
+    private static final int INVOKE_CNT = 50;
+
+    /** Utility holder of current grid number. */
+    private final AtomicInteger gridNum = new AtomicInteger();
+
+    /** */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /** */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        System.clearProperty(IGNITE_SERVICE_METRICS_ENABLED);
+    }
+
+    /** Makes sure {@code IgniteSystemProperties#IGNITE_SERVICE_METRICS_ENABLED} works correctly. */
+    @Test
+    public void testMetricsEnabledDisabled() throws Throwable {
+        IgniteEx server = startGrid(0);
+
+        assertFalse("Service metric registry must not be created yet.",
+            findMetric(server.context().metric(), METRIC_REGISTRY_INVOCATIONS));
+
+        String srvcName = "testMetricsEnabledService";
+
+        server.services().deploy(serviceCfg(srvcName, 1, 1));
+
+        assertTrue("Service metric registry must be already created.",
+            findMetric(server.context().metric(), METRIC_REGISTRY_INVOCATIONS));
+
+        stopAllGrids();
+
+        System.setProperty(IGNITE_SERVICE_METRICS_ENABLED, "false");
 
 Review comment:
   Isn't it redundant safety? This is new specific parameter, unused in other tests.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401141419
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
 
 Review comment:
   @ivandasch Yep, just realized we can lose value on parallel puts. Doesn’t matter. I finally remembered the reason why staying with simple HashMap without sync blocks or any other concurrency protections. Service deploying/undeploying are guided by discovery messages which are serial. Actually, all we do here we do in single thread. This is also important to avoid memory leaks. We either are launching service and registering metrics or we are canceling service and removing metrics. Serially. Just using syncs and ConcuremtHashMap doesn’t guarantee we stored statistics after service cancelation. WDYT?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401133474
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
 
 Review comment:
   Same here. You are right about usage of separate method. But the synchronization you suggest seems already relies in the logic above. I don’t think `IgniteServiceProcessor.undeploy()` and ` IgniteServiceProcessor.redeploy()` can happen concurrently but we should consider it can, ok. Let’s see:
   -	Metrics are erased by `IgniteServiceProcessor.unregisterMetrics()` in 2 places (): `IgniteServiceProcessor.redeploy()` and `IgniteServiceProcessor.undeploy()`.
   -	Metrics are created by `IgniteServiceProcessor.registerMetrics()`  in one place: `IgniteServiceProcessor.redeploy()`.
   
   These calls are not any APIs, are private.
   
   All 3 calls covered with sync by service context collection given bt same serviced:
   ```
   Collection<ServiceContextImpl> ctxs …
   synchronized (ctxs) {
   	unregisterMetrics(cfg.getName());
           }
   ```
   and
   ```
   Collection<ServiceContextImpl> ctxs …
               synchronized (ctxs) {
                   if (!ctxs.iterator().next().isCancelled())
                       registerMetrics(srvc, srvcCtx.name());
               } 
   ```
   
   I think I really missed the last part earlier. Thanks for the note. Isn’t it the synchronized block you suggest?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400768921
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i < MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append("_");
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385233580
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1156,10 +1274,15 @@ void redeploy(IgniteUuid srvcId, ServiceConfiguration cfg,
 
         Collection<ServiceContextImpl> toInit = new ArrayList<>();
 
+        ServiceContextImpl firstInitialized = !metricsEnabled || ctxs.isEmpty() ? null : ctxs.iterator().next();
 
 Review comment:
   Several service instances can be deployed per node.  One service context per deployed instance. But one metric per node(all deployed instances of one service), isn't it?

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400937869
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,336 @@
+package org.apache.ignite.internal.processors.service;
+
+import com.google.common.collect.Iterables;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.spi.metric.jmx.JmxMetricExporterSpi;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Test;
+
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.MAX_ABBREVIATE_NAME_LVL;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.serviceMetricRegistryName;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.sumHistogramEntries;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.SERVICE_METRIC_REGISTRY;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.methodMetricName;
+
+/** Tests metrics of service invocations. */
+public class GridServiceMetricsTest extends GridCommonAbstractTest {
+    /** Number of service invocations. */
+    private static final int INVOKE_CNT = 100;
+
+    /** Utility holder of current grid number. */
+    private final AtomicInteger gridNum = new AtomicInteger();
+
+    /** Service name used in the tests. */
+    private static final String SRVC_NAME = GridServiceMetricsTest.class.getSimpleName()+"_service";
+
+    /** Error message of created metrics. */
+    private static final String METRICS_MUST_NOT_BE_CREATED = "Service metric registry must not be created.";
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        // JMX metrics exposition for debug launch mode.
+        cfg.setMetricExporterSpi(new JmxMetricExporterSpi());
+
+        return cfg;
+    }
+
+    /** Checks metric behaviour when launched several service instances via #IgniteServices#deployMultiple */
+    @Test
+    public void testMultipleDeployment() throws Throwable {
+        List<IgniteEx> servers = new ArrayList<>();
+
+        servers.add(startGrid(gridNum.getAndIncrement()));
+
+        IgniteEx server = servers.get(0);
+
+        IgniteEx client = startClientGrid(gridNum.getAndIncrement());
+
+        assertNull(METRICS_MUST_NOT_BE_CREATED, findMetricRegistry(server.context().metric(), SERVICE_METRIC_REGISTRY));
+
+        int totalInstance = 2;
+
+        int perNode = 2;
+
+        server.services().deployMultiple(SRVC_NAME, MyServiceFactory.create(), totalInstance, perNode);
+
+        awaitPartitionMapExchange();
+
+        // Call proxies on the clients.
+        Stream.generate(() -> client.services().serviceProxy(SRVC_NAME, MyService.class, true))
+            .limit(totalInstance).forEach(srvc -> ((MyService)srvc).hello());
+
+        ReadOnlyMetricRegistry metrics = findMetricRegistry(server.context().metric(), SRVC_NAME);
+
+        // Total service calls number.
+        int callsCnt = 0;
+
+        for (Metric m : metrics) {
+            if (m instanceof HistogramMetric)
+                callsCnt += sumHistogramEntries((HistogramMetric)m);
+        }
+
+        assertEquals(callsCnt, totalInstance);
+
+        // Add servers more than service instances.
+        servers.add(startGrid(gridNum.getAndIncrement()));
+
+        servers.add(startGrid(gridNum.getAndIncrement()));
+
+        awaitPartitionMapExchange();
+
+        int deployedCnt = 0;
+
+        int metricsCnt = 0;
+
+        for (IgniteEx ignite : servers) {
+            if (ignite.services().service(SRVC_NAME) != null)
+                deployedCnt++;
+
+            if (findMetricRegistry(ignite.context().metric(), SRVC_NAME) != null)
+                metricsCnt++;
+        }
+
+        assertEquals(deployedCnt, metricsCnt);
+
+        assertEquals(metricsCnt, totalInstance);
+    }
+
+    /** Checks metric are created when service is deployed and removed when service is undeployed. */
+    @Test
+    public void testMetricDeplotmentUndeployment() throws Exception {
+        List<IgniteEx> servers = startGrids(3, false);
+
+        // 2 services per node.
+        servers.get(0).services().deploy(serviceCfg(SRVC_NAME, servers.size(), 2));
+
+        awaitPartitionMapExchange();
+
+        // Make sure metrics are registered.
+        for (IgniteEx ignite : servers)
+            assertEquals(metricsCnt(ignite, SRVC_NAME), MyService.class.getDeclaredMethods().length);
+
+        servers.get(0).services().cancel(SRVC_NAME);
+
+        awaitPartitionMapExchange();
+
+        for (IgniteEx ignite : servers)
+            assertEquals(metricsCnt(ignite, SRVC_NAME), 0);
+    }
+
+    /** Checks two different histograms are created for the same short names of service methods. */
+    @Test
+    public void testMetricNaming() throws Exception {
+        IgniteEx ignite = startGrid(1);
+
+        ignite.services().deployNodeSingleton(SRVC_NAME, new NamingServiceImpl());
+
+        MetricRegistry registry = ignite.context().metric().registry(serviceMetricRegistryName(SRVC_NAME));
+
+        List<Metric> metricsFound = new ArrayList<>();
+
+        for (Method mtd : NamingService.class.getDeclaredMethods()) {
+            Metric curMetric = null;
+
+            for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+                String metricName = methodMetricName(mtd, i);
+
+                if ((curMetric = registry.findMetric(metricName)) instanceof HistogramMetric
+                    && !metricsFound.contains(curMetric)) {
+                    metricsFound.add(curMetric);
+
+                    break;
+                }
+            }
+
+            assertNotNull("No metric found for method " + mtd, curMetric);
+        }
+    }
+
+    /** Tests service metrics for single service instance. */
+    @Test
+    public void testServiceMetricsSingle() throws Throwable {
+        testServiceMetrics(1, 1, 1, 1);
+    }
+
+    /** Tests service metrics for multy service instance: one per server. */
+    @Test
+    public void testServiceMetricsMulty() throws Throwable {
+        testServiceMetrics(3, 3, 3, 1);
+    }
+
+    /** Tests service metrics for multy service instance: fewer that servers and clients. */
+    @Test
+    public void testServiceMetricsMultyFew() throws Throwable {
+        testServiceMetrics(4, 3, 2, 1);
+    }
+
+    /** Tests service metrics for multy service instance: serveral instances per node */
+    @Test
+    public void testServiceMetricsMultyDuplicated() throws Throwable {
+        testServiceMetrics(3, 2, 3, 3);
+    }
+
+    /** Tests service metrics for multy service instance: serveral instances per node, total fewer that servers. */
+    @Test
+    public void testServiceMetricsMultyFewDuplicated() throws Throwable {
+        testServiceMetrics(5, 4, 3, 2);
+    }
+
+    /**
+     * Invokes service in various ways: from clients, servers, etc. Checks these calls reflect in the metrics.
+     *
+     * @param serverCnt Number of server nodes.
+     * @param clientCnt Number of client nodes.
+     * @param perClusterCnt Number of service instances per cluster.
+     * @param perNodeCnt Number of service instances per node.
+     */
+    private void testServiceMetrics(int serverCnt, int clientCnt, int perClusterCnt, int perNodeCnt) throws Throwable {
+        List<IgniteEx> servers = startGrids(serverCnt, false);
+
+        List<IgniteEx> clients = startGrids(clientCnt, true);
+
+        servers.get(0).services().deploy(serviceCfg(SRVC_NAME, perClusterCnt, perNodeCnt));
+
+        awaitPartitionMapExchange();
+
+        List<MyService> serverStickyProxies = servers.stream()
+            .map(ignite -> (MyService)ignite.services().serviceProxy(SRVC_NAME, MyService.class, true))
+            .collect(Collectors.toList());
+
+        List<MyService> clientStickyProxies = clients.stream()
+            .map(ignite -> (MyService)ignite.services().serviceProxy(SRVC_NAME, MyService.class, true))
+            .collect(Collectors.toList());
+
+        long invokeCollector = 0;
+
+        // Call service through the server proxies.
+        for (AtomicInteger i = new AtomicInteger(); i.get() < INVOKE_CNT; i.incrementAndGet()) {
+            // Call from server.
+            IgniteEx ignite = servers.get(i.get() % servers.size());
+
+            invokeCollector += callService(ignite, () -> serverStickyProxies.get(i.get() % serverStickyProxies.size()));
+
+            // Call from client.
+            ignite = clients.get(i.get() % clients.size());
+
+            invokeCollector += callService(ignite, () -> clientStickyProxies.get(i.get() % clientStickyProxies.size()));
+        }
+
+        long invokesInMetrics = 0;
+
+        // Calculate and check invocations within the metrics.
+        for (IgniteEx ignite : servers) {
+            ReadOnlyMetricRegistry metrics = findMetricRegistry(ignite.context().metric(), SRVC_NAME);
+
+            // Metrics may not be deployed on this server node.
+            if (metrics == null)
+                continue;
+
+            for (Metric metric : metrics) {
+                if (metric instanceof HistogramMetric)
+                    invokesInMetrics += sumHistogramEntries((HistogramMetric)metric);
+            }
+        }
+
+        // Compare calls number and metrics number.
+        assertEquals("Calculated wrong service invocation number.", invokesInMetrics, invokeCollector);
+    }
+
+    /**
+     * Invokes service method via proxies and local deployments if available. Calculates the invocations done.
+     *
+     * @param ignite Server or client node.
+     * @param extraSrvc Extra service instance or proxy to call.
+     * @return Total invokes done.
+     */
+    private int callService(IgniteEx ignite, @Nullable Supplier<MyService> extraSrvc) {
+        MyService srvc = ignite.services().serviceProxy(SRVC_NAME, MyService.class, false);
+
+        srvc.hello();
+
+        assertEquals(srvc.hello(12), 12);
+
+        // We just did 2 service calls.
+        int invokesDone = 2;
+
+        if (extraSrvc != null) {
+            srvc.hello();
+
+            assertEquals(srvc.hello(10), 10);
+
+            invokesDone += 2;
+        }
+
+        return invokesDone;
+    }
+
+    /** Provides test service configuration. */
+    private ServiceConfiguration serviceCfg(String svcName, int perClusterCnt, int perNodeCnt) {
+        ServiceConfiguration svcCfg = new ServiceConfiguration();
+
+        svcCfg.setService(MyServiceFactory.create());
+
+        svcCfg.setName(svcName);
+
+        svcCfg.setMaxPerNodeCount(perNodeCnt);
+
+        svcCfg.setTotalCount(perClusterCnt);
+
+        return svcCfg;
+    }
+
+    /** Expose ignite-references of the nodes as list. */
+    private List<IgniteEx> startGrids(int cnt, boolean client) {
+        return Stream.generate(() -> {
 
 Review comment:
   I suppose, that simple loop and `List#add` is simpler and a way more readable.
   Moreover, this approach doesn't make you to use `AtomicInteger` as type of `gridNum`

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401069181
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
 
 Review comment:
   @ivandasch , can you clarify what you mean 'thread-safe'? Isn't 'computeIfAbsent' is not enough? I suggest to make sure there is no concurrent call of `IgniteProcessor.undeploy()`:
   
   ```
               synchronized (ctxs) {
                   if(!ctxs.iterator().next().isCancelled())
                       registerMetrics(srvc, srvcCtx.name());
               }
   ```
   
   WDYT?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401141419
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
 
 Review comment:
   @ivandasch Yep, just realized we can lose value on parallel puts. Doesn’t matter. I finally remembered the reason why staying with simple HashMap without sync blocks or any other concurrency protections. Service deploying/un deploying are guided by discovery messages which are serial. Actually, all we do here we do in single thread. WDYT?

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r402763486
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java
 ##########
 @@ -354,6 +358,37 @@ T proxy() {
         return proxy;
     }
 
+    /**
+     * Calls service method, measures and registers its duration.
+     *
+     * @param srvcProc Current service processor.
+     * @param srvc The service object.
+     * @param srvcName The service name.
+     * @param mtd Method to call.
+     * @param args Arguments for {@code mtd}.
+     */
+    private static Object measureServiceMethod(ServiceProcessorAdapter srvcProc, Service srvc, String srvcName,
 
 Review comment:
   Rewrite a declaration, please, each param on new line, bracket and curly bracket also on new line

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400767371
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java
 ##########
 @@ -354,6 +355,37 @@ T proxy() {
         return proxy;
     }
 
+    /**
+     * Calls service method, measures and registers its performance.
+     *
+     * @param srvcProc Current service processor.
+     * @param srvc The service object.
+     * @param srvcName The service name.
+     * @param mtd Method to call.
+     * @param args Arguments for {@code mtd}.
+     */
+    private static Object callSrvcMtd(ServiceProcessorAdapter srvcProc, Service srvc, String srvcName, Method mtd,
+        Object[] args) throws InvocationTargetException, IllegalAccessException {
+
+        long timing = System.nanoTime();
+
+        try {
+            return mtd.invoke(srvc, args);
+        }
+        finally {
+            if (srvcProc instanceof IgniteServiceProcessor) {
+                timing = System.nanoTime() - timing;
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401070065
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,336 @@
+package org.apache.ignite.internal.processors.service;
+
+import com.google.common.collect.Iterables;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.spi.metric.jmx.JmxMetricExporterSpi;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Test;
+
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.MAX_ABBREVIATE_NAME_LVL;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.serviceMetricRegistryName;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.sumHistogramEntries;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.SERVICE_METRIC_REGISTRY;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.methodMetricName;
+
+/** Tests metrics of service invocations. */
+public class GridServiceMetricsTest extends GridCommonAbstractTest {
+    /** Number of service invocations. */
+    private static final int INVOKE_CNT = 100;
+
+    /** Utility holder of current grid number. */
+    private final AtomicInteger gridNum = new AtomicInteger();
+
+    /** Service name used in the tests. */
+    private static final String SRVC_NAME = GridServiceMetricsTest.class.getSimpleName()+"_service";
+
+    /** Error message of created metrics. */
+    private static final String METRICS_MUST_NOT_BE_CREATED = "Service metric registry must not be created.";
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        // JMX metrics exposition for debug launch mode.
+        cfg.setMetricExporterSpi(new JmxMetricExporterSpi());
+
+        return cfg;
+    }
+
+    /** Checks metric behaviour when launched several service instances via #IgniteServices#deployMultiple */
+    @Test
+    public void testMultipleDeployment() throws Throwable {
+        List<IgniteEx> servers = new ArrayList<>();
+
+        servers.add(startGrid(gridNum.getAndIncrement()));
+
+        IgniteEx server = servers.get(0);
+
+        IgniteEx client = startClientGrid(gridNum.getAndIncrement());
+
+        assertNull(METRICS_MUST_NOT_BE_CREATED, findMetricRegistry(server.context().metric(), SERVICE_METRIC_REGISTRY));
+
+        int totalInstance = 2;
+
+        int perNode = 2;
+
+        server.services().deployMultiple(SRVC_NAME, MyServiceFactory.create(), totalInstance, perNode);
+
+        awaitPartitionMapExchange();
+
+        // Call proxies on the clients.
+        Stream.generate(() -> client.services().serviceProxy(SRVC_NAME, MyService.class, true))
+            .limit(totalInstance).forEach(srvc -> ((MyService)srvc).hello());
+
+        ReadOnlyMetricRegistry metrics = findMetricRegistry(server.context().metric(), SRVC_NAME);
+
+        // Total service calls number.
+        int callsCnt = 0;
+
+        for (Metric m : metrics) {
+            if (m instanceof HistogramMetric)
+                callsCnt += sumHistogramEntries((HistogramMetric)m);
+        }
+
+        assertEquals(callsCnt, totalInstance);
+
+        // Add servers more than service instances.
+        servers.add(startGrid(gridNum.getAndIncrement()));
+
+        servers.add(startGrid(gridNum.getAndIncrement()));
+
+        awaitPartitionMapExchange();
+
+        int deployedCnt = 0;
+
+        int metricsCnt = 0;
+
+        for (IgniteEx ignite : servers) {
+            if (ignite.services().service(SRVC_NAME) != null)
+                deployedCnt++;
+
+            if (findMetricRegistry(ignite.context().metric(), SRVC_NAME) != null)
+                metricsCnt++;
+        }
+
+        assertEquals(deployedCnt, metricsCnt);
+
+        assertEquals(metricsCnt, totalInstance);
+    }
+
+    /** Checks metric are created when service is deployed and removed when service is undeployed. */
+    @Test
+    public void testMetricDeplotmentUndeployment() throws Exception {
+        List<IgniteEx> servers = startGrids(3, false);
+
+        // 2 services per node.
+        servers.get(0).services().deploy(serviceCfg(SRVC_NAME, servers.size(), 2));
+
+        awaitPartitionMapExchange();
+
+        // Make sure metrics are registered.
+        for (IgniteEx ignite : servers)
+            assertEquals(metricsCnt(ignite, SRVC_NAME), MyService.class.getDeclaredMethods().length);
+
+        servers.get(0).services().cancel(SRVC_NAME);
+
+        awaitPartitionMapExchange();
+
+        for (IgniteEx ignite : servers)
+            assertEquals(metricsCnt(ignite, SRVC_NAME), 0);
+    }
+
+    /** Checks two different histograms are created for the same short names of service methods. */
+    @Test
+    public void testMetricNaming() throws Exception {
+        IgniteEx ignite = startGrid(1);
+
+        ignite.services().deployNodeSingleton(SRVC_NAME, new NamingServiceImpl());
+
+        MetricRegistry registry = ignite.context().metric().registry(serviceMetricRegistryName(SRVC_NAME));
+
+        List<Metric> metricsFound = new ArrayList<>();
+
+        for (Method mtd : NamingService.class.getDeclaredMethods()) {
+            Metric curMetric = null;
+
+            for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+                String metricName = methodMetricName(mtd, i);
+
+                if ((curMetric = registry.findMetric(metricName)) instanceof HistogramMetric
+                    && !metricsFound.contains(curMetric)) {
+                    metricsFound.add(curMetric);
+
+                    break;
+                }
+            }
+
+            assertNotNull("No metric found for method " + mtd, curMetric);
+        }
+    }
+
+    /** Tests service metrics for single service instance. */
+    @Test
+    public void testServiceMetricsSingle() throws Throwable {
+        testServiceMetrics(1, 1, 1, 1);
+    }
+
+    /** Tests service metrics for multy service instance: one per server. */
+    @Test
+    public void testServiceMetricsMulty() throws Throwable {
+        testServiceMetrics(3, 3, 3, 1);
+    }
+
+    /** Tests service metrics for multy service instance: fewer that servers and clients. */
+    @Test
+    public void testServiceMetricsMultyFew() throws Throwable {
+        testServiceMetrics(4, 3, 2, 1);
+    }
+
+    /** Tests service metrics for multy service instance: serveral instances per node */
+    @Test
+    public void testServiceMetricsMultyDuplicated() throws Throwable {
+        testServiceMetrics(3, 2, 3, 3);
+    }
+
+    /** Tests service metrics for multy service instance: serveral instances per node, total fewer that servers. */
+    @Test
+    public void testServiceMetricsMultyFewDuplicated() throws Throwable {
+        testServiceMetrics(5, 4, 3, 2);
+    }
+
+    /**
+     * Invokes service in various ways: from clients, servers, etc. Checks these calls reflect in the metrics.
+     *
+     * @param serverCnt Number of server nodes.
+     * @param clientCnt Number of client nodes.
+     * @param perClusterCnt Number of service instances per cluster.
+     * @param perNodeCnt Number of service instances per node.
+     */
+    private void testServiceMetrics(int serverCnt, int clientCnt, int perClusterCnt, int perNodeCnt) throws Throwable {
+        List<IgniteEx> servers = startGrids(serverCnt, false);
+
+        List<IgniteEx> clients = startGrids(clientCnt, true);
+
+        servers.get(0).services().deploy(serviceCfg(SRVC_NAME, perClusterCnt, perNodeCnt));
+
+        awaitPartitionMapExchange();
+
+        List<MyService> serverStickyProxies = servers.stream()
+            .map(ignite -> (MyService)ignite.services().serviceProxy(SRVC_NAME, MyService.class, true))
+            .collect(Collectors.toList());
+
+        List<MyService> clientStickyProxies = clients.stream()
+            .map(ignite -> (MyService)ignite.services().serviceProxy(SRVC_NAME, MyService.class, true))
+            .collect(Collectors.toList());
+
+        long invokeCollector = 0;
+
+        // Call service through the server proxies.
+        for (AtomicInteger i = new AtomicInteger(); i.get() < INVOKE_CNT; i.incrementAndGet()) {
+            // Call from server.
+            IgniteEx ignite = servers.get(i.get() % servers.size());
+
+            invokeCollector += callService(ignite, () -> serverStickyProxies.get(i.get() % serverStickyProxies.size()));
+
+            // Call from client.
+            ignite = clients.get(i.get() % clients.size());
+
+            invokeCollector += callService(ignite, () -> clientStickyProxies.get(i.get() % clientStickyProxies.size()));
+        }
+
+        long invokesInMetrics = 0;
+
+        // Calculate and check invocations within the metrics.
+        for (IgniteEx ignite : servers) {
+            ReadOnlyMetricRegistry metrics = findMetricRegistry(ignite.context().metric(), SRVC_NAME);
+
+            // Metrics may not be deployed on this server node.
+            if (metrics == null)
+                continue;
+
+            for (Metric metric : metrics) {
+                if (metric instanceof HistogramMetric)
+                    invokesInMetrics += sumHistogramEntries((HistogramMetric)metric);
+            }
+        }
+
+        // Compare calls number and metrics number.
+        assertEquals("Calculated wrong service invocation number.", invokesInMetrics, invokeCollector);
+    }
+
+    /**
+     * Invokes service method via proxies and local deployments if available. Calculates the invocations done.
+     *
+     * @param ignite Server or client node.
+     * @param extraSrvc Extra service instance or proxy to call.
+     * @return Total invokes done.
+     */
+    private int callService(IgniteEx ignite, @Nullable Supplier<MyService> extraSrvc) {
+        MyService srvc = ignite.services().serviceProxy(SRVC_NAME, MyService.class, false);
+
+        srvc.hello();
+
+        assertEquals(srvc.hello(12), 12);
+
+        // We just did 2 service calls.
+        int invokesDone = 2;
+
+        if (extraSrvc != null) {
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385215138
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1964,50 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /** Invocation proxy handler for service to measure durations of its methods. */
+    private class LocalInvocationHandler implements InvocationHandler {
 
 Review comment:
   Can be static

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400413156
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java
 ##########
 @@ -354,6 +355,37 @@ T proxy() {
         return proxy;
     }
 
+    /**
+     * Calls service method, measures and registers its performance.
 
 Review comment:
   The method measures the invocation duration, not performance.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401141419
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
 
 Review comment:
   As far as I know concurrent put/get/remove is not atomic but is safe meaning won't fail, throw an exception. You can only get null when a value exist, or a value when it is already removed.
   
   Please, take a look to this simple test. Forks for me. Gives null periodically, and, I believe, inconsistent values. But no any lock/crash scenario. What else should we check?
   
   ```
   @Test
       public void testMapConcurrency() throws InterruptedException {
           final Map<Integer, Integer> map = new HashMap<>(1);
           final Random rnd = new Random();
           final int valueCnt = 100000;
           final Integer[] holder = new Integer[1];
   
           for(int i=0; i<5; ++i) {
               new Thread(() -> {
                   while (true) {
                       for (int v = 0; v < valueCnt; ++v)
                           map.put(v, rnd.nextInt(valueCnt));
   
                       System.err.println("Filled");
   
                       try {
                           Thread.sleep(rnd.nextInt(5000));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
               }, "putter_"+i).start();
           }
   
           for(int i=0; i<30; ++i) {
               new Thread(() -> {
                   while (true) {
   
                       try {
                           holder[0] = map.get(rnd.nextInt(valueCnt));
   
                           Thread.sleep(rnd.nextInt(50));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                       catch (Exception e) {
                           e.printStackTrace();
                       }
                   }
               }, "getter_"+i).start();
           }
   
           for(int i=0; i<5; ++i) {
               new Thread(() -> {
                   while (true) {
                       try {
                           Thread.sleep(rnd.nextInt(5000));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
   
                       System.err.println("Clearing");
   
                       map.clear();
   
                       System.err.println("Cleared");
                   }
               }, "clearer_"+i).start();
           }
   
           Thread.sleep(5*60000);
       }
   ```
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385209842
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -976,6 +1103,39 @@ private boolean hasLocalNode(ClusterGroup prj) {
         return false;
     }
 
+    /**
+     * Creates metric for service method. If the metric exists then considers one or several argument types has same
+     * name but different packages. Then skips existing metric and tries to extend metric name with abbreviation of
+     * java package name. @see {@link #abbreviatePgkName(Class, int)}.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogramm of service method timings.
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385209499
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -113,6 +123,15 @@
     /** */
     public static final String SVCS_VIEW_DESC = "Services";
 
+    /** Base name domain for invocation metrics. @see {@link #invocationsMetric(String, Method)}. */
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400926764
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
 
 Review comment:
   This method is supposed to be called from various threads. But `invocationHistograms` is just a HashMap,
   and value of `invocationHistograms` is just a HashMap.
   Moreover, `HistogramHolder#getHistogram` is also not synchronized (but `HistogramHolder#addIfAbsent` is synchronized).
   By the way, use of Optional doesn't make this code more readable, IMHO.
   I suggest this variant
   ```
   HistogramMetricImpl histogram(String srvcName, Method mtd) {
       Map<String, MethodHistogramHolder> srvHistos = invocationHistograms.get(srvcName);
   
       if (srvHistos == null)
           return null;
   
       synchronized (srvHistos) {
           MethodHistogramHolder holder = srvHistos.get(mtd.getName());
   
           return holder != null ? holder.getHistogram(mtd): null;
       }
   }
   ```
   

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400940304
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -188,6 +216,9 @@
     /** Disconnected flag. */
     private volatile boolean disconnected;
 
+    /** Keeps histograms to measure durations of service methods. Guided by service name, then method name. */
+    private final Map<String, Map<String, MethodHistogramHolder>> invocationHistograms = new HashMap<>(1);
 
 Review comment:
   Lookup in `invocationHistograms` may occur in multiple threads, but `HashMap` is not a thread safe.
   You should consider using of `ConcurrentHashMap`
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400791320
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MetricUtils.java
 ##########
 @@ -163,4 +168,69 @@ private static boolean ensureAllNamesNotEmpty(String... names) {
 
         return names;
     }
+
+    /**
+     * Abbreviates package name for metric naming purposes.
+     *
+     * @param pkgNameDepth Exhibition level of java package name. The bigger, the wider.
+     *                     Max level is {@link #MAX_ABBREVIATE_NAME_LVL}. Values:
+     *                     <pre>
+     *                         0 - wont add package name;
+     *                         1 - add only first char of each name in java package;
+     *                         2 - add first and last char of each name in java package;
+     *                         Any other - add full name of java package.
+     *                     </pre>
+     * @return Abbreviated name of {@code cls}.
+     */
+    public static String abbreviateName(Class<?> cls, int pkgNameDepth) {
 
 Review comment:
   @NSAmelchev , in your example you two different services and their metric name has different service name like different domain. However, in particular case it would require some efforts to distinguish metrics. If methods like in your case are contained in same interface. I think it is rare case and should not affect common simplicity of metric names. I suggest to keep metric names as simple as possible. Available improvement is adding 2 chars of package name:
   void_testMethod(Param)
   void_testMethod(og.ae.ie.il.ps.se.ir.il.Param)
   
   Still possible to get abbreviated package name complicated when firs/last chars are the same. I believe keeping rape case confusing is better that keep long names for 99% cases. WDYT?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401141419
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
 
 Review comment:
   As far as I know, concurrent put/get/remove are not atomic but are safe meaning do not fail or throw an exception. Iteration is a problem here. You can only get null when a value exist, or a value when it is already removed.
   
   Please, take a look to this simple test. Forks for me. Gives null periodically, and, I believe, inconsistent values. But no any lock/crash scenario. What else should we check?
   
   ```
   @Test
       public void testMapConcurrency() throws InterruptedException {
           final Map<Integer, Integer> map = new HashMap<>(1);
           final Random rnd = new Random();
           final int valueCnt = 100000;
           final Integer[] holder = new Integer[1];
   
           for(int i=0; i<5; ++i) {
               new Thread(() -> {
                   while (true) {
                       for (int v = 0; v < valueCnt; ++v)
                           map.put(v, rnd.nextInt(valueCnt));
   
                       System.err.println("Filled");
   
                       try {
                           Thread.sleep(rnd.nextInt(5000));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
               }, "putter_"+i).start();
           }
   
           for(int i=0; i<30; ++i) {
               new Thread(() -> {
                   while (true) {
   
                       try {
                           holder[0] = map.get(rnd.nextInt(valueCnt));
   
                           Thread.sleep(rnd.nextInt(50));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                       catch (Exception e) {
                           e.printStackTrace();
                       }
                   }
               }, "getter_"+i).start();
           }
   
           for(int i=0; i<5; ++i) {
               new Thread(() -> {
                   while (true) {
                       try {
                           Thread.sleep(rnd.nextInt(5000));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
   
                       System.err.println("Clearing");
   
                       map.clear();
   
                       System.err.println("Cleared");
                   }
               }, "clearer_"+i).start();
           }
   
           Thread.sleep(5*60000);
       }
   ```
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401070042
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,336 @@
+package org.apache.ignite.internal.processors.service;
+
+import com.google.common.collect.Iterables;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.spi.metric.jmx.JmxMetricExporterSpi;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Test;
+
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.MAX_ABBREVIATE_NAME_LVL;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.serviceMetricRegistryName;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.sumHistogramEntries;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.SERVICE_METRIC_REGISTRY;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.methodMetricName;
+
+/** Tests metrics of service invocations. */
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401141419
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
 
 Review comment:
   As far as I know, concurrent put/get/remove are not atomic but are safe meaning won't fail, throw an exception. You can only get null when a value exist, or a value when it is already removed.
   
   Please, take a look to this simple test. Forks for me. Gives null periodically, and, I believe, inconsistent values. But no any lock/crash scenario. What else should we check?
   
   ```
   @Test
       public void testMapConcurrency() throws InterruptedException {
           final Map<Integer, Integer> map = new HashMap<>(1);
           final Random rnd = new Random();
           final int valueCnt = 100000;
           final Integer[] holder = new Integer[1];
   
           for(int i=0; i<5; ++i) {
               new Thread(() -> {
                   while (true) {
                       for (int v = 0; v < valueCnt; ++v)
                           map.put(v, rnd.nextInt(valueCnt));
   
                       System.err.println("Filled");
   
                       try {
                           Thread.sleep(rnd.nextInt(5000));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
               }, "putter_"+i).start();
           }
   
           for(int i=0; i<30; ++i) {
               new Thread(() -> {
                   while (true) {
   
                       try {
                           holder[0] = map.get(rnd.nextInt(valueCnt));
   
                           Thread.sleep(rnd.nextInt(50));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                       catch (Exception e) {
                           e.printStackTrace();
                       }
                   }
               }, "getter_"+i).start();
           }
   
           for(int i=0; i<5; ++i) {
               new Thread(() -> {
                   while (true) {
                       try {
                           Thread.sleep(rnd.nextInt(5000));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
   
                       System.err.println("Clearing");
   
                       map.clear();
   
                       System.err.println("Cleared");
                   }
               }, "clearer_"+i).start();
           }
   
           Thread.sleep(5*60000);
       }
   ```
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401133474
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
 
 Review comment:
   Same here. You are right about usage of separate method. But the synchronization you suggest seems already relies in the logic above. I don’t think `IgniteServiceProcessor.undeploy()` and ` IgniteServiceProcessor.redeploy()` can happen concurrently but we should consider it can, ok. Let’s see:
   -	Metrics are erased by `IgniteServiceProcessor.unregisterMetrics()` in 2 places (): `IgniteServiceProcessor.redeploy()` and `IgniteServiceProcessor.undeploy()`. Both leads to removing whole map by service name ‘invocationHistograms.remove(srvcName);’
   -	Metrics are created by `IgniteServiceProcessor.registerMetrics()`  in one place: `IgniteServiceProcessor.redeploy()`.
   
   These calls are not any APIs, are private.
   
   All 3 calls covered with sync by service context collection given bt same serviced:
   ```
   Collection<ServiceContextImpl> ctxs …
   synchronized (ctxs) {
   	unregisterMetrics(cfg.getName());
           }
   ```
   and
   ```
   Collection<ServiceContextImpl> ctxs …
               synchronized (ctxs) {
                   if (!ctxs.iterator().next().isCancelled())
                       registerMetrics(srvc, srvcCtx.name());
               } 
   ```
   
   I think I really missed the last part earlier. Thanks for the note. Isn’t it the synchronized block you suggest?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401101543
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
 
 Review comment:
   In this case we need to skip metric if it exists and described in the javadoc: 
   
   ```
   Creates histogram for service method. If exists, considers one or several argument types has same name but
        * different package and tries to extend metric name with abbreviation of java package name.
   ```
   
   Please see `NamingService` and `GridServiceMetricsTest.testMetricNaming()`

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on issue #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on issue #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#issuecomment-608468769
 
 
   Migrated to better solution: https://github.com/apache/ignite/pull/7622.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400813600
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
 
 Review comment:
   @NSAmelchev , the problem is:
   
   ```
   interface A {
           void foo();
       }
   
       interface B extends A {
           @Override void foo();
       }
   
       static class C implements Service, B {
           @Override public void foo() {
               System.err.println("foo");
           }
       }
   
      @Test
       public void test() throws Exception {
           Method methodA = A.class.getMethod("foo");
           Method methodB = B.class.getMethod("foo");
           Method methodC = C.class.getMethod("foo");
   
           assertEquals(methodA, methodB);
           assertEquals(methodA, methodC);
   
           assertEquals(methodB, methodA);
           assertEquals(methodB, methodC);
   
           assertEquals(methodC, methodA);
           assertEquals(methodC, methodB);
       }
   ```
   
   They are not equal. And yes, significant invocation boost. If we keep direct link to not-overloaded method, we avoid:
   
   1) Creation new Method() (`getMethod()` always create new one)
   2) Creation new Object[] when calling `Method.getParameterTypes()` to identify method.
   3) We do not search overloaded methods map at all. We get method by it name.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r384501941
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -188,6 +210,80 @@
     /** Disconnected flag. */
     private volatile boolean disconnected;
 
+    /**
+     * Creates proper registry name for service metrics.
+     *
+     * @param srvcName Name of the service.
+     * @return Registry name.
+     */
+    static String serviceMetricsName(String srvcName) {
+        return metricName(METRIC_REGISTRY_INVOCATIONS, srvcName);
+    }
+
+    /**
+     * @param method       Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. @see #abbreviatePgkName(Class, int).
+     * @return Metric name for {@code method}. Doesn't guaratee same name with same {@code pkgNameDepth} is used for
+     * real metric registry.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        // Name of the return type. Better for human readability.
+        sb.append(method.getReturnType() == null ? Void.class.getSimpleName() :
+            abbreviatePgkName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviatePgkName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /**
+     * @param pkgNameDepth Exhibition level of java package name. The bigger, the wider:
+     *                     <pre>
+     *                         0 - wont add package name;
+     *                         1 - add only first char of each name in java package;
+     *                         2 - add first and last char of each name in java package;
+     *                         Any other - add full java package name.
+     *                     </pre>
+     * @return Abbreviated name of the type {@code cl}.
+     */
+    private static String abbreviatePgkName(Class<?> cl, int pkgNameDepth) {
 
 Review comment:
   I suggest moving static utility methods to some utility class. For example `MetricUtils`, `IgniteUtils`.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385211180
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceContextImpl.java
 ##########
 @@ -136,24 +140,70 @@ ExecutorService executor() {
      * @return Method.
      */
     @Nullable Method method(GridServiceMethodReflectKey key) {
-        Method mtd = mtds.get(key);
+        IgniteBiTuple<Method, HistogramMetricImpl> mtdRecord = methodRecord(key);
+
+        Method mtd = mtdRecord.get1();
 
         if (mtd == null) {
-            try {
-                mtd = svc.getClass().getMethod(key.methodName(), key.argTypes());
+            synchronized (mtdRecord) {
+                mtd = mtdRecord.get1();
 
-                mtd.setAccessible(true);
-            }
-            catch (NoSuchMethodException ignored) {
-                mtd = NULL_METHOD;
-            }
+                if (mtd == null) {
+                    try {
+                        mtd = svc.getClass().getMethod(key.methodName(), key.argTypes());
 
-            mtds.put(key, mtd);
+                        mtd.setAccessible(true);
+                    }
+                    catch (NoSuchMethodException ignored) {
+                        mtd = NULL_METHOD;
+                    }
+
+                    mtdRecord.set1(mtd);
+                }
+            }
         }
 
         return mtd == NULL_METHOD ? null : mtd;
     }
 
+    /**
+     * @param key Method key.
+     * @param histogrammInitiator Histogramm supplier if the histogramm isn't initialized yet.
+     * @return Service method performance histogramm.
+     */
+    @Nullable HistogramMetricImpl invokeHistogramm(GridServiceMethodReflectKey key,
+        Supplier<HistogramMetricImpl> histogrammInitiator) {
+        IgniteBiTuple<Method, HistogramMetricImpl> mtdRecord = methodRecord(key);
+
+        HistogramMetricImpl histogramm = mtdRecord.get2();
+
+        if (histogramm == null) {
 
 Review comment:
   Refactored.

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r402763136
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/IgniteServicesImpl.java
 ##########
 @@ -75,6 +75,30 @@ public IgniteServicesImpl(GridKernalContext ctx, ClusterGroupAdapter prj, boolea
         return prj;
     }
 
+    /** {@inheritDoc} */
+    @Override public ServiceConfiguration clusterSingletonConfiguration(String name, Service svc) {
+        return ctx.service().serviceConfiguration(name, svc, 1, 1);
+    }
+
+    /** {@inheritDoc} */
+    @Override public ServiceConfiguration nodeSingletonConfiguration(String name, Service svc) {
+        return ctx.service().serviceConfiguration(name, svc, 0, 1);
+    }
+
+    /** {@inheritDoc} */
+    @Override public ServiceConfiguration keyAffinitySingletonConfiguration(String name, Service svc, String cacheName,
 
 Review comment:
   According to codestyle, you should rewrite declaration as
   ``` 
   public ServiceConfiguration keyAffinitySingletonConfiguration(
       String name,
       Service svc,
       String cacheName,
       Object affKey
   ) {
     ......
   ```

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385211063
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceContextImpl.java
 ##########
 @@ -56,8 +59,9 @@
     @GridToStringExclude
     private final ExecutorService exe;
 
-    /** Methods reflection cache. */
-    private final ConcurrentMap<GridServiceMethodReflectKey, Method> mtds = new ConcurrentHashMap<>();
+    /** Keeps cached data bound to service method. */
+    private final ConcurrentMap<GridServiceMethodReflectKey, IgniteBiTuple<Method, HistogramMetricImpl>> mtds =
 
 Review comment:
   The map has been split.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401133474
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
 
 Review comment:
   Same here. Service deploying/un deploying are guided by discovery messages which are serial. Actually, all we do here we do in single thread. WDYT?

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r402762503
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MetricUtils.java
 ##########
 @@ -163,4 +168,66 @@ private static boolean ensureAllNamesNotEmpty(String... names) {
 
         return names;
     }
+
+    /**
+     * Abbreviates package name for metric naming purposes.
+     *
+     * @param pkgNameDepth Exhibition level of java package name. The bigger, the wider.
+     *                     Max level is {@link #MAX_ABBREVIATE_NAME_LVL}. Values:
+     *                     <pre>
+     *                         0 or negative - wont add package name;
+     *                         1 - add first and last char of each name in java package;
+     *                         2 or bigger - add full name of java package.
+     *                     </pre>
+     * @return Abbreviated name of {@code cls}.
+     */
+    public static String abbreviateName(Class<?> cls, int pkgNameDepth) {
+        if (pkgNameDepth < 1)
+            return cls.getSimpleName();
+
+        if (pkgNameDepth >= MAX_ABBREVIATE_NAME_LVL)
+            return cls.getName();
+
+        String[] pkgNameParts = cls.getName().split("\\.");
+
+        // No package like 'void' or 'int'.
+        if (pkgNameParts.length == 1)
+            return pkgNameParts[0];
+
+        StringBuilder sb = new StringBuilder();
+
+        for (int i = 0; i < pkgNameParts.length - 1; ++i) {
+            sb.append(pkgNameParts[i].charAt(0));
+
+            if (pkgNameParts[i].length() > 1)
+                sb.append(pkgNameParts[i].charAt(pkgNameParts[i].length() - 1));
+
+            sb.append(".");
+        }
+
+        // Add name to the class.
+        sb.append(pkgNameParts[pkgNameParts.length - 1]);
+
+        return sb.toString();
+    }
+
+    /**
+     * Gives proper name for service metric registry.
+     *
+     * @param srvcName Name of the service.
+     * @return registry name for service {@code srvcName}.
+     */
+    public static String serviceMetricRegistryName(String srvcName) {
+        return metricName(SERVICE_METRIC_REGISTRY, srvcName);
+    }
+
+    /**
+     * Count total of histogram values.
+     *
+     * @param histogram Histogram to traverse.
+     * @return Sum of all entries of {@code histogram} buckets.
+     */
+    public static long sumHistogramEntries(HistogramMetric histogram) {
 
 Review comment:
   What if histogram is null? I suppose we should check this.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401068478
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
 
 Review comment:
   @ivandasch , there is a gap between
   `metricRegistry.findMetric(methodMetricName)`
   and
   `metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
                           DESCRIPTION_OF_INVOCATION_METRIC)`
   
   It is important. If something creates metric after `metricRegistry.findMetric(methodMetricName)`, it would cause incorrent metric naming or NPE.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401115708
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -188,6 +216,9 @@
     /** Disconnected flag. */
     private volatile boolean disconnected;
 
+    /** Keeps histograms to measure durations of service methods. Guided by service name, then method name. */
+    private final Map<String, Map<String, MethodHistogramHolder>> invocationHistograms = new HashMap<>(1);
 
 Review comment:
   This is not cached variable, not a class property. It is re-requested every time. Yes, some gap in getting histogram is possible. But why long?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385230354
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1156,10 +1274,15 @@ void redeploy(IgniteUuid srvcId, ServiceConfiguration cfg,
 
         Collection<ServiceContextImpl> toInit = new ArrayList<>();
 
+        ServiceContextImpl firstInitialized = !metricsEnabled || ctxs.isEmpty() ? null : ctxs.iterator().next();
 
 Review comment:
   The map will be held by IgniteServiceProcessor. This would force using not-static LocalInvocationHandler. Also, there is the ServiceContext to keep something about certain service. Making the map outside it can make similar question: why not in service context?

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400892563
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,336 @@
+package org.apache.ignite.internal.processors.service;
+
+import com.google.common.collect.Iterables;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.spi.metric.jmx.JmxMetricExporterSpi;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Test;
+
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.MAX_ABBREVIATE_NAME_LVL;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.serviceMetricRegistryName;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.sumHistogramEntries;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.SERVICE_METRIC_REGISTRY;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.methodMetricName;
+
+/** Tests metrics of service invocations. */
 
 Review comment:
   Here and below:
   according to codestyle, on-line javadocs doesn't permitted for class and for methods.
   Exception only for `/** {@inheritDoc} */`

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385229477
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -976,6 +1061,39 @@ private boolean hasLocalNode(ClusterGroup prj) {
         return false;
     }
 
+    /**
+     * Creates metric for service method. If the metric exists then considers one or several argument types has same
+     * name but different packages. Then skips existing metric and tries to extend metric name with abbreviation of
+     * java package name. See {@link MetricUtils#abbreviateName(Class, int)}.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl invocationsMetric(String srvcName, Method method) {
+        MetricRegistry metricRegistry = null;
+
+        metricRegistry = ctx.metric().registry(metricRegistryName(srvcName));
 
 Review comment:
   Can be inlined

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401088897
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
 
 Review comment:
   Well, lets take a look over the javaDoc
   
   The default implementation **makes no guarantees about synchronization or atomicity properties** of this method. Any implementation providing atomicity guarantees must override this method and document its concurrency properties. In particular, all implementations of subinterface java.util.concurrent.ConcurrentMap must document whether the function is applied once atomically only if the value is not present.
   

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385077958
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,418 @@
+package org.apache.ignite.internal.processors.service;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICE_METRICS_ENABLED;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.METRIC_REGISTRY_INVOCATIONS;
+
+/** */
+public class GridServiceMetricsTest extends GridCommonAbstractTest {
+    /** Number of service invcations. */
+    private static final int INVOKE_CNT = 50;
+
+    /** Utility holder of current grid number. */
+    private final AtomicInteger gridNum = new AtomicInteger();
+
+    /** */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /** */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        System.clearProperty(IGNITE_SERVICE_METRICS_ENABLED);
+    }
+
+    /** Makes sure {@code IgniteSystemProperties#IGNITE_SERVICE_METRICS_ENABLED} works correctly. */
+    @Test
+    public void testMetricsEnabledDisabled() throws Throwable {
+        IgniteEx server = startGrid(0);
+
+        assertFalse("Service metric registry must not be created yet.",
+            findMetric(server.context().metric(), METRIC_REGISTRY_INVOCATIONS));
+
+        String srvcName = "testMetricsEnabledService";
+
+        server.services().deploy(serviceCfg(srvcName, 1, 1));
+
+        assertTrue("Service metric registry must be already created.",
+            findMetric(server.context().metric(), METRIC_REGISTRY_INVOCATIONS));
+
+        stopAllGrids();
+
+        System.setProperty(IGNITE_SERVICE_METRICS_ENABLED, "false");
 
 Review comment:
   The system property is not cleared after the test (may affect other tests). Lets use  `@WithSystemProperty` or `try .. finally`

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400813600
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
 
 Review comment:
   @NSAmelchev , the problem is:
   
   `interface A {
           void foo();
       }
   
       interface B extends A {
           @Override void foo();
       }
   
       static class C implements Service, B {
           @Override public void foo() {
               System.err.println("foo");
           }
       }
   
      @Test
       public void test() throws Exception {
           Method methodA = A.class.getMethod("foo");
           Method methodB = B.class.getMethod("foo");
           Method methodC = C.class.getMethod("foo");
   
           assertEquals(methodA, methodB);
           assertEquals(methodA, methodC);
   
           assertEquals(methodB, methodA);
           assertEquals(methodB, methodC);
   
           assertEquals(methodC, methodA);
           assertEquals(methodC, methodB);
       }`
   
   They are not equal. And yes, significant invocation boost. If we keep direct link to not-overloaded method, we avoid:
   
   1) Creation new Method() (`getMethod()` always create new one)
   2) Creation new Object[] when calling `Method.getParameterTypes()` to identify method.
   3) We do not search overloaded methods map at all. We get method by it name.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385167733
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,418 @@
+package org.apache.ignite.internal.processors.service;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICE_METRICS_ENABLED;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.METRIC_REGISTRY_INVOCATIONS;
+
+/** */
+public class GridServiceMetricsTest extends GridCommonAbstractTest {
+    /** Number of service invcations. */
+    private static final int INVOKE_CNT = 50;
+
+    /** Utility holder of current grid number. */
+    private final AtomicInteger gridNum = new AtomicInteger();
+
+    /** */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /** */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        System.clearProperty(IGNITE_SERVICE_METRICS_ENABLED);
+    }
+
+    /** Makes sure {@code IgniteSystemProperties#IGNITE_SERVICE_METRICS_ENABLED} works correctly. */
+    @Test
+    public void testMetricsEnabledDisabled() throws Throwable {
+        IgniteEx server = startGrid(0);
+
+        assertFalse("Service metric registry must not be created yet.",
+            findMetric(server.context().metric(), METRIC_REGISTRY_INVOCATIONS));
+
+        String srvcName = "testMetricsEnabledService";
+
+        server.services().deploy(serviceCfg(srvcName, 1, 1));
+
+        assertTrue("Service metric registry must be already created.",
+            findMetric(server.context().metric(), METRIC_REGISTRY_INVOCATIONS));
+
+        stopAllGrids();
+
+        System.setProperty(IGNITE_SERVICE_METRICS_ENABLED, "false");
 
 Review comment:
   Not redundant. The test shouldn't affect other tests.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400467296
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/inner/NamingServiceImpl.java
 ##########
 @@ -0,0 +1,31 @@
+package org.apache.ignite.internal.processors.service.inner;
+
+import org.apache.ignite.services.ServiceContext;
+
+/** {@inheritDoc} */
+public class NamingServiceImpl implements NamingService {
+    /** {@inheritDoc} */
+    @Override public int process(org.apache.ignite.internal.processors.service.inner.impl.Param param) {
+        return param.value();
+    }
+
+    /** {@inheritDoc} */
+    @Override public int process(org.apache.ignite.internal.processors.service.inner.experimental.Param param) {
+        return param.value();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void cancel(ServiceContext ctx) {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void init(ServiceContext ctx) throws Exception {
 
 Review comment:
   `throws Exception` is redundant.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385225142
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1156,10 +1274,15 @@ void redeploy(IgniteUuid srvcId, ServiceConfiguration cfg,
 
         Collection<ServiceContextImpl> toInit = new ArrayList<>();
 
+        ServiceContextImpl firstInitialized = !metricsEnabled || ctxs.isEmpty() ? null : ctxs.iterator().next();
 
 Review comment:
   I suggest keeping metric in a Map: service name -> method metrics. (if names are unique) Like `Map<String, Map<Method, HistogramMetricImpl>>`. WDYT?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400768450
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/inner/NamingServiceImpl.java
 ##########
 @@ -0,0 +1,31 @@
+package org.apache.ignite.internal.processors.service.inner;
+
+import org.apache.ignite.services.ServiceContext;
+
+/** {@inheritDoc} */
+public class NamingServiceImpl implements NamingService {
+    /** {@inheritDoc} */
+    @Override public int process(org.apache.ignite.internal.processors.service.inner.impl.Param param) {
+        return param.value();
+    }
+
+    /** {@inheritDoc} */
+    @Override public int process(org.apache.ignite.internal.processors.service.inner.experimental.Param param) {
+        return param.value();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void cancel(ServiceContext ctx) {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void init(ServiceContext ctx) throws Exception {
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 closed pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 closed pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446
 
 
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400813600
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
 
 Review comment:
   @NSAmelchev , the problem is:
   
   ```interface A {
           void foo();
       }
   
       interface B extends A {
           @Override void foo();
       }
   
       static class C implements Service, B {
           @Override public void foo() {
               System.err.println("foo");
           }
       }
   
      @Test
       public void test() throws Exception {
           Method methodA = A.class.getMethod("foo");
           Method methodB = B.class.getMethod("foo");
           Method methodC = C.class.getMethod("foo");
   
           assertEquals(methodA, methodB);
           assertEquals(methodA, methodC);
   
           assertEquals(methodB, methodA);
           assertEquals(methodB, methodC);
   
           assertEquals(methodC, methodA);
           assertEquals(methodC, methodB);
       }```
   
   They are not equal. And yes, significant invocation boost. If we keep direct link to not-overloaded method, we avoid:
   
   1) Creation new Method() (`getMethod()` always create new one)
   2) Creation new Object[] when calling `Method.getParameterTypes()` to identify method.
   3) We do not search overloaded methods map at all. We get method by it name.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385071924
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,418 @@
+package org.apache.ignite.internal.processors.service;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICE_METRICS_ENABLED;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.METRIC_REGISTRY_INVOCATIONS;
+
+/** */
+public class GridServiceMetricsTest extends GridCommonAbstractTest {
+    /** Number of service invcations. */
+    private static final int INVOKE_CNT = 50;
+
+    /** Utility holder of current grid number. */
+    private final AtomicInteger gridNum = new AtomicInteger();
+
+    /** */
 
 Review comment:
   Use `    /** {@inheritDoc} */`

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400457537
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i < MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append("_");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
+        MethodHistogramHolder histogramHolder = Optional.ofNullable(invocationHistograms.get(srvcName))
+            .orElse(Collections.emptyMap()).get(mtd.getName());
+
+        return histogramHolder == null ? null : histogramHolder.getHistogram(mtd);
+    }
+
+    /**
+     * Histogram holder for service methods. Helps to fasten invocation of not-overloaded methods.
+     * Keeps either map of histograms for overloaded method or single histogram.
+     */
+    private static final class MethodHistogramHolder {
+        /** Not overloaded method. */
+        private Method singleMtd;
+
+        /** Histogram if method is not overloaded. */
+        private HistogramMetricImpl singleHistogram;
+
+        /** Histograms for overloaded method. */
+        private Map<Object, HistogramMetricImpl> overloadedMtd;
+
+        /**
+         * Saves new histogram.
+         *
+         * @param mtd Method to keep histogram for.
+         * @param initiator Histogram creator.
+         */
+        private synchronized void addIfAbsent(Method mtd, Supplier<HistogramMetricImpl> initiator) {
+            if (singleMtd == null && overloadedMtd == null) {
+                singleMtd = mtd;
+
+                singleHistogram = initiator.get();
+            }
+            else if (!isSameSingleMtd(mtd) && (overloadedMtd == null || !overloadedMtd.containsKey(key(mtd)))) {
+                overloadedMtd = new HashMap<>(2);
+
+                overloadedMtd.put(key(singleMtd), singleHistogram);
 
 Review comment:
   I create the void empty method 
   ```
   public interface NamingService extends Service {
       ...
       default void process() {}
       ...
   }
   ```
   run tests and catch exception: 
   ```
   java.lang.NullPointerException
   	at org.apache.ignite.internal.processors.service.IgniteServiceProcessor$MethodHistogramHolder.key(IgniteServiceProcessor.java:1995)
   	at org.apache.ignite.internal.processors.service.IgniteServiceProcessor$MethodHistogramHolder.addIfAbsent(IgniteServiceProcessor.java:1979)
   	at org.apache.ignite.internal.processors.service.IgniteServiceProcessor$MethodHistogramHolder.access$1100(IgniteServiceProcessor.java:1954)
   	at org.apache.ignite.internal.processors.service.IgniteServiceProcessor.lambda$registerMetrics$14(IgniteServiceProcessor.java:1864)
   ```

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400461006
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
 
 Review comment:
   Why not just create `Map<Method, HistogramMetricImpl>`? Is it have a significant performance boost?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on issue #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on issue #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#issuecomment-588933230
 
 
   Major changes:
   1)	The services are now proxied with IgniteServiceProcessor# LocalInvocationHandler
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401113540
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
 
 Review comment:
   I'm talking about whole usage, not certain method. This method is not a public API, not an internal API. It is called from one place. Result of this method is not cached into any variable. What may happen:
   Service method is being invoked concurrently with metrics registration. Service is already initialized. The method works. Metrics is already actually put, but `srvHistos.get` returned null. Well, we just skip measuring a coulpe of calls. It is rare case and doesn't affect whole histogram. What could be wrong here? What I missed?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401141419
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
 
 Review comment:
   As far as I know, concurrent put/get/remove are not atomic but are safe for values like int of Reference. Meaning, they do not fail or throw an exception. You can only get null when a value exist, or a value when it is already removed. Iteration is a problem, yes. We do not iterate.
   
   Please, take a look to this simple test. Forks for me. Gives null periodically, and, I believe, inconsistent values. But no any lock/crash scenario. What else should we check?
   
   ```
   @Test
       public void testMapConcurrency() throws InterruptedException {
           final Map<Integer, Integer> map = new HashMap<>(1);
           final Random rnd = new Random();
           final int valueCnt = 100000;
           final Integer[] holder = new Integer[1];
   
           for(int i=0; i<5; ++i) {
               new Thread(() -> {
                   while (true) {
                       for (int v = 0; v < valueCnt; ++v)
                           map.put(v, rnd.nextInt(valueCnt));
   
                       System.err.println("Filled");
   
                       try {
                           Thread.sleep(rnd.nextInt(5000));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
               }, "putter_"+i).start();
           }
   
           for(int i=0; i<30; ++i) {
               new Thread(() -> {
                   while (true) {
   
                       try {
                           holder[0] = map.get(rnd.nextInt(valueCnt));
   
                           Thread.sleep(rnd.nextInt(50));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                       catch (Exception e) {
                           e.printStackTrace();
                       }
                   }
               }, "getter_"+i).start();
           }
   
           for(int i=0; i<5; ++i) {
               new Thread(() -> {
                   while (true) {
                       try {
                           Thread.sleep(rnd.nextInt(5000));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
   
                       System.err.println("Clearing");
   
                       map.clear();
   
                       System.err.println("Cleared");
                   }
               }, "clearer_"+i).start();
           }
   
           Thread.sleep(5*60000);
       }
   ```
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385210322
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,418 @@
+package org.apache.ignite.internal.processors.service;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICE_METRICS_ENABLED;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.METRIC_REGISTRY_INVOCATIONS;
+
+/** */
+public class GridServiceMetricsTest extends GridCommonAbstractTest {
+    /** Number of service invcations. */
+    private static final int INVOKE_CNT = 50;
+
+    /** Utility holder of current grid number. */
+    private final AtomicInteger gridNum = new AtomicInteger();
+
+    /** */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /** */
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401133474
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
 
 Review comment:
   Same here. You are right about usage of separate method. But the synchronization you suggest seems already relies in the logic above. I don’t think `IgniteServiceProcessor.undeploy()` and ` IgniteServiceProcessor.redeploy()` can happen concurrently but we should consider it can, ok. Let’s see:
   -	Metrics are erased by `IgniteServiceProcessor.unregisterMetrics()` in 2 places (): `IgniteServiceProcessor.redeploy()` and `IgniteServiceProcessor.undeploy()`.
   -	Metrics are created by `IgniteServiceProcessor.registerMetrics()`  in one place: `IgniteServiceProcessor.redeploy()`.
   
   These calls are not any APIs, are private.
   
   All all the calls are covered with synchronized on collection of service contexts given by same service id:
   ```
   Collection<ServiceContextImpl> ctxs …
   synchronized (ctxs) {
   	unregisterMetrics(cfg.getName());
   }
   ```
   and
   ```
   Collection<ServiceContextImpl> ctxs …
   synchronized (ctxs) {
      if (!ctxs.iterator().next().isCancelled())
         registerMetrics(srvc, srvcCtx.name());
    } 
   ```
   
   I think I really missed the last part earlier. Thanks for the note. Isn’t it the synchronized block you suggest?

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401099749
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
 
 Review comment:
   As I wrote above, there is no guarantee that `srvHistos.get` would work correctly and return something meaningfull without synchronization. Synchronized block guarantees that if we obtain monitor  and read from map after releasing it after write to map, that write **happened-before** read. 

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385210187
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceContextImpl.java
 ##########
 @@ -136,24 +140,70 @@ ExecutorService executor() {
      * @return Method.
      */
     @Nullable Method method(GridServiceMethodReflectKey key) {
-        Method mtd = mtds.get(key);
+        IgniteBiTuple<Method, HistogramMetricImpl> mtdRecord = methodRecord(key);
+
+        Method mtd = mtdRecord.get1();
 
         if (mtd == null) {
-            try {
-                mtd = svc.getClass().getMethod(key.methodName(), key.argTypes());
+            synchronized (mtdRecord) {
+                mtd = mtdRecord.get1();
 
-                mtd.setAccessible(true);
-            }
-            catch (NoSuchMethodException ignored) {
-                mtd = NULL_METHOD;
-            }
+                if (mtd == null) {
+                    try {
+                        mtd = svc.getClass().getMethod(key.methodName(), key.argTypes());
 
-            mtds.put(key, mtd);
+                        mtd.setAccessible(true);
+                    }
+                    catch (NoSuchMethodException ignored) {
+                        mtd = NULL_METHOD;
+                    }
+
+                    mtdRecord.set1(mtd);
+                }
+            }
         }
 
         return mtd == NULL_METHOD ? null : mtd;
     }
 
+    /**
+     * @param key Method key.
+     * @param histogrammInitiator Histogramm supplier if the histogramm isn't initialized yet.
+     * @return Service method performance histogramm.
+     */
+    @Nullable HistogramMetricImpl invokeHistogramm(GridServiceMethodReflectKey key,
+        Supplier<HistogramMetricImpl> histogrammInitiator) {
+        IgniteBiTuple<Method, HistogramMetricImpl> mtdRecord = methodRecord(key);
+
+        HistogramMetricImpl histogramm = mtdRecord.get2();
+
+        if (histogramm == null) {
+            synchronized (mtdRecord) {
+                histogramm = mtdRecord.get2();
+
+                if (histogramm == null) {
+                    histogramm = histogrammInitiator.get();
+
+                    assert histogramm != null;
+
+                    mtdRecord.set2(histogramm);
+                }
+            }
+        }
+
+        return histogramm;
+    }
+
+    /** Creates utility recod by method key {@code key}. Thread-safe.  */
+    private IgniteBiTuple<Method, HistogramMetricImpl> methodRecord(GridServiceMethodReflectKey key) {
+        return mtds.compute(key, (k, v) -> {
 
 Review comment:
   Refactored.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r384492586
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -113,6 +123,15 @@
     /** */
     public static final String SVCS_VIEW_DESC = "Services";
 
+    /** Base name domain for invocation metrics. @see {@link #invocationsMetric(String, Method)}. */
 
 Review comment:
   `@see` annotation isn't work for inline comment. I suggest: `See {@link #invocationsMetric(String, Method)}.`

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385210551
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,418 @@
+package org.apache.ignite.internal.processors.service;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICE_METRICS_ENABLED;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.METRIC_REGISTRY_INVOCATIONS;
+
+/** */
+public class GridServiceMetricsTest extends GridCommonAbstractTest {
+    /** Number of service invcations. */
+    private static final int INVOKE_CNT = 50;
+
+    /** Utility holder of current grid number. */
+    private final AtomicInteger gridNum = new AtomicInteger();
+
+    /** */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /** */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        System.clearProperty(IGNITE_SERVICE_METRICS_ENABLED);
+    }
+
+    /** Makes sure {@code IgniteSystemProperties#IGNITE_SERVICE_METRICS_ENABLED} works correctly. */
+    @Test
+    public void testMetricsEnabledDisabled() throws Throwable {
+        IgniteEx server = startGrid(0);
+
+        assertFalse("Service metric registry must not be created yet.",
+            findMetric(server.context().metric(), METRIC_REGISTRY_INVOCATIONS));
+
+        String srvcName = "testMetricsEnabledService";
+
+        server.services().deploy(serviceCfg(srvcName, 1, 1));
+
+        assertTrue("Service metric registry must be already created.",
+            findMetric(server.context().metric(), METRIC_REGISTRY_INVOCATIONS));
+
+        stopAllGrids();
+
+        System.setProperty(IGNITE_SERVICE_METRICS_ENABLED, "false");
 
 Review comment:
   Fixed with try-finally.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on issue #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on issue #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#issuecomment-607779282
 
 
   > Also, I suppose, that we should leave to user the final conclusion to instrument methods of
   > his or her service or not. I would suggest to add a bit of API for users, 
   
   Ok, many people propose to give user the decision to enable/disable service metrics. Makes sense. My + is for Andrey Gura’s suggestion ( http://apache-ignite-developers.2346864.n4.nabble.com/Reference-of-local-service-tp46071p46307.html ) :
   “we should provide a way for configuring service metrics (in
   sense of enabled/disabled) during service deploy. It's easy for cases
   where deploy() methods have ServiceConfiguration as parameter.”
   
   The reasons:
   -	It is quite obvious. Good place without any other condition.
   -	CacheConfiguration has same property. Analogous approach simplifies product for user.
   -	Might work with some global “metrics_enable
   
   So, I’ve introduced ServiceConfiguration.isStatisticsEnabled and the supporting methods.
   
   
   

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400903767
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MetricUtils.java
 ##########
 @@ -163,4 +168,66 @@ private static boolean ensureAllNamesNotEmpty(String... names) {
 
         return names;
     }
+
+    /**
+     * Abbreviates package name for metric naming purposes.
+     *
+     * @param pkgNameDepth Exhibition level of java package name. The bigger, the wider.
+     *                     Max level is {@link #MAX_ABBREVIATE_NAME_LVL}. Values:
+     *                     <pre>
+     *                         0 or negative - wont add package name;
+     *                         1 - add first and last char of each name in java package;
+     *                         2 or bigger - add full name of java package.
+     *                     </pre>
+     * @return Abbreviated name of {@code cls}.
+     */
+    public static String abbreviateName(Class<?> cls, int pkgNameDepth) {
+        if (pkgNameDepth < 1)
+            return cls.getSimpleName();
+
+        if (pkgNameDepth >= MAX_ABBREVIATE_NAME_LVL)
+            return cls.getName();
+
+        String[] pkgNameParts = cls.getName().split("\\.");
+
+        // No package like 'void' or 'int'.
+        if (pkgNameParts.length == 1)
+            return pkgNameParts[0];
+
+        StringBuilder sb = new StringBuilder();
+
+        for (int i = 0; i < pkgNameParts.length - 1; ++i) {
+            sb.append(pkgNameParts[i].charAt(0));
+
+            if (pkgNameParts[i].length() > 1)
+                sb.append(pkgNameParts[i].charAt(pkgNameParts[i].length() - 1));
+
+            sb.append(".");
+        }
+
+        // Add name to the class.
+        sb.append(pkgNameParts[pkgNameParts.length - 1]);
+
+        return sb.toString();
+    }
+
+    /**
+     * Gives proper name for service metric registry.
+     *
+     * @param srvcName Name of the service.
+     * @return registry name for service {@code srvcName}.
+     */
+    public static String serviceMetricRegistryName(String srvcName) {
+        return metricName(SERVICE_METRIC_REGISTRY, srvcName);
+    }
+
+    /**
+     * Count total of histogram values.
+     *
+     * @param histogram Histogram to traverse.
+     * @return Sum of all entries of {@code histogram} buckets.
+     */
+    public static long sumHistogramEntries(HistogramMetric histogram) {
 
 Review comment:
   I suppose that simple for loop over array of primitives is better. 

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401069532
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -188,6 +216,9 @@
     /** Disconnected flag. */
     private volatile boolean disconnected;
 
+    /** Keeps histograms to measure durations of service methods. Guided by service name, then method name. */
+    private final Map<String, Map<String, MethodHistogramHolder>> invocationHistograms = new HashMap<>(1);
 
 Review comment:
   @ivandasch, I considered using `ConcurrentHashMap`. I didn’t see a case for it. Getting histogram should be quick. You can find there are no iteration over the map and parallel puts/removes. The map isn’t available outside. I think it can occur that service method might be concurrently invoked when service is being undeployed. It would lead we get null-histogram. There is npe-protection for this case in `GridServiceProxy.callServiceMethod()`: 
   ```
                   if (histogram != null)
                       histogram.value(duration);
   ```

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385211339
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/ComputeJobCancelWithServiceSelfTest.java
 ##########
 @@ -85,7 +93,7 @@ public void testJobCancel() throws Exception {
         /**
          * @return Response.
          */
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400887678
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,336 @@
+package org.apache.ignite.internal.processors.service;
+
+import com.google.common.collect.Iterables;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.spi.metric.jmx.JmxMetricExporterSpi;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Test;
+
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.MAX_ABBREVIATE_NAME_LVL;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.serviceMetricRegistryName;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.sumHistogramEntries;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.SERVICE_METRIC_REGISTRY;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.methodMetricName;
+
+/** Tests metrics of service invocations. */
+public class GridServiceMetricsTest extends GridCommonAbstractTest {
+    /** Number of service invocations. */
+    private static final int INVOKE_CNT = 100;
+
+    /** Utility holder of current grid number. */
+    private final AtomicInteger gridNum = new AtomicInteger();
+
+    /** Service name used in the tests. */
+    private static final String SRVC_NAME = GridServiceMetricsTest.class.getSimpleName()+"_service";
+
+    /** Error message of created metrics. */
+    private static final String METRICS_MUST_NOT_BE_CREATED = "Service metric registry must not be created.";
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        // JMX metrics exposition for debug launch mode.
+        cfg.setMetricExporterSpi(new JmxMetricExporterSpi());
+
+        return cfg;
+    }
+
+    /** Checks metric behaviour when launched several service instances via #IgniteServices#deployMultiple */
+    @Test
+    public void testMultipleDeployment() throws Throwable {
+        List<IgniteEx> servers = new ArrayList<>();
+
+        servers.add(startGrid(gridNum.getAndIncrement()));
+
+        IgniteEx server = servers.get(0);
+
+        IgniteEx client = startClientGrid(gridNum.getAndIncrement());
+
+        assertNull(METRICS_MUST_NOT_BE_CREATED, findMetricRegistry(server.context().metric(), SERVICE_METRIC_REGISTRY));
+
+        int totalInstance = 2;
+
+        int perNode = 2;
+
+        server.services().deployMultiple(SRVC_NAME, MyServiceFactory.create(), totalInstance, perNode);
+
+        awaitPartitionMapExchange();
+
+        // Call proxies on the clients.
+        Stream.generate(() -> client.services().serviceProxy(SRVC_NAME, MyService.class, true))
+            .limit(totalInstance).forEach(srvc -> ((MyService)srvc).hello());
+
+        ReadOnlyMetricRegistry metrics = findMetricRegistry(server.context().metric(), SRVC_NAME);
+
+        // Total service calls number.
+        int callsCnt = 0;
+
+        for (Metric m : metrics) {
+            if (m instanceof HistogramMetric)
+                callsCnt += sumHistogramEntries((HistogramMetric)m);
+        }
+
+        assertEquals(callsCnt, totalInstance);
+
+        // Add servers more than service instances.
+        servers.add(startGrid(gridNum.getAndIncrement()));
+
+        servers.add(startGrid(gridNum.getAndIncrement()));
+
+        awaitPartitionMapExchange();
+
+        int deployedCnt = 0;
+
+        int metricsCnt = 0;
+
+        for (IgniteEx ignite : servers) {
+            if (ignite.services().service(SRVC_NAME) != null)
+                deployedCnt++;
+
+            if (findMetricRegistry(ignite.context().metric(), SRVC_NAME) != null)
+                metricsCnt++;
+        }
+
+        assertEquals(deployedCnt, metricsCnt);
+
+        assertEquals(metricsCnt, totalInstance);
+    }
+
+    /** Checks metric are created when service is deployed and removed when service is undeployed. */
+    @Test
+    public void testMetricDeplotmentUndeployment() throws Exception {
+        List<IgniteEx> servers = startGrids(3, false);
+
+        // 2 services per node.
+        servers.get(0).services().deploy(serviceCfg(SRVC_NAME, servers.size(), 2));
+
+        awaitPartitionMapExchange();
+
+        // Make sure metrics are registered.
+        for (IgniteEx ignite : servers)
+            assertEquals(metricsCnt(ignite, SRVC_NAME), MyService.class.getDeclaredMethods().length);
+
+        servers.get(0).services().cancel(SRVC_NAME);
+
+        awaitPartitionMapExchange();
+
+        for (IgniteEx ignite : servers)
+            assertEquals(metricsCnt(ignite, SRVC_NAME), 0);
+    }
+
+    /** Checks two different histograms are created for the same short names of service methods. */
+    @Test
+    public void testMetricNaming() throws Exception {
+        IgniteEx ignite = startGrid(1);
+
+        ignite.services().deployNodeSingleton(SRVC_NAME, new NamingServiceImpl());
+
+        MetricRegistry registry = ignite.context().metric().registry(serviceMetricRegistryName(SRVC_NAME));
+
+        List<Metric> metricsFound = new ArrayList<>();
+
+        for (Method mtd : NamingService.class.getDeclaredMethods()) {
+            Metric curMetric = null;
+
+            for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+                String metricName = methodMetricName(mtd, i);
+
+                if ((curMetric = registry.findMetric(metricName)) instanceof HistogramMetric
+                    && !metricsFound.contains(curMetric)) {
+                    metricsFound.add(curMetric);
+
+                    break;
+                }
+            }
+
+            assertNotNull("No metric found for method " + mtd, curMetric);
+        }
+    }
+
+    /** Tests service metrics for single service instance. */
+    @Test
+    public void testServiceMetricsSingle() throws Throwable {
+        testServiceMetrics(1, 1, 1, 1);
+    }
+
+    /** Tests service metrics for multy service instance: one per server. */
+    @Test
+    public void testServiceMetricsMulty() throws Throwable {
+        testServiceMetrics(3, 3, 3, 1);
+    }
+
+    /** Tests service metrics for multy service instance: fewer that servers and clients. */
+    @Test
+    public void testServiceMetricsMultyFew() throws Throwable {
+        testServiceMetrics(4, 3, 2, 1);
+    }
+
+    /** Tests service metrics for multy service instance: serveral instances per node */
+    @Test
+    public void testServiceMetricsMultyDuplicated() throws Throwable {
+        testServiceMetrics(3, 2, 3, 3);
+    }
+
+    /** Tests service metrics for multy service instance: serveral instances per node, total fewer that servers. */
+    @Test
+    public void testServiceMetricsMultyFewDuplicated() throws Throwable {
+        testServiceMetrics(5, 4, 3, 2);
+    }
+
+    /**
+     * Invokes service in various ways: from clients, servers, etc. Checks these calls reflect in the metrics.
+     *
+     * @param serverCnt Number of server nodes.
+     * @param clientCnt Number of client nodes.
+     * @param perClusterCnt Number of service instances per cluster.
+     * @param perNodeCnt Number of service instances per node.
+     */
+    private void testServiceMetrics(int serverCnt, int clientCnt, int perClusterCnt, int perNodeCnt) throws Throwable {
+        List<IgniteEx> servers = startGrids(serverCnt, false);
+
+        List<IgniteEx> clients = startGrids(clientCnt, true);
+
+        servers.get(0).services().deploy(serviceCfg(SRVC_NAME, perClusterCnt, perNodeCnt));
+
+        awaitPartitionMapExchange();
+
+        List<MyService> serverStickyProxies = servers.stream()
+            .map(ignite -> (MyService)ignite.services().serviceProxy(SRVC_NAME, MyService.class, true))
+            .collect(Collectors.toList());
+
+        List<MyService> clientStickyProxies = clients.stream()
+            .map(ignite -> (MyService)ignite.services().serviceProxy(SRVC_NAME, MyService.class, true))
+            .collect(Collectors.toList());
+
+        long invokeCollector = 0;
+
+        // Call service through the server proxies.
+        for (AtomicInteger i = new AtomicInteger(); i.get() < INVOKE_CNT; i.incrementAndGet()) {
+            // Call from server.
+            IgniteEx ignite = servers.get(i.get() % servers.size());
+
+            invokeCollector += callService(ignite, () -> serverStickyProxies.get(i.get() % serverStickyProxies.size()));
+
+            // Call from client.
+            ignite = clients.get(i.get() % clients.size());
+
+            invokeCollector += callService(ignite, () -> clientStickyProxies.get(i.get() % clientStickyProxies.size()));
+        }
+
+        long invokesInMetrics = 0;
+
+        // Calculate and check invocations within the metrics.
+        for (IgniteEx ignite : servers) {
+            ReadOnlyMetricRegistry metrics = findMetricRegistry(ignite.context().metric(), SRVC_NAME);
+
+            // Metrics may not be deployed on this server node.
+            if (metrics == null)
+                continue;
+
+            for (Metric metric : metrics) {
+                if (metric instanceof HistogramMetric)
+                    invokesInMetrics += sumHistogramEntries((HistogramMetric)metric);
+            }
+        }
+
+        // Compare calls number and metrics number.
+        assertEquals("Calculated wrong service invocation number.", invokesInMetrics, invokeCollector);
+    }
+
+    /**
+     * Invokes service method via proxies and local deployments if available. Calculates the invocations done.
+     *
+     * @param ignite Server or client node.
+     * @param extraSrvc Extra service instance or proxy to call.
+     * @return Total invokes done.
+     */
+    private int callService(IgniteEx ignite, @Nullable Supplier<MyService> extraSrvc) {
+        MyService srvc = ignite.services().serviceProxy(SRVC_NAME, MyService.class, false);
+
+        srvc.hello();
+
+        assertEquals(srvc.hello(12), 12);
+
+        // We just did 2 service calls.
+        int invokesDone = 2;
+
+        if (extraSrvc != null) {
 
 Review comment:
   `extraSrvc` always not null. To be honest, I doesn't understand why you desided to use here supplier. 
   Firstly, I don't see any invocation of `extraSrvc.get()`. You just call srvc again.
   Secondly, you have to use AtomicInteger in code above. May be better just pass here instance of stickyProxy itself? 

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401069614
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,336 @@
+package org.apache.ignite.internal.processors.service;
+
+import com.google.common.collect.Iterables;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.spi.metric.jmx.JmxMetricExporterSpi;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Test;
+
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.MAX_ABBREVIATE_NAME_LVL;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.serviceMetricRegistryName;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.sumHistogramEntries;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.SERVICE_METRIC_REGISTRY;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.methodMetricName;
+
+/** Tests metrics of service invocations. */
+public class GridServiceMetricsTest extends GridCommonAbstractTest {
+    /** Number of service invocations. */
+    private static final int INVOKE_CNT = 100;
+
+    /** Utility holder of current grid number. */
+    private final AtomicInteger gridNum = new AtomicInteger();
+
+    /** Service name used in the tests. */
+    private static final String SRVC_NAME = GridServiceMetricsTest.class.getSimpleName()+"_service";
+
+    /** Error message of created metrics. */
+    private static final String METRICS_MUST_NOT_BE_CREATED = "Service metric registry must not be created.";
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        // JMX metrics exposition for debug launch mode.
+        cfg.setMetricExporterSpi(new JmxMetricExporterSpi());
+
+        return cfg;
+    }
+
+    /** Checks metric behaviour when launched several service instances via #IgniteServices#deployMultiple */
+    @Test
+    public void testMultipleDeployment() throws Throwable {
+        List<IgniteEx> servers = new ArrayList<>();
+
+        servers.add(startGrid(gridNum.getAndIncrement()));
+
+        IgniteEx server = servers.get(0);
+
+        IgniteEx client = startClientGrid(gridNum.getAndIncrement());
+
+        assertNull(METRICS_MUST_NOT_BE_CREATED, findMetricRegistry(server.context().metric(), SERVICE_METRIC_REGISTRY));
+
+        int totalInstance = 2;
+
+        int perNode = 2;
+
+        server.services().deployMultiple(SRVC_NAME, MyServiceFactory.create(), totalInstance, perNode);
+
+        awaitPartitionMapExchange();
+
+        // Call proxies on the clients.
+        Stream.generate(() -> client.services().serviceProxy(SRVC_NAME, MyService.class, true))
+            .limit(totalInstance).forEach(srvc -> ((MyService)srvc).hello());
+
+        ReadOnlyMetricRegistry metrics = findMetricRegistry(server.context().metric(), SRVC_NAME);
+
+        // Total service calls number.
+        int callsCnt = 0;
+
+        for (Metric m : metrics) {
+            if (m instanceof HistogramMetric)
+                callsCnt += sumHistogramEntries((HistogramMetric)m);
+        }
+
+        assertEquals(callsCnt, totalInstance);
+
+        // Add servers more than service instances.
+        servers.add(startGrid(gridNum.getAndIncrement()));
+
+        servers.add(startGrid(gridNum.getAndIncrement()));
+
+        awaitPartitionMapExchange();
+
+        int deployedCnt = 0;
+
+        int metricsCnt = 0;
+
+        for (IgniteEx ignite : servers) {
+            if (ignite.services().service(SRVC_NAME) != null)
+                deployedCnt++;
+
+            if (findMetricRegistry(ignite.context().metric(), SRVC_NAME) != null)
+                metricsCnt++;
+        }
+
+        assertEquals(deployedCnt, metricsCnt);
+
+        assertEquals(metricsCnt, totalInstance);
+    }
+
+    /** Checks metric are created when service is deployed and removed when service is undeployed. */
+    @Test
+    public void testMetricDeplotmentUndeployment() throws Exception {
+        List<IgniteEx> servers = startGrids(3, false);
+
+        // 2 services per node.
+        servers.get(0).services().deploy(serviceCfg(SRVC_NAME, servers.size(), 2));
+
+        awaitPartitionMapExchange();
+
+        // Make sure metrics are registered.
+        for (IgniteEx ignite : servers)
+            assertEquals(metricsCnt(ignite, SRVC_NAME), MyService.class.getDeclaredMethods().length);
+
+        servers.get(0).services().cancel(SRVC_NAME);
+
+        awaitPartitionMapExchange();
+
+        for (IgniteEx ignite : servers)
+            assertEquals(metricsCnt(ignite, SRVC_NAME), 0);
+    }
+
+    /** Checks two different histograms are created for the same short names of service methods. */
+    @Test
+    public void testMetricNaming() throws Exception {
+        IgniteEx ignite = startGrid(1);
+
+        ignite.services().deployNodeSingleton(SRVC_NAME, new NamingServiceImpl());
+
+        MetricRegistry registry = ignite.context().metric().registry(serviceMetricRegistryName(SRVC_NAME));
+
+        List<Metric> metricsFound = new ArrayList<>();
+
+        for (Method mtd : NamingService.class.getDeclaredMethods()) {
+            Metric curMetric = null;
+
+            for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+                String metricName = methodMetricName(mtd, i);
+
+                if ((curMetric = registry.findMetric(metricName)) instanceof HistogramMetric
+                    && !metricsFound.contains(curMetric)) {
+                    metricsFound.add(curMetric);
+
+                    break;
+                }
+            }
+
+            assertNotNull("No metric found for method " + mtd, curMetric);
+        }
+    }
+
+    /** Tests service metrics for single service instance. */
+    @Test
+    public void testServiceMetricsSingle() throws Throwable {
+        testServiceMetrics(1, 1, 1, 1);
+    }
+
+    /** Tests service metrics for multy service instance: one per server. */
+    @Test
+    public void testServiceMetricsMulty() throws Throwable {
+        testServiceMetrics(3, 3, 3, 1);
+    }
+
+    /** Tests service metrics for multy service instance: fewer that servers and clients. */
+    @Test
+    public void testServiceMetricsMultyFew() throws Throwable {
+        testServiceMetrics(4, 3, 2, 1);
+    }
+
+    /** Tests service metrics for multy service instance: serveral instances per node */
+    @Test
+    public void testServiceMetricsMultyDuplicated() throws Throwable {
+        testServiceMetrics(3, 2, 3, 3);
+    }
+
+    /** Tests service metrics for multy service instance: serveral instances per node, total fewer that servers. */
+    @Test
+    public void testServiceMetricsMultyFewDuplicated() throws Throwable {
+        testServiceMetrics(5, 4, 3, 2);
+    }
+
+    /**
+     * Invokes service in various ways: from clients, servers, etc. Checks these calls reflect in the metrics.
+     *
+     * @param serverCnt Number of server nodes.
+     * @param clientCnt Number of client nodes.
+     * @param perClusterCnt Number of service instances per cluster.
+     * @param perNodeCnt Number of service instances per node.
+     */
+    private void testServiceMetrics(int serverCnt, int clientCnt, int perClusterCnt, int perNodeCnt) throws Throwable {
+        List<IgniteEx> servers = startGrids(serverCnt, false);
+
+        List<IgniteEx> clients = startGrids(clientCnt, true);
+
+        servers.get(0).services().deploy(serviceCfg(SRVC_NAME, perClusterCnt, perNodeCnt));
+
+        awaitPartitionMapExchange();
+
+        List<MyService> serverStickyProxies = servers.stream()
+            .map(ignite -> (MyService)ignite.services().serviceProxy(SRVC_NAME, MyService.class, true))
+            .collect(Collectors.toList());
+
+        List<MyService> clientStickyProxies = clients.stream()
+            .map(ignite -> (MyService)ignite.services().serviceProxy(SRVC_NAME, MyService.class, true))
+            .collect(Collectors.toList());
+
+        long invokeCollector = 0;
+
+        // Call service through the server proxies.
+        for (AtomicInteger i = new AtomicInteger(); i.get() < INVOKE_CNT; i.incrementAndGet()) {
+            // Call from server.
+            IgniteEx ignite = servers.get(i.get() % servers.size());
+
+            invokeCollector += callService(ignite, () -> serverStickyProxies.get(i.get() % serverStickyProxies.size()));
+
+            // Call from client.
+            ignite = clients.get(i.get() % clients.size());
+
+            invokeCollector += callService(ignite, () -> clientStickyProxies.get(i.get() % clientStickyProxies.size()));
+        }
+
+        long invokesInMetrics = 0;
+
+        // Calculate and check invocations within the metrics.
+        for (IgniteEx ignite : servers) {
+            ReadOnlyMetricRegistry metrics = findMetricRegistry(ignite.context().metric(), SRVC_NAME);
+
+            // Metrics may not be deployed on this server node.
+            if (metrics == null)
+                continue;
+
+            for (Metric metric : metrics) {
+                if (metric instanceof HistogramMetric)
+                    invokesInMetrics += sumHistogramEntries((HistogramMetric)metric);
+            }
+        }
+
+        // Compare calls number and metrics number.
+        assertEquals("Calculated wrong service invocation number.", invokesInMetrics, invokeCollector);
+    }
+
+    /**
+     * Invokes service method via proxies and local deployments if available. Calculates the invocations done.
+     *
+     * @param ignite Server or client node.
+     * @param extraSrvc Extra service instance or proxy to call.
+     * @return Total invokes done.
+     */
+    private int callService(IgniteEx ignite, @Nullable Supplier<MyService> extraSrvc) {
+        MyService srvc = ignite.services().serviceProxy(SRVC_NAME, MyService.class, false);
+
+        srvc.hello();
+
+        assertEquals(srvc.hello(12), 12);
+
+        // We just did 2 service calls.
+        int invokesDone = 2;
+
+        if (extraSrvc != null) {
+            srvc.hello();
+
+            assertEquals(srvc.hello(10), 10);
+
+            invokesDone += 2;
+        }
+
+        return invokesDone;
+    }
+
+    /** Provides test service configuration. */
+    private ServiceConfiguration serviceCfg(String svcName, int perClusterCnt, int perNodeCnt) {
+        ServiceConfiguration svcCfg = new ServiceConfiguration();
+
+        svcCfg.setService(MyServiceFactory.create());
+
+        svcCfg.setName(svcName);
+
+        svcCfg.setMaxPerNodeCount(perNodeCnt);
+
+        svcCfg.setTotalCount(perClusterCnt);
+
+        return svcCfg;
+    }
+
+    /** Expose ignite-references of the nodes as list. */
+    private List<IgniteEx> startGrids(int cnt, boolean client) {
+        return Stream.generate(() -> {
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401133474
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
 
 Review comment:
   Same here. You are right about usage of separate method. But the synchronization you suggest seems already relies in the logic above. I don’t think `IgniteServiceProcessor.undeploy()` and ` IgniteServiceProcessor.redeploy()` can happen concurrently but we should consider it can, ok. Let’s see:
   -	Metrics are erased by `IgniteServiceProcessor.unregisterMetrics()` in 2 places (): `IgniteServiceProcessor.redeploy()` and `IgniteServiceProcessor.undeploy()`.
   -	Metrics are created by `IgniteServiceProcessor.registerMetrics()`  in one place: `IgniteServiceProcessor.redeploy()`.
   
   These calls are not any APIs, are private.
   
   All 3 calls covered with sync by service context collection given by same service id:
   ```
   Collection<ServiceContextImpl> ctxs …
   synchronized (ctxs) {
   	unregisterMetrics(cfg.getName());
   }
   ```
   and
   ```
   Collection<ServiceContextImpl> ctxs …
   synchronized (ctxs) {
      if (!ctxs.iterator().next().isCancelled())
         registerMetrics(srvc, srvcCtx.name());
    } 
   ```
   
   I think I really missed the last part earlier. Thanks for the note. Isn’t it the synchronized block you suggest?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400813600
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
 
 Review comment:
   @NSAmelchev , the problem is:
   
   ```
       interface A {
           void foo();
       }
   
       interface B extends A {
           @Override void foo();
       }
   
       static class C implements Service, B {
           @Override public void foo() {
               System.err.println("foo");
           }
       }
   
      @Test
       public void test() throws Exception {
           Method methodA = A.class.getMethod("foo");
           Method methodB = B.class.getMethod("foo");
           Method methodC = C.class.getMethod("foo");
   
           assertEquals(methodA, methodB);
           assertEquals(methodA, methodC);
   
           assertEquals(methodB, methodA);
           assertEquals(methodB, methodC);
   
           assertEquals(methodC, methodA);
           assertEquals(methodC, methodB);
       }
   ```
   
   They are not equal. And yes, significant invocation boost. If we keep direct link to not-overloaded method, we avoid:
   
   1) Creation new Method() (`getMethod()` always create new one)
   2) Creation new Object[] when calling `Method.getParameterTypes()` to identify method.
   3) We do not search overloaded methods map at all. We get method by it name.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400813600
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
 
 Review comment:
   @NSAmelchev , the problem is:
   
   `interface A {
           void foo();
       }
   
       interface B extends A {
           @Override void foo();
       }
   
       static class C implements Service, B {
           @Override public void foo() {
               System.err.println("foo");
           }
           ...
       }
   
   @Test
       public void test() throws Exception {
           Method methodA = A.class.getMethod("foo");
           Method methodB = B.class.getMethod("foo");
           Method methodC = C.class.getMethod("foo");
   
           assertEquals(methodA, methodB);
           assertEquals(methodA, methodC);
           assertEquals(methodB, methodA);
   
           assertEquals(methodB, methodC);
           assertEquals(methodC, methodA);
           assertEquals(methodC, methodB);
       }`
   
   They are not equal. And yes, significant invocation boost. If we keep direct link to not-overloaded method, we avoid:
   
   1) Creation new Method() (`getMethod()` always create new one)
   2) Creation new Object[] when calling `Method.getParameterTypes()` to identify method.
   3) We do not search overloaded methods map at all. We get method by it name.

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


With regards,
Apache Git Services

[GitHub] [ignite] agura commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
agura commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r381247504
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -188,6 +205,80 @@
     /** Disconnected flag. */
     private volatile boolean disconnected;
 
+    /**
+     * Creates proper registry name for service metrics.
+     *
+     * @param srvcName Name of the service.
+     * @return Registry name.
+     */
+    static String serviceMetricsName(String srvcName) {
+        return metricName(METRIC_REGISTRY_INVOCATIONS, srvcName);
+    }
+
+    /**
+     * @param method       Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. @see #abbreviatePgkName(Class, int).
+     * @return Metric name for {@code method}. Doesn't guaratee same name with same {@code pkgNameDepth} is used for
+     * real metric registry.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
 
 Review comment:
   What if we have set of overloaded methods?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385209955
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,418 @@
+package org.apache.ignite.internal.processors.service;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICE_METRICS_ENABLED;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.METRIC_REGISTRY_INVOCATIONS;
+
+/** */
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385210254
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,418 @@
+package org.apache.ignite.internal.processors.service;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICE_METRICS_ENABLED;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.METRIC_REGISTRY_INVOCATIONS;
+
+/** */
+public class GridServiceMetricsTest extends GridCommonAbstractTest {
+    /** Number of service invcations. */
+    private static final int INVOKE_CNT = 50;
+
+    /** Utility holder of current grid number. */
+    private final AtomicInteger gridNum = new AtomicInteger();
+
+    /** */
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 edited a comment on issue #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 edited a comment on issue #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#issuecomment-607779282
 
 
   > Also, I suppose, that we should leave to user the final conclusion to instrument methods of
   > his or her service or not. I would suggest to add a bit of API for users, 
   
   Ok, many people propose to give user the decision to enable/disable service metrics. Makes sense. My + is for Andrey Gura’s suggestion ( http://apache-ignite-developers.2346864.n4.nabble.com/Reference-of-local-service-tp46071p46307.html ) :
   “we should provide a way for configuring service metrics (in
   sense of enabled/disabled) during service deploy. It's easy for cases
   where deploy() methods have ServiceConfiguration as parameter.”
   
   The reasons:
   -	It is quite obvious. Good place without any other condition.
   -	CacheConfiguration has same property. Analogous approach simplifies product for user.
   -	Can work with some global "service_metrics_enabled" or targeted "@MetricsEnabled", "@MetricsDisabled"
   
   So, I’ve introduced `ServiceConfiguration.isStatisticsEnabled`.
   
   
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401069896
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
 
 Review comment:
   @ivandasch , I agree with the code simplifying. I'm against synchronization and `ConcurrentHashMap` without certain case because metrics should be quick and do not affect invocation of target service method. Here is no iteration over the map and parallel puts. So, parallel gets from several threads are safe. Why do we need any synchronization here? 
   `HistogramHolder#addIfAbsent()` is synchronized because there are several put/assigns/writes. And concurrent calls made from `IgniteServiceProcessor.undeploy()` and `IgniteServiceProcessor.redeploy()` are possible.

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401088897
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
 
 Review comment:
   Well, lets take a look over the javaDoc
   ```
   The default implementation makes no guarantees about synchronization or atomicity properties of this method. Any implementation providing atomicity guarantees must override this method and document its concurrency properties. In particular, all implementations of subinterface java.util.concurrent.ConcurrentMap must document whether the function is applied once atomically only if the value is not present.
   ```

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r384509729
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,418 @@
+package org.apache.ignite.internal.processors.service;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICE_METRICS_ENABLED;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.METRIC_REGISTRY_INVOCATIONS;
+
+/** */
 
 Review comment:
   Add description, please.

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401097001
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
 
 Review comment:
   In code of method `MetricRegistry#histogram` I see clearly, that if a metric with same name exists, this method returns the old metric with bounds reset. If this is not OK, I suggest to rewrite a little bit `MetricRegistry#histogram`  or create specialized method. This task can be done without blocking code, I presume.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401101543
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
 
 Review comment:
   In this case we need to skip metric if it exists as described in the javadoc: 
   
   ```
   Creates histogram for service method. If exists, considers one or several argument types has same name but
        * different package and tries to extend metric name with abbreviation of java package name.
   ```
   
   Please see `NamingService` and `GridServiceMetricsTest.testMetricNaming()`

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r384532628
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceContextImpl.java
 ##########
 @@ -136,24 +140,70 @@ ExecutorService executor() {
      * @return Method.
      */
     @Nullable Method method(GridServiceMethodReflectKey key) {
-        Method mtd = mtds.get(key);
+        IgniteBiTuple<Method, HistogramMetricImpl> mtdRecord = methodRecord(key);
+
+        Method mtd = mtdRecord.get1();
 
         if (mtd == null) {
-            try {
-                mtd = svc.getClass().getMethod(key.methodName(), key.argTypes());
+            synchronized (mtdRecord) {
+                mtd = mtdRecord.get1();
 
-                mtd.setAccessible(true);
-            }
-            catch (NoSuchMethodException ignored) {
-                mtd = NULL_METHOD;
-            }
+                if (mtd == null) {
+                    try {
+                        mtd = svc.getClass().getMethod(key.methodName(), key.argTypes());
 
-            mtds.put(key, mtd);
+                        mtd.setAccessible(true);
+                    }
+                    catch (NoSuchMethodException ignored) {
+                        mtd = NULL_METHOD;
+                    }
+
+                    mtdRecord.set1(mtd);
+                }
+            }
         }
 
         return mtd == NULL_METHOD ? null : mtd;
     }
 
+    /**
+     * @param key Method key.
+     * @param histogrammInitiator Histogramm supplier if the histogramm isn't initialized yet.
+     * @return Service method performance histogramm.
+     */
+    @Nullable HistogramMetricImpl invokeHistogramm(GridServiceMethodReflectKey key,
+        Supplier<HistogramMetricImpl> histogrammInitiator) {
+        IgniteBiTuple<Method, HistogramMetricImpl> mtdRecord = methodRecord(key);
+
+        HistogramMetricImpl histogramm = mtdRecord.get2();
+
+        if (histogramm == null) {
+            synchronized (mtdRecord) {
+                histogramm = mtdRecord.get2();
+
+                if (histogramm == null) {
+                    histogramm = histogrammInitiator.get();
+
+                    assert histogramm != null;
+
+                    mtdRecord.set2(histogramm);
+                }
+            }
+        }
+
+        return histogramm;
+    }
+
+    /** Creates utility recod by method key {@code key}. Thread-safe.  */
+    private IgniteBiTuple<Method, HistogramMetricImpl> methodRecord(GridServiceMethodReflectKey key) {
+        return mtds.compute(key, (k, v) -> {
 
 Review comment:
   Can we replace it with: 
   `return mtds.computeIfAbsent(key, k -> new IgniteBiTuple<>());` ?

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385071989
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/processors/service/GridServiceMetricsTest.java
 ##########
 @@ -0,0 +1,418 @@
+package org.apache.ignite.internal.processors.service;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.processors.metric.GridMetricManager;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.internal.processors.service.inner.MyService;
+import org.apache.ignite.internal.processors.service.inner.MyServiceFactory;
+import org.apache.ignite.internal.processors.service.inner.NamingService;
+import org.apache.ignite.internal.processors.service.inner.NamingServiceImpl;
+import org.apache.ignite.services.Service;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.metric.HistogramMetric;
+import org.apache.ignite.spi.metric.Metric;
+import org.apache.ignite.spi.metric.ReadOnlyMetricRegistry;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_SERVICE_METRICS_ENABLED;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.METRIC_REGISTRY_INVOCATIONS;
+
+/** */
+public class GridServiceMetricsTest extends GridCommonAbstractTest {
+    /** Number of service invcations. */
+    private static final int INVOKE_CNT = 50;
+
+    /** Utility holder of current grid number. */
+    private final AtomicInteger gridNum = new AtomicInteger();
+
+    /** */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /** */
 
 Review comment:
   Use `    /** {@inheritDoc} */`

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400791320
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MetricUtils.java
 ##########
 @@ -163,4 +168,69 @@ private static boolean ensureAllNamesNotEmpty(String... names) {
 
         return names;
     }
+
+    /**
+     * Abbreviates package name for metric naming purposes.
+     *
+     * @param pkgNameDepth Exhibition level of java package name. The bigger, the wider.
+     *                     Max level is {@link #MAX_ABBREVIATE_NAME_LVL}. Values:
+     *                     <pre>
+     *                         0 - wont add package name;
+     *                         1 - add only first char of each name in java package;
+     *                         2 - add first and last char of each name in java package;
+     *                         Any other - add full name of java package.
+     *                     </pre>
+     * @return Abbreviated name of {@code cls}.
+     */
+    public static String abbreviateName(Class<?> cls, int pkgNameDepth) {
 
 Review comment:
   @NSAmelchev , in your example you have two different services and their metric name has different service name like different domain. However, in particular case it would require some efforts to distinguish metrics. If methods like in your case are contained in same interface. I think it is rare case and should not affect common simplicity of metric names. I suggest to keep metric names as simple as possible. Available improvement is adding 2 chars of package name:
   void_testMethod(Param)
   void_testMethod(og.ae.ie.il.ps.se.ir.il.Param)
   
   Still possible to get abbreviated package name complicated when firs/last chars are the same. I believe keeping rape case confusing is better that keep long names for 99% cases. WDYT?

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400943267
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
 
 Review comment:
   ```
   for (Class<?> iface : getInterfaces(srvc.getClass())) {
       for (Method mtd : iface.getMethods()) {
           if (!isMetricIgnoredFor(mtd.getDeclaringClass()))
               continue;
   
           Map<String, MethodHistogramHolder> srvcHistograms =
               invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
   
           synchronized (srvcHistograms) {
               srvcHistograms.compute(mtd.getName(), (mtdName, hldr) -> {
                   MethodHistogramHolder hldr0 = hldr == null ? new MethodHistogramHolder() : hldr;
                   
                   hldr0.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
                   
                   return hldr0;
               });
           }
       }
   ```
    I suppose, that this is a way more readable. And thread safe. By the way, `MethodHistogramHolder#addIfAbsent` may not be synchronized, if the method is implemented this way.
   
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400813600
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
 
 Review comment:
   @NSAmelchev , the problem is:
   
   `interface A {
           void foo();
       }
   
       interface B extends A {
           @Override void foo();
       }
   
       static class C implements Service, B {
           @Override public void foo() {
               System.err.println("foo");
           }
           ...
       }
   
   @Test
       public void test() throws Exception {
           Method methodA = A.class.getMethod("foo");
           Method methodB = B.class.getMethod("foo");
           Method methodC = C.class.getMethod("foo");
   
           assertEquals(methodA, methodB);
           assertEquals(methodA, methodC);
   
           assertEquals(methodB, methodA);
           assertEquals(methodB, methodC);
   
           assertEquals(methodC, methodA);
           assertEquals(methodC, methodB);
       }`
   
   They are not equal. And yes, significant invocation boost. If we keep direct link to not-overloaded method, we avoid:
   
   1) Creation new Method() (`getMethod()` always create new one)
   2) Creation new Object[] when calling `Method.getParameterTypes()` to identify method.
   3) We do not search overloaded methods map at all. We get method by it name.

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401127308
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
 
 Review comment:
   Putting in HashMap is not an atomic operation. There is no guarantee, that when performing get in another thread, this thread sees underlying array and bucket linked list in consistent state. Returning null is a one of good scenarious. Things may be even worse. 

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


With regards,
Apache Git Services

[GitHub] [ignite] agura commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
agura commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r381247504
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -188,6 +205,80 @@
     /** Disconnected flag. */
     private volatile boolean disconnected;
 
+    /**
+     * Creates proper registry name for service metrics.
+     *
+     * @param srvcName Name of the service.
+     * @return Registry name.
+     */
+    static String serviceMetricsName(String srvcName) {
+        return metricName(METRIC_REGISTRY_INVOCATIONS, srvcName);
+    }
+
+    /**
+     * @param method       Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. @see #abbreviatePgkName(Class, int).
+     * @return Metric name for {@code method}. Doesn't guaratee same name with same {@code pkgNameDepth} is used for
+     * real metric registry.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
 
 Review comment:
   What if we have set of overloaded methods?

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401091334
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -188,6 +216,9 @@
     /** Disconnected flag. */
     private volatile boolean disconnected;
 
+    /** Keeps histograms to measure durations of service methods. Guided by service name, then method name. */
+    private final Map<String, Map<String, MethodHistogramHolder>> invocationHistograms = new HashMap<>(1);
 
 Review comment:
   Event if getting histogram is quick, this fact doesn't make incorrect code correct. There is no guarantee, that after publication in one thread (put), you will see any result (get) in another. Even after a some long period of time.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 edited a comment on issue #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 edited a comment on issue #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#issuecomment-607779282
 
 
   > Also, I suppose, that we should leave to user the final conclusion to instrument methods of
   > his or her service or not. I would suggest to add a bit of API for users, 
   
   Ok, many people propose to give user the decision to enable/disable service metrics. Makes sense. My + is for Andrey Gura’s suggestion ( http://apache-ignite-developers.2346864.n4.nabble.com/Reference-of-local-service-tp46071p46307.html ) :
   “we should provide a way for configuring service metrics (in
   sense of enabled/disabled) during service deploy. It's easy for cases
   where deploy() methods have ServiceConfiguration as parameter.”
   
   The reasons:
   -	It is quite obvious. Good place without any other condition.
   -	CacheConfiguration has same property. Analogous approach simplifies product for user.
   -	Can work with some global "service_metrics_enabled" or targeted "@MetricsEnabled", "@MetricsDisabled"
   
   So, I’ve introduced ServiceConfiguration.isStatisticsEnabled and the supporting methods.
   
   
   

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385305822
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1188,7 +1303,10 @@ else if (ctxs.size() < assignCnt) {
                 // Initialize service.
                 srvc.init(srvcCtx);
 
-                srvcCtx.service(srvc);
+                if (metricsEnabled)
+                    registerMetrics(srvc, srvcCtx.name());
 
 Review comment:
   Seem we shouldn't register metrics if service was not deployed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385209748
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -188,6 +210,80 @@
     /** Disconnected flag. */
     private volatile boolean disconnected;
 
+    /**
+     * Creates proper registry name for service metrics.
+     *
+     * @param srvcName Name of the service.
+     * @return Registry name.
+     */
+    static String serviceMetricsName(String srvcName) {
+        return metricName(METRIC_REGISTRY_INVOCATIONS, srvcName);
+    }
+
+    /**
+     * @param method       Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. @see #abbreviatePgkName(Class, int).
+     * @return Metric name for {@code method}. Doesn't guaratee same name with same {@code pkgNameDepth} is used for
+     * real metric registry.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        // Name of the return type. Better for human readability.
+        sb.append(method.getReturnType() == null ? Void.class.getSimpleName() :
+            abbreviatePgkName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviatePgkName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /**
+     * @param pkgNameDepth Exhibition level of java package name. The bigger, the wider:
+     *                     <pre>
+     *                         0 - wont add package name;
+     *                         1 - add only first char of each name in java package;
+     *                         2 - add first and last char of each name in java package;
+     *                         Any other - add full java package name.
+     *                     </pre>
+     * @return Abbreviated name of the type {@code cl}.
+     */
+    private static String abbreviatePgkName(Class<?> cl, int pkgNameDepth) {
 
 Review comment:
   Moved to MetricUtils.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400474132
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i < MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append("_");
 
 Review comment:
   I think it should be the whitespace char. Like in `mtd.toGenericString()`.
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401070008
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MetricUtils.java
 ##########
 @@ -163,4 +168,66 @@ private static boolean ensureAllNamesNotEmpty(String... names) {
 
         return names;
     }
+
+    /**
+     * Abbreviates package name for metric naming purposes.
+     *
+     * @param pkgNameDepth Exhibition level of java package name. The bigger, the wider.
+     *                     Max level is {@link #MAX_ABBREVIATE_NAME_LVL}. Values:
+     *                     <pre>
+     *                         0 or negative - wont add package name;
+     *                         1 - add first and last char of each name in java package;
+     *                         2 or bigger - add full name of java package.
+     *                     </pre>
+     * @return Abbreviated name of {@code cls}.
+     */
+    public static String abbreviateName(Class<?> cls, int pkgNameDepth) {
+        if (pkgNameDepth < 1)
+            return cls.getSimpleName();
+
+        if (pkgNameDepth >= MAX_ABBREVIATE_NAME_LVL)
+            return cls.getName();
+
+        String[] pkgNameParts = cls.getName().split("\\.");
+
+        // No package like 'void' or 'int'.
+        if (pkgNameParts.length == 1)
+            return pkgNameParts[0];
+
+        StringBuilder sb = new StringBuilder();
+
+        for (int i = 0; i < pkgNameParts.length - 1; ++i) {
+            sb.append(pkgNameParts[i].charAt(0));
+
+            if (pkgNameParts[i].length() > 1)
+                sb.append(pkgNameParts[i].charAt(pkgNameParts[i].length() - 1));
+
+            sb.append(".");
+        }
+
+        // Add name to the class.
+        sb.append(pkgNameParts[pkgNameParts.length - 1]);
+
+        return sb.toString();
+    }
+
+    /**
+     * Gives proper name for service metric registry.
+     *
+     * @param srvcName Name of the service.
+     * @return registry name for service {@code srvcName}.
+     */
+    public static String serviceMetricRegistryName(String srvcName) {
+        return metricName(SERVICE_METRIC_REGISTRY, srvcName);
+    }
+
+    /**
+     * Count total of histogram values.
+     *
+     * @param histogram Histogram to traverse.
+     * @return Sum of all entries of {@code histogram} buckets.
+     */
+    public static long sumHistogramEntries(HistogramMetric histogram) {
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400813600
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
 
 Review comment:
   @NSAmelchev , the problem is:
   
   ```
       interface A {
           void foo();
       }
   
       interface B extends A {
           @Override void foo();
       }
   
       static class C implements Service, B {
           @Override public void foo() {
               System.err.println("foo");
           }
       }
   
      @Test
       public void test() throws Exception {
           Method methodA = A.class.getMethod("foo");
           Method methodB = B.class.getMethod("foo");
           Method methodC = C.class.getMethod("foo");
   
           assertEquals(methodA, methodB);
           assertEquals(methodA, methodC);
   
           assertEquals(methodB, methodA);
           assertEquals(methodB, methodC);
   
           assertEquals(methodC, methodA);
           assertEquals(methodC, methodB);
       }
   ```
   
   Same for:
   ```
       interface A {
           void foo();
       }
   
       interface B /* not extends A */ {
           void foo();
       }
   
       class C implements Service, A, B {
           @Override public void foo() {
               System.err.println("foo");
           }
       }
   ```
   
   They are not equal. And yes, significant invocation boost. If we keep direct link to not-overloaded method, we avoid:
   
   1) Creation new Method() (`getMethod()` always create new one)
   2) Creation new Object[] when calling `Method.getParameterTypes()` to identify method.
   3) We do not search overloaded methods map at all. We get method by it name.

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


With regards,
Apache Git Services

[GitHub] [ignite] ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
ivandasch commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401121469
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
 
 Review comment:
   Ok, It seems to be a not a problem, because of one registry per service approach. Seems that we can leave blocking code as is 

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 edited a comment on issue #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 edited a comment on issue #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#issuecomment-588933230
 
 
   Major changes:
   1)	The services are now proxied with IgniteServiceProcessor#LocalInvocationHandler which measures service methods duration.
   2)     Service metrics are created for each interface method on service deployment, after init(), before execute().
   3)     Fixed failed tests which used service class directly instead of its interface.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 edited a comment on issue #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 edited a comment on issue #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#issuecomment-588933230
 
 
   Behaviour cnages:
   - Durations of service method can be measured and stored into histogram.
   - If service proxy requested, it is now proxy fol local service instead of direct link.
   - ServiceConfiguration can now disable/enable metrics for service.
   - Service metrics are stored in registey "Services" (`IgniteServiceProcessor.SERVICE_METRIC_REGISTRY`) by service name.
   
   Significant code changes:
   - `IgniteServices.serviceProxy(*)` now returns proxy even for locally deployed service.
   - Deprecated `IgniteServices.service()` and `IgniteServices.services()`.
   - Introduced `ServiceConfiguration.isStatisticsEnabled`.
   - Introduced in `IgniteServices`: `clusterSingletonConfiguration()`, `nodeSingletonConfiguration()`, `keyAffinitySingletonConfiguration()` and `multipleConfiguration()`.
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401115708
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -188,6 +216,9 @@
     /** Disconnected flag. */
     private volatile boolean disconnected;
 
+    /** Keeps histograms to measure durations of service methods. Guided by service name, then method name. */
+    private final Map<String, Map<String, MethodHistogramHolder>> invocationHistograms = new HashMap<>(1);
 
 Review comment:
   This is not a cached variable, not a class property. It is re-requested every time. Yes, some gap in getting histogram is possible. But why long? 
   
   With concurrent undeploying, I think, we either can;t find service context / deployed service before incrementing the histogram or we increment histogram which is going to be removed soon. Tests of concurrent service deploying/undeploying and calling shows the same. We do not stumble over `assert histogram != null;` But I introduced it for possible changes in future to indicate problem.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400409479
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java
 ##########
 @@ -354,6 +355,37 @@ T proxy() {
         return proxy;
     }
 
+    /**
+     * Calls service method, measures and registers its performance.
+     *
+     * @param srvcProc Current service processor.
+     * @param srvc The service object.
+     * @param srvcName The service name.
+     * @param mtd Method to call.
+     * @param args Arguments for {@code mtd}.
+     */
+    private static Object callSrvcMtd(ServiceProcessorAdapter srvcProc, Service srvc, String srvcName, Method mtd,
 
 Review comment:
   Please, do not shorten the name of the methods.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400484274
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/IgniteServices.java
 ##########
 @@ -575,6 +578,7 @@ public void deployMultiple(String name, Service svc, int totalCnt, int maxPerNod
      * @param <T> Service type.
      * @return all deployed services with specified name.
      */
+    @Deprecated
 
 Review comment:
   Add javadoc, please.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401141419
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i <= MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append(" ");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
 
 Review comment:
   As far as I know, concurrent put/get/remove are not atomic but are safe meaning do not fail or throw an exception. You can only get null when a value exist, or a value when it is already removed. Iteration is a problem, yes. We do not iterate.
   
   Please, take a look to this simple test. Forks for me. Gives null periodically, and, I believe, inconsistent values. But no any lock/crash scenario. What else should we check?
   
   ```
   @Test
       public void testMapConcurrency() throws InterruptedException {
           final Map<Integer, Integer> map = new HashMap<>(1);
           final Random rnd = new Random();
           final int valueCnt = 100000;
           final Integer[] holder = new Integer[1];
   
           for(int i=0; i<5; ++i) {
               new Thread(() -> {
                   while (true) {
                       for (int v = 0; v < valueCnt; ++v)
                           map.put(v, rnd.nextInt(valueCnt));
   
                       System.err.println("Filled");
   
                       try {
                           Thread.sleep(rnd.nextInt(5000));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
               }, "putter_"+i).start();
           }
   
           for(int i=0; i<30; ++i) {
               new Thread(() -> {
                   while (true) {
   
                       try {
                           holder[0] = map.get(rnd.nextInt(valueCnt));
   
                           Thread.sleep(rnd.nextInt(50));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                       catch (Exception e) {
                           e.printStackTrace();
                       }
                   }
               }, "getter_"+i).start();
           }
   
           for(int i=0; i<5; ++i) {
               new Thread(() -> {
                   while (true) {
                       try {
                           Thread.sleep(rnd.nextInt(5000));
                       }
                       catch (InterruptedException e) {
                           e.printStackTrace();
                       }
   
                       System.err.println("Clearing");
   
                       map.clear();
   
                       System.err.println("Cleared");
                   }
               }, "clearer_"+i).start();
           }
   
           Thread.sleep(5*60000);
       }
   ```
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385141284
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceContextImpl.java
 ##########
 @@ -136,24 +140,70 @@ ExecutorService executor() {
      * @return Method.
      */
     @Nullable Method method(GridServiceMethodReflectKey key) {
-        Method mtd = mtds.get(key);
+        IgniteBiTuple<Method, HistogramMetricImpl> mtdRecord = methodRecord(key);
+
+        Method mtd = mtdRecord.get1();
 
         if (mtd == null) {
-            try {
-                mtd = svc.getClass().getMethod(key.methodName(), key.argTypes());
+            synchronized (mtdRecord) {
+                mtd = mtdRecord.get1();
 
-                mtd.setAccessible(true);
-            }
-            catch (NoSuchMethodException ignored) {
-                mtd = NULL_METHOD;
-            }
+                if (mtd == null) {
+                    try {
+                        mtd = svc.getClass().getMethod(key.methodName(), key.argTypes());
 
-            mtds.put(key, mtd);
+                        mtd.setAccessible(true);
+                    }
+                    catch (NoSuchMethodException ignored) {
+                        mtd = NULL_METHOD;
+                    }
+
+                    mtdRecord.set1(mtd);
+                }
+            }
         }
 
         return mtd == NULL_METHOD ? null : mtd;
     }
 
+    /**
+     * @param key Method key.
+     * @param histogrammInitiator Histogramm supplier if the histogramm isn't initialized yet.
+     * @return Service method performance histogramm.
+     */
+    @Nullable HistogramMetricImpl invokeHistogramm(GridServiceMethodReflectKey key,
+        Supplier<HistogramMetricImpl> histogrammInitiator) {
+        IgniteBiTuple<Method, HistogramMetricImpl> mtdRecord = methodRecord(key);
+
+        HistogramMetricImpl histogramm = mtdRecord.get2();
+
+        if (histogramm == null) {
 
 Review comment:
   I don't think so. This record might be created not by call for historgam, but by call for GridServiceMethodReflectKey. The record would exist without histogram.
   
   Also
   assert histogramm != null;
   is useful.
   
   I'll try to split the map.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400438477
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
 
 Review comment:
   `ConcurrentHashMap` should be used. Otherwise, it's possible to get the exception here:
   ```
   java.lang.ClassCastException: java.util.HashMap$Node cannot be cast to java.util.HashMap$TreeNode
   	at java.util.HashMap$TreeNode.moveRootToFront(HashMap.java:1835)
   	at java.util.HashMap$TreeNode.treeify(HashMap.java:1951)
   	at java.util.HashMap.treeifyBin(HashMap.java:772)
   	at java.util.HashMap.computeIfAbsent(HashMap.java:1140)
   ```

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400767440
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java
 ##########
 @@ -354,6 +355,37 @@ T proxy() {
         return proxy;
     }
 
+    /**
+     * Calls service method, measures and registers its performance.
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401133474
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
 
 Review comment:
   Same here. You are right about usage of separate method. But the synchronization you suggest seems already relies in the logic above. I don’t think `IgniteServiceProcessor.undeploy()` and ` IgniteServiceProcessor.redeploy()` can happen concurrently but we should consider it can, ok. Let’s see:
   -	Metrics are erased by `IgniteServiceProcessor.unregisterMetrics()` in 2 places (): `IgniteServiceProcessor.redeploy()` and `IgniteServiceProcessor.undeploy()`.
   -	Metrics are created by `IgniteServiceProcessor.registerMetrics()`  in one place: `IgniteServiceProcessor.redeploy()`.
   
   These calls are not any APIs, are private.
   
   All 3 calls covered with sync by service context collection given by same service id:
   ```
   Collection<ServiceContextImpl> ctxs …
   synchronized (ctxs) {
   	unregisterMetrics(cfg.getName());
           }
   ```
   and
   ```
   Collection<ServiceContextImpl> ctxs …
               synchronized (ctxs) {
                   if (!ctxs.iterator().next().isCancelled())
                       registerMetrics(srvc, srvcCtx.name());
               } 
   ```
   
   I think I really missed the last part earlier. Thanks for the note. Isn’t it the synchronized block you suggest?

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 edited a comment on issue #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 edited a comment on issue #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#issuecomment-588933230
 
 
   Major changes:
   1)	The services are now proxied with IgniteServiceProcessor#LocalInvocationHandler which measures service methods duration.
   2)     Service metrics are created for each interface method on service deployment, after init(), before execute().
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400767595
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,176 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
+            .filter(mtd -> !isMetricIgnoredFor(mtd.getDeclaringClass()))
+            .forEach(mtd -> {
+                // All metrics for current service.
+                Map<String, MethodHistogramHolder> srvcHistograms =
+                    invocationHistograms.computeIfAbsent(srvcName, name -> new HashMap<>(1));
+
+                // Histograms for this method name.
+                MethodHistogramHolder mtdHistograms =
+                    srvcHistograms.computeIfAbsent(mtd.getName(), mdtName -> new MethodHistogramHolder());
+
+                mtdHistograms.addIfAbsent(mtd, () -> createHistogram(srvcName, mtd));
+            });
+    }
+
+    /**
+     * Removes metrics for service {@code srvcName}.
+     *
+     * @param srvcName Service name.
+     */
+    private void unregisterMetrics(String srvcName) {
+        ctx.metric().remove(serviceMetricRegistryName(srvcName));
+
+        invocationHistograms.remove(srvcName);
+    }
+
+    /**
+     * Creates histogram for service method. If exist,s considers one or several argument types has same name but
+     * different package and tries to extend metric name with abbreviation of java package name.
+     *
+     * @param srvcName Service name.
+     * @param method Method to measure.
+     * @return Histogram of service method timings.
+     */
+    HistogramMetricImpl createHistogram(String srvcName, Method method) {
+        MetricRegistry metricRegistry = ctx.metric().registry(serviceMetricRegistryName(srvcName));
+
+        HistogramMetricImpl histogram = null;
+
+        // Find/create histogram.
+        for (int i = 0; i < MAX_ABBREVIATE_NAME_LVL; ++i) {
+            String methodMetricName = methodMetricName(method, i);
+
+            synchronized (metricRegistry) {
+                // If the metric exists skip and try extending metric name in next cycle.
+                if (metricRegistry.findMetric(methodMetricName) == null) {
+                    histogram = metricRegistry.histogram(methodMetricName, DEFAULT_INVOCATION_BOUNDS,
+                        DESCRIPTION_OF_INVOCATION_METRIC);
+
+                    break;
+                }
+            }
+        }
+
+        assert histogram != null;
+
+        return histogram;
+    }
+
+    /**
+     * @param method Method for the invocation timings.
+     * @param pkgNameDepth Level of package name abbreviation. See {@link MetricUtils#abbreviateName(Class, int)}.
+     * @return Metric name for {@code method}.
+     */
+    static String methodMetricName(Method method, int pkgNameDepth) {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(abbreviateName(method.getReturnType(), pkgNameDepth));
+        sb.append("_");
+        sb.append(method.getName());
+        sb.append("(");
+        sb.append(Stream.of(method.getParameterTypes()).map(t -> abbreviateName(t, pkgNameDepth))
+            .collect(Collectors.joining(", ")));
+        sb.append(")");
+
+        return sb.toString();
+    }
+
+    /** @return {@code True} if metrics should not be created for this class or interface. */
+    private static boolean isMetricIgnoredFor(Class<?> cls){
+        return Object.class.equals(cls) || Service.class.equals(cls) || Externalizable.class.equals(cls);
+    }
+
+    /**
+     * Searches histogram for service method.
+     *
+     * @param srvcName Service name.
+     * @param mtd Service method.
+     * @return Histogram for {@code srvcName} and {@code mtd} or {@code null} if not found.
+     */
+    HistogramMetricImpl histogram(String srvcName, Method mtd) {
+        MethodHistogramHolder histogramHolder = Optional.ofNullable(invocationHistograms.get(srvcName))
+            .orElse(Collections.emptyMap()).get(mtd.getName());
+
+        return histogramHolder == null ? null : histogramHolder.getHistogram(mtd);
+    }
+
+    /**
+     * Histogram holder for service methods. Helps to fasten invocation of not-overloaded methods.
+     * Keeps either map of histograms for overloaded method or single histogram.
+     */
+    private static final class MethodHistogramHolder {
+        /** Not overloaded method. */
+        private Method singleMtd;
+
+        /** Histogram if method is not overloaded. */
+        private HistogramMetricImpl singleHistogram;
+
+        /** Histograms for overloaded method. */
+        private Map<Object, HistogramMetricImpl> overloadedMtd;
+
+        /**
+         * Saves new histogram.
+         *
+         * @param mtd Method to keep histogram for.
+         * @param initiator Histogram creator.
+         */
+        private synchronized void addIfAbsent(Method mtd, Supplier<HistogramMetricImpl> initiator) {
+            if (singleMtd == null && overloadedMtd == null) {
+                singleMtd = mtd;
+
+                singleHistogram = initiator.get();
+            }
+            else if (!isSameSingleMtd(mtd) && (overloadedMtd == null || !overloadedMtd.containsKey(key(mtd)))) {
+                overloadedMtd = new HashMap<>(2);
+
+                overloadedMtd.put(key(singleMtd), singleHistogram);
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385209389
 
 

 ##########
 File path: modules/core/src/test/java/org/apache/ignite/internal/ComputeJobCancelWithServiceSelfTest.java
 ##########
 @@ -85,7 +93,7 @@ public void testJobCancel() throws Exception {
         /**
          * @return Response.
          */
 
 Review comment:
   Use `    /** {@inheritDoc} */`

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r402808310
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/GridServiceProxy.java
 ##########
 @@ -354,6 +358,37 @@ T proxy() {
         return proxy;
     }
 
+    /**
+     * Calls service method, measures and registers its duration.
+     *
+     * @param srvcProc Current service processor.
+     * @param srvc The service object.
+     * @param srvcName The service name.
+     * @param mtd Method to call.
+     * @param args Arguments for {@code mtd}.
+     */
+    private static Object measureServiceMethod(ServiceProcessorAdapter srvcProc, Service srvc, String srvcName,
 
 Review comment:
   Fixed.

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 edited a comment on issue #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 edited a comment on issue #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#issuecomment-588933230
 
 
   Major changes:
   1)	The services are now proxied with IgniteServiceProcessor#LocalInvocationHandler which measures service methods duration.
   2)     Service metrics are created for each interface method on service deployment, after init(), before execute().
   4)     Fixed failed tests which used service class directly instead of its interface.
   

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


With regards,
Apache Git Services

[GitHub] [ignite] Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
Vladsz83 commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r401133474
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/IgniteServiceProcessor.java
 ##########
 @@ -1801,4 +1842,178 @@ private boolean enterBusy() {
     private void leaveBusy() {
         opsLock.readLock().unlock();
     }
+
+    /**
+     * Registers metrics to measure durations of service methods.
+     *
+     * @param srvc Service for invocations measurement.
+     * @param srvcName Name of {@code srvc}.
+     */
+    private void registerMetrics(Service srvc, String srvcName) {
+        getInterfaces(srvc.getClass()).stream().map(Class::getMethods).flatMap(Arrays::stream)
 
 Review comment:
   Same here. Service deploying/un deploying are guided by discovery messages which are serial. I reverted this synchronized block. Actually, all we do here we do in single thread. WDYT?

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r385098924
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceContextImpl.java
 ##########
 @@ -136,24 +140,70 @@ ExecutorService executor() {
      * @return Method.
      */
     @Nullable Method method(GridServiceMethodReflectKey key) {
-        Method mtd = mtds.get(key);
+        IgniteBiTuple<Method, HistogramMetricImpl> mtdRecord = methodRecord(key);
+
+        Method mtd = mtdRecord.get1();
 
         if (mtd == null) {
-            try {
-                mtd = svc.getClass().getMethod(key.methodName(), key.argTypes());
+            synchronized (mtdRecord) {
+                mtd = mtdRecord.get1();
 
-                mtd.setAccessible(true);
-            }
-            catch (NoSuchMethodException ignored) {
-                mtd = NULL_METHOD;
-            }
+                if (mtd == null) {
+                    try {
+                        mtd = svc.getClass().getMethod(key.methodName(), key.argTypes());
 
-            mtds.put(key, mtd);
+                        mtd.setAccessible(true);
+                    }
+                    catch (NoSuchMethodException ignored) {
+                        mtd = NULL_METHOD;
+                    }
+
+                    mtdRecord.set1(mtd);
+                }
+            }
         }
 
         return mtd == NULL_METHOD ? null : mtd;
     }
 
+    /**
+     * @param key Method key.
+     * @param histogrammInitiator Histogramm supplier if the histogramm isn't initialized yet.
+     * @return Service method performance histogramm.
+     */
+    @Nullable HistogramMetricImpl invokeHistogramm(GridServiceMethodReflectKey key,
+        Supplier<HistogramMetricImpl> histogrammInitiator) {
+        IgniteBiTuple<Method, HistogramMetricImpl> mtdRecord = methodRecord(key);
+
+        HistogramMetricImpl histogramm = mtdRecord.get2();
+
+        if (histogramm == null) {
 
 Review comment:
   I think we can avoid double-checked locking by initiating on map#computeIfAbsent.

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


With regards,
Apache Git Services

[GitHub] [ignite] NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics

Posted by GitBox <gi...@apache.org>.
NSAmelchev commented on a change in pull request #7446: IGNITE-12464 : Service metrics
URL: https://github.com/apache/ignite/pull/7446#discussion_r400483166
 
 

 ##########
 File path: modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MetricUtils.java
 ##########
 @@ -163,4 +168,69 @@ private static boolean ensureAllNamesNotEmpty(String... names) {
 
         return names;
     }
+
+    /**
+     * Abbreviates package name for metric naming purposes.
+     *
+     * @param pkgNameDepth Exhibition level of java package name. The bigger, the wider.
+     *                     Max level is {@link #MAX_ABBREVIATE_NAME_LVL}. Values:
+     *                     <pre>
+     *                         0 - wont add package name;
+     *                         1 - add only first char of each name in java package;
+     *                         2 - add first and last char of each name in java package;
+     *                         Any other - add full name of java package.
+     *                     </pre>
+     * @return Abbreviated name of {@code cls}.
+     */
+    public static String abbreviateName(Class<?> cls, int pkgNameDepth) {
 
 Review comment:
   Suppose there are two interfaces:
   ```
   public interface NamingServiceV2 extends Service {
       default void testMethod(org.apache.ignite.internal.processors.service.inner.implV2.Param param) {}
   }
   public interface NamingService extends Service {
       default void testMethod(org.apache.ignite.internal.processors.service.inner.impl.Param param) {}
   }
   public class NamingServiceImpl implements NamingService, NamingServiceV2 { }
   ```
   so, metric names will be:
   `void_testMethod(Param)`
   `void_testMethod(o.a.i.i.p.s.i.i.Param)`
   How should I understand which method the metric refers to?
   
   Also, there are possible names collision on different JVM's.
   Possible solution - use `mtd.toGenericString()` as metric name. However, this will have poor readability.

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


With regards,
Apache Git Services