This is an automated email from the ASF dual-hosted git repository.

sergey-chugunov-1985 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 b6779b7805d IGNITE-28692 Add cache partition distribution metrics for 
caches in MDC environments (#13238)
b6779b7805d is described below

commit b6779b7805d10d514b74dae8b48cf2c571946c69
Author: Sergey Chugunov <[email protected]>
AuthorDate: Mon Jul 6 12:40:22 2026 +0400

    IGNITE-28692 Add cache partition distribution metrics for caches in MDC 
environments (#13238)
---
 .../processors/cache/CacheMetricsImpl.java         |  92 ++++
 .../processors/cache/GridCacheProcessor.java       |  16 +
 .../cache/ValidationOnNodeJoinUtils.java           |  34 ++
 .../processors/cluster/BaselineTopology.java       |  38 +-
 .../MdcAffinityBackupFilterSelfTest.java           |   2 +
 .../processors/cache/MdcCacheMetricsTest.java      | 600 +++++++++++++++++++++
 .../ignite/testsuites/IgniteCacheTestSuite2.java   |   2 +
 7 files changed, 773 insertions(+), 11 deletions(-)

diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java
index a67d265dbf7..b483dd64904 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java
@@ -19,16 +19,20 @@ package org.apache.ignite.internal.processors.cache;
 
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Supplier;
 import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.cache.CacheMetrics;
+import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.processors.affinity.AffinityAssignment;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import 
org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTopologyFuture;
 import 
org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition;
 import 
org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState;
 import 
org.apache.ignite.internal.processors.cache.store.GridCacheWriteBehindStore;
+import org.apache.ignite.internal.processors.cluster.BaselineTopology;
 import org.apache.ignite.internal.processors.metric.MetricRegistryImpl;
 import org.apache.ignite.internal.processors.metric.impl.AtomicLongMetric;
 import org.apache.ignite.internal.processors.metric.impl.HistogramMetricImpl;
@@ -246,6 +250,15 @@ public class CacheMetricsImpl implements CacheMetrics {
     /** Conflict resolver merged entries count. */
     private LongAdderMetric rslvrMergedCnt;
 
+    /** Affinity configuration MDC safe metric. */
+    private volatile Boolean affCfgMdcSafe;
+
+    /** Current partition distribution MDC safe metric. */
+    private volatile Boolean mdcSafePartDistrib;
+
+    /** Last affinity version when MdcSafe Partition Distribution metric was 
recalculated. */
+    private final AtomicReference<AffinityTopologyVersion> 
mdcSafeMetricLastVer = new AtomicReference<>();
+
     /**
      * Creates cache metrics.
      *
@@ -1679,6 +1692,71 @@ public class CacheMetricsImpl implements CacheMetrics {
         return fut != null && !fut.isDone();
     }
 
+    /**
+     * Returns {@code true} if affinity configuration is aware of multiple 
data centers, and
+     * it is able to spread partitions' copies across data centers.
+     */
+    private boolean isAffinityCfgMdcSafe() {
+        return affCfgMdcSafe != null && affCfgMdcSafe;
+    }
+
+    /**
+     * Returns {@code true} if current cache partition distribution maintains 
guarantee 'at least one partition copy in each datacenter'.
+     */
+    private boolean isMdcSafePartitionDistribution() {
+        return updateMdcSafeDistributionMetricIfNeeded();
+    }
+
+    /**
+     * Updates calculated value of Partition Distribution MDC safe metric if 
affinity has changed
+     * since last affinity change.
+     *
+     * @return Updated value of Partition Distribution MDC safe metric or 
cached value if affinity has not changed.
+     */
+    private boolean updateMdcSafeDistributionMetricIfNeeded() {
+        GridCacheAffinityManager aff = cctx.affinity();
+
+        try {
+            AffinityTopologyVersion currVer = aff.affinityTopologyVersion();
+            AffinityTopologyVersion lastVer = mdcSafeMetricLastVer.get();
+
+            // Skip expensive recalculation if the aff topology has not 
changed.
+            if (!currVer.equals(lastVer)) {
+                if (mdcSafeMetricLastVer.compareAndSet(lastVer, currVer))
+                    mdcSafePartDistrib = 
recalculateMdcSafeMetric(aff.assignment(currVer));
+            }
+        }
+        catch (Exception ignored) {
+            // Affinity manager could throw an exception if aff not found for 
the cache.
+            // This should not break any code calling this method, so we just 
ignore it.
+        }
+
+        return mdcSafePartDistrib == null || mdcSafePartDistrib;
+    }
+
+    /**
+     * Recalcalculates Partition Distribution MDC safe metric based on 
provided assignment.
+     *
+     * @param assignment New assignment for the cache.
+     */
+    private Boolean recalculateMdcSafeMetric(AffinityAssignment assignment) {
+        BaselineTopology top = 
cctx.discovery().discoCache().state().baselineTopology();
+        if (top != null && top.numberOfDatacenters() > 1) {
+            int numberOfDataCenters = top.numberOfDatacenters();
+
+            for (List<ClusterNode> nodes : assignment.assignment()) {
+                int dcsCnt = 
(int)nodes.stream().map(ClusterNode::dataCenterId).distinct().count();
+
+                if (dcsCnt < numberOfDataCenters)
+                    return false;
+            }
+
+            return true;
+        }
+
+        return mdcSafePartDistrib;
+    }
+
     /** {@inheritDoc} */
     @Override public long getIndexRebuildKeysProcessed() {
         return idxRebuildKeyProcessed.value();
@@ -1745,6 +1823,20 @@ public class CacheMetricsImpl implements CacheMetrics {
             "Conflict resolver merged entries count");
     }
 
+    /** Registers metric for partition distribution.  */
+    public void registerPartitionDistributionSafeMetric() {
+        mreg.register("IsCachePartitionDistributionSafe", 
this::isMdcSafePartitionDistribution,
+            "True if current cache partition distribution maintains guarantee 
'one partition copy in each datacenter'.");
+    }
+
+    /** Registers metric for cache configuration related to distributing 
partitions across DCs. */
+    public void registerAffinityConfigurationSafeMetric(boolean affCfgMdcSafe) 
{
+        mreg.register("IsCacheAffinityConfigurationMdcSafe", 
this::isAffinityCfgMdcSafe,
+            "True if cache affinity guarantees having a copy of each partition 
in each data center.");
+
+        this.affCfgMdcSafe = affCfgMdcSafe;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(CacheMetricsImpl.class, this);
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
index a82a8a9179c..d38fc3db417 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
@@ -217,6 +217,7 @@ import static 
org.apache.ignite.internal.GridComponent.DiscoveryDataExchangeType
 import static org.apache.ignite.internal.IgniteComponentType.JTA;
 import static 
org.apache.ignite.internal.processors.cache.GridCacheUtils.isNearEnabled;
 import static 
org.apache.ignite.internal.processors.cache.GridCacheUtils.isPersistentCache;
+import static 
org.apache.ignite.internal.processors.cache.ValidationOnNodeJoinUtils.isAffinityConfigurationMdcSafe;
 import static 
org.apache.ignite.internal.processors.cache.ValidationOnNodeJoinUtils.validateHashIdResolvers;
 import static 
org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition.DFLT_CACHE_REMOVE_ENTRIES_TTL;
 import static 
org.apache.ignite.internal.processors.metric.impl.MetricUtils.metricName;
@@ -1136,6 +1137,8 @@ public class GridCacheProcessor extends 
GridProcessorAdapter {
 
         cache.onKernalStart();
 
+        registerMdcMetricsIfNeeded(cache);
+
         if (ctx.events().isRecordable(EventType.EVT_CACHE_STARTED))
             ctx.events().addEvent(EventType.EVT_CACHE_STARTED);
 
@@ -1144,6 +1147,19 @@ public class GridCacheProcessor extends 
GridProcessorAdapter {
                 cache.configuration().getCacheMode() + ']');
     }
 
+    /** */
+    private void registerMdcMetricsIfNeeded(GridCacheAdapter<?, ?> cache) {
+        if (ctx.clientNode())
+            return;
+
+        if (ctx.discovery().localNode() == null || 
ctx.discovery().localNode().dataCenterId() == null)
+            return;
+
+        
cache.metrics0().registerAffinityConfigurationSafeMetric(isAffinityConfigurationMdcSafe(cache.configuration()));
+
+        cache.metrics0().registerPartitionDistributionSafeMetric();
+    }
+
     /**
      * @param cache Cache to stop.
      * @param cancel Cancel flag.
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ValidationOnNodeJoinUtils.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ValidationOnNodeJoinUtils.java
index ac8d97b2a12..16ea96c3cf4 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ValidationOnNodeJoinUtils.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ValidationOnNodeJoinUtils.java
@@ -35,6 +35,10 @@ import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.cache.CacheRebalanceMode;
 import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.cache.affinity.AffinityFunction;
+import 
org.apache.ignite.cache.affinity.rendezvous.ClusterNodeAttributeAffinityBackupFilter;
+import 
org.apache.ignite.cache.affinity.rendezvous.ClusterNodeAttributeColocatedBackupFilter;
+import org.apache.ignite.cache.affinity.rendezvous.MdcAffinityBackupFilter;
 import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.cache.store.CacheStore;
 import org.apache.ignite.cluster.ClusterNode;
@@ -56,6 +60,7 @@ import org.apache.ignite.internal.thread.context.Scope;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.marshaller.Marshaller;
 import org.apache.ignite.plugin.security.SecurityException;
 import org.apache.ignite.spi.IgniteNodeValidationResult;
@@ -70,6 +75,7 @@ import static org.apache.ignite.cache.CacheMode.REPLICATED;
 import static org.apache.ignite.cache.CacheRebalanceMode.SYNC;
 import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_ASYNC;
 import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_CONSISTENCY_CHECK_SKIPPED;
+import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_DATA_CENTER_ID;
 import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_TX_AWARE_QUERIES_ENABLED;
 import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_TX_SERIALIZABLE_ENABLED;
 import static 
org.apache.ignite.internal.processors.cache.GridCacheUtils.isDefaultDataRegionPersistent;
@@ -631,6 +637,34 @@ public class ValidationOnNodeJoinUtils {
         return null;
     }
 
+    /**
+     * Analyzes affinity settings of a provided {@link CacheConfiguration} to 
inspect if it provides guarantees
+     * that partitions of the cache will be spread across all datacenters 
presented in cluster.
+     *
+     * @return {@code true} if affinity settings guarantee spreading 
partitions across all datacenters and {@code false} otherwise.
+     */
+    static boolean isAffinityConfigurationMdcSafe(CacheConfiguration cc) {
+        if (cc.getCacheMode() == REPLICATED)
+            return true;
+
+        AffinityFunction affFunc = cc.getAffinity();
+
+        if (affFunc instanceof RendezvousAffinityFunction) {
+            IgniteBiPredicate<ClusterNode, List<ClusterNode>> filter = 
((RendezvousAffinityFunction)affFunc).getAffinityBackupFilter();
+
+            if (filter instanceof ClusterNodeAttributeAffinityBackupFilter 
attrFilter) {
+                if 
(!F.asList(attrFilter.getAttributeNames()).contains(ATTR_DATA_CENTER_ID))
+                    return false;
+            }
+
+            return filter instanceof MdcAffinityBackupFilter
+                    || filter instanceof 
ClusterNodeAttributeColocatedBackupFilter
+                    || filter instanceof 
ClusterNodeAttributeAffinityBackupFilter;
+        }
+
+        return true;
+    }
+
     /**
      * @param rmtNode Remote node to check.
      * @param ctx Context.
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/BaselineTopology.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/BaselineTopology.java
index 1f71cb192a2..0a573ff3cc9 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/BaselineTopology.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/BaselineTopology.java
@@ -39,10 +39,12 @@ import org.apache.ignite.lang.IgnitePredicate;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_DATA_CENTER_ID;
+
 /**
  * BaselineTopology represents a set of "database nodes" - nodes responsible 
for holding persistent-enabled caches
  * and persisting their information to durable storage.
- *
+ * <p/>
  * Two major features BaselineTopology allows are:
  * <ol>
  *     <li>Protection from conflicting updates.</li>
@@ -61,10 +63,10 @@ import org.jetbrains.annotations.Nullable;
  *         [A,B]  [C]
  *           |     |
  *      (2)updates to both parts
- *
+ * <p/>
  *      After independent updates applied to both parts of cluster at point(2) 
node C should not be allowed to join
  *      [A,B] part.
- *
+ * <p/>
  *      The following algorithm makes sure node C will never join [A,B] part 
back:
  *      <ol>
  *          <li>
@@ -95,10 +97,10 @@ import org.jetbrains.annotations.Nullable;
  *     <li>
  *         When BaselineTopology is set (e.g. on first activation) or 
recreated (e.g. with set-baseline command)
  *         its ID on all nodes is incremented by one.
- *
+ * <p/>
  *         So when cluster receives a join request with BaselineTopology it 
firstly compares joining node BlT ID with
  *         local BlT ID.
- *
+ * <p/>
  *         If joining node has a BaselineTopology with ID greater than one in 
cluster it means that BlT was changed
  *         more times there; therefore new node is not allowed to join the 
cluster.
  *     </li>
@@ -107,27 +109,27 @@ import org.jetbrains.annotations.Nullable;
  *         Instead current set of online nodes from BaselineTopology is used 
to update {@link BaselineTopology#branchingPntHash}
  *         property of current BaselineTopology.
  *         Old value of the property is moved to {@link 
BaselineTopology#branchingHist} list.
- *
+ * <p/>
  *         If joining node and local BlT IDs are the same then cluster takes 
<b>branchingPntHash</b> of joining node
  *         and verifies that its local <b>branchingHist</b> contains that hash.
- *
+ * <p/>
  *         If joining node hash is not presented in cluster branching history 
list
  *         it means that joining node was activated independently of currently 
running cluster;
  *         therefore new node is not allowed to join the cluster.
- *
+ * <p/>
  *         If joining node hash is presented in the history, that it is safe 
to let the node join the cluster.
  *     </li>
  *     <li>
  *         When BaselineTopology is recreated (e.g. with set-baseline command) 
previous BaselineTopology is moved
  *         to BaselineHistory (consult source code of {@link 
GridClusterStateProcessor} for more details).
- *
+ * <p/>
  *         If cluster sees that joining node BlT ID is less than cluster BlT 
ID it looks up for BaselineHistory item
  *         for new node ID.
  *         Having this BaselineHistory item cluster verifies that branching 
history of the item contains
  *         branching point hash of joining node
  *         (similar check as in the case above with only difference that 
joining node BlT is compared against
  *         BaselineHistory item instead of BaselineTopology).
- *
+ * <p/>
  *         If new node branching point hash is found in the history than node 
is allowed to join;
  *         otherwise it is rejected.
  *     </li>
@@ -172,7 +174,7 @@ public class BaselineTopology implements Serializable {
     private final List<Long> branchingHist;
 
     /**
-     * @param nodeMap Map of node consistent ID to it's attributes.
+     * @param nodeMap Map of node consistent ID to its attributes.
      */
     private BaselineTopology(Map<Object, Map<String, Object>> nodeMap, int id) 
{
         this.id = id;
@@ -274,6 +276,20 @@ public class BaselineTopology implements Serializable {
         return nodeMap.get(consId);
     }
 
+    /**
+     * Calculates number of datacenters presented in current baseline.
+     *
+     * @return Number of datacenters presented in the baseline or {@code -1} 
if unknown.
+     */
+    public int numberOfDatacenters() {
+        Collection<Map<String, Object>> allNodesAttrs = nodeMap.values();
+
+        if (!allNodesAttrs.isEmpty() && 
allNodesAttrs.iterator().next().get(ATTR_DATA_CENTER_ID) != null)
+            return (int)allNodesAttrs.stream().map(m -> 
m.get(ATTR_DATA_CENTER_ID)).distinct().count();
+
+        return -1;
+    }
+
     /**
      *
      */
diff --git 
a/modules/core/src/test/java/org/apache/ignite/cache/affinity/rendezvous/MdcAffinityBackupFilterSelfTest.java
 
b/modules/core/src/test/java/org/apache/ignite/cache/affinity/rendezvous/MdcAffinityBackupFilterSelfTest.java
index a45f3ccd901..97c19494584 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/cache/affinity/rendezvous/MdcAffinityBackupFilterSelfTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/cache/affinity/rendezvous/MdcAffinityBackupFilterSelfTest.java
@@ -314,6 +314,8 @@ public class MdcAffinityBackupFilterSelfTest extends 
GridCommonAbstractTest {
                 lastNode = startGrid(nodeIdx++);
         }
 
+        System.clearProperty(IgniteSystemProperties.IGNITE_DATA_CENTER_ID);
+
         return lastNode;
     }
 
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/MdcCacheMetricsTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/MdcCacheMetricsTest.java
new file mode 100644
index 00000000000..8f390775c52
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/MdcCacheMetricsTest.java
@@ -0,0 +1,600 @@
+/*
+ * 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.cache;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.ignite.IgniteSystemProperties;
+import 
org.apache.ignite.cache.affinity.rendezvous.ClusterNodeAttributeAffinityBackupFilter;
+import 
org.apache.ignite.cache.affinity.rendezvous.ClusterNodeAttributeColocatedBackupFilter;
+import org.apache.ignite.cache.affinity.rendezvous.MdcAffinityBackupFilter;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.cluster.ClusterState;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.lang.IgniteBiPredicate;
+import org.apache.ignite.spi.metric.BooleanMetric;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+import static 
org.apache.ignite.internal.IgniteNodeAttributes.ATTR_DATA_CENTER_ID;
+import static 
org.apache.ignite.internal.processors.metric.impl.MetricUtils.cacheMetricsRegistryName;
+
+/**
+ * Test for new cache metrics for highlighting two data safety issues in Multi 
DataCenter environments:
+ * 1. If cache configuration doesn't specify an affinity backup filter that 
could guarantee presence of data copy in each DC.
+ * 2. If cluster topology changed in such a way that partition copies are not 
spread across all available DCs.
+ */
+public class MdcCacheMetricsTest extends GridCommonAbstractTest {
+    /** */
+    private static final int NODES_NUMBER = 5;
+
+    /** */
+    private static final String CACHE_WITH_MDC_FILTER = "mdcSafeCache0";
+
+    /** */
+    private static final String CACHE_WITH_COLOCATED_FILTER = "mdcSafeCache1";
+
+    /** */
+    private static final String CACHE_WITH_MDC_SAFE_ATTRIBUTE_FILTER = 
"mdcSafeCache2";
+
+    /** */
+    private static final String MDC_UNSAFE_CACHE = "mdcUnsafeCache0";
+
+    /** */
+    private static final String CACHE_WITH_MDC_UNSAFE_ATTRIBUTE_FILTER = 
"mdcUnsafeCache1";
+
+    /** */
+    private static final String STRETCHED_CELL_ATTR_NAME = "DC_CELL_ATTR";
+
+    /** */
+    private static final String ATTR_FOR_UNSAFE_ATTR_FILTER = 
"MDC_UNAWARE_ATTR";
+
+    /** */
+    private static final String[] STRETCHED_CELL_IDS = {"CELL_0", "CELL_1"};
+
+    /** */
+    private static final String DC_ID_0 = "DC_0";
+
+    /** */
+    private static final String DC_ID_1 = "DC_1";
+
+    /** */
+    private static final String AFFINITY_CFG_MDC_SAFE_METRIC_NAME = 
"IsCacheAffinityConfigurationMdcSafe";
+
+    /** */
+    private static final String PARTITION_DISTRIBUTION_SAFE_METRIC_NAME = 
"IsCachePartitionDistributionSafe";
+
+    /** */
+    private String dcId;
+
+    /** */
+    private String cellId;
+
+    /** */
+    private boolean useStaticCaches;
+
+    /** */
+    private boolean persistenceEnabled;
+
+    /** */
+    private final Set<String> allCaches = new HashSet<>();
+
+    /** */
+    private final Set<String> mdcSafeCaches = new HashSet<>();
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        stopAllGrids();
+
+        allCaches.clear();
+        mdcSafeCaches.clear();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        stopAllGrids();
+
+        cleanPersistenceDir();
+
+        allCaches.clear();
+        mdcSafeCaches.clear();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String 
igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        cfg.setDataStorageConfiguration(new DataStorageConfiguration()
+            .setDefaultDataRegionConfiguration(new DataRegionConfiguration()
+                .setPersistenceEnabled(persistenceEnabled)
+                .setMaxSize(32 * 1024 * 1024)
+            ));
+
+        if (useStaticCaches) {
+            CacheConfiguration mdcSafeCacheCfg0 = prepareCacheCfg(
+                CACHE_WITH_MDC_FILTER,
+                new MdcAffinityBackupFilter(2, 1),
+                true);
+
+            CacheConfiguration mdcSafeCacheCfg1 = prepareCacheCfg(
+                CACHE_WITH_COLOCATED_FILTER,
+                new 
ClusterNodeAttributeColocatedBackupFilter(STRETCHED_CELL_ATTR_NAME),
+                true);
+
+            CacheConfiguration mdcUnsafeCacheCfg0 = 
prepareCacheCfg(MDC_UNSAFE_CACHE, null, false);
+
+            CacheConfiguration mdcUnsafeCacheCfg1 = prepareCacheCfg(
+                CACHE_WITH_MDC_UNSAFE_ATTRIBUTE_FILTER,
+                new 
ClusterNodeAttributeAffinityBackupFilter(ATTR_FOR_UNSAFE_ATTR_FILTER),
+                false);
+
+            cfg.setCacheConfiguration(mdcSafeCacheCfg0, mdcSafeCacheCfg1, 
mdcUnsafeCacheCfg0, mdcUnsafeCacheCfg1);
+        }
+
+        if (!cfg.isClientMode())
+            cfg.setUserAttributes(F.asMap(
+                STRETCHED_CELL_ATTR_NAME,
+                cellId,
+                IgniteSystemProperties.IGNITE_DATA_CENTER_ID,
+                dcId));
+
+        return cfg;
+    }
+
+    /** */
+    private CacheConfiguration prepareCacheCfg(
+        String cacheName,
+        IgniteBiPredicate<ClusterNode, List<ClusterNode>> affBackupFilter,
+        boolean affCfgMdcSafe) {
+        return prepareCacheCfg(cacheName, affBackupFilter, affCfgMdcSafe, 
null);
+    }
+
+    /** */
+    private CacheConfiguration prepareCacheCfg(
+        String cacheName,
+        IgniteBiPredicate<ClusterNode, List<ClusterNode>> affBackupFilter,
+        boolean affCfgMdcSafe,
+        String cacheGroupName) {
+        CacheConfiguration cacheCfg = new CacheConfiguration(cacheName)
+            .setCacheMode(PARTITIONED)
+            .setBackups(1);
+
+        if (cacheGroupName != null)
+            cacheCfg.setGroupName(cacheGroupName);
+
+        cacheCfg.setAffinity(
+            new RendezvousAffinityFunction()
+                .setPartitions(32)
+                .setAffinityBackupFilter(affBackupFilter));
+
+        if (affCfgMdcSafe)
+            mdcSafeCaches.add(cacheName);
+
+        allCaches.add(cacheName);
+
+        return cacheCfg;
+    }
+
+    /**
+     * Test verifies correctness of metric for cache configuration related to 
data distribution across DCs
+     * if caches are organized into groups.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testAffinityCfgMdcSafeMetricForCacheGroup() throws Exception {
+        startClusterAcrossDataCenters(new String[] {DC_ID_0, DC_ID_1}, 2);
+
+        IgniteEx client = startClientGrid(NODES_NUMBER - 1);
+
+        client.getOrCreateCache(
+            prepareCacheCfg(
+                CACHE_WITH_MDC_FILTER + "_0",
+                new MdcAffinityBackupFilter(2, 1),
+                true,
+                "mdcSafeCachesGroup"));
+
+        client.getOrCreateCache(
+            prepareCacheCfg(
+                CACHE_WITH_MDC_FILTER + "_1",
+                new MdcAffinityBackupFilter(2, 1),
+                true,
+                "mdcSafeCachesGroup"));
+
+        client.getOrCreateCache(
+            prepareCacheCfg(MDC_UNSAFE_CACHE + "_0", null, false, 
"mdcUnsafeCachesGroup"));
+
+        client.getOrCreateCache(
+            prepareCacheCfg(MDC_UNSAFE_CACHE + "_1", null, false, 
"mdcUnsafeCachesGroup"));
+
+        checkMdcReadyMetric();
+    }
+
+    /**
+     * Test verifies correctness of metric for partition copies distribution 
across DCs
+     * if caches are organized into groups.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testPartitionDistributionMetricForCacheGroups() throws 
Exception {
+        persistenceEnabled = true;
+
+        startClusterAcrossDataCenters(new String[] {DC_ID_0, DC_ID_1}, 2);
+
+        IgniteEx client = startClientGrid(NODES_NUMBER - 1);
+
+        client.cluster().state(ClusterState.ACTIVE);
+
+        client.getOrCreateCache(prepareCacheCfg(
+            CACHE_WITH_MDC_FILTER + "_0",
+            new MdcAffinityBackupFilter(2, 1),
+            true,
+            "mdcFilterCacheGroup"));
+        client.getOrCreateCache(prepareCacheCfg(
+            CACHE_WITH_MDC_FILTER + "_1",
+            new MdcAffinityBackupFilter(2, 1),
+            true,
+            "mdcFilterCacheGroup"));
+
+        awaitPartitionMapExchange();
+
+        BooleanMetric cache0DistributionSafeMetric = findMetricForCache(
+            grid(1),
+            CACHE_WITH_MDC_FILTER + "_0",
+            PARTITION_DISTRIBUTION_SAFE_METRIC_NAME);
+        BooleanMetric cache1DistributionSafeMetric = findMetricForCache(
+            grid(1),
+            CACHE_WITH_MDC_FILTER + "_1",
+            PARTITION_DISTRIBUTION_SAFE_METRIC_NAME);
+
+        assertNotNull(cache0DistributionSafeMetric);
+        assertNotNull(cache1DistributionSafeMetric);
+        assertTrue(cache0DistributionSafeMetric.value());
+        assertTrue(cache1DistributionSafeMetric.value());
+
+        stopGrid(0);
+
+        assertFalse(cache0DistributionSafeMetric.value());
+        assertFalse(cache1DistributionSafeMetric.value());
+
+        
client.cluster().setBaselineTopology(client.cluster().topologyVersion());
+
+        assertTrue(cache0DistributionSafeMetric.value());
+        assertTrue(cache1DistributionSafeMetric.value());
+    }
+
+    /**
+     * Test verifies correctness of metric for cache configuration related to 
data distribution across DCs for dynamically started caches.
+     * Metric should take a {@code false} value if cache configuration doesn't 
guarantee presence of data copy in each DC
+     * and {@code true} otherwise.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testAffinityCfgMdcSafeMetricForDynamicCaches() throws 
Exception {
+        startClusterAcrossDataCenters(new String[] {DC_ID_0, DC_ID_1}, 2);
+
+        IgniteEx client = startClientGrid(NODES_NUMBER - 1);
+
+        client.cluster().state(ClusterState.ACTIVE);
+
+        client.getOrCreateCache(
+            prepareCacheCfg(CACHE_WITH_MDC_FILTER, new 
MdcAffinityBackupFilter(2, 1), true));
+
+        client.getOrCreateCache(
+            prepareCacheCfg(CACHE_WITH_COLOCATED_FILTER, new 
ClusterNodeAttributeColocatedBackupFilter(STRETCHED_CELL_ATTR_NAME), true));
+
+        client.getOrCreateCache(
+            prepareCacheCfg(MDC_UNSAFE_CACHE, null, false));
+
+        client.getOrCreateCache(
+            prepareCacheCfg(CACHE_WITH_MDC_UNSAFE_ATTRIBUTE_FILTER,
+                new 
ClusterNodeAttributeAffinityBackupFilter(ATTR_FOR_UNSAFE_ATTR_FILTER), false));
+
+        checkMdcReadyMetric();
+    }
+
+    /**
+     * Test verifies correctness of metric for cache configuration related to 
data distribution across DCs for statically configured caches.
+     * Metric should take a {@code false} value if cache configuration doesn't 
guarantee presence of data copy in each DC
+     * and {@code true} otherwise.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testAffinityCfgMdcSafeMetricForStaticCaches() throws Exception 
{
+        useStaticCaches = true;
+
+        startClusterAcrossDataCenters(new String[] {DC_ID_0, DC_ID_1}, 2);
+
+        IgniteEx client = startClientGrid(NODES_NUMBER - 1);
+
+        client.cluster().state(ClusterState.ACTIVE);
+
+        checkMdcReadyMetric();
+    }
+
+    /**
+     * Test verifies correctness of metric for partition copies distribution 
across DCs.
+     * Metric should take a {@code false} value if there is at least one 
partition which doesn't have copies in all DCs
+     * and {@code true} otherwise.
+     * <p/>
+     * This test considers in-memory caches only.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testPartitionDistributionMetricInMemoryCaches() throws 
Exception {
+        startClusterAcrossDataCenters(new String[] {DC_ID_0, DC_ID_1}, 2);
+
+        IgniteEx client = startClientGrid(NODES_NUMBER - 1);
+
+        client.getOrCreateCache(prepareCacheCfg(CACHE_WITH_MDC_FILTER, new 
MdcAffinityBackupFilter(2, 1), true));
+        client.getOrCreateCache(prepareCacheCfg(CACHE_WITH_COLOCATED_FILTER,
+            new 
ClusterNodeAttributeColocatedBackupFilter(STRETCHED_CELL_ATTR_NAME), true));
+        
client.getOrCreateCache(prepareCacheCfg(CACHE_WITH_MDC_SAFE_ATTRIBUTE_FILTER,
+            new ClusterNodeAttributeAffinityBackupFilter(ATTR_DATA_CENTER_ID), 
true));
+
+        awaitPartitionMapExchange();
+
+        BooleanMetric cacheWithMdcFilterDistributionSafeMetric = 
findMetricForCache(
+            grid(1),
+            CACHE_WITH_MDC_FILTER,
+            PARTITION_DISTRIBUTION_SAFE_METRIC_NAME);
+        BooleanMetric cacheWithColocatedFilterDistributionSafeMetric = 
findMetricForCache(
+            grid(1),
+            CACHE_WITH_COLOCATED_FILTER,
+            PARTITION_DISTRIBUTION_SAFE_METRIC_NAME);
+        BooleanMetric cacheWithMdcSafeAttrFilterDistributionSafeMetric = 
findMetricForCache(
+            grid(1),
+            CACHE_WITH_MDC_SAFE_ATTRIBUTE_FILTER,
+            PARTITION_DISTRIBUTION_SAFE_METRIC_NAME
+        );
+
+        assertNotNull(cacheWithMdcFilterDistributionSafeMetric);
+        assertNotNull(cacheWithColocatedFilterDistributionSafeMetric);
+        assertNotNull(cacheWithMdcSafeAttrFilterDistributionSafeMetric);
+        assertTrue(cacheWithMdcFilterDistributionSafeMetric.value());
+        assertTrue(cacheWithColocatedFilterDistributionSafeMetric.value());
+        assertTrue(cacheWithMdcSafeAttrFilterDistributionSafeMetric.value());
+
+        stopGrid(0);
+
+        assertTrue(cacheWithMdcFilterDistributionSafeMetric.value());
+        assertTrue(cacheWithMdcSafeAttrFilterDistributionSafeMetric.value());
+        assertFalse(cacheWithColocatedFilterDistributionSafeMetric.value());
+    }
+
+    /**
+     * Test verifies correctness of metric for partition copies distribution 
across DCs.
+     * Metric should take a {@code false} value if there is at least one 
partition which doesn't have copies in all DCs
+     * and {@code true} otherwise.
+     * <p/>
+     * This test considers persistent caches only and takes into account 
changes of BaselineTopology.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testPartitionDistributionMetricPersistentCaches() throws 
Exception {
+        persistenceEnabled = true;
+
+        startClusterAcrossDataCenters(new String[] {DC_ID_0, DC_ID_1}, 2);
+
+        IgniteEx client = startClientGrid(NODES_NUMBER - 1);
+
+        client.cluster().state(ClusterState.ACTIVE);
+
+        client.getOrCreateCache(prepareCacheCfg(
+            CACHE_WITH_MDC_FILTER, new MdcAffinityBackupFilter(2, 1), true));
+        client.getOrCreateCache(prepareCacheCfg(CACHE_WITH_COLOCATED_FILTER,
+            new 
ClusterNodeAttributeColocatedBackupFilter(STRETCHED_CELL_ATTR_NAME), true));
+        
client.getOrCreateCache(prepareCacheCfg(CACHE_WITH_MDC_SAFE_ATTRIBUTE_FILTER,
+            new ClusterNodeAttributeAffinityBackupFilter(ATTR_DATA_CENTER_ID), 
true));
+
+        awaitPartitionMapExchange();
+
+        BooleanMetric cacheWithMdcFilterDistributionSafeMetric = 
findMetricForCache(
+            grid(1),
+            CACHE_WITH_MDC_FILTER,
+            PARTITION_DISTRIBUTION_SAFE_METRIC_NAME);
+        BooleanMetric cacheWithColocatedFilterDistributionSafeMetric = 
findMetricForCache(
+            grid(1),
+            CACHE_WITH_COLOCATED_FILTER,
+            PARTITION_DISTRIBUTION_SAFE_METRIC_NAME);
+        BooleanMetric cacheWithMdcSafeAttrFilterDistributionSafeMetric = 
findMetricForCache(
+            grid(1),
+            CACHE_WITH_MDC_SAFE_ATTRIBUTE_FILTER,
+            PARTITION_DISTRIBUTION_SAFE_METRIC_NAME
+        );
+
+        assertNotNull(cacheWithMdcFilterDistributionSafeMetric);
+        assertNotNull(cacheWithColocatedFilterDistributionSafeMetric);
+        assertNotNull(cacheWithMdcSafeAttrFilterDistributionSafeMetric);
+        assertTrue(cacheWithMdcFilterDistributionSafeMetric.value());
+        assertTrue(cacheWithColocatedFilterDistributionSafeMetric.value());
+        assertTrue(cacheWithMdcSafeAttrFilterDistributionSafeMetric.value());
+
+        stopGrid(0);
+
+        assertFalse(cacheWithMdcFilterDistributionSafeMetric.value());
+        assertFalse(cacheWithColocatedFilterDistributionSafeMetric.value());
+        assertFalse(cacheWithMdcSafeAttrFilterDistributionSafeMetric.value());
+
+        
client.cluster().setBaselineTopology(client.cluster().topologyVersion());
+
+        // MdcAffinityBackupFilter and 
ClusterNodeAttributeAffinityBackupFilter are able to reassign partitions
+        // after BaselineTopology change, thus distribution safe metric 
restores to true.
+        assertTrue(cacheWithMdcFilterDistributionSafeMetric.value());
+        assertTrue(cacheWithMdcSafeAttrFilterDistributionSafeMetric.value());
+        // But ClusterNodeAttributeColocatedBackupFilter doesn't reassign 
partitions after BaselineTopology change
+        // so distribution safe metric for this cache remains false.
+        assertFalse(cacheWithColocatedFilterDistributionSafeMetric.value());
+    }
+
+    /** */
+    private BooleanMetric findMetricForCache(IgniteEx grid, String cacheName, 
String metricName) {
+        GridCacheContext<Object, Object> cacheCtx = 
grid.cachex(cacheName).context();
+
+        return 
cacheCtx.kernalContext().metric().registry(cacheMetricsRegistryName(
+            cacheCtx.name(), 
cacheCtx.cache().isNear())).findMetric(metricName);
+    }
+
+    /** */
+    private void checkMdcReadyMetric() throws InterruptedException {
+        awaitPartitionMapExchange();
+
+        for (int i = 0; i < NODES_NUMBER; i++) {
+            IgniteEx ig = grid(i);
+
+            for (String cacheName : allCaches) {
+                BooleanMetric cacheMdcSafeMetric = findMetricForCache(ig, 
cacheName, AFFINITY_CFG_MDC_SAFE_METRIC_NAME);
+
+                if (ig.localNode().isClient()) {
+                    assertNull(cacheMdcSafeMetric);
+
+                    continue;
+                }
+                else
+                    assertNotNull("Grid: " + i + ", cache: " + cacheName, 
cacheMdcSafeMetric);
+
+                boolean cacheMdcSafe = cacheMdcSafeMetric.value();
+
+                assertEquals(mdcSafeCaches.contains(cacheName), cacheMdcSafe);
+            }
+        }
+    }
+
+    /**
+     * Test verifies that IsCacheAffinityConfigurationMdcSafe metric is NOT 
registered
+     * when MDC attribute (data center ID) is not configured in the cluster.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testAffinityCfgMdcSafeMetricNotRegisteredOnNonMdcCluster() 
throws Exception {
+        startGrids(2);
+
+        IgniteEx client = startClientGrid();
+
+        client.cluster().state(ClusterState.ACTIVE);
+
+        client.getOrCreateCache(
+            prepareCacheCfg(CACHE_WITH_MDC_FILTER, new 
MdcAffinityBackupFilter(2, 1), true));
+
+        client.getOrCreateCache(
+            prepareCacheCfg(MDC_UNSAFE_CACHE, null, false));
+
+        awaitPartitionMapExchange();
+
+        // Verify that IsCacheAffinityConfigurationMdcSafe metric is NOT 
registered on server nodes
+        for (int i = 0; i < 2; i++) {
+            IgniteEx srv = grid(i);
+
+            for (String cacheName : allCaches) {
+                BooleanMetric cacheMdcSafeMetric = findMetricForCache(srv, 
cacheName, AFFINITY_CFG_MDC_SAFE_METRIC_NAME);
+
+                assertNull("Metric " + AFFINITY_CFG_MDC_SAFE_METRIC_NAME +
+                    " should not be registered when MDC attribute is not 
configured [grid=" + i +
+                    ", cache=" + cacheName + ']', cacheMdcSafeMetric);
+            }
+        }
+
+        // Verify that the metric is also NOT registered on client nodes
+        for (String cacheName : allCaches) {
+            BooleanMetric cacheMdcSafeMetric = findMetricForCache(client, 
cacheName, AFFINITY_CFG_MDC_SAFE_METRIC_NAME);
+
+            assertNull("Metric " + AFFINITY_CFG_MDC_SAFE_METRIC_NAME +
+                " should not be registered on client node [cache=" + cacheName 
+ ']', cacheMdcSafeMetric);
+        }
+    }
+
+    /**
+     * Test verifies that IsCachePartitionDistributionSafe metric is NOT 
registered
+     * when MDC attribute (data center ID) is not configured in the cluster.
+     *
+     * @throws Exception If failed.
+     */
+    @Test
+    public void testPartitionDistributionMetricNotRegisteredOnNonMdcCluster() 
throws Exception {
+        startGrids(2);
+
+        IgniteEx client = startClientGrid();
+
+        client.cluster().state(ClusterState.ACTIVE);
+
+        client.getOrCreateCache(
+            prepareCacheCfg(CACHE_WITH_MDC_FILTER, new 
MdcAffinityBackupFilter(2, 1), true));
+
+        client.getOrCreateCache(
+            prepareCacheCfg(MDC_UNSAFE_CACHE, null, false));
+
+        awaitPartitionMapExchange();
+
+        // Verify that IsCachePartitionDistributionSafe metric is NOT 
registered on server nodes
+        for (int i = 0; i < 2; i++) {
+            IgniteEx srv = grid(i);
+
+            for (String cacheName : allCaches) {
+                BooleanMetric partDistMetric = findMetricForCache(srv, 
cacheName, PARTITION_DISTRIBUTION_SAFE_METRIC_NAME);
+
+                assertNull("Metric " + PARTITION_DISTRIBUTION_SAFE_METRIC_NAME 
+
+                    " should not be registered when MDC attribute is not 
configured [grid=" + i +
+                    ", cache=" + cacheName + ']', partDistMetric);
+            }
+        }
+
+        // Verify that the metric is also NOT registered on client nodes
+        for (String cacheName : allCaches) {
+            BooleanMetric partDistMetric = findMetricForCache(client, 
cacheName, PARTITION_DISTRIBUTION_SAFE_METRIC_NAME);
+
+            assertNull("Metric " + PARTITION_DISTRIBUTION_SAFE_METRIC_NAME +
+                " should not be registered on client node [cache=" + cacheName 
+ ']', partDistMetric);
+        }
+    }
+
+    /** */
+    private IgniteEx startClusterAcrossDataCenters(String[] dcIds, int 
nodesPerDc) throws Exception {
+        int nodeIdx = 0;
+        IgniteEx lastNode = null;
+
+        for (String dcId : dcIds) {
+            this.dcId = dcId;
+
+            for (int i = 0; i < nodesPerDc; i++) {
+                cellId = STRETCHED_CELL_IDS[i];
+
+                lastNode = startGrid(nodeIdx++);
+            }
+        }
+
+        return lastNode;
+    }
+}
diff --git 
a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java
 
b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java
index 58b1b84819a..6b6dd442dad 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java
@@ -40,6 +40,7 @@ import 
org.apache.ignite.internal.processors.cache.IgniteCacheIncrementTxTest;
 import 
org.apache.ignite.internal.processors.cache.IgniteCachePartitionMapUpdateSafeLossPolicyTest;
 import 
org.apache.ignite.internal.processors.cache.IgniteDynamicCacheAndNodeStop;
 import 
org.apache.ignite.internal.processors.cache.IgniteOnePhaseCommitNearReadersTest;
+import org.apache.ignite.internal.processors.cache.MdcCacheMetricsTest;
 import 
org.apache.ignite.internal.processors.cache.NonAffinityCoordinatorDynamicStartStopTest;
 import 
org.apache.ignite.internal.processors.cache.RebalanceIteratorLargeEntriesOOMTest;
 import 
org.apache.ignite.internal.processors.cache.distributed.CacheLoadingConcurrentGridStartSelfTestAllowOverwrite;
@@ -208,6 +209,7 @@ public class IgniteCacheTestSuite2 {
         GridTestUtils.addTestIfNeeded(suite, 
RendezvousAffinityFunctionBackupFilterSelfTest.class, ignoredTests);
         GridTestUtils.addTestIfNeeded(suite, 
ClusterNodeAttributeColocatedBackupFilterSelfTest.class, ignoredTests);
         GridTestUtils.addTestIfNeeded(suite, 
MdcAffinityBackupFilterSelfTest.class, ignoredTests);
+        GridTestUtils.addTestIfNeeded(suite, MdcCacheMetricsTest.class, 
ignoredTests);
 
         GridTestUtils.addTestIfNeeded(suite, CachePartitionStateTest.class, 
ignoredTests);
         GridTestUtils.addTestIfNeeded(suite, CacheComparatorTest.class, 
ignoredTests);


Reply via email to