This is an automated email from the ASF dual-hosted git repository.
alexpl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 4e517b9402b IGNITE-26510 Add max value aggregated interval metric -
Fixes #12371.
4e517b9402b is described below
commit 4e517b9402b86b855142648a06650c14ad01c8a1
Author: Aleksey Plekhanov <[email protected]>
AuthorDate: Thu Oct 2 20:06:48 2025 +0300
IGNITE-26510 Add max value aggregated interval metric - Fixes #12371.
Signed-off-by: Aleksey Plekhanov <[email protected]>
---
.../benchmarks/jol/GridMetricsJolBenchmark.java | 2 +-
.../org/apache/ignite/util/MetricCommandTest.java | 26 ++-
.../internal/management/metric/MetricCommand.java | 3 +-
.../metric/MetricConfigureMaxValueCommand.java | 48 ++++
.../metric/MetricConfigureMaxValueCommandArg.java | 59 +++++
.../internal/management/metric/MetricTask.java | 5 +
.../processors/metric/GridMetricManager.java | 72 ++++--
.../processors/metric/MetricRegistryImpl.java | 45 +++-
.../metric/impl/AbstractIntervalMetric.java | 243 +++++++++++++++++++++
.../processors/metric/impl/HitRateMetric.java | 196 ++---------------
.../processors/metric/impl/MaxValueMetric.java | 85 +++++++
.../ignite/internal/metric/JmxExporterSpiTest.java | 2 +-
.../internal/metric/MetricsConfigurationTest.java | 76 ++++++-
.../ignite/internal/metric/MetricsSelfTest.java | 90 +++++++-
.../tcp/GridTcpCommunicationSpiConfigSelfTest.java | 2 +-
.../ignite/testframework/GridSpiTestContext.java | 2 +-
...ridCommandHandlerClusterByClassTest_help.output | 8 +
...andHandlerClusterByClassWithSSLTest_help.output | 8 +
18 files changed, 761 insertions(+), 211 deletions(-)
diff --git
a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jol/GridMetricsJolBenchmark.java
b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jol/GridMetricsJolBenchmark.java
index 29195814092..cf996f1a7cb 100644
---
a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jol/GridMetricsJolBenchmark.java
+++
b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jol/GridMetricsJolBenchmark.java
@@ -111,7 +111,7 @@ public class GridMetricsJolBenchmark {
* Calculates and prints the size of metric registry of {@code TOTAL} size;
*/
private static void measureMetricRegistry() {
- MetricRegistryImpl mreg = new MetricRegistryImpl("test", name -> null,
name -> null, null);
+ MetricRegistryImpl mreg = new MetricRegistryImpl("test", name -> null,
name -> null, name -> null, null);
for (int i = 0; i < BOOLEAN_CNT; i++)
mreg.booleanMetric(BOOLEAN_METRIC + i, null);
diff --git
a/modules/control-utility/src/test/java/org/apache/ignite/util/MetricCommandTest.java
b/modules/control-utility/src/test/java/org/apache/ignite/util/MetricCommandTest.java
index 7450bad6783..8af01ebcb5b 100644
---
a/modules/control-utility/src/test/java/org/apache/ignite/util/MetricCommandTest.java
+++
b/modules/control-utility/src/test/java/org/apache/ignite/util/MetricCommandTest.java
@@ -27,6 +27,7 @@ import
org.apache.ignite.internal.management.metric.MetricCommand;
import org.apache.ignite.internal.processors.metric.MetricRegistryImpl;
import org.apache.ignite.internal.processors.metric.impl.HistogramMetricImpl;
import org.apache.ignite.internal.processors.metric.impl.HitRateMetric;
+import org.apache.ignite.internal.processors.metric.impl.MaxValueMetric;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.junit.Test;
@@ -54,6 +55,9 @@ public class MetricCommandTest extends
GridCommandHandlerClusterByClassAbstractT
/** */
private static final String CONFIGURE_HITRATE = "--configure-hitrate";
+ /** */
+ private static final String CONFIGURE_MAXVAL = "--configure-max-value";
+
/** Test node with 0 index. */
private IgniteEx ignite0;
@@ -219,11 +223,29 @@ public class MetricCommandTest extends
GridCommandHandlerClusterByClassAbstractT
HitRateMetric hitrate = mreg.hitRateMetric("hitrate", null, 500, 5);
- assertEquals(500, hitrate.rateTimeInterval());
+ assertEquals(500, hitrate.timeInterval());
executeCommand(EXIT_CODE_OK, CMD_METRIC, CONFIGURE_HITRATE,
hitrate.name(), "100");
- assertEquals(100, hitrate.rateTimeInterval());
+ assertEquals(100, hitrate.timeInterval());
+ }
+
+ /** Tests configuration of MaxValue metric. */
+ @Test
+ public void testConfigureMaxValue() {
+ String mregName = "configure-registry";
+
+ ignite0.context().metric().remove(mregName);
+
+ MetricRegistryImpl mreg =
ignite0.context().metric().registry(mregName);
+
+ MaxValueMetric maxVal = mreg.maxValueMetric("maxval", null, 500, 5);
+
+ assertEquals(500, maxVal.timeInterval());
+
+ executeCommand(EXIT_CODE_OK, CMD_METRIC, CONFIGURE_MAXVAL,
maxVal.name(), "100");
+
+ assertEquals(100, maxVal.timeInterval());
}
/** */
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricCommand.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricCommand.java
index f9ddc76eeee..3709a0764d0 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricCommand.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricCommand.java
@@ -41,7 +41,8 @@ public class MetricCommand extends
CommandRegistryImpl<MetricCommandArg, Map<Str
public MetricCommand() {
super(
new MetricConfigureHistogramCommand(),
- new MetricConfigureHitrateCommand()
+ new MetricConfigureHitrateCommand(),
+ new MetricConfigureMaxValueCommand()
);
}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricConfigureMaxValueCommand.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricConfigureMaxValueCommand.java
new file mode 100644
index 00000000000..8f59274650b
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricConfigureMaxValueCommand.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.internal.management.metric;
+
+import java.util.Collection;
+import java.util.Map;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.internal.management.api.ComputeCommand;
+
+import static
org.apache.ignite.internal.management.api.CommandUtils.nodeOrNull;
+
+/** */
+public class MetricConfigureMaxValueCommand implements
ComputeCommand<MetricCommandArg, Map<String, ?>> {
+ /** {@inheritDoc} */
+ @Override public String description() {
+ return "Configure MaxValue metric";
+ }
+
+ /** {@inheritDoc} */
+ @Override public Class<MetricConfigureMaxValueCommandArg> argClass() {
+ return MetricConfigureMaxValueCommandArg.class;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Class<MetricTask> taskClass() {
+ return MetricTask.class;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Collection<ClusterNode> nodes(Collection<ClusterNode>
nodes, MetricCommandArg arg) {
+ return nodeOrNull(arg.nodeId(), nodes);
+ }
+}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricConfigureMaxValueCommandArg.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricConfigureMaxValueCommandArg.java
new file mode 100644
index 00000000000..09ae7ee95a0
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricConfigureMaxValueCommandArg.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.internal.management.metric;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import org.apache.ignite.internal.management.api.Argument;
+import org.apache.ignite.internal.management.api.Positional;
+
+/** */
+public class MetricConfigureMaxValueCommandArg extends MetricCommandArg {
+ /** */
+ private static final long serialVersionUID = 0;
+
+ /** */
+ @Argument(description = "Time interval of the metric", example =
"newTimeInterval")
+ @Positional
+ private long newTimeInterval;
+
+ /** {@inheritDoc} */
+ @Override protected void writeExternalData(ObjectOutput out) throws
IOException {
+ super.writeExternalData(out);
+
+ out.writeLong(newTimeInterval);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void readExternalData(ObjectInput in) throws
IOException, ClassNotFoundException {
+ super.readExternalData(in);
+
+ newTimeInterval = in.readLong();
+ }
+
+ /** */
+ public long newTimeInterval() {
+ return newTimeInterval;
+ }
+
+ /** */
+ public void newTimeInterval(long interval) {
+ this.newTimeInterval = interval;
+ }
+}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricTask.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricTask.java
index cd3e66b5c8c..fe6e002d6d7 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricTask.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/metric/MetricTask.java
@@ -81,6 +81,11 @@ public class MetricTask extends
VisorOneNodeTask<MetricCommandArg, Map<String, ?
else if (arg instanceof MetricConfigureHitrateCommandArg) {
mmgr.configureHitRate(arg.name(),
((MetricConfigureHitrateCommandArg)arg).newRateTimeInterval());
+ return null;
+ }
+ else if (arg instanceof MetricConfigureMaxValueCommandArg) {
+ mmgr.configureMaxValueMetric(arg.name(),
((MetricConfigureMaxValueCommandArg)arg).newTimeInterval());
+
return null;
}
}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java
index 43c69ef84e6..3474e3d3dfa 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/GridMetricManager.java
@@ -41,9 +41,11 @@ import
org.apache.ignite.internal.managers.GridManagerAdapter;
import
org.apache.ignite.internal.processors.metastorage.DistributedMetaStorage;
import
org.apache.ignite.internal.processors.metastorage.DistributedMetastorageLifecycleListener;
import
org.apache.ignite.internal.processors.metastorage.ReadableDistributedMetaStorage;
+import
org.apache.ignite.internal.processors.metric.impl.AbstractIntervalMetric;
import org.apache.ignite.internal.processors.metric.impl.AtomicLongMetric;
import org.apache.ignite.internal.processors.metric.impl.DoubleMetricImpl;
import org.apache.ignite.internal.processors.metric.impl.HitRateMetric;
+import org.apache.ignite.internal.processors.metric.impl.MaxValueMetric;
import org.apache.ignite.internal.processors.metric.impl.MetricUtils;
import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor;
import org.apache.ignite.internal.util.future.GridCompoundFuture;
@@ -159,6 +161,9 @@ public class GridMetricManager extends
GridManagerAdapter<MetricExporterSpi> imp
/** Prefix for {@link HitRateMetric} configuration property name. */
public static final String HITRATE_CFG_PREFIX = metricName("metrics",
"hitrate");
+ /** Prefix for {@link MaxValueMetric} configuration property name. */
+ public static final String MAXVAL_CFG_PREFIX = metricName("metrics",
"maxval");
+
/** Prefix for {@link HistogramMetric} configuration property name. */
public static final String HISTOGRAM_CFG_PREFIX = metricName("metrics",
"histogram");
@@ -278,9 +283,12 @@ public class GridMetricManager extends
GridManagerAdapter<MetricExporterSpi> imp
roMetastorage = metastorage;
try {
- metastorage.iterate(HITRATE_CFG_PREFIX, (name, val) ->
onHitRateConfigChanged(
+ metastorage.iterate(HITRATE_CFG_PREFIX, (name, val) ->
onIntervalMetricConfigChanged(
name.substring(HITRATE_CFG_PREFIX.length() + 1),
(Long)val));
+ metastorage.iterate(MAXVAL_CFG_PREFIX, (name, val) ->
onIntervalMetricConfigChanged(
+ name.substring(MAXVAL_CFG_PREFIX.length() + 1),
(Long)val));
+
metastorage.iterate(HISTOGRAM_CFG_PREFIX, (name, val)
-> onHistogramConfigChanged(
name.substring(HISTOGRAM_CFG_PREFIX.length() + 1),
(long[])val));
}
@@ -289,9 +297,13 @@ public class GridMetricManager extends
GridManagerAdapter<MetricExporterSpi> imp
}
metastorage.listen(n -> n.startsWith(HITRATE_CFG_PREFIX),
- (name, oldVal, newVal) -> onHitRateConfigChanged(
+ (name, oldVal, newVal) ->
onIntervalMetricConfigChanged(
name.substring(HITRATE_CFG_PREFIX.length() + 1),
(Long)newVal));
+ metastorage.listen(n -> n.startsWith(MAXVAL_CFG_PREFIX),
+ (name, oldVal, newVal) ->
onIntervalMetricConfigChanged(
+ name.substring(MAXVAL_CFG_PREFIX.length() + 1),
(Long)newVal));
+
metastorage.listen(n -> n.startsWith(HISTOGRAM_CFG_PREFIX),
(name, oldVal, newVal) -> onHistogramConfigChanged(
name.substring(HISTOGRAM_CFG_PREFIX.length() + 1),
(long[])newVal));
@@ -324,6 +336,7 @@ public class GridMetricManager extends
GridManagerAdapter<MetricExporterSpi> imp
return (MetricRegistryImpl)registries.computeIfAbsent(name, n -> {
MetricRegistryImpl mreg = new MetricRegistryImpl(name,
custom ? null : mname ->
readFromMetastorage(metricName(HITRATE_CFG_PREFIX, mname)),
+ custom ? null : mname ->
readFromMetastorage(metricName(MAXVAL_CFG_PREFIX, mname)),
custom ? null : mname ->
readFromMetastorage(metricName(HISTOGRAM_CFG_PREFIX, mname)),
log);
@@ -405,6 +418,8 @@ public class GridMetricManager extends
GridManagerAdapter<MetricExporterSpi> imp
for (Metric m : mreg) {
if (m instanceof HitRateMetric)
opsFut.add(metastorage0.removeAsync(metricName(HITRATE_CFG_PREFIX, m.name())));
+ else if (m instanceof MaxValueMetric)
+
opsFut.add(metastorage0.removeAsync(metricName(MAXVAL_CFG_PREFIX, m.name())));
else if (m instanceof HistogramMetric)
opsFut.add(metastorage0.removeAsync(metricName(HISTOGRAM_CFG_PREFIX,
m.name())));
}
@@ -437,16 +452,47 @@ public class GridMetricManager extends
GridManagerAdapter<MetricExporterSpi> imp
* @see HitRateMetric#reset(long, int)
*/
public void configureHitRate(String name, long rateTimeInterval) throws
IgniteCheckedException {
+ configureIntervalMetric(name, HitRateMetric.class, HITRATE_CFG_PREFIX,
rateTimeInterval);
+ }
+
+ /**
+ * Change {@link AbstractIntervalMetric} configuration if it exists.
+ *
+ * @param name Metric name.
+ * @param interval New time interval.
+ * @throws IgniteCheckedException If write of configuration failed.
+ * @see AbstractIntervalMetric#reset(long, int)
+ */
+ public void configureMaxValueMetric(String name, long interval) throws
IgniteCheckedException {
+ configureIntervalMetric(name, MaxValueMetric.class, MAXVAL_CFG_PREFIX,
interval);
+ }
+
+ /**
+ * Change {@link AbstractIntervalMetric} configuration if it exists.
+ *
+ * @param name Metric name.
+ * @param cls Metric class.
+ * @param cfgPrefix Metric config prefix.
+ * @param interval New time interval.
+ * @throws IgniteCheckedException If write of configuration failed.
+ * @see AbstractIntervalMetric#reset(long, int)
+ */
+ private void configureIntervalMetric(
+ String name,
+ Class<? extends AbstractIntervalMetric> cls,
+ String cfgPrefix,
+ long interval
+ ) throws IgniteCheckedException {
A.notNullOrEmpty(name, "name");
- A.ensure(rateTimeInterval > 0, "rateTimeInterval should be positive");
+ A.ensure(interval > 0, "interval should be positive");
A.notNull(metastorage, "Metastorage not ready. Node not started?");
if (ctx.isStopping())
throw new NodeStoppingException("Operation has been cancelled
(node is stopping)");
- ensureMetricRegistered(name, HitRateMetric.class);
+ ensureMetricRegistered(name, cls);
- metastorage.write(metricName(HITRATE_CFG_PREFIX, name),
rateTimeInterval);
+ metastorage.write(metricName(cfgPrefix, name), interval);
}
/**
@@ -470,24 +516,24 @@ public class GridMetricManager extends
GridManagerAdapter<MetricExporterSpi> imp
}
/**
- * Change {@link HitRateMetric} instance configuration.
+ * Change {@link AbstractIntervalMetric} instance configuration.
*
* @param name Metric name.
- * @param rateTimeInterval New rateTimeInterval.
- * @see HitRateMetric#reset(long)
+ * @param interval New interval.
+ * @see AbstractIntervalMetric#reset(long)
*/
- private void onHitRateConfigChanged(String name, @Nullable Long
rateTimeInterval) {
- if (rateTimeInterval == null)
+ private void onIntervalMetricConfigChanged(String name, @Nullable Long
interval) {
+ if (interval == null)
return;
- A.ensure(rateTimeInterval > 0, "rateTimeInterval should be positive");
+ A.ensure(interval > 0, "interval should be positive");
- HitRateMetric m = find(name, HitRateMetric.class);
+ AbstractIntervalMetric m = find(name, AbstractIntervalMetric.class);
if (m == null)
return;
- m.reset(rateTimeInterval);
+ m.reset(interval);
}
/**
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/MetricRegistryImpl.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/MetricRegistryImpl.java
index 227f7901136..d4fe5729ef2 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/MetricRegistryImpl.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/MetricRegistryImpl.java
@@ -39,6 +39,7 @@ import
org.apache.ignite.internal.processors.metric.impl.IntMetricImpl;
import org.apache.ignite.internal.processors.metric.impl.LongAdderMetric;
import
org.apache.ignite.internal.processors.metric.impl.LongAdderWithDelegateMetric;
import org.apache.ignite.internal.processors.metric.impl.LongGauge;
+import org.apache.ignite.internal.processors.metric.impl.MaxValueMetric;
import org.apache.ignite.internal.processors.metric.impl.ObjectGauge;
import org.apache.ignite.internal.processors.metric.impl.ObjectMetricImpl;
import org.apache.ignite.internal.util.typedef.internal.LT;
@@ -47,7 +48,7 @@ import org.apache.ignite.spi.metric.Metric;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import static
org.apache.ignite.internal.processors.metric.impl.HitRateMetric.DFLT_SIZE;
+import static
org.apache.ignite.internal.processors.metric.impl.AbstractIntervalMetric.DFLT_SIZE;
import static
org.apache.ignite.internal.processors.metric.impl.MetricUtils.customMetric;
import static
org.apache.ignite.internal.processors.metric.impl.MetricUtils.fromFullName;
import static
org.apache.ignite.internal.processors.metric.impl.MetricUtils.metricName;
@@ -57,10 +58,10 @@ import static
org.apache.ignite.internal.processors.metric.impl.MetricUtils.metr
*/
public class MetricRegistryImpl implements MetricRegistry {
/** Registry name. */
- private String regName;
+ private final String regName;
/** Logger. */
- private IgniteLogger log;
+ private final IgniteLogger log;
/** Registered metrics. */
private final ConcurrentHashMap<String, Metric> metrics = new
ConcurrentHashMap<>();
@@ -68,20 +69,30 @@ public class MetricRegistryImpl implements MetricRegistry {
/** HitRate config provider. */
private final Function<String, Long> hitRateCfgProvider;
+ /** MaxValue metric config provider. */
+ private final Function<String, Long> maxValCfgProvider;
+
/** Histogram config provider. */
private final Function<String, long[]> histogramCfgProvider;
/**
* @param regName Registry name.
* @param hitRateCfgProvider HitRate config provider.
+ * @param maxValCfgProvider MaxVal config provider.
* @param histogramCfgProvider Histogram config provider.
* @param log Logger.
*/
- public MetricRegistryImpl(String regName, Function<String, Long>
hitRateCfgProvider,
- Function<String, long[]> histogramCfgProvider, IgniteLogger log) {
+ public MetricRegistryImpl(
+ String regName,
+ Function<String, Long> hitRateCfgProvider,
+ Function<String, Long> maxValCfgProvider,
+ Function<String, long[]> histogramCfgProvider,
+ IgniteLogger log
+ ) {
this.regName = regName;
this.log = log;
this.hitRateCfgProvider = hitRateCfgProvider;
+ this.maxValCfgProvider = maxValCfgProvider;
this.histogramCfgProvider = histogramCfgProvider;
}
@@ -234,6 +245,21 @@ public class MetricRegistryImpl implements MetricRegistry {
return addMetric(name, new HitRateMetric(metricName(regName, name),
desc, rateTimeInterval, size));
}
+ /**
+ * Creates and register metric for max value during certain time interval.
+ *
+ * It will accumulates approximate max value statistics.
+ * Calculates max value in last timeInterval milliseconds.
+ *
+ * @param timeInterval Time interval.
+ * @param size Array size for underlying calculations (buckets count).
+ * @return {@link MaxValueMetric}
+ * @see MaxValueMetric
+ */
+ public MaxValueMetric maxValueMetric(String name, @Nullable String desc,
long timeInterval, int size) {
+ return addMetric(name, new MaxValueMetric(metricName(regName, name),
desc, timeInterval, size));
+ }
+
/**
* Creates and register named gauge.
* Returned instance are thread safe.
@@ -305,6 +331,15 @@ public class MetricRegistryImpl implements MetricRegistry {
if (cfgRateTimeInterval != null)
((HitRateMetric)metric).reset(cfgRateTimeInterval, DFLT_SIZE);
}
+ else if (metric instanceof MaxValueMetric) {
+ if (maxValCfgProvider == null)
+ return;
+
+ Long cfgTimeInterval = maxValCfgProvider.apply(metric.name());
+
+ if (cfgTimeInterval != null)
+ ((MaxValueMetric)metric).reset(cfgTimeInterval, DFLT_SIZE);
+ }
}
/** {@inheritDoc} */
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/AbstractIntervalMetric.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/AbstractIntervalMetric.java
new file mode 100644
index 00000000000..ea7a58fd766
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/AbstractIntervalMetric.java
@@ -0,0 +1,243 @@
+/*
+* 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.
+*/
+package org.apache.ignite.internal.processors.metric.impl;
+
+import java.util.concurrent.atomic.AtomicLongArray;
+import org.apache.ignite.internal.processors.metric.AbstractMetric;
+import org.apache.ignite.internal.util.typedef.internal.A;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.metric.LongMetric;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Accumulates approximate values statistics.
+ * Calculates accumulated value in last {@code timeInterval} milliseconds.
+ * Algorithm is based on circular array of {@code size} values, each is
responsible for last corresponding time
+ * subinterval of {@code timeInterval}/{@code size} milliseconds. Resulting
value is accumulated for all subintervals.
+ *
+ * Implementation is nonblocking and protected from values loss.
+ * Maximum relative error is 1/{@code size}.
+ * Maximum value per interval is {@code 2^55 - 1}.
+ */
+public abstract class AbstractIntervalMetric extends AbstractMetric implements
LongMetric {
+ /** Default values array size (number of buckets). */
+ public static final int DFLT_SIZE = 10;
+
+ /** Metric instance. */
+ protected volatile AbstractIntervalMetricImpl cntr;
+
+ /**
+ * @param name Name.
+ * @param desc Description.
+ * @param timeInterval Time interval in milliseconds.
+ * @param size Values array size.
+ */
+ protected AbstractIntervalMetric(String name, @Nullable String desc, long
timeInterval, int size) {
+ super(name, desc);
+
+ reset(timeInterval, size);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void reset() {
+ AbstractIntervalMetricImpl cntr0 = cntr;
+
+ reset(cntr0.timeInterval, cntr0.size);
+ }
+
+ /**
+ * Resets metric with the new parametes.
+ *
+ * @param timeInterval New rate time interval.
+ */
+ public void reset(long timeInterval) {
+ reset(timeInterval, DFLT_SIZE);
+ }
+
+ /**
+ * Resets metric with the new parameters.
+ *
+ * @param timeInterval New time interval.
+ * @param size New values array size.
+ */
+ public void reset(long timeInterval, int size) {
+ cntr = createImpl(timeInterval, size);
+ }
+
+ /** */
+ protected abstract AbstractIntervalMetricImpl createImpl(long
timeInterval, int size);
+
+ /** {@inheritDoc} */
+ @Override public long value() {
+ return cntr.value();
+ }
+
+ /** @return Time interval in milliseconds. */
+ public long timeInterval() {
+ return cntr.timeInterval;
+ }
+
+ /**
+ * Actual metric.
+ */
+ protected abstract static class AbstractIntervalMetricImpl {
+ /** Bits that store actual hit count. */
+ private static final int TAG_OFFSET = 56;
+
+ /** Tag mask. */
+ protected static final long TAG_MASK = -1L << TAG_OFFSET;
+
+ /** Useful part mask. */
+ protected static final long NO_TAG_MASK = ~TAG_MASK;
+
+ /** Time interval when values are counted to calculate accumulated
value, in milliseconds. */
+ private final long timeInterval;
+
+ /** Counters array size. */
+ private final int size;
+
+ /** Last value times. */
+ private final AtomicLongArray lastValTimes;
+
+ /** Tagged values. */
+ protected final AtomicLongArray taggedVals;
+
+ /**
+ * @param timeInterval Time interval.
+ * @param size Number of buckets.
+ */
+ protected AbstractIntervalMetricImpl(long timeInterval, int size) {
+ A.ensure(timeInterval > 0, "timeInterval should be positive");
+
+ A.ensure(size > 1, "Minimum value for size is 2");
+
+ this.timeInterval = timeInterval;
+
+ this.size = size;
+
+ taggedVals = new AtomicLongArray(size);
+
+ lastValTimes = new AtomicLongArray(size);
+ }
+
+ /**
+ * Adds val to the metric.
+ *
+ * @param val Value.
+ */
+ public void update(long val) {
+ long curTs = U.currentTimeMillis();
+
+ int curPos = position(curTs);
+
+ clearIfObsolete(curTs, curPos);
+
+ lastValTimes.set(curPos, curTs);
+
+ // Order is important. Value won't be cleared by concurrent
#clearIfObsolete.
+ accumulateBucket(curPos, val);
+ }
+
+ /**
+ * @return Accumulated value in last {@link #timeInterval}
milliseconds.
+ */
+ public long value() {
+ long curTs = U.currentTimeMillis();
+
+ long res = 0;
+
+ for (int i = 0; i < size; i++) {
+ clearIfObsolete(curTs, i);
+
+ res = accumulate(res, untag(taggedVals.get(i)));
+ }
+
+ return res;
+ }
+
+ /**
+ * Folds value into a result.
+ *
+ * @return Accumulated value.
+ */
+ protected abstract long accumulate(long res, long val);
+
+ /**
+ * Folds value into a bucket.
+ */
+ protected abstract void accumulateBucket(int bucket, long val);
+
+ /**
+ * @param curTs Current timestamp.
+ * @param i Index.
+ */
+ private void clearIfObsolete(long curTs, int i) {
+ long cur = taggedVals.get(i);
+
+ byte curTag = getTag(cur);
+
+ long lastTs = lastValTimes.get(i);
+
+ if (isObsolete(curTs, lastTs)) {
+ if (taggedVals.compareAndSet(i, cur,
taggedLongZero(++curTag))) // ABA problem prevention.
+ lastValTimes.set(i, curTs);
+ // If CAS failed, counter is reset by another thread.
+ }
+ }
+
+ /**
+ * @param curTs Current timestamp.
+ * @param lastValTime Last value timestamp.
+ * @return True, is last value time was too long ago.
+ */
+ private boolean isObsolete(long curTs, long lastValTime) {
+ return curTs - lastValTime > timeInterval * (size - 1) / size;
+ }
+
+ /**
+ * @param time Timestamp.
+ * @return Index of bucket for given timestamp.
+ */
+ private int position(long time) {
+ return (int)((time % timeInterval * size) / timeInterval);
+ }
+
+ /**
+ * @param tag Tag byte.
+ * @return 0L with given tag byte.
+ */
+ private static long taggedLongZero(byte tag) {
+ return ((long)tag << TAG_OFFSET);
+ }
+
+ /**
+ * @param l Tagged long.
+ * @return Long without tag byte.
+ */
+ private static long untag(long l) {
+ return l & NO_TAG_MASK;
+ }
+
+ /**
+ * @param taggedLong Tagged long.
+ * @return Tag byte.
+ */
+ private static byte getTag(long taggedLong) {
+ return (byte)(taggedLong >> TAG_OFFSET);
+ }
+ }
+}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/HitRateMetric.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/HitRateMetric.java
index 5ac88a94c96..d4da705c4fd 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/HitRateMetric.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/HitRateMetric.java
@@ -16,30 +16,15 @@
*/
package org.apache.ignite.internal.processors.metric.impl;
-import java.util.concurrent.atomic.AtomicLongArray;
-import org.apache.ignite.internal.processors.metric.AbstractMetric;
-import org.apache.ignite.internal.util.typedef.internal.A;
-import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.spi.metric.LongMetric;
import org.jetbrains.annotations.Nullable;
/**
* Accumulates approximate hit rate statistics.
* Calculates number of hits in last {@code rateTimeInterval} milliseconds.
- * Algorithm is based on circular array of {@code size} hit counters, each is
responsible for last corresponding time
- * interval of {@code rateTimeInterval}/{@code size} milliseconds. Resulting
number of hits is sum of all counters.
*
- * <p>Implementation is nonblocking and protected from hits loss.
- * Maximum relative error is 1/{@code size}.
- * 2^55 - 1 hits per interval can be accumulated without numeric overflow.
+ * @see AbstractIntervalMetric for implementation details.
*/
-public class HitRateMetric extends AbstractMetric implements LongMetric {
- /** Default counters array size. */
- public static final int DFLT_SIZE = 10;
-
- /** Metric instance. */
- private volatile HitRateMetricImpl cntr;
-
+public class HitRateMetric extends AbstractIntervalMetric {
/**
* @param name Name.
* @param desc Description.
@@ -47,35 +32,12 @@ public class HitRateMetric extends AbstractMetric
implements LongMetric {
* @param size Counters array size.
*/
public HitRateMetric(String name, @Nullable String desc, long
rateTimeInterval, int size) {
- super(name, desc);
-
- cntr = new HitRateMetricImpl(rateTimeInterval, size);
+ super(name, desc, rateTimeInterval, size);
}
/** {@inheritDoc} */
- @Override public void reset() {
- HitRateMetricImpl cntr0 = cntr;
-
- cntr = new HitRateMetricImpl(cntr0.rateTimeInterval, cntr0.size);
- }
-
- /**
- * Resets metric with the new parametes.
- *
- * @param rateTimeInterval New rate time interval.
- */
- public void reset(long rateTimeInterval) {
- reset(rateTimeInterval, DFLT_SIZE);
- }
-
- /**
- * Resets metric with the new parameters.
- *
- * @param rateTimeInterval New rate time interval.
- * @param size New counters array size.
- */
- public void reset(long rateTimeInterval, int size) {
- cntr = new HitRateMetricImpl(rateTimeInterval, size);
+ @Override protected AbstractIntervalMetricImpl createImpl(long
timeInterval, int size) {
+ return new HitRateMetricImpl(timeInterval, size);
}
/**
@@ -84,7 +46,7 @@ public class HitRateMetric extends AbstractMetric implements
LongMetric {
* @param x Value to be added.
*/
public void add(long x) {
- cntr.add(x);
+ cntr.update(x);
}
/** Adds 1 to the metric. */
@@ -92,150 +54,26 @@ public class HitRateMetric extends AbstractMetric
implements LongMetric {
add(1);
}
- /** {@inheritDoc} */
- @Override public long value() {
- return cntr.value();
- }
-
- /** @return Rate time interval in milliseconds. */
- public long rateTimeInterval() {
- return cntr.rateTimeInterval;
- }
-
/**
* Actual metric.
- *
- * Separated class required to
*/
- private static class HitRateMetricImpl {
- /** Bits that store actual hit count. */
- private static final int TAG_OFFSET = 56;
-
- /** Useful part mask. */
- private static final long NO_TAG_MASK = ~(-1L << TAG_OFFSET);
-
- /** Time interval when hits are counted to calculate rate, in
milliseconds. */
- private final long rateTimeInterval;
-
- /** Counters array size. */
- private final int size;
-
- /** Tagged counters. */
- private final AtomicLongArray taggedCounters;
-
- /** Last hit times. */
- private final AtomicLongArray lastHitTimes;
-
- /**
- * @param rateTimeInterval Rate time interval.
- * @param size Number of counters.
- */
- public HitRateMetricImpl(long rateTimeInterval, int size) {
- A.ensure(rateTimeInterval > 0, "rateTimeInterval should be
positive");
-
- A.ensure(size > 1, "Minimum value for size is 2");
-
- this.rateTimeInterval = rateTimeInterval;
-
- this.size = size;
-
- taggedCounters = new AtomicLongArray(size);
-
- lastHitTimes = new AtomicLongArray(size);
- }
-
+ private static class HitRateMetricImpl extends AbstractIntervalMetricImpl {
/**
- * Adds hits to the metric.
- *
- * @param hits Number of hits.
+ * @param timeInterval Time interval.
+ * @param size Buckets count.
*/
- public void add(long hits) {
- long curTs = U.currentTimeMillis();
-
- int curPos = position(curTs);
-
- clearIfObsolete(curTs, curPos);
-
- lastHitTimes.set(curPos, curTs);
-
- // Order is important. Hit won't be cleared by concurrent
#clearIfObsolete.
- taggedCounters.addAndGet(curPos, hits);
- }
-
- /**
- * @return Total number of hits in last {@link #rateTimeInterval}
milliseconds.
- */
- public long value() {
- long curTs = U.currentTimeMillis();
-
- long sum = 0;
-
- for (int i = 0; i < size; i++) {
- clearIfObsolete(curTs, i);
-
- sum += untag(taggedCounters.get(i));
- }
-
- return sum;
+ public HitRateMetricImpl(long timeInterval, int size) {
+ super(timeInterval, size);
}
- /**
- * @param curTs Current timestamp.
- * @param i Index.
- */
- private void clearIfObsolete(long curTs, int i) {
- long cur = taggedCounters.get(i);
-
- byte curTag = getTag(cur);
-
- long lastTs = lastHitTimes.get(i);
-
- if (isObsolete(curTs, lastTs)) {
- if (taggedCounters.compareAndSet(i, cur,
taggedLongZero(++curTag))) // ABA problem prevention.
- lastHitTimes.set(i, curTs);
- // If CAS failed, counter is reset by another thread.
- }
+ /** {@inheritDoc} */
+ @Override protected long accumulate(long res, long val) {
+ return res + val;
}
- /**
- * @param curTs Current timestamp.
- * @param lastHitTime Last hit timestamp.
- * @return True, is last hit time was too long ago.
- */
- private boolean isObsolete(long curTs, long lastHitTime) {
- return curTs - lastHitTime > rateTimeInterval * (size - 1) / size;
- }
-
- /**
- * @param time Timestamp.
- * @return Index of counter for given timestamp.
- */
- private int position(long time) {
- return (int)((time % rateTimeInterval * size) / rateTimeInterval);
- }
-
- /**
- * @param tag Tag byte.
- * @return 0L with given tag byte.
- */
- private static long taggedLongZero(byte tag) {
- return ((long)tag << TAG_OFFSET);
- }
-
- /**
- * @param l Tagged long.
- * @return Long without tag byte.
- */
- private static long untag(long l) {
- return l & NO_TAG_MASK;
- }
-
- /**
- * @param taggedLong Tagged long.
- * @return Tag byte.
- */
- private static byte getTag(long taggedLong) {
- return (byte)(taggedLong >> TAG_OFFSET);
+ /** {@inheritDoc} */
+ @Override protected void accumulateBucket(int bucket, long val) {
+ taggedVals.addAndGet(bucket, val);
}
}
}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MaxValueMetric.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MaxValueMetric.java
new file mode 100644
index 00000000000..0ad4e31d5fe
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MaxValueMetric.java
@@ -0,0 +1,85 @@
+/*
+* 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.
+*/
+package org.apache.ignite.internal.processors.metric.impl;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Accumulates approximate maximum value statistics.
+ * Calculates maximum value in last {@code timeInterval} milliseconds.
+ *
+ * @see AbstractIntervalMetric for implementation details.
+ */
+public class MaxValueMetric extends AbstractIntervalMetric {
+ /**
+ * @param name Name.
+ * @param desc Description.
+ * @param timeInterval Time interval in milliseconds.
+ * @param size Values array size (number of buckets).
+ */
+ public MaxValueMetric(String name, @Nullable String desc, long
timeInterval, int size) {
+ super(name, desc, timeInterval, size);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected AbstractIntervalMetricImpl createImpl(long
timeInterval, int size) {
+ return new MaxValueMetricImpl(timeInterval, size);
+ }
+
+ /**
+ * Accumulate x value to the metric.
+ *
+ * @param x Value to be accumulate.
+ */
+ public void update(long x) {
+ cntr.update(x);
+ }
+
+ /**
+ * Actual metric.
+ */
+ private static class MaxValueMetricImpl extends AbstractIntervalMetricImpl
{
+ /**
+ * @param timeInterval Time interval.
+ * @param size Buckets count.
+ */
+ public MaxValueMetricImpl(long timeInterval, int size) {
+ super(timeInterval, size);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected long accumulate(long res, long val) {
+ return Math.max(res, val);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void accumulateBucket(int bucket, long val) {
+ long oldVal;
+ long val0;
+
+ do {
+ oldVal = taggedVals.get(bucket);
+
+ val0 = (val & NO_TAG_MASK) | (oldVal & TAG_MASK);
+
+ if (val0 <= oldVal)
+ return;
+ }
+ while (!taggedVals.compareAndSet(bucket, oldVal, val0));
+ }
+ }
+}
diff --git
a/modules/core/src/test/java/org/apache/ignite/internal/metric/JmxExporterSpiTest.java
b/modules/core/src/test/java/org/apache/ignite/internal/metric/JmxExporterSpiTest.java
index ed21575c046..d01649ea29a 100644
---
a/modules/core/src/test/java/org/apache/ignite/internal/metric/JmxExporterSpiTest.java
+++
b/modules/core/src/test/java/org/apache/ignite/internal/metric/JmxExporterSpiTest.java
@@ -607,7 +607,7 @@ public class JmxExporterSpiTest extends
AbstractExporterSpiTest {
/** */
@Test
public void testHistogramSearchByName() throws Exception {
- MetricRegistryImpl mreg = new MetricRegistryImpl("test", name -> null,
name -> null, null);
+ MetricRegistryImpl mreg = new MetricRegistryImpl("test", name -> null,
name -> null, name -> null, null);
createTestHistogram(mreg);
diff --git
a/modules/core/src/test/java/org/apache/ignite/internal/metric/MetricsConfigurationTest.java
b/modules/core/src/test/java/org/apache/ignite/internal/metric/MetricsConfigurationTest.java
index 7892f43f41f..9041b4bb8b2 100644
---
a/modules/core/src/test/java/org/apache/ignite/internal/metric/MetricsConfigurationTest.java
+++
b/modules/core/src/test/java/org/apache/ignite/internal/metric/MetricsConfigurationTest.java
@@ -17,15 +17,19 @@
package org.apache.ignite.internal.metric;
+import java.util.Collections;
+import javax.management.DynamicMBean;
import org.apache.ignite.cluster.ClusterState;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.DataStorageConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.management.api.CommandMBean;
import org.apache.ignite.internal.processors.metric.MetricRegistryImpl;
import org.apache.ignite.internal.processors.metric.MetricsMxBeanImpl;
import org.apache.ignite.internal.processors.metric.impl.HistogramMetricImpl;
import org.apache.ignite.internal.processors.metric.impl.HitRateMetric;
+import org.apache.ignite.internal.processors.metric.impl.MaxValueMetric;
import
org.apache.ignite.internal.processors.metric.impl.PeriodicHistogramMetricImpl;
import org.apache.ignite.mxbean.MetricsMxBean;
import org.apache.ignite.spi.metric.HistogramMetric;
@@ -37,6 +41,7 @@ import static
org.apache.ignite.internal.binary.BinaryUtils.arrayEq;
import static
org.apache.ignite.internal.processors.cache.transactions.TransactionMetricsAdapter.METRIC_SYSTEM_TIME_HISTOGRAM;
import static
org.apache.ignite.internal.processors.metric.GridMetricManager.HISTOGRAM_CFG_PREFIX;
import static
org.apache.ignite.internal.processors.metric.GridMetricManager.HITRATE_CFG_PREFIX;
+import static
org.apache.ignite.internal.processors.metric.GridMetricManager.MAXVAL_CFG_PREFIX;
import static
org.apache.ignite.internal.processors.metric.GridMetricManager.TX_METRICS;
import static
org.apache.ignite.internal.processors.metric.impl.MetricUtils.cacheMetricsRegistryName;
import static
org.apache.ignite.internal.processors.metric.impl.MetricUtils.metricName;
@@ -54,6 +59,9 @@ public class MetricsConfigurationTest extends
GridCommonAbstractTest {
/** Test hitrate metric name. */
public static final String HITRATE_NAME = "hitrate";
+ /** Test maxval metric name. */
+ public static final String MAXVAL_NAME = "maxval";
+
/** Test histogram metric name. */
public static final String HISTOGRAM_NAME = "histogram";
@@ -115,7 +123,57 @@ public class MetricsConfigurationTest extends
GridCommonAbstractTest {
HitRateMetric allocationRate =
g.context().metric().registry(metricName("io.dataregion.default"))
.findMetric("AllocationRate");
- assertEquals(5000, allocationRate.rateTimeInterval());
+ assertEquals(5000, allocationRate.timeInterval());
+ }
+ }
+
+ /** Tests configuration of {@link MaxValueMetric}. */
+ @Test
+ public void testMaxValueMetricConfiguration() throws Exception {
+ try (IgniteEx g = startGrid(0)) {
+ MetricRegistryImpl mreg = g.context().metric().registry(TEST_REG);
+ MaxValueMetric metric = mreg.maxValueMetric(MAXVAL_NAME, "test",
10000, 5);
+ String metricName = metricName(TEST_REG, MAXVAL_NAME);
+
+ // Empty name.
+ assertThrowsWithCause(
+ () -> configureMaxValueMetric(g, null, 1),
+ NullPointerException.class);
+
+ // Wrong interval value.
+ assertThrowsWithCause(
+ () -> configureMaxValueMetric(g, metricName, 0),
+ IllegalArgumentException.class);
+
+ assertThrowsWithCause(
+ () -> configureMaxValueMetric(g, metricName, -1),
+ IllegalArgumentException.class);
+
+ configureMaxValueMetric(g, metricName, 5000);
+
+ assertEquals(5000, metric.timeInterval());
+ }
+ }
+
+ /** */
+ private void configureMaxValueMetric(IgniteEx ignite, String metricName,
int interval) {
+ DynamicMBean mbean = getMxBean(
+ ignite.context().igniteInstanceName(),
+ "management",
+ Collections.singletonList("Metric"),
+ "ConfigureMaxValue",
+ DynamicMBean.class
+ );
+
+ try {
+ mbean.invoke(
+ CommandMBean.INVOKE,
+ new Object[] {metricName, Integer.toString(interval), null},
+ new String[] {String.class.getName(), String.class.getName(),
String.class.getName()}
+ );
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
}
}
@@ -242,28 +300,38 @@ public class MetricsConfigurationTest extends
GridCommonAbstractTest {
MetricRegistryImpl mreg = g0.context().metric().registry(TEST_REG);
mreg.hitRateMetric(HITRATE_NAME, "test", 10000, 5);
+ mreg.maxValueMetric(MAXVAL_NAME, "test", 10000, 5);
mreg.histogram(HISTOGRAM_NAME, new long[] {250, 500}, "test");
metricsBean(g0).configureHistogramMetric(metricName(TEST_REG,
HISTOGRAM_NAME), BOUNDS);
metricsBean(g0).configureHitRateMetric(metricName(TEST_REG,
HITRATE_NAME), 1000);
+ configureMaxValueMetric(g0, metricName(TEST_REG, MAXVAL_NAME),
1000);
}, (g0, g1) -> {
MetricRegistryImpl mreg = g0.context().metric().registry(TEST_REG);
HitRateMetric hitRate = mreg.hitRateMetric(HITRATE_NAME, "test",
10000, 5);
+ MaxValueMetric maxVal = mreg.maxValueMetric(MAXVAL_NAME, "test",
10000, 5);
HistogramMetricImpl histogram = mreg.histogram(HISTOGRAM_NAME, new
long[] {250, 500}, "test");
- assertEquals(1000, hitRate.rateTimeInterval());
+ assertEquals(1000, hitRate.timeInterval());
+ assertEquals(1000, maxVal.timeInterval());
assertArrayEquals(BOUNDS, histogram.bounds());
assertEquals((Long)1000L,
g0.context().distributedMetastorage().read(metricName(HITRATE_CFG_PREFIX,
TEST_REG, HITRATE_NAME)));
+ assertEquals((Long)1000L,
+
g0.context().distributedMetastorage().read(metricName(MAXVAL_CFG_PREFIX,
TEST_REG, MAXVAL_NAME)));
+
assertArrayEquals(BOUNDS,
g0.context().distributedMetastorage().read(metricName(HISTOGRAM_CFG_PREFIX,
TEST_REG, HISTOGRAM_NAME)));
assertEquals((Long)1000L,
g1.context().distributedMetastorage().read(metricName(HITRATE_CFG_PREFIX,
TEST_REG, HITRATE_NAME)));
+ assertEquals((Long)1000L,
+
g1.context().distributedMetastorage().read(metricName(MAXVAL_CFG_PREFIX,
TEST_REG, MAXVAL_NAME)));
+
assertArrayEquals(BOUNDS,
g1.context().distributedMetastorage().read(metricName(HISTOGRAM_CFG_PREFIX,
TEST_REG, HISTOGRAM_NAME)));
@@ -271,11 +339,15 @@ public class MetricsConfigurationTest extends
GridCommonAbstractTest {
assertNull(
g0.context().distributedMetastorage().read(metricName(HITRATE_CFG_PREFIX,
TEST_REG, HITRATE_NAME)));
+ assertNull(
+
g0.context().distributedMetastorage().read(metricName(MAXVAL_CFG_PREFIX,
TEST_REG, MAXVAL_NAME)));
assertNull(
g0.context().distributedMetastorage().read(metricName(HISTOGRAM_CFG_PREFIX,
TEST_REG, HISTOGRAM_NAME)));
assertNull(
g1.context().distributedMetastorage().read(metricName(HITRATE_CFG_PREFIX,
TEST_REG, HITRATE_NAME)));
+ assertNull(
+
g1.context().distributedMetastorage().read(metricName(MAXVAL_CFG_PREFIX,
TEST_REG, MAXVAL_NAME)));
assertNull(
g1.context().distributedMetastorage().read(metricName(HISTOGRAM_CFG_PREFIX,
TEST_REG, HISTOGRAM_NAME)));
});
diff --git
a/modules/core/src/test/java/org/apache/ignite/internal/metric/MetricsSelfTest.java
b/modules/core/src/test/java/org/apache/ignite/internal/metric/MetricsSelfTest.java
index bff7e75fe8d..17d6ac88efd 100644
---
a/modules/core/src/test/java/org/apache/ignite/internal/metric/MetricsSelfTest.java
+++
b/modules/core/src/test/java/org/apache/ignite/internal/metric/MetricsSelfTest.java
@@ -23,6 +23,8 @@ import java.util.List;
import java.util.Set;
import java.util.Spliterators;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.StreamSupport;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.IgniteInternalFuture;
@@ -34,6 +36,8 @@ import
org.apache.ignite.internal.processors.metric.impl.HistogramMetricImpl;
import org.apache.ignite.internal.processors.metric.impl.HitRateMetric;
import org.apache.ignite.internal.processors.metric.impl.IntMetricImpl;
import org.apache.ignite.internal.processors.metric.impl.LongAdderMetric;
+import org.apache.ignite.internal.processors.metric.impl.MaxValueMetric;
+import org.apache.ignite.internal.util.GridTestClockTimer;
import org.apache.ignite.internal.util.typedef.T2;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.spi.IgniteSpiException;
@@ -70,7 +74,7 @@ public class MetricsSelfTest extends GridCommonAbstractTest {
/** */
@Before
public void setUp() throws Exception {
- mreg = new MetricRegistryImpl("group", name -> null, name -> null,
null);
+ mreg = new MetricRegistryImpl("group", name -> null, name -> null,
name -> null, null);
}
/** */
@@ -293,7 +297,7 @@ public class MetricsSelfTest extends GridCommonAbstractTest
{
/** */
@Test
public void testGetMetrics() throws Exception {
- MetricRegistryImpl mreg = new MetricRegistryImpl("group", name ->
null, name -> null, null);
+ MetricRegistryImpl mreg = new MetricRegistryImpl("group", name ->
null, name -> null, name -> null, null);
mreg.longMetric("test1", "");
mreg.longMetric("test2", "");
@@ -314,7 +318,7 @@ public class MetricsSelfTest extends GridCommonAbstractTest
{
/** */
@Test
public void testRemove() throws Exception {
- MetricRegistryImpl mreg = new MetricRegistryImpl("group", name ->
null, name -> null, null);
+ MetricRegistryImpl mreg = new MetricRegistryImpl("group", name ->
null, name -> null, name -> null, null);
AtomicLongMetric cntr = mreg.longMetric("my.name", null);
AtomicLongMetric cntr2 = mreg.longMetric("my.name.x", null);
@@ -354,13 +358,89 @@ public class MetricsSelfTest extends
GridCommonAbstractTest {
assertEquals(0, metric.value());
- assertEquals(rateTimeInterval, metric.rateTimeInterval());
+ assertEquals(rateTimeInterval, metric.timeInterval());
metric.reset(rateTimeInterval * 2, 10);
- assertEquals(rateTimeInterval * 2, metric.rateTimeInterval());
+ assertEquals(rateTimeInterval * 2, metric.timeInterval());
}
+ /** */
+ @Test
+ public void testMaxValueMetric() {
+ try {
+ long timeInterval = 500;
+
+ MaxValueMetric metric = mreg.maxValueMetric("testMaxVal", null,
timeInterval, 5);
+
+ assertEquals(0, metric.value());
+
+ long startTs = U.currentTimeMillis();
+
+ updateMaxValMetric(metric, startTs + 40, 5);
+ updateMaxValMetric(metric, startTs + 50, 10);
+ updateMaxValMetric(metric, startTs + 60, 5);
+
+ assertEquals(10, metric.value());
+
+ updateMaxValMetric(metric, startTs + 140, 10);
+ updateMaxValMetric(metric, startTs + 150, 20);
+ updateMaxValMetric(metric, startTs + 160, 10);
+
+ assertEquals(20, metric.value());
+
+ updateMaxValMetric(metric, startTs + 240, 10);
+ updateMaxValMetric(metric, startTs + 250, 15);
+ updateMaxValMetric(metric, startTs + 260, 10);
+
+ assertEquals(20, metric.value());
+
+ GridTestClockTimer.timeSupplier(() -> startTs + 650);
+ GridTestClockTimer.update();
+
+ assertEquals(15, metric.value());
+
+ GridTestClockTimer.timeSupplier(() -> startTs + 750);
+ GridTestClockTimer.update();
+
+ assertEquals(0, metric.value());
+ }
+ finally {
+
GridTestClockTimer.timeSupplier(GridTestClockTimer.DFLT_TIME_SUPPLIER);
+ }
+ }
+
+ /** */
+ @Test
+ public void testMaxValueMetricMultithreaded() throws Exception {
+ long timeInterval = 500;
+ long maxVal = 100;
+ AtomicInteger threadId = new AtomicInteger();
+
+ MaxValueMetric metric = mreg.maxValueMetric("testMaxVal", null,
timeInterval, 500);
+
+ assertEquals(0, metric.value());
+
+ long startTs = U.currentTimeMillis();
+
+ GridTestUtils.runMultiThreaded(() -> {
+ int id = threadId.getAndIncrement();
+
+ while (U.currentTimeMillis() < startTs + timeInterval)
+ metric.update(id == 0 ? maxVal :
ThreadLocalRandom.current().nextLong(maxVal));
+ }, 10, "metric-update");
+
+ assertEquals(maxVal, metric.value());
+ }
+
+ /** */
+ private void updateMaxValMetric(MaxValueMetric metric, long ts, long val) {
+ GridTestClockTimer.timeSupplier(() -> ts);
+ GridTestClockTimer.update();
+ metric.update(val);
+ }
+
+
/** */
@Test
public void testHistogramNames() throws Exception {
diff --git
a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiConfigSelfTest.java
b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiConfigSelfTest.java
index b1b26e3924b..d4d63ac7e66 100644
---
a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiConfigSelfTest.java
+++
b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiConfigSelfTest.java
@@ -194,7 +194,7 @@ public class GridTcpCommunicationSpiConfigSelfTest extends
GridSpiAbstractConfig
// No-op.
}
- return new MetricRegistryImpl(name, null, null, new NullLogger());
+ return new MetricRegistryImpl(name, null, null, null, new
NullLogger());
});
TcpCommunicationSpi receiverSpi = initializeSpi(receiverCtx,
receiverNode, listeningLog, true);
diff --git
a/modules/core/src/test/java/org/apache/ignite/testframework/GridSpiTestContext.java
b/modules/core/src/test/java/org/apache/ignite/testframework/GridSpiTestContext.java
index 56852ea365a..7f5d876e21f 100644
---
a/modules/core/src/test/java/org/apache/ignite/testframework/GridSpiTestContext.java
+++
b/modules/core/src/test/java/org/apache/ignite/testframework/GridSpiTestContext.java
@@ -620,7 +620,7 @@ public class GridSpiTestContext implements IgniteSpiContext
{
if (metricsRegistryProducer != null)
return metricsRegistryProducer.apply(name);
- return new MetricRegistryImpl(name, null, null, new NullLogger());
+ return new MetricRegistryImpl(name, null, null, null, new
NullLogger());
}
/** {@inheritDoc} */
diff --git
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
index 939c60c0609..662227a1938 100644
---
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
+++
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
@@ -382,6 +382,14 @@ If the file name isn't specified the output file name is:
'<typeId>.bin':
newRateTimeInterval - Rate time interval of hitrate.
--node-id node_id - Node id.
+ Configure MaxValue metric:
+ control.(sh|bat) --metric --configure-max-value name newTimeInterval
[--node-id node_id]
+
+ Parameters:
+ name - Name of the metric.
+ newTimeInterval - Time interval of the metric.
+ --node-id node_id - Node id.
+
Print information about potentially corrupted caches on local node:
control.(sh|bat) --persistence
diff --git
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
index 2dd6bb73815..4ca9e56b1ea 100644
---
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
+++
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
@@ -382,6 +382,14 @@ If the file name isn't specified the output file name is:
'<typeId>.bin':
newRateTimeInterval - Rate time interval of hitrate.
--node-id node_id - Node id.
+ Configure MaxValue metric:
+ control.(sh|bat) --metric --configure-max-value name newTimeInterval
[--node-id node_id]
+
+ Parameters:
+ name - Name of the metric.
+ newTimeInterval - Time interval of the metric.
+ --node-id node_id - Node id.
+
Print information about potentially corrupted caches on local node:
control.(sh|bat) --persistence