Cleaning
diff --git a/modules/metrics/pom.xml b/modules/metrics/pom.xml
new file mode 100644
index 0000000..76ea09b
--- /dev/null
+++ b/modules/metrics/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-parent</artifactId>
+ <version>1</version>
+ <relativePath>../../parent/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>ignite-metrics</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-core</artifactId>
+ </dependency>
+
+ <!-- 3rd party dependencies -->
+ <dependency>
+ <groupId>org.jetbrains</groupId>
+ <artifactId>annotations</artifactId>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AbstractMetric.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AbstractMetric.java
new file mode 100644
index 0000000..edaac8c
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AbstractMetric.java
@@ -0,0 +1,54 @@
+package org.apache.ignite.internal.metrics;
+
+import org.jetbrains.annotations.Nullable;
+
+public abstract class AbstractMetric implements Metric {
+ /** Metric name. It is local for a particular {@link MetricsSet}. */
+ private final String name;
+
+ /** Metric description. */
+ private final String desc;
+
+ /**
+ * @param name Name.
+ * @param desc Description.
+ */
+ public AbstractMetric(String name, String desc) {
+ assert name != null;
+ assert !name.isEmpty();
+
+ this.name = name;
+ this.desc = desc;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return name;
+ }
+
+ /** {@inheritDoc} */
+ @Override @Nullable public String description() {
+ return desc;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ AbstractMetric metric = (AbstractMetric)o;
+
+ if (!name.equals(metric.name))
+ return false;
+
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return name.hashCode();
+ }
+}
\ No newline at end of file
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AbstractMetricsSource.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AbstractMetricsSource.java
new file mode 100644
index 0000000..964b2aa
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AbstractMetricsSource.java
@@ -0,0 +1,119 @@
+package org.apache.ignite.internal.metrics;
+
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+import static java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater;
+
+/**
+ * Base class for all metric sources.
+ *
+ * @param <T> Holder type.
+ */
+public abstract class AbstractMetricsSource<T extends AbstractMetricsSource.Holder<T>> implements MetricsSource {
+ /** Holder field updater. */
+ @SuppressWarnings("rawtypes")
+ private static final AtomicReferenceFieldUpdater<AbstractMetricsSource, Holder> HOLDER_FIELD_UPD =
+ newUpdater(AbstractMetricsSource.class, AbstractMetricsSource.Holder.class, "holder");
+
+ /** Metric source name. */
+ private final String name;
+
+ /** Metric instances holder. */
+ private volatile T holder;
+
+ /**
+ * Base constructor for all metric source implemnetations.
+ *
+ * @param name Metric source name.
+ */
+ protected AbstractMetricsSource(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns metric source name.
+ *
+ * @return Metric source name.
+ */
+ @Override public final String name() {
+ return name;
+ }
+
+ /**
+ * Checks whether metrics is enabled (switched on) or not (switched off) for metric source.
+ *
+ * @return {@code True} if metrics are enabled, otherwise - {@code false}.
+ */
+ @Override public final boolean enabled() {
+ return holder != null;
+ }
+
+ /**
+ * Returns metric instances holder. Use this on oreder to avoid metric lookup from map-like data structures.
+ * Returned value is {@code null} if metrics are disabled.
+ *
+ * @return Metrics holder instance if metrics are enabled, otherwise - {@code null}.
+ */
+ protected final T holder() {
+ return holder;
+ }
+
+ /**
+ * Method is responsible for creation of appropriate holder instance in underlying implementations.
+ *
+ * @return New instance of metrics holder that must implements {@link Holder} interface.
+ */
+ protected abstract T createHolder();
+
+ /** {@inheritDoc} */
+ @Override public final MetricsSet enable() {
+ MetricsSetBuilder bldr = new MetricsSetBuilder(name);
+
+ T hldr = createHolder();
+
+ init(bldr, hldr);
+
+ MetricsSet reg = bldr.build();
+
+ return HOLDER_FIELD_UPD.compareAndSet(this, null, hldr) ? reg : null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public final void disable() {
+ T holder0 = holder;
+
+ if (HOLDER_FIELD_UPD.compareAndSet(this, holder0, null))
+ cleanup(holder0);
+ }
+
+ /**
+ * Method is responsible for:
+ * <ol>
+ * <li>Creation of {@link MetricsSet} instance using provided {@link MetricsSetBuilder}.</li>
+ * <li>Creation of metric instances in given holder.</li>
+ * <li>Other initialization if needed.</li>
+ * <ol/>
+ *
+ * @param bldr Metric registry builder.
+ * @param holder Metric instances holder.
+ */
+ protected abstract void init(MetricsSetBuilder bldr, T holder);
+
+ /**
+ * Method is responsible for cleanup and release of all resources initialized or created during {@link #init} method
+ * execution. Note that {@link MetricsSet} and {@link Holder} instances will be released automatically.
+ *
+ * @param holder Metric instances holder.
+ */
+ protected void cleanup(T holder) {
+ // No-op.
+ }
+
+ /**
+ * Marker interface for metric instances holder.
+ *
+ * @param <T> Holder type subclass.
+ */
+ protected interface Holder<T extends Holder<T>> {
+ }
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AtomicDoubleMetric.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AtomicDoubleMetric.java
new file mode 100644
index 0000000..281d3c0
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AtomicDoubleMetric.java
@@ -0,0 +1,50 @@
+package org.apache.ignite.internal.metrics;
+
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+
+public class AtomicDoubleMetric extends AbstractMetric implements DoubleMetric {
+ /** Field updater. */
+ private static final AtomicLongFieldUpdater<AtomicDoubleMetric> updater =
+ AtomicLongFieldUpdater.newUpdater(AtomicDoubleMetric.class, "val");
+
+ /** Value. */
+ private volatile long val;
+
+ /**
+ * @param name Name.
+ * @param desc Description.
+ */
+ public AtomicDoubleMetric(String name, String desc) {
+ super(name, desc);
+ }
+
+ /**
+ * Adds given value to the metric value.
+ *
+ * @param v Value to be added.
+ */
+ public void add(double v) {
+ for (;;) {
+ long exp = val;
+ long upd = Double.doubleToLongBits(Double.longBitsToDouble(exp) + v);
+ if (updater.compareAndSet(this, exp, upd)) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Sets value.
+ *
+ * @param val Value.
+ */
+ public void value(double val) {
+ this.val = Double.doubleToLongBits(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double value() {
+ return Double.longBitsToDouble(val);
+ }
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AtomicIntMetric.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AtomicIntMetric.java
new file mode 100644
index 0000000..a534402
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AtomicIntMetric.java
@@ -0,0 +1,53 @@
+package org.apache.ignite.internal.metrics;
+
+import org.jetbrains.annotations.Nullable;
+
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+
+/**
+ * Integer metric is implemented as a volatile {@code int} value.
+ */
+public class AtomicIntMetric extends AbstractMetric implements IntMetric {
+ /** Field updater. */
+ private static final AtomicIntegerFieldUpdater<AtomicIntMetric> updater =
+ AtomicIntegerFieldUpdater.newUpdater(AtomicIntMetric.class, "val");
+
+ /** Value. */
+ private volatile int val;
+
+ /**
+ * @param name Name.
+ * @param desc Description.
+ */
+ public AtomicIntMetric(String name, @Nullable String desc) {
+ super(name, desc);
+ }
+
+ /**
+ * Adds x to the metric.
+ *
+ * @param x Value to be added.
+ */
+ public void add(int x) {
+ updater.addAndGet(this, x);
+ }
+
+ /** Adds 1 to the metric. */
+ public void increment() {
+ add(1);
+ }
+
+ /**
+ * Sets value.
+ *
+ * @param val Value.
+ */
+ public void value(int val) {
+ this.val = val;
+ }
+
+ /** {@inheritDoc} */
+ @Override public int value() {
+ return val;
+ }
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AtomicLongMetric.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AtomicLongMetric.java
new file mode 100644
index 0000000..9926dee
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/AtomicLongMetric.java
@@ -0,0 +1,58 @@
+package org.apache.ignite.internal.metrics;
+
+import org.jetbrains.annotations.Nullable;
+
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+
+/**
+ * Long metric implementation.
+ */
+public class AtomicLongMetric extends AbstractMetric implements LongMetric {
+ /** Field updater. */
+ static final AtomicLongFieldUpdater<AtomicLongMetric> updater =
+ AtomicLongFieldUpdater.newUpdater(AtomicLongMetric.class, "val");
+
+ /** Field value. */
+ private volatile long val;
+
+ /**
+ * @param name Name.
+ * @param desc Description.
+ */
+ public AtomicLongMetric(String name, @Nullable String desc) {
+ super(name, desc);
+ }
+
+ /**
+ * Adds x to the metric.
+ *
+ * @param x Value to be added.
+ */
+ public void add(long x) {
+ updater.getAndAdd(this, x);
+ }
+
+ /** Adds 1 to the metric. */
+ public void increment() {
+ add(1);
+ }
+
+ /** Adds -1 to the metric. */
+ public void decrement() {
+ add(-1);
+ }
+
+ /** {@inheritDoc} */
+ @Override public long value() {
+ return val;
+ }
+
+ /**
+ * Sets value.
+ *
+ * @param val Value.
+ */
+ public void value(long val) {
+ this.val = val;
+ }
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/DoubleAdderMetric.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/DoubleAdderMetric.java
new file mode 100644
index 0000000..02805b3
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/DoubleAdderMetric.java
@@ -0,0 +1,49 @@
+package org.apache.ignite.internal.metrics;
+
+import java.util.concurrent.atomic.DoubleAdder;
+import org.apache.ignite.internal.metrics.AbstractMetric;
+import org.apache.ignite.internal.metrics.DoubleMetric;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Double metric.
+ */
+public class DoubleAdderMetric extends AbstractMetric implements DoubleMetric {
+ /** Value. */
+ private volatile DoubleAdder val;
+
+ /**
+ * @param name Name.
+ * @param desc Description.
+ */
+ public DoubleAdderMetric(String name, @Nullable String desc) {
+ super(name, desc);
+
+ this.val = new DoubleAdder();
+ }
+
+ /**
+ * Adds x to the metric.
+ *
+ * @param x Value to be added.
+ */
+ public void add(double x) {
+ val.add(x);
+ }
+
+ /**
+ * Sets value.
+ *
+ * @param val Value.
+ */
+ public void value(double val) {
+ DoubleAdder adder = new DoubleAdder();
+ adder.add(val);
+ this.val = adder;
+ }
+
+ /** {@inheritDoc} */
+ @Override public double value() {
+ return val.sum();
+ }
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/DoubleGauge.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/DoubleGauge.java
new file mode 100644
index 0000000..98dde98
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/DoubleGauge.java
@@ -0,0 +1,28 @@
+package org.apache.ignite.internal.metrics;
+
+import org.apache.ignite.internal.metrics.AbstractMetric;
+import org.apache.ignite.internal.metrics.DoubleMetric;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.function.DoubleSupplier;
+
+public class DoubleGauge extends AbstractMetric implements DoubleMetric {
+ /** Value supplier. */
+ private final DoubleSupplier val;
+
+ /**
+ * @param name Name.
+ * @param desc Description.
+ * @param val Supplier.
+ */
+ public DoubleGauge(String name, @Nullable String desc, DoubleSupplier val) {
+ super(name, desc);
+
+ this.val = val;
+ }
+
+ /** {@inheritDoc} */
+ @Override public double value() {
+ return val.getAsDouble();
+ }
+}
\ No newline at end of file
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/DoubleMetric.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/DoubleMetric.java
new file mode 100644
index 0000000..e149112
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/DoubleMetric.java
@@ -0,0 +1,11 @@
+package org.apache.ignite.internal.metrics;
+
+public interface DoubleMetric extends Metric {
+ /** @return Value of the metric. */
+ public double value();
+
+ /** {@inheritDoc} */
+ @Override public default String getAsString() {
+ return Double.toString(value());
+ }
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/IntGauge.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/IntGauge.java
new file mode 100644
index 0000000..af47db6
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/IntGauge.java
@@ -0,0 +1,31 @@
+package org.apache.ignite.internal.metrics;
+
+import org.apache.ignite.internal.metrics.AbstractMetric;
+import org.apache.ignite.internal.metrics.IntMetric;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.function.IntSupplier;
+
+/**
+ * Implementation based on primitive supplier.
+ */
+public class IntGauge extends AbstractMetric implements IntMetric {
+ /** Value supplier. */
+ private final IntSupplier val;
+
+ /**
+ * @param name Name.
+ * @param desc Description.
+ * @param val Supplier.
+ */
+ public IntGauge(String name, @Nullable String desc, IntSupplier val) {
+ super(name, desc);
+
+ this.val = val;
+ }
+
+ /** {@inheritDoc} */
+ @Override public int value() {
+ return val.getAsInt();
+ }
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/IntMetric.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/IntMetric.java
new file mode 100644
index 0000000..1c42d01
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/IntMetric.java
@@ -0,0 +1,14 @@
+package org.apache.ignite.internal.metrics;
+
+/**
+ * Interface for the metrics that holds int primitive.
+ */
+public interface IntMetric extends Metric {
+ /** @return Value of the metric. */
+ int value();
+
+ /** {@inheritDoc} */
+ default String getAsString() {
+ return Integer.toString(value());
+ }
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/LongAdderMetric.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/LongAdderMetric.java
new file mode 100644
index 0000000..0f9f863
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/LongAdderMetric.java
@@ -0,0 +1,47 @@
+package org.apache.ignite.internal.metrics;
+
+import java.util.concurrent.atomic.LongAdder;
+import org.apache.ignite.internal.metrics.AbstractMetric;
+import org.apache.ignite.internal.metrics.LongMetric;
+import org.jetbrains.annotations.Nullable;
+
+public class LongAdderMetric extends AbstractMetric implements LongMetric {
+ /** Value. */
+ private volatile LongAdder val;
+
+ /**
+ * @param name Name.
+ * @param desc Description.
+ */
+ public LongAdderMetric(String name, @Nullable String desc) {
+ super(name, desc);
+
+ this.val = new LongAdder();
+ }
+
+ /**
+ * Adds x to the metric.
+ *
+ * @param x Value to be added.
+ */
+ public void add(long x) {
+ val.add(x);
+ }
+
+ /**
+ * Sets value.
+ *
+ * @param val Value.
+ */
+ public void value(long val) {
+ LongAdder adder = new LongAdder();
+ adder.add(val);
+ this.val = adder;
+ }
+
+ /** {@inheritDoc} */
+ @Override public long value() {
+ return val.sum();
+ }
+
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/LongGauge.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/LongGauge.java
new file mode 100644
index 0000000..e2e21dc
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/LongGauge.java
@@ -0,0 +1,31 @@
+package org.apache.ignite.internal.metrics;
+
+import org.apache.ignite.internal.metrics.AbstractMetric;
+import org.apache.ignite.internal.metrics.LongMetric;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.function.LongSupplier;
+
+/**
+ * Implementation based on primitive supplier.
+ */
+public class LongGauge extends AbstractMetric implements LongMetric {
+ /** Value supplier. */
+ private final LongSupplier val;
+
+ /**
+ * @param name Name.
+ * @param desc Description.
+ * @param val Supplier.
+ */
+ public LongGauge(String name, @Nullable String desc, LongSupplier val) {
+ super(name, desc);
+
+ this.val = val;
+ }
+
+ /** {@inheritDoc} */
+ @Override public long value() {
+ return val.getAsLong();
+ }
+}
\ No newline at end of file
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/LongMetric.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/LongMetric.java
new file mode 100644
index 0000000..61dbcf1
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/LongMetric.java
@@ -0,0 +1,14 @@
+package org.apache.ignite.internal.metrics;
+
+/**
+ * Interface for the metrics that holds long primitive.
+ */
+public interface LongMetric extends Metric {
+ /** @return Value of the metric. */
+ public long value();
+
+ /** {@inheritDoc} */
+ @Override public default String getAsString() {
+ return Long.toString(value());
+ }
+}
\ No newline at end of file
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/Metric.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/Metric.java
new file mode 100644
index 0000000..fc76e45
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/Metric.java
@@ -0,0 +1,21 @@
+package org.apache.ignite.internal.metrics;
+
+import org.jetbrains.annotations.Nullable;
+
+public interface Metric {
+ /**
+ * @return Name of the metric.
+ */
+ String name();
+
+ /**
+ * @return Description of the metric.
+ */
+ String description();
+
+ /**
+ * @return String representation of metric value.
+ */
+ @Nullable
+ String getAsString();
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricsRegistry.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricsRegistry.java
new file mode 100644
index 0000000..c78bb33
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricsRegistry.java
@@ -0,0 +1,73 @@
+package org.apache.ignite.internal.metrics;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class MetricsRegistry {
+ private final Lock lock = new ReentrantLock();
+
+ /** Version always should be changed on metrics enabled/disabled action. */
+ private long ver;
+ private final Map<String, MetricsSource> sources = new HashMap<>();
+
+ private final Map<String, MetricsSet> sets = new TreeMap<>();
+
+ public void registerSource(MetricsSource src) {
+ lock.lock();
+
+ try {
+ MetricsSource old = sources.putIfAbsent(src.name(), src);
+
+ if (old != null)
+ throw new IllegalStateException("Metrics source with given name is already exists: " + src.name());
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public void unregisterSource(MetricsSource src) {
+ lock.lock();
+
+ try {
+ disable(src.name());
+
+ sources.remove(src.name());
+ } finally {
+ lock.unlock();
+ }
+ }
+
+
+ public void enable(final String srcName) {
+ lock.lock();
+
+ try {
+ MetricsSource src = sources.get(srcName);
+
+ if (src == null)
+ throw new IllegalStateException("Metrics source with given name doesn't exists: " + srcName);
+
+ sets.put(srcName, src.enable());
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public void disable(final String srcName) {
+ lock.lock();
+
+ try {
+ MetricsSource src = sources.get(srcName);
+
+ src.disable();
+
+ sets.remove(srcName);
+ } finally {
+ lock.unlock();
+ }
+ }
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricsSet.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricsSet.java
new file mode 100644
index 0000000..092316c
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricsSet.java
@@ -0,0 +1,48 @@
+package org.apache.ignite.internal.metrics;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
+
+/**
+ * The Metric set that consists of set of metrics identified by a metric name.
+ * The metrics set is immutable.
+ */
+public class MetricsSet implements Iterable<Metric> {
+ /** Metrics set name. */
+ private final String name;
+
+ /** Registered metrics. */
+ private final Map<String, Metric> metrics;
+
+ /**
+ * Creates an instance of a metrics set with given name and metrics.
+ *
+ * @param name Metrics set name.
+ * @param metrics Metrics.
+ */
+ public MetricsSet(String name, Map<String, Metric> metrics) {
+ this.name = name;
+ this.metrics = Collections.unmodifiableMap(metrics);
+ }
+
+ /** {@inheritDoc} */
+ @Nullable
+ @TestOnly
+ public <M extends Metric> M get(String name) {
+ return (M)metrics.get(name);
+ }
+
+ /** {@inheritDoc} */
+ public Iterator<Metric> iterator() {
+ return metrics.values().iterator();
+ }
+
+ /** @return Name of the metrics set. */
+ public String name() {
+ return name;
+ }
+
+}
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricsSetBuilder.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricsSetBuilder.java
new file mode 100644
index 0000000..8717251
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricsSetBuilder.java
@@ -0,0 +1,98 @@
+package org.apache.ignite.internal.metrics;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.DoubleSupplier;
+import java.util.function.IntSupplier;
+import java.util.function.LongSupplier;
+
+public class MetricsSetBuilder {
+ /** Metrics set name. */
+ private final String name;
+
+ /** Registered metrics. */
+ private Map<String, Metric> metrics = new LinkedHashMap<>();
+
+ /**
+ * Creates a new instance of metrics set builder with given name.
+ *
+ * @param name Name of metrics set. Can't be null.
+ */
+ public MetricsSetBuilder(String name) {
+ Objects.requireNonNull(name, "Metrics set name can't be null");
+ this.name = name;
+ }
+
+ public MetricsSet build() {
+ if (metrics == null) {
+ throw new IllegalStateException("Builder can't be used twice.");
+ }
+
+ MetricsSet reg = new MetricsSet(name, metrics);
+
+ metrics = null;
+
+ return reg;
+ }
+
+ /**
+ * Returns metrics set name.
+ *
+ * @return Metrics set name.
+ */
+ public String name() {
+ return name;
+ }
+
+ /**
+ * Adds existing metric with the specified name.
+ *
+ * @param metric Metric.
+ * @throws IllegalStateException If metric with given name is already added.
+ * @deprecated Wrong method. Breaks contract.
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends Metric> T register(T metric) {
+ T old = (T)metrics.putIfAbsent(metric.name(), metric);
+
+ if (old != null) {
+ throw new IllegalStateException("Metric with given name is already registered [name=" + name +
+ ", metric=" + metric + ']');
+ }
+
+ return metric;
+ }
+
+ public AtomicIntMetric atomicInt(String name, String description) {
+ return register(new AtomicIntMetric(name, description));
+ }
+
+ public IntGauge intGauge(String name, String description, IntSupplier supplier) {
+ return register(new IntGauge(name, description, supplier));
+ }
+
+ public AtomicLongMetric atomicLong(String name, String description) {
+ return register(new AtomicLongMetric(name, description));
+ }
+
+ public LongAdderMetric longAdder(String name, String description) {
+ return register(new LongAdderMetric(name, description));
+ }
+
+ public LongGauge longGauge(String name, String description, LongSupplier supplier) {
+ return register(new LongGauge(name, description, supplier));
+ }
+
+ public AtomicDoubleMetric atomicDouble(String name, String description) {
+ return register(new AtomicDoubleMetric(name, description));
+ }
+
+ public DoubleAdderMetric doubleAdder(String name, String description) {
+ return register(new DoubleAdderMetric(name, description));
+ }
+
+ public DoubleGauge doubleGauge(String name, String description, DoubleSupplier supplier) {
+ return register(new DoubleGauge(name, description, supplier));
+ }
+}
\ No newline at end of file
diff --git a/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricsSource.java b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricsSource.java
new file mode 100644
index 0000000..e729d58
--- /dev/null
+++ b/modules/metrics/src/main/java/org/apache/ignite/internal/metrics/MetricsSource.java
@@ -0,0 +1,32 @@
+package org.apache.ignite.internal.metrics;
+
+/**
+ * Interface for all metrics source.
+ */
+public interface MetricsSource {
+ /**
+ * Returns metric source name.
+ *
+ * @return Metric source name.
+ */
+ String name();
+
+ /**
+ * Enables metrics for metric source. Creates and returns {@link MetricsSet} built during enabling.
+ *
+ * @return Newly created {@link MetricsSet} instance or {@code null} if metrics are already enabled.
+ */
+ MetricsSet enable();
+
+ /**
+ * Disables metrics for metric source.
+ */
+ void disable();
+
+ /**
+ * Checks whether metrics is enabled (switched on) or not (switched off) for metric source.
+ *
+ * @return {@code True} if metrics are enabled, otherwise - {@code false}.
+ */
+ boolean enabled();
+}
diff --git a/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/examples/threadpool/ThreadPoolExample.java b/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/examples/threadpool/ThreadPoolExample.java
new file mode 100644
index 0000000..b6a87ed
--- /dev/null
+++ b/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/examples/threadpool/ThreadPoolExample.java
@@ -0,0 +1,41 @@
+package org.apache.ignite.internal.metrics.examples.threadpool;
+
+import org.apache.ignite.internal.metrics.MetricsRegistry;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+public class ThreadPoolExample {
+ public static void main(String[] args) {
+ // Should be one per node.
+ MetricsRegistry registry = new MetricsRegistry();
+
+ // ------------------------------------------------------------------------
+
+ // System component, e.g. thread pool executor
+ ThreadPoolExecutor exec = new ThreadPoolExecutor(4, 4,
+ 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
+
+ // Metrics source for thread pool
+ ThreadPoolMetricsSource src = new ThreadPoolMetricsSource("example.thread_pool.ExamplePool", exec);
+
+ // Register source after the component created.
+ registry.registerSource(src);
+
+ // ------------------------------------------------------------------------
+
+ // Enable metrics by signal (or because configuration)
+ registry.enable(src.name());
+
+ // ------------------------------------------------------------------------
+
+ // Disable metrics by signal
+ registry.disable(src.name());
+
+ // ------------------------------------------------------------------------
+
+ // Component is stopped\destroyed
+ registry.unregisterSource(src);
+ }
+}
diff --git a/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/examples/threadpool/ThreadPoolMetricsSource.java b/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/examples/threadpool/ThreadPoolMetricsSource.java
new file mode 100644
index 0000000..ae6c42a
--- /dev/null
+++ b/modules/metrics/src/test/java/org/apache/ignite/internal/metrics/examples/threadpool/ThreadPoolMetricsSource.java
@@ -0,0 +1,74 @@
+package org.apache.ignite.internal.metrics.examples.threadpool;
+
+import org.apache.ignite.internal.metrics.AbstractMetricsSource;
+import org.apache.ignite.internal.metrics.MetricsSetBuilder;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+public class ThreadPoolMetricsSource extends AbstractMetricsSource<ThreadPoolMetricsSource.Holder> {
+ private final ThreadPoolExecutor exec;
+
+ public ThreadPoolMetricsSource(String name, ThreadPoolExecutor exec) {
+ super(name);
+
+ this.exec = exec;
+ }
+
+
+ /** {@inheritDoc} */
+ @Override protected Holder createHolder() {
+ return new Holder();
+ }
+
+ @Override
+ protected void init(MetricsSetBuilder bldr, Holder holder) {
+ bldr.intGauge(
+ "ActiveCount",
+ "Approximate number of threads that are actively executing tasks.",
+ exec::getActiveCount
+ );
+
+ bldr.longGauge(
+ "CompletedTaskCount",
+ "Approximate total number of tasks that have completed execution.",
+ exec::getCompletedTaskCount
+ );
+
+ bldr.intGauge("CorePoolSize", "The core number of threads.", exec::getCorePoolSize);
+
+ bldr.intGauge(
+ "LargestPoolSize",
+ "Largest number of threads that have ever simultaneously been in the pool.",
+ exec::getLargestPoolSize
+ );
+
+ bldr.intGauge(
+ "MaximumPoolSize",
+ "The maximum allowed number of threads.",
+ exec::getMaximumPoolSize
+ );
+
+ bldr.intGauge("PoolSize", "Current number of threads in the pool.", exec::getPoolSize);
+
+ bldr.longGauge(
+ "TaskCount",
+ "Approximate total number of tasks that have been scheduled for execution.",
+ exec::getTaskCount
+ );
+
+ bldr.intGauge("QueueSize", "Current size of the execution queue.", () -> exec.getQueue().size());
+
+ bldr.longGauge(
+ "KeepAliveTime",
+ "Thread keep-alive time, which is the amount of time which threads in excess of " +
+ "the core pool size may remain idle before being terminated.",
+ () -> exec.getKeepAliveTime(MILLISECONDS)
+ );
+ }
+
+ protected static class Holder implements AbstractMetricsSource.Holder<Holder> {
+
+ }
+}
diff --git a/pom.xml b/pom.xml
index 3893628..0248e2f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -62,6 +62,7 @@
<module>modules/metastorage-client</module>
<module>modules/metastorage-common</module>
<module>modules/metastorage-server</module>
+ <module>modules/metrics</module>
<module>modules/network</module>
<module>modules/network-annotation-processor</module>
<module>modules/network-api</module>