blob: e2e3fdc6851f1237dacec879a44522a2dd2065b6 [file] [log] [blame]
/*
* 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.metric;
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.MBeanServerInvocationHandler;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import org.apache.ignite.IgniteException;
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.processors.metric.MetricRegistry;
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.util.typedef.internal.U;
import org.apache.ignite.mxbean.MetricsMxBean;
import org.apache.ignite.spi.metric.HistogramMetric;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
import org.junit.Test;
import static org.apache.ignite.configuration.WALMode.FSYNC;
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.TX_METRICS;
import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.cacheMetricsRegistryName;
import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.metricName;
import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNotEquals;
/** Tests metrics configuration. */
public class MetricsConfigurationTest extends GridCommonAbstractTest {
/** Test metric registry. */
public static final String TEST_REG = "testReg";
/** Test hitrate metric name. */
public static final String HITRATE_NAME = "hitrate";
/** Test histogram metric name. */
public static final String HISTOGRAM_NAME = "histogram";
/** Test bounds. */
public static final long[] BOUNDS = new long[] {50, 100};
/** {@inheritDoc} */
@Override protected void beforeTest() throws Exception {
cleanPersistenceDir();
}
/** {@inheritDoc} */
@Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
if (igniteInstanceName.startsWith("persistent")) {
DataStorageConfiguration dsCfg = new DataStorageConfiguration();
dsCfg.getDefaultDataRegionConfiguration().setPersistenceEnabled(true);
dsCfg.setWalMode(FSYNC);
cfg.setDataStorageConfiguration(dsCfg);
}
return cfg;
}
/** Tests configuration of {@link HitRateMetric}. */
@Test
public void testHitRateConfiguration() throws Exception {
try (IgniteEx g = startGrid(0)) {
MetricsMxBean bean = metricsBean(g);
//Empty name.
assertThrowsWithCause(
() -> bean.configureHitRateMetric(null, 1),
NullPointerException.class);
//Wrong rateTimeInterval value.
assertThrowsWithCause(
() -> bean.configureHitRateMetric("io.dataregion.default.AllocationRate", 0),
IllegalArgumentException.class);
assertThrowsWithCause(
() -> bean.configureHitRateMetric("io.dataregion.default.AllocationRate", -1),
IllegalArgumentException.class);
bean.configureHitRateMetric("io.dataregion.default.AllocationRate", 5000);
HitRateMetric allocationRate = g.context().metric().registry(metricName("io.dataregion.default"))
.findMetric("AllocationRate");
assertEquals(5000, allocationRate.rateTimeInterval());
}
}
/** Tests configuration of {@link HistogramMetric}. */
@Test
public void testHistogramConfiguration() throws Exception {
try (IgniteEx g = startGrid(0)) {
MetricsMxBean bean = metricsBean(g);
//Empty name.
assertThrowsWithCause(() -> bean.configureHistogramMetric(null, BOUNDS), NullPointerException.class);
//Wrong bounds value.
assertThrowsWithCause(
() -> bean.configureHistogramMetric(metricName(TX_METRICS, METRIC_SYSTEM_TIME_HISTOGRAM), null),
NullPointerException.class);
assertThrowsWithCause(
() -> bean.configureHistogramMetric(metricName(TX_METRICS, METRIC_SYSTEM_TIME_HISTOGRAM), new long[0]),
IllegalArgumentException.class);
bean.configureHistogramMetric(metricName(TX_METRICS, METRIC_SYSTEM_TIME_HISTOGRAM), BOUNDS);
HistogramMetric systemTime = g.context().metric().registry(TX_METRICS)
.findMetric(METRIC_SYSTEM_TIME_HISTOGRAM);
assertArrayEquals(BOUNDS, systemTime.bounds());
}
}
/** Tests metric configuration applied on all nodes. */
@Test
public void testConfigurationSeveralNodes() throws Exception {
try (IgniteEx g0 = startGrid(0); IgniteEx g1 = startGrid(1)) {
assertNotEquals(BOUNDS.length, g0.context().metric().registry(TX_METRICS)
.<HistogramMetric>findMetric(METRIC_SYSTEM_TIME_HISTOGRAM).bounds().length);
assertNotEquals(BOUNDS.length, g1.context().metric().registry(TX_METRICS)
.<HistogramMetric>findMetric(METRIC_SYSTEM_TIME_HISTOGRAM).bounds().length);
metricsBean(g0).configureHistogramMetric(metricName(TX_METRICS, METRIC_SYSTEM_TIME_HISTOGRAM), BOUNDS);
assertArrayEquals(BOUNDS, g0.context().metric().registry(TX_METRICS)
.<HistogramMetric>findMetric(METRIC_SYSTEM_TIME_HISTOGRAM).bounds());
assertArrayEquals(BOUNDS, g1.context().metric().registry(TX_METRICS)
.<HistogramMetric>findMetric(METRIC_SYSTEM_TIME_HISTOGRAM).bounds());
}
}
/** Tests metric configuration applied on all nodes. */
@Test
public void testNodeRestart() throws Exception {
checkOnStartAndRestart((g0, g1) -> {
assertNotEquals(BOUNDS.length, g0.context().metric().registry(TX_METRICS)
.<HistogramMetric>findMetric(METRIC_SYSTEM_TIME_HISTOGRAM).bounds().length);
assertNotEquals(BOUNDS.length, g1.context().metric().registry(TX_METRICS)
.<HistogramMetric>findMetric(METRIC_SYSTEM_TIME_HISTOGRAM).bounds().length);
metricsBean(g0).configureHistogramMetric(metricName(TX_METRICS, METRIC_SYSTEM_TIME_HISTOGRAM), BOUNDS);
assertArrayEquals(BOUNDS, g0.context().metric().registry(TX_METRICS)
.<HistogramMetric>findMetric(METRIC_SYSTEM_TIME_HISTOGRAM).bounds());
assertArrayEquals(BOUNDS, g1.context().metric().registry(TX_METRICS)
.<HistogramMetric>findMetric(METRIC_SYSTEM_TIME_HISTOGRAM).bounds());
}, (g0, g1) -> {
assertArrayEquals(BOUNDS, g0.context().metric().registry(TX_METRICS)
.<HistogramMetric>findMetric(METRIC_SYSTEM_TIME_HISTOGRAM).bounds());
assertArrayEquals(BOUNDS, g1.context().metric().registry(TX_METRICS)
.<HistogramMetric>findMetric(METRIC_SYSTEM_TIME_HISTOGRAM).bounds());
});
}
/** Tests metric configuration removed on registry remove. */
@Test
public void testConfigRemovedOnRegistryRemove() throws Exception {
checkOnStartAndRestart((g0, g1) -> {
MetricRegistry mreg = g0.context().metric().registry(TEST_REG);
mreg.hitRateMetric(HITRATE_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);
}, (g0, g1) -> {
MetricRegistry mreg = g0.context().metric().registry(TEST_REG);
HitRateMetric hitRate = mreg.hitRateMetric(HITRATE_NAME, "test", 10000, 5);
HistogramMetricImpl histogram = mreg.histogram(HISTOGRAM_NAME, new long[] {250, 500}, "test");
assertEquals(1000, hitRate.rateTimeInterval());
assertArrayEquals(BOUNDS, histogram.bounds());
assertEquals((Long)1000L,
g0.context().distributedMetastorage().read(metricName(HITRATE_CFG_PREFIX, TEST_REG, HITRATE_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)));
assertArrayEquals(BOUNDS,
g1.context().distributedMetastorage().read(metricName(HISTOGRAM_CFG_PREFIX, TEST_REG, HISTOGRAM_NAME)));
g0.context().metric().remove(TEST_REG);
assertNull(
g0.context().distributedMetastorage().read(metricName(HITRATE_CFG_PREFIX, TEST_REG, HITRATE_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(HISTOGRAM_CFG_PREFIX, TEST_REG, HISTOGRAM_NAME)));
});
}
/** Tests metric configuration removed on registry remove. */
@Test
public void testConfigRemovedOnCacheRemove() throws Exception {
String cacheRegName = cacheMetricsRegistryName("test", false);
checkOnStartAndRestart((g0, g1) -> {
g0.createCache("test");
awaitPartitionMapExchange();
HistogramMetricImpl getTime = g0.context().metric().registry(cacheRegName).findMetric("GetTime");
assertNotEquals(BOUNDS.length, getTime.bounds().length);
metricsBean(g0).configureHistogramMetric(metricName(cacheRegName, "GetTime"), BOUNDS);
assertArrayEquals(BOUNDS,
g0.context().metric().registry(cacheRegName).<HistogramMetric>findMetric("GetTime").bounds());
assertArrayEquals(BOUNDS,
g1.context().metric().registry(cacheRegName).<HistogramMetric>findMetric("GetTime").bounds());
}, (g0, g1) -> {
assertArrayEquals(BOUNDS,
g0.context().metric().registry(cacheRegName).<HistogramMetric>findMetric("GetTime").bounds());
assertArrayEquals(BOUNDS,
g1.context().metric().registry(cacheRegName).<HistogramMetric>findMetric("GetTime").bounds());
g0.destroyCache("test");
awaitPartitionMapExchange();
assertNull(g0.context().distributedMetastorage().read(metricName(cacheRegName, "GetTime")));
assertNull(g1.context().distributedMetastorage().read(metricName(cacheRegName, "GetTime")));
});
}
/** Tests metric configuration removed on registry remove. */
@Test
public void testConfigRemovedOnCacheGroupRemove() throws Exception {
String cacheRegName = cacheMetricsRegistryName("test", false);
String mname = metricName(cacheRegName, "GetTime");
checkOnStartAndRestart((g0, g1) -> {
CacheConfiguration<String, String> ccfg = new CacheConfiguration<>("test");
ccfg.setGroupName("group");
g0.createCache(ccfg);
awaitPartitionMapExchange();
HistogramMetricImpl getTime = g0.context().metric().registry(cacheRegName).findMetric("GetTime");
assertNotEquals(BOUNDS.length, getTime.bounds().length);
metricsBean(g0).configureHistogramMetric(mname, BOUNDS);
assertArrayEquals(BOUNDS,
g0.context().metric().registry(cacheRegName).<HistogramMetric>findMetric("GetTime").bounds());
assertArrayEquals(BOUNDS,
g1.context().metric().registry(cacheRegName).<HistogramMetric>findMetric("GetTime").bounds());
}, (g0, g1) -> {
assertArrayEquals(BOUNDS,
g0.context().metric().registry(cacheRegName).<HistogramMetric>findMetric("GetTime").bounds());
assertArrayEquals(BOUNDS,
g1.context().metric().registry(cacheRegName).<HistogramMetric>findMetric("GetTime").bounds());
g0.destroyCache("test");
awaitPartitionMapExchange();
assertNull(g0.context().distributedMetastorage().read(mname));
assertNull(g1.context().distributedMetastorage().read(mname));
});
}
/** Executes provided closures after cluster start and after cluster restart. */
public void checkOnStartAndRestart(IgniteBiInClosureX<IgniteEx, IgniteEx> afterStart,
IgniteBiInClosureX<IgniteEx, IgniteEx> afterRestart) throws Exception {
IgniteEx g0 = startGrid("persistent-0");
IgniteEx g1 = startGrid("persistent-1");
try {
g0.cluster().active(true);
afterStart.apply(g0, g1);
g0.close();
g1.close();
g0 = startGrid("persistent-0");
g1 = startGrid("persistent-1");
g0.cluster().active(true);
afterRestart.apply(g0, g1);
}
finally {
g0.close();
g1.close();
}
}
/** */
public static MetricsMxBean metricsBean(IgniteEx g) {
try {
ObjectName mbeanName = U.makeMBeanName(g.name(), "Metrics", MetricsMxBeanImpl.class.getSimpleName());
MBeanServer mbeanSrv = ManagementFactory.getPlatformMBeanServer();
if (!mbeanSrv.isRegistered(mbeanName))
throw new IgniteException("MBean not registered.");
return MBeanServerInvocationHandler.newProxyInstance(mbeanSrv, mbeanName, MetricsMxBean.class, false);
}
catch (MalformedObjectNameException e) {
throw new IgniteException(e);
}
}
/** */
public interface IgniteBiInClosureX<E1, E2> {
/**
* Closure body.
*
* @param e1 First parameter.
* @param e2 Second parameter.
*/
public default void apply(E1 e1, E2 e2) {
try {
applyx(e1, e2);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Closure body that can throw exception.
*
* @param e1 First parameter.
* @param e2 Second parameter.
*/
public void applyx(E1 e1, E2 e2) throws Exception;
}
}