This is an automated email from the ASF dual-hosted git repository.
sergeychugunov 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 3df1cab8922 IGNITE-28085 Add the EvictionsStarted metric to
DataRegionMetrics (#12866)
3df1cab8922 is described below
commit 3df1cab8922b921af977577e7e63febf92a2b0b6
Author: oleg-vlsk <[email protected]>
AuthorDate: Fri Mar 13 17:32:48 2026 +1000
IGNITE-28085 Add the EvictionsStarted metric to DataRegionMetrics (#12866)
---
docs/_docs/monitoring-metrics/new-metrics.adoc | 1 +
.../java/org/apache/ignite/DataRegionMetrics.java | 7 ++
.../cache/persistence/DataRegionMetricsImpl.java | 18 +++++
.../persistence/DataRegionMetricsSnapshot.java | 9 +++
.../IgniteCacheDatabaseSharedManager.java | 2 +
.../IgniteDataStorageMetricsSelfTest.java | 81 ++++++++++++++++++++--
6 files changed, 113 insertions(+), 5 deletions(-)
diff --git a/docs/_docs/monitoring-metrics/new-metrics.adoc
b/docs/_docs/monitoring-metrics/new-metrics.adoc
index 19a2ca3121e..0850d9ae331 100644
--- a/docs/_docs/monitoring-metrics/new-metrics.adoc
+++ b/docs/_docs/monitoring-metrics/new-metrics.adoc
@@ -394,6 +394,7 @@ Register name: `io.dataregion.{data_region_name}`
|DirtyPages | long| Number of pages in memory not yet synchronized with
persistent storage.
|EmptyDataPages| long| Calculates empty data pages count for region. It
counts only totally free pages that can be reused (e. g. pages that are
contained in reuse bucket of free list).
|EvictionRate| hitrate| Eviction rate (pages per second).
+|EvictionsStarted | boolean | True if page eviction was triggered due to
data region memory pressure.
|LargeEntriesPagesCount| long| Count of pages that fully ocupied by large
entries that go beyond page size
|OffHeapSize| long| Offheap size in bytes.
|OffheapUsedSize| long| Offheap used size in bytes.
diff --git
a/modules/core/src/main/java/org/apache/ignite/DataRegionMetrics.java
b/modules/core/src/main/java/org/apache/ignite/DataRegionMetrics.java
index a1539e1e8b7..28d7c4004bf 100644
--- a/modules/core/src/main/java/org/apache/ignite/DataRegionMetrics.java
+++ b/modules/core/src/main/java/org/apache/ignite/DataRegionMetrics.java
@@ -241,4 +241,11 @@ public interface DataRegionMetrics {
* @return Total used offheap size in bytes.
*/
public long getOffheapUsedSize();
+
+ /**
+ * Data region eviction-started flag.
+ *
+ * @return {@code true} if page eviction was triggered due to data region
memory pressure.
+ */
+ public boolean isEvictionsStarted();
}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java
index 549ffc399f7..1e962331f11 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java
@@ -30,6 +30,7 @@ import
org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMetri
import
org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMetricsImpl;
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.BooleanMetricImpl;
import org.apache.ignite.internal.processors.metric.impl.HitRateMetric;
import org.apache.ignite.internal.processors.metric.impl.LongAdderMetric;
import
org.apache.ignite.internal.processors.metric.impl.LongAdderWithDelegateMetric;
@@ -178,6 +179,9 @@ public class DataRegionMetricsImpl implements
DataRegionMetrics {
@Nullable
private final PeriodicHistogramMetricImpl pageTsHistogram;
+ /** Metric indicating whether page eviction has started. */
+ private final BooleanMetricImpl evictionsStarted;
+
/**
* Same as {@link #DataRegionMetricsImpl(DataRegionConfiguration,
GridKernalContext, DataRegionMetricsProvider)}
* but uses a no-op implementation for the {@link
DataRegionMetricsProvider}.
@@ -281,6 +285,9 @@ public class DataRegionMetricsImpl implements
DataRegionMetrics {
mreg.longMetric("MaxSize", "Maximum memory region size in bytes
defined by its data region.")
.value(dataRegionCfg.getMaxSize());
+ evictionsStarted = mreg.booleanMetric("EvictionsStarted",
+ "True if page eviction was triggered due to data region memory
pressure.");
+
if (persistenceEnabled) {
// Reserve 1 sec, page ts can be slightly lower than
currentTimeMillis, due to applied to ts mask. This
// reservation mainly affects only tests (we can check buckets
more predictevely).
@@ -875,4 +882,15 @@ public class DataRegionMetricsImpl implements
DataRegionMetrics {
return list;
}
+
+ /** {@inheritDoc} */
+ @Override public boolean isEvictionsStarted() {
+ return evictionsStarted.value();
+ }
+
+ /** */
+ public void onPageEvictionsStarted() {
+ if (!evictionsStarted.value())
+ evictionsStarted.value(true);
+ }
}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsSnapshot.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsSnapshot.java
index 316f98fe875..b56b9a9baf8 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsSnapshot.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsSnapshot.java
@@ -92,6 +92,9 @@ public class DataRegionMetricsSnapshot implements
DataRegionMetrics {
/** */
private final long offHeapUsedSize;
+ /** */
+ private final boolean evictionsStarted;
+
/**
* @param metrics Metrics instance to take a copy.
*/
@@ -119,6 +122,7 @@ public class DataRegionMetricsSnapshot implements
DataRegionMetrics {
replacedPage = metrics.getPagesReplaced();
offHeapSize = metrics.getOffHeapSize();
offHeapUsedSize = metrics.getOffheapUsedSize();
+ evictionsStarted = metrics.isEvictionsStarted();
}
/** {@inheritDoc} */
@@ -235,4 +239,9 @@ public class DataRegionMetricsSnapshot implements
DataRegionMetrics {
@Override public long getOffheapUsedSize() {
return offHeapUsedSize;
}
+
+ /** {@inheritDoc} */
+ @Override public boolean isEvictionsStarted() {
+ return evictionsStarted;
+ }
}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java
index d8b14ce718a..a20a38e7093 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java
@@ -1246,6 +1246,8 @@ public class IgniteCacheDatabaseSharedManager extends
GridCacheSharedManagerAdap
return;
while (memPlc.evictionTracker().evictionRequired()) {
+ memPlc.metrics().onPageEvictionsStarted();
+
warnFirstEvict(memPlc.config());
memPlc.evictionTracker().evictDataPage();
diff --git
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteDataStorageMetricsSelfTest.java
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteDataStorageMetricsSelfTest.java
index 9cff28d9882..dffaf8a29a9 100644
---
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteDataStorageMetricsSelfTest.java
+++
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteDataStorageMetricsSelfTest.java
@@ -63,14 +63,17 @@ import org.apache.ignite.metric.MetricRegistry;
import org.apache.ignite.spi.metric.HistogramMetric;
import org.apache.ignite.spi.metric.LongMetric;
import org.apache.ignite.testframework.ListeningTestLogger;
+import org.apache.ignite.testframework.LogListener;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
import org.junit.Test;
import static java.util.Collections.emptyList;
+import static org.apache.commons.lang3.StringUtils.repeat;
import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
import static org.apache.ignite.cache.CacheMode.PARTITIONED;
import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
import static org.apache.ignite.cluster.ClusterState.ACTIVE;
+import static org.apache.ignite.configuration.DataPageEvictionMode.RANDOM_LRU;
import static
org.apache.ignite.internal.processors.cache.CacheGroupMetricsImpl.CACHE_GROUP_METRICS_PREFIX;
import static
org.apache.ignite.internal.processors.cache.persistence.DataStorageMetricsImpl.DATASTORAGE_METRIC_PREFIX;
import static
org.apache.ignite.internal.processors.cache.persistence.wal.serializer.RecordV1Serializer.HEADER_RECORD_SIZE;
@@ -89,7 +92,10 @@ public class IgniteDataStorageMetricsSelfTest extends
GridCommonAbstractTest {
private static final String GROUP2 = "grp2";
/** */
- private static final String NO_PERSISTENCE = "no-persistence";
+ private static final String NO_PERSISTENCE_1 = "no-persistence-1";
+
+ /** */
+ private static final String NO_PERSISTENCE_2 = "no-persistence-2";
/** */
private static final String PERSISTENCE_REGION_1 = "persistence-1";
@@ -137,7 +143,14 @@ public class IgniteDataStorageMetricsSelfTest extends
GridCommonAbstractTest {
.setMaxSize(maxRegionSize)
.setPersistenceEnabled(false)
.setMetricsEnabled(true)
- .setName(NO_PERSISTENCE))
+ .setName(NO_PERSISTENCE_1)
+ .setPageEvictionMode(RANDOM_LRU),
+ new DataRegionConfiguration()
+ .setMaxSize(maxRegionSize)
+ .setPersistenceEnabled(false)
+ .setMetricsEnabled(true)
+ .setName(NO_PERSISTENCE_2)
+ .setPageEvictionMode(RANDOM_LRU))
.setWalMode(WALMode.LOG_ONLY)
.setMetricsEnabled(true);
@@ -148,7 +161,8 @@ public class IgniteDataStorageMetricsSelfTest extends
GridCommonAbstractTest {
cfg.setCacheConfiguration(
cacheConfiguration(GROUP1, "cache", PARTITIONED, ATOMIC, 1, null),
cacheConfiguration(GROUP2, "cache2", PARTITIONED, ATOMIC, 1,
PERSISTENCE_REGION_2),
- cacheConfiguration(null, "cache-np", PARTITIONED, ATOMIC, 1,
NO_PERSISTENCE));
+ cacheConfiguration(null, "cache-np", PARTITIONED, ATOMIC, 1,
NO_PERSISTENCE_1),
+ cacheConfiguration(null, "cache-np2", PARTITIONED, ATOMIC, 1,
NO_PERSISTENCE_2));
cfg.setGridLogger(listeningLog);
@@ -191,7 +205,7 @@ public class IgniteDataStorageMetricsSelfTest extends
GridCommonAbstractTest {
ccfg.setDataRegionName(dataRegName);
ccfg.setAffinity(new RendezvousAffinityFunction(false, 32));
- if (NO_PERSISTENCE.equals(dataRegName))
+ if (NO_PERSISTENCE_1.equals(dataRegName))
ccfg.setDiskPageCompression(null);
return ccfg;
@@ -226,7 +240,7 @@ public class IgniteDataStorageMetricsSelfTest extends
GridCommonAbstractTest {
assertTrue(memMetrics.getDirtyPages() > 0);
assertTrue(memMetrics.getPagesFillFactor() > 0);
- memMetrics = ig.dataRegionMetrics("no-persistence");
+ memMetrics = ig.dataRegionMetrics(NO_PERSISTENCE_1);
assertNotNull(memMetrics);
assertTrue(memMetrics.getTotalAllocatedPages() > 0);
@@ -505,6 +519,63 @@ public class IgniteDataStorageMetricsSelfTest extends
GridCommonAbstractTest {
checkWalArchiveAndTotalSize(n, false);
}
+ /**
+ * Verifies that the 'EvictionsStarted' metric is tracked per data region
and becomes {@code true} only for the
+ * region where page eviction is triggered, remaining unaffected by
evictions in other regions. If eviction starts
+ * in multiple regions, the metric becomes {@code true} independently for
each of them.
+ */
+ @Test
+ public void testEvictionsStartedMetric() throws Exception {
+ IgniteEx ignite = startGrid(0);
+
+ ignite.cluster().state(ClusterState.ACTIVE);
+
+ String template = "Page-based evictions started. Consider increasing
'maxSize' on Data Region configuration: ";
+
+ LogListener lsnr = LogListener.matches(template +
NO_PERSISTENCE_1).build();
+
+ listeningLog.registerListener(lsnr);
+
+ DataRegionMetrics memMetrics1 =
ignite.dataRegionMetrics(NO_PERSISTENCE_1);
+ DataRegionMetrics memMetrics2 =
ignite.dataRegionMetrics(NO_PERSISTENCE_2);
+
+ assertNotNull(memMetrics1);
+ assertNotNull(memMetrics2);
+
+ assertFalse(memMetrics1.isEvictionsStarted());
+ assertFalse(memMetrics2.isEvictionsStarted());
+
+ IgniteCache<Object, Object> cacheNp1 = ignite.cache("cache-np");
+ IgniteCache<Object, Object> cacheNp2 = ignite.cache("cache-np2");
+
+ String big = repeat('X', 256 * 1024);
+
+ int entryCnt = 0;
+
+ for (int i = 0; i < 1_000_000 && !lsnr.check(); i++) {
+ cacheNp1.put(i, new Person("first-" + i + "-" + big, "last-" + i +
"-" + big));
+
+ entryCnt++;
+ }
+
+ assertTrue(lsnr.check());
+
+ memMetrics1 = ignite.dataRegionMetrics(NO_PERSISTENCE_1);
+ memMetrics2 = ignite.dataRegionMetrics(NO_PERSISTENCE_2);
+
+ assertTrue(memMetrics1.isEvictionsStarted());
+ assertFalse(memMetrics2.isEvictionsStarted());
+
+ for (int i = 0; i < entryCnt + 10; i++)
+ cacheNp2.put(i, new Person("first-" + i + "-" + big, "last-" + i +
"-" + big));
+
+ memMetrics1 = ignite.dataRegionMetrics(NO_PERSISTENCE_1);
+ memMetrics2 = ignite.dataRegionMetrics(NO_PERSISTENCE_2);
+
+ assertTrue(memMetrics1.isEvictionsStarted());
+ assertTrue(memMetrics2.isEvictionsStarted());
+ }
+
/**
* Populates a cache w/32 KB of data.
*