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

namelchev 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 887955c593e IGNITE-23645 Added logging of cache group partition 
eviction (#11672)
887955c593e is described below

commit 887955c593ecde0d95a4b2dffb8f40fe5a74b4d8
Author: oleg-vlsk <[email protected]>
AuthorDate: Thu Apr 16 22:17:34 2026 +1000

    IGNITE-23645 Added logging of cache group partition eviction (#11672)
---
 .../dht/preloader/GridDhtPartitionDemander.java    |   8 +-
 .../dht/topology/GridDhtLocalPartition.java        |  23 +-
 .../dht/topology/GridDhtPartitionTopologyImpl.java |  56 +++-
 .../GridDhtLocalPartitionSyncEviction.java         |   3 +-
 .../dht/topology/LogEvictionResultsTest.java       | 324 +++++++++++++++++++++
 .../ignite/testsuites/IgniteBasicTestSuite.java    |   4 +-
 6 files changed, 403 insertions(+), 15 deletions(-)

diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
index f106d804430..3c9660c212e 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
@@ -1207,8 +1207,14 @@ public class GridDhtPartitionDemander {
                                     return;
                                 }
 
-                                if (waitCnt.decrementAndGet() == 0)
+                                if (waitCnt.decrementAndGet() == 0) {
+                                    U.log(log, "Eviction completed 
successfully" +
+                                        " [grp=" + grp.cacheOrGroupName() + ", 
reason='preparation for rebalancing'" +
+                                        ", evictedPartsCount=" + parts.size() +
+                                        ", evictedParts=" + 
S.toStringSortedDistinct(d.partitions().fullSet()) + "]");
+
                                     
ctx.kernalContext().closure().runLocalSafe((GridPlainRunnable)() -> 
requestPartitions0(node, parts, d));
+                                }
                             }
                         });
                     }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartition.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartition.java
index 7ae4141ad5b..1c565177cbd 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartition.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartition.java
@@ -132,7 +132,7 @@ public class GridDhtLocalPartition extends 
GridCacheConcurrentMapImpl implements
 
     /** Rent future. */
     @GridToStringExclude
-    private final GridFutureAdapter<?> rent;
+    private final RentFuture rent;
 
     /** */
     @GridToStringExclude
@@ -212,11 +212,7 @@ public class GridDhtLocalPartition extends 
GridCacheConcurrentMapImpl implements
             cacheMaps = null;
         }
 
-        rent = new GridFutureAdapter<Object>() {
-            @Override public String toString() {
-                return "PartitionRentFuture [part=" + 
GridDhtLocalPartition.this + ']';
-            }
-        };
+        rent = new RentFuture();
 
         int delQueueSize = grp.systemCache() ? 100 :
             Math.max(MAX_DELETE_QUEUE_SIZE / grp.affinity().partitions(), 20);
@@ -694,7 +690,7 @@ public class GridDhtLocalPartition extends 
GridCacheConcurrentMapImpl implements
      * @return Future to signal that this node is no longer an owner or backup 
or null if corresponding partition
      * state is {@code RENTING} or {@code EVICTED}.
      */
-    public IgniteInternalFuture<?> rent() {
+    public RentFuture rent() {
         long state0 = this.state.get();
 
         GridDhtPartitionState partState = getPartState(state0);
@@ -1409,4 +1405,17 @@ public class GridDhtLocalPartition extends 
GridCacheConcurrentMapImpl implements
 
         buf.a(']');
     }
+
+    /** */
+    public class RentFuture extends GridFutureAdapter<Void> {
+        /** */
+        public int partitionId() {
+            return id;
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(RentFuture.class, this);
+        }
+    }
 }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java
index b004053ca6f..5c651e8e7ad 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtPartitionTopologyImpl.java
@@ -62,6 +62,7 @@ import org.apache.ignite.internal.util.GridAtomicLong;
 import org.apache.ignite.internal.util.GridLongList;
 import org.apache.ignite.internal.util.GridPartitionStateMap;
 import org.apache.ignite.internal.util.StripedCompositeReadWriteLock;
+import org.apache.ignite.internal.util.future.GridCompoundFuture;
 import org.apache.ignite.internal.util.tostring.GridToStringExclude;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.X;
@@ -467,6 +468,8 @@ public class GridDhtPartitionTopologyImpl implements 
GridDhtPartitionTopology {
             else {
                 // If preloader is disabled, then we simply clear out
                 // the partitions this node is not responsible for.
+                GridCompoundFuture<Void, Void> grpRentFut = new 
GridCompoundFuture<>();
+
                 for (int p = 0; p < partitions; p++) {
                     GridDhtLocalPartition locPart = localPartition0(p, affVer, 
false, true);
 
@@ -477,7 +480,7 @@ public class GridDhtPartitionTopologyImpl implements 
GridDhtPartitionTopology {
                             GridDhtPartitionState state = locPart.state();
 
                             if (state.active()) {
-                                locPart.rent();
+                                grpRentFut.add(locPart.rent());
 
                                 updateSeq = updateLocal(p, locPart.state(), 
updateSeq, affVer);
 
@@ -502,6 +505,8 @@ public class GridDhtPartitionTopologyImpl implements 
GridDhtPartitionTopology {
                         updateLocal(p, locPart.state(), updateSeq, affVer);
                     }
                 }
+
+                logEvictionResults(grpRentFut, "rebalancing is disabled 
(partitions do not belong to affinity)");
             }
         }
 
@@ -804,6 +809,8 @@ public class GridDhtPartitionTopologyImpl implements 
GridDhtPartitionTopology {
 
                 // Skip partition updates in case of not real exchange.
                 if (!ctx.localNode().isClient() && exchFut.exchangeType() == 
ALL) {
+                    GridCompoundFuture<Void, Void> grpRentFut = new 
GridCompoundFuture<>();
+
                     for (int p = 0; p < partitions; p++) {
                         GridDhtLocalPartition locPart = localPartition0(p, 
topVer, false, true);
 
@@ -835,7 +842,7 @@ public class GridDhtPartitionTopologyImpl implements 
GridDhtPartitionTopology {
                                 GridDhtPartitionState state = locPart.state();
 
                                 if (state == MOVING) {
-                                    locPart.rent();
+                                    grpRentFut.add(locPart.rent());
 
                                     updateSeq = updateLocal(p, 
locPart.state(), updateSeq, topVer);
 
@@ -849,6 +856,8 @@ public class GridDhtPartitionTopologyImpl implements 
GridDhtPartitionTopology {
                             }
                         }
                     }
+
+                    logEvictionResults(grpRentFut, "MOVING partitions do not 
belong to affinity");
                 }
 
                 AffinityAssignment aff = grp.affinity().readyAffinity(topVer);
@@ -2538,6 +2547,8 @@ public class GridDhtPartitionTopologyImpl implements 
GridDhtPartitionTopology {
 
         UUID locId = ctx.localNodeId();
 
+        GridCompoundFuture<Void, Void> grpRentFut = new GridCompoundFuture<>();
+
         for (int p = 0; p < locParts.length(); p++) {
             GridDhtLocalPartition part = locParts.get(p);
 
@@ -2557,7 +2568,7 @@ public class GridDhtPartitionTopologyImpl implements 
GridDhtPartitionTopology {
             if (nodeIds.containsAll(nodeIds(affNodes))) {
                 GridDhtPartitionState state0 = part.state();
 
-                part.rent();
+                grpRentFut.add(part.rent());
 
                 updateSeq = updateLocal(part.id(), part.state(), updateSeq, 
aff.topologyVersion());
 
@@ -2586,7 +2597,7 @@ public class GridDhtPartitionTopologyImpl implements 
GridDhtPartitionTopology {
                         if (locId.equals(n.id())) {
                             GridDhtPartitionState state0 = part.state();
 
-                            part.rent();
+                            grpRentFut.add(part.rent());
 
                             updateSeq = updateLocal(part.id(), part.state(), 
updateSeq, aff.topologyVersion());
 
@@ -2607,6 +2618,8 @@ public class GridDhtPartitionTopologyImpl implements 
GridDhtPartitionTopology {
             }
         }
 
+        logEvictionResults(grpRentFut, "partitions no longer belong to 
affinity");
+
         return hasEvictedPartitions;
     }
 
@@ -3360,6 +3373,41 @@ public class GridDhtPartitionTopologyImpl implements 
GridDhtPartitionTopology {
         return sb.toString();
     }
 
+    /**
+     * Prints eviction results to the log.
+     *
+     * @param grpRentFut Group rent future.
+     * @param reason Eviction reason.
+     */
+    private void logEvictionResults(GridCompoundFuture<Void, Void> grpRentFut, 
String reason) {
+        grpRentFut.markInitialized();
+
+        grpRentFut.listen(() -> {
+            Collection<GridDhtLocalPartition.RentFuture> futs =
+                F.viewReadOnly(grpRentFut.futures(), f -> 
(GridDhtLocalPartition.RentFuture)f);
+
+            if (futs.isEmpty())
+                return;
+
+            Collection<Integer> evicted = F.viewReadOnly(futs, 
GridDhtLocalPartition.RentFuture::partitionId, f -> f.error() == null);
+            Collection<Integer> failed = F.viewReadOnly(futs, 
GridDhtLocalPartition.RentFuture::partitionId, f -> f.error() != null);
+
+            boolean allEvicted = failed.isEmpty();
+
+            String msg = "Eviction completed" +
+                (allEvicted ? " successfully" : " with failures (some 
partitions failed to evict)") +
+                " [grp=" + grp.cacheOrGroupName() + ", reason='" + reason + 
"'" +
+                ", evictedPartsCount=" + evicted.size() + ", evictedParts=" + 
S.toStringSortedDistinct(evicted) +
+                (allEvicted ? "" : ", nonEvictedPartsCount=" + failed.size() +
+                ", nonEvictedParts=" + S.toStringSortedDistinct(failed)) + "]";
+
+            if (allEvicted)
+                log.info(msg);
+            else
+                log.warning(msg);
+        });
+    }
+
     /**
      * Iterator over current local partitions.
      */
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartitionSyncEviction.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartitionSyncEviction.java
index c8e87b955a9..ac92d6725ca 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartitionSyncEviction.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/GridDhtLocalPartitionSyncEviction.java
@@ -19,7 +19,6 @@ package 
org.apache.ignite.internal.processors.cache.distributed.dht.topology;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteInterruptedCheckedException;
 import org.apache.ignite.internal.NodeStoppingException;
 import org.apache.ignite.internal.processors.cache.CacheGroupContext;
@@ -75,7 +74,7 @@ public class GridDhtLocalPartitionSyncEviction extends 
GridDhtLocalPartition {
     }
 
     /** {@inheritDoc} */
-    @Override public IgniteInternalFuture<?> rent() {
+    @Override public RentFuture rent() {
         if (mode == 0)
             sync();
 
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/LogEvictionResultsTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/LogEvictionResultsTest.java
new file mode 100644
index 00000000000..046d5f43e9b
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/topology/LogEvictionResultsTest.java
@@ -0,0 +1,324 @@
+/*
+ * 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.distributed.dht.topology;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
+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.processors.resource.DependencyResolver;
+import org.apache.ignite.internal.util.lang.RunnableX;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.testframework.CallbackExecutorLogListener;
+import org.apache.ignite.testframework.ListeningTestLogger;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static org.apache.ignite.cache.CacheRebalanceMode.NONE;
+import static org.apache.ignite.testframework.GridTestUtils.waitForCondition;
+
+/** Test class for verifying eviction result log messages. */
+public class LogEvictionResultsTest extends GridCommonAbstractTest {
+    /** Number of keys to load into a partition. */
+    private static final int KEY_CNT = 10;
+
+    /** Number of partitions to move to the MOVING state. */
+    private static final int MOVING_PARTS_CNT = 3;
+
+    /** Template for extracting parameter value from log messages. */
+    private static final String PARAM_VALUE_TEMPLATE = "\\b%s=(\\d+)\\b";
+
+    /** Template for matching eviction completion log messages. */
+    private static final String EVICTION_PATTERN_TEMPLATE = "Eviction 
completed successfully \\[grp=[^,]+, reason='%s'.*";
+
+    /** Listening test logger. */
+    private final ListeningTestLogger testLog = new ListeningTestLogger(log);
+
+    /** Latch for locking partition clearing. */
+    private final CountDownLatch lock = new CountDownLatch(1);
+
+    /** Latch for unlocking partition clearing. */
+    private final CountDownLatch unlock = new CountDownLatch(1);
+
+    /** Function to obtain a dependency resolver for launching a grid, 
allowing delayed partition clearing. */
+    private final Function<List<Integer>, DependencyResolver> depResolverFunc 
= (evictedParts) ->
+        new DependencyResolver() {
+            @Override public <T> T resolve(T instance) {
+                if (instance instanceof GridDhtPartitionTopologyImpl) {
+                    GridDhtPartitionTopologyImpl top = 
(GridDhtPartitionTopologyImpl)instance;
+
+                    top.partitionFactory(
+                        (ctx, grp, id, recovery) -> evictedParts.contains(id)
+                            ? new GridDhtLocalPartitionSyncEviction(ctx, grp, 
id, recovery, 2, lock, unlock)
+                            : new GridDhtLocalPartition(ctx, grp, id, 
recovery));
+                }
+
+                return instance;
+            }
+        };
+
+    /** Flag indicating whether the cluster is configured as persistent. */
+    private boolean persistenceEnabled;
+
+    /** Flag indicating whether rebalance is disabled. */
+    private boolean rebalanceDisabled;
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        cleanPersistenceDir();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        cleanPersistenceDir();
+
+        super.afterTest();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String 
igniteInstanceName) throws Exception {
+        CacheConfiguration<?, ?> cacheCfg = new 
CacheConfiguration<>(DEFAULT_CACHE_NAME)
+            .setBackups(2)
+            .setAffinity(new RendezvousAffinityFunction(false, 32));
+
+        if (rebalanceDisabled)
+            cacheCfg.setRebalanceMode(NONE);
+
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName)
+            .setRebalanceThreadPoolSize(MOVING_PARTS_CNT)
+            .setGridLogger(testLog)
+            .setConsistentId(igniteInstanceName)
+            .setCacheConfiguration(cacheCfg);
+
+        if (persistenceEnabled) {
+            DataStorageConfiguration dsCfg = new DataStorageConfiguration();
+
+            dsCfg.getDefaultDataRegionConfiguration()
+                .setPersistenceEnabled(true);
+
+            cfg.setDataStorageConfiguration(dsCfg);
+        }
+
+        return cfg;
+    }
+
+    /** */
+    private void startTestGrids() throws Exception {
+        startGrids(2);
+        awaitPartitionMapExchange();
+
+        startGrid(2);
+        awaitPartitionMapExchange();
+
+        startGrid(3);
+        awaitPartitionMapExchange();
+    }
+
+    /** Verifies log messages for partition clearing completion during 
rebalancing. */
+    @Test
+    public void testClearingDuringRebalance() throws Exception {
+        List<String> rebalPrepMsgs = new ArrayList<>();
+        List<String> rebalEvictMsgs = new ArrayList<>();
+
+        CallbackExecutorLogListener rebalPrepLsnr = new 
CallbackExecutorLogListener(
+            "Prepared rebalancing.*", rebalPrepMsgs::add);
+
+        CallbackExecutorLogListener rebalEvictLsnr = new 
CallbackExecutorLogListener(
+            evictionMsg("preparation for rebalancing"), rebalEvictMsgs::add);
+
+        testLog.registerAllListeners(rebalPrepLsnr, rebalEvictLsnr);
+
+        startTestGrids();
+
+        Collection<Integer> prepared = extractPartsCount(rebalPrepMsgs, 
"partitionsCount");
+        Collection<Integer> evicted = extractPartsCount(rebalEvictMsgs, 
"evictedPartsCount");
+
+        assertTrue(CollectionUtils.isEqualCollection(prepared, evicted));
+    }
+
+    /** Verifies log messages for eviction completion triggered by topology 
changes. */
+    @Test
+    public void testCheckEviction() throws Exception {
+        String prepMsg = "Partition has been scheduled for eviction \\((all 
affinity nodes are owners|this node " +
+            "is oldest non-affinity node)\\).*";
+
+        String evictMsg = evictionMsg("partitions no longer belong to 
affinity");
+
+        Pattern partIdPattern = paramPattern("p");
+
+        checkLogMessages(prepMsg, evictMsg, partIdPattern, 
this::startTestGrids);
+    }
+
+    /** Verifies log messages for eviction completion when rebalancing is 
disabled. */
+    @Test
+    public void testRebalanceDisabled() throws Exception {
+        String prepMsg = "Evicting partition with rebalancing disabled \\(it 
does not belong to affinity\\).*";
+
+        String evictMsg = evictionMsg("rebalancing is disabled \\(partitions 
do not belong to affinity\\)");
+
+        Pattern partIdPattern = paramPattern("id");
+
+        checkLogMessages(prepMsg, evictMsg, partIdPattern, () -> {
+            rebalanceDisabled = true;
+
+            startTestGrids();
+        });
+    }
+
+    /** Verifies log messages for eviction of partitions in MOVING state. */
+    @Test
+    public void testEvictMovingPartitions() throws Exception {
+        String prepMsg = "Evicting MOVING partition \\(it does not belong to 
affinity\\).*";
+
+        String evictMsg = evictionMsg("MOVING partitions do not belong to 
affinity");
+
+        Pattern partIdPattern = paramPattern("p");
+
+        checkLogMessages(prepMsg, evictMsg, partIdPattern, () -> {
+            persistenceEnabled = true;
+
+            startGrids(3);
+
+            grid(0).cluster().state(ClusterState.ACTIVE);
+
+            List<Integer> evictedParts = evictingPartitionsAfterJoin(grid(2),
+                grid(2).cache(DEFAULT_CACHE_NAME), MOVING_PARTS_CNT);
+
+            evictedParts.forEach(p ->
+                loadDataToPartition(p, getTestIgniteInstanceName(0), 
DEFAULT_CACHE_NAME, KEY_CNT, 0));
+
+            forceCheckpoint();
+
+            stopGrid(2);
+
+            evictedParts.forEach(p -> 
partitionKeys(grid(0).cache(DEFAULT_CACHE_NAME), p, KEY_CNT, 0)
+                .forEach(k -> grid(0).cache(DEFAULT_CACHE_NAME).remove(k)));
+
+            startGrid(2, depResolverFunc.apply(evictedParts));
+
+            assertTrue(U.await(lock, 
GridDhtLocalPartitionSyncEviction.TIMEOUT, TimeUnit.MILLISECONDS));
+
+            startGrid(3);
+
+            resetBaselineTopology();
+
+            awaitPartitionMapExchange();
+
+            unlock.countDown();
+
+            awaitPartitionMapExchange();
+        });
+    }
+
+    /**
+     * Verifies log messages produced during partition preparation and 
eviction.
+     *
+     * @param prepMsg Log message indicating partition preparation for 
eviction.
+     * @param evictMsg Log message indicating completion of partition eviction.
+     * @param partIdPattern Pattern used to extract partition ids from log 
messages indicating preparation for eviction.
+     * @param task Action that triggers the expected log output.
+     */
+    private void checkLogMessages(String prepMsg, String evictMsg, Pattern 
partIdPattern, RunnableX task) throws Exception {
+        setLoggerDebugLevel();
+
+        List<String> preparedMsgs = new ArrayList<>();
+        List<String> evictedMsgs = new ArrayList<>();
+
+        CallbackExecutorLogListener prepLsnr = new 
CallbackExecutorLogListener(prepMsg, preparedMsgs::add);
+        CallbackExecutorLogListener evictLsnr = new 
CallbackExecutorLogListener(evictMsg, evictedMsgs::add);
+
+        testLog.registerAllListeners(prepLsnr, evictLsnr);
+
+        task.run();
+
+        Pattern evictedPartsPattern = 
Pattern.compile("evictedParts=\\[([^\\]]+)\\]");
+
+        assertTrue(waitForCondition(() -> {
+            Collection<Integer> prepared = extractParts(preparedMsgs, 
partIdPattern);
+            Collection<Integer> evicted = extractParts(evictedMsgs, 
evictedPartsPattern);
+
+            return CollectionUtils.isEqualCollection(prepared, evicted);
+        }, getTestTimeout()));
+    }
+
+    /**
+     * @param logMsgs List of log messages.
+     * @param evictedCntParamName Log message parameter name for evicted 
partitions count.
+     */
+    private Collection<Integer> extractPartsCount(List<String> logMsgs, String 
evictedCntParamName) {
+        return F.viewReadOnly(logMsgs, msg -> {
+            Matcher matcher = paramPattern(evictedCntParamName).matcher(msg);
+
+            assertTrue(matcher.find());
+
+            return Integer.parseInt(matcher.group(1));
+        });
+    }
+
+    /**
+     * @param logMsgs List of log messages.
+     * @param pattern Pattern used to extract partitions from debug log 
messages.
+     */
+    private Collection<Integer> extractParts(List<String> logMsgs, Pattern 
pattern) {
+        List<Integer> res = new ArrayList<>();
+
+        for (String msg : logMsgs) {
+            Matcher matcher = pattern.matcher(msg);
+
+            if (matcher.find()) {
+                String[] parts = matcher.group(1).split(",");
+
+                for (String part : parts)
+                    res.add(Integer.parseInt(part.trim()));
+            }
+        }
+
+        return res;
+    }
+
+    /**
+     * @param reason Eviction reason.
+     * @return Regex pattern string matching the corresponding log entry.
+     */
+    private static String evictionMsg(String reason) {
+        return String.format(EVICTION_PATTERN_TEMPLATE, reason);
+    }
+
+    /**
+     * @param paramName Parameter name.
+     * @return Pattern for extracting value for the given parameter name.
+     */
+    private static Pattern paramPattern(String paramName) {
+        return Pattern.compile(String.format(PARAM_VALUE_TEMPLATE, paramName));
+    }
+}
diff --git 
a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
 
b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
index c3587ca0b3c..96c03839da5 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
@@ -50,6 +50,7 @@ import 
org.apache.ignite.internal.processors.cache.GridLocalIgniteSerializationT
 import 
org.apache.ignite.internal.processors.cache.IgniteMarshallerCacheConcurrentReadWriteTest;
 import 
org.apache.ignite.internal.processors.cache.SetTxTimeoutOnPartitionMapExchangeTest;
 import 
org.apache.ignite.internal.processors.cache.distributed.dht.topology.EvictPartitionInLogTest;
+import 
org.apache.ignite.internal.processors.cache.distributed.dht.topology.LogEvictionResultsTest;
 import 
org.apache.ignite.internal.processors.cache.distributed.dht.topology.PartitionEvictionOrderTest;
 import 
org.apache.ignite.internal.processors.cache.query.continuous.DiscoveryDataDeserializationFailureHanderTest;
 import 
org.apache.ignite.internal.processors.closure.GridClosureProcessorRemoteTest;
@@ -151,7 +152,8 @@ import org.junit.runners.Suite;
     ErrorMessageSelfTest.class,
     DefaultEnumMapperTest.class,
     IgniteDataTransferObjectProcessorTest.class,
-    CompressedMessageTest.class
+    CompressedMessageTest.class,
+    LogEvictionResultsTest.class,
 })
 public class IgniteBasicTestSuite {
 }

Reply via email to