Skip to content

Commit 3df1cab

Browse files
authored
IGNITE-28085 Add the EvictionsStarted metric to DataRegionMetrics (#12866)
1 parent d48adb1 commit 3df1cab

6 files changed

Lines changed: 113 additions & 5 deletions

File tree

docs/_docs/monitoring-metrics/new-metrics.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ Register name: `io.dataregion.{data_region_name}`
394394
|DirtyPages | long| Number of pages in memory not yet synchronized with persistent storage.
395395
|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).
396396
|EvictionRate| hitrate| Eviction rate (pages per second).
397+
|EvictionsStarted | boolean | True if page eviction was triggered due to data region memory pressure.
397398
|LargeEntriesPagesCount| long| Count of pages that fully ocupied by large entries that go beyond page size
398399
|OffHeapSize| long| Offheap size in bytes.
399400
|OffheapUsedSize| long| Offheap used size in bytes.

modules/core/src/main/java/org/apache/ignite/DataRegionMetrics.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,4 +241,11 @@ public interface DataRegionMetrics {
241241
* @return Total used offheap size in bytes.
242242
*/
243243
public long getOffheapUsedSize();
244+
245+
/**
246+
* Data region eviction-started flag.
247+
*
248+
* @return {@code true} if page eviction was triggered due to data region memory pressure.
249+
*/
250+
public boolean isEvictionsStarted();
244251
}

modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsImpl.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMetricsImpl;
3131
import org.apache.ignite.internal.processors.metric.MetricRegistryImpl;
3232
import org.apache.ignite.internal.processors.metric.impl.AtomicLongMetric;
33+
import org.apache.ignite.internal.processors.metric.impl.BooleanMetricImpl;
3334
import org.apache.ignite.internal.processors.metric.impl.HitRateMetric;
3435
import org.apache.ignite.internal.processors.metric.impl.LongAdderMetric;
3536
import org.apache.ignite.internal.processors.metric.impl.LongAdderWithDelegateMetric;
@@ -178,6 +179,9 @@ private static LongAdderMetricDelegate delegate(LongAdderMetric delegate) {
178179
@Nullable
179180
private final PeriodicHistogramMetricImpl pageTsHistogram;
180181

182+
/** Metric indicating whether page eviction has started. */
183+
private final BooleanMetricImpl evictionsStarted;
184+
181185
/**
182186
* Same as {@link #DataRegionMetricsImpl(DataRegionConfiguration, GridKernalContext, DataRegionMetricsProvider)}
183187
* but uses a no-op implementation for the {@link DataRegionMetricsProvider}.
@@ -281,6 +285,9 @@ public DataRegionMetricsImpl(
281285
mreg.longMetric("MaxSize", "Maximum memory region size in bytes defined by its data region.")
282286
.value(dataRegionCfg.getMaxSize());
283287

288+
evictionsStarted = mreg.booleanMetric("EvictionsStarted",
289+
"True if page eviction was triggered due to data region memory pressure.");
290+
284291
if (persistenceEnabled) {
285292
// Reserve 1 sec, page ts can be slightly lower than currentTimeMillis, due to applied to ts mask. This
286293
// reservation mainly affects only tests (we can check buckets more predictevely).
@@ -875,4 +882,15 @@ public Collection<PagesTimestampHistogramView> pagesTimestampHistogramView() {
875882

876883
return list;
877884
}
885+
886+
/** {@inheritDoc} */
887+
@Override public boolean isEvictionsStarted() {
888+
return evictionsStarted.value();
889+
}
890+
891+
/** */
892+
public void onPageEvictionsStarted() {
893+
if (!evictionsStarted.value())
894+
evictionsStarted.value(true);
895+
}
878896
}

modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/DataRegionMetricsSnapshot.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ public class DataRegionMetricsSnapshot implements DataRegionMetrics {
9292
/** */
9393
private final long offHeapUsedSize;
9494

95+
/** */
96+
private final boolean evictionsStarted;
97+
9598
/**
9699
* @param metrics Metrics instance to take a copy.
97100
*/
@@ -119,6 +122,7 @@ public DataRegionMetricsSnapshot(DataRegionMetrics metrics) {
119122
replacedPage = metrics.getPagesReplaced();
120123
offHeapSize = metrics.getOffHeapSize();
121124
offHeapUsedSize = metrics.getOffheapUsedSize();
125+
evictionsStarted = metrics.isEvictionsStarted();
122126
}
123127

124128
/** {@inheritDoc} */
@@ -235,4 +239,9 @@ public DataRegionMetricsSnapshot(DataRegionMetrics metrics) {
235239
@Override public long getOffheapUsedSize() {
236240
return offHeapUsedSize;
237241
}
242+
243+
/** {@inheritDoc} */
244+
@Override public boolean isEvictionsStarted() {
245+
return evictionsStarted;
246+
}
238247
}

modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,8 @@ public void ensureFreeSpace(DataRegion memPlc) throws IgniteCheckedException {
12461246
return;
12471247

12481248
while (memPlc.evictionTracker().evictionRequired()) {
1249+
memPlc.metrics().onPageEvictionsStarted();
1250+
12491251
warnFirstEvict(memPlc.config());
12501252

12511253
memPlc.evictionTracker().evictDataPage();

modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/IgniteDataStorageMetricsSelfTest.java

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,17 @@
6363
import org.apache.ignite.spi.metric.HistogramMetric;
6464
import org.apache.ignite.spi.metric.LongMetric;
6565
import org.apache.ignite.testframework.ListeningTestLogger;
66+
import org.apache.ignite.testframework.LogListener;
6667
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
6768
import org.junit.Test;
6869

6970
import static java.util.Collections.emptyList;
71+
import static org.apache.commons.lang3.StringUtils.repeat;
7072
import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
7173
import static org.apache.ignite.cache.CacheMode.PARTITIONED;
7274
import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
7375
import static org.apache.ignite.cluster.ClusterState.ACTIVE;
76+
import static org.apache.ignite.configuration.DataPageEvictionMode.RANDOM_LRU;
7477
import static org.apache.ignite.internal.processors.cache.CacheGroupMetricsImpl.CACHE_GROUP_METRICS_PREFIX;
7578
import static org.apache.ignite.internal.processors.cache.persistence.DataStorageMetricsImpl.DATASTORAGE_METRIC_PREFIX;
7679
import static org.apache.ignite.internal.processors.cache.persistence.wal.serializer.RecordV1Serializer.HEADER_RECORD_SIZE;
@@ -89,7 +92,10 @@ public class IgniteDataStorageMetricsSelfTest extends GridCommonAbstractTest {
8992
private static final String GROUP2 = "grp2";
9093

9194
/** */
92-
private static final String NO_PERSISTENCE = "no-persistence";
95+
private static final String NO_PERSISTENCE_1 = "no-persistence-1";
96+
97+
/** */
98+
private static final String NO_PERSISTENCE_2 = "no-persistence-2";
9399

94100
/** */
95101
private static final String PERSISTENCE_REGION_1 = "persistence-1";
@@ -137,7 +143,14 @@ public class IgniteDataStorageMetricsSelfTest extends GridCommonAbstractTest {
137143
.setMaxSize(maxRegionSize)
138144
.setPersistenceEnabled(false)
139145
.setMetricsEnabled(true)
140-
.setName(NO_PERSISTENCE))
146+
.setName(NO_PERSISTENCE_1)
147+
.setPageEvictionMode(RANDOM_LRU),
148+
new DataRegionConfiguration()
149+
.setMaxSize(maxRegionSize)
150+
.setPersistenceEnabled(false)
151+
.setMetricsEnabled(true)
152+
.setName(NO_PERSISTENCE_2)
153+
.setPageEvictionMode(RANDOM_LRU))
141154
.setWalMode(WALMode.LOG_ONLY)
142155
.setMetricsEnabled(true);
143156

@@ -148,7 +161,8 @@ public class IgniteDataStorageMetricsSelfTest extends GridCommonAbstractTest {
148161
cfg.setCacheConfiguration(
149162
cacheConfiguration(GROUP1, "cache", PARTITIONED, ATOMIC, 1, null),
150163
cacheConfiguration(GROUP2, "cache2", PARTITIONED, ATOMIC, 1, PERSISTENCE_REGION_2),
151-
cacheConfiguration(null, "cache-np", PARTITIONED, ATOMIC, 1, NO_PERSISTENCE));
164+
cacheConfiguration(null, "cache-np", PARTITIONED, ATOMIC, 1, NO_PERSISTENCE_1),
165+
cacheConfiguration(null, "cache-np2", PARTITIONED, ATOMIC, 1, NO_PERSISTENCE_2));
152166

153167
cfg.setGridLogger(listeningLog);
154168

@@ -191,7 +205,7 @@ private CacheConfiguration cacheConfiguration(
191205
ccfg.setDataRegionName(dataRegName);
192206
ccfg.setAffinity(new RendezvousAffinityFunction(false, 32));
193207

194-
if (NO_PERSISTENCE.equals(dataRegName))
208+
if (NO_PERSISTENCE_1.equals(dataRegName))
195209
ccfg.setDiskPageCompression(null);
196210

197211
return ccfg;
@@ -226,7 +240,7 @@ public void testPersistenceMetrics() throws Exception {
226240
assertTrue(memMetrics.getDirtyPages() > 0);
227241
assertTrue(memMetrics.getPagesFillFactor() > 0);
228242

229-
memMetrics = ig.dataRegionMetrics("no-persistence");
243+
memMetrics = ig.dataRegionMetrics(NO_PERSISTENCE_1);
230244

231245
assertNotNull(memMetrics);
232246
assertTrue(memMetrics.getTotalAllocatedPages() > 0);
@@ -505,6 +519,63 @@ public void testWalTotalSizeWithArchiveTurnedOff() throws Exception {
505519
checkWalArchiveAndTotalSize(n, false);
506520
}
507521

522+
/**
523+
* Verifies that the 'EvictionsStarted' metric is tracked per data region and becomes {@code true} only for the
524+
* region where page eviction is triggered, remaining unaffected by evictions in other regions. If eviction starts
525+
* in multiple regions, the metric becomes {@code true} independently for each of them.
526+
*/
527+
@Test
528+
public void testEvictionsStartedMetric() throws Exception {
529+
IgniteEx ignite = startGrid(0);
530+
531+
ignite.cluster().state(ClusterState.ACTIVE);
532+
533+
String template = "Page-based evictions started. Consider increasing 'maxSize' on Data Region configuration: ";
534+
535+
LogListener lsnr = LogListener.matches(template + NO_PERSISTENCE_1).build();
536+
537+
listeningLog.registerListener(lsnr);
538+
539+
DataRegionMetrics memMetrics1 = ignite.dataRegionMetrics(NO_PERSISTENCE_1);
540+
DataRegionMetrics memMetrics2 = ignite.dataRegionMetrics(NO_PERSISTENCE_2);
541+
542+
assertNotNull(memMetrics1);
543+
assertNotNull(memMetrics2);
544+
545+
assertFalse(memMetrics1.isEvictionsStarted());
546+
assertFalse(memMetrics2.isEvictionsStarted());
547+
548+
IgniteCache<Object, Object> cacheNp1 = ignite.cache("cache-np");
549+
IgniteCache<Object, Object> cacheNp2 = ignite.cache("cache-np2");
550+
551+
String big = repeat('X', 256 * 1024);
552+
553+
int entryCnt = 0;
554+
555+
for (int i = 0; i < 1_000_000 && !lsnr.check(); i++) {
556+
cacheNp1.put(i, new Person("first-" + i + "-" + big, "last-" + i + "-" + big));
557+
558+
entryCnt++;
559+
}
560+
561+
assertTrue(lsnr.check());
562+
563+
memMetrics1 = ignite.dataRegionMetrics(NO_PERSISTENCE_1);
564+
memMetrics2 = ignite.dataRegionMetrics(NO_PERSISTENCE_2);
565+
566+
assertTrue(memMetrics1.isEvictionsStarted());
567+
assertFalse(memMetrics2.isEvictionsStarted());
568+
569+
for (int i = 0; i < entryCnt + 10; i++)
570+
cacheNp2.put(i, new Person("first-" + i + "-" + big, "last-" + i + "-" + big));
571+
572+
memMetrics1 = ignite.dataRegionMetrics(NO_PERSISTENCE_1);
573+
memMetrics2 = ignite.dataRegionMetrics(NO_PERSISTENCE_2);
574+
575+
assertTrue(memMetrics1.isEvictionsStarted());
576+
assertTrue(memMetrics2.isEvictionsStarted());
577+
}
578+
508579
/**
509580
* Populates a cache w/32 KB of data.
510581
*

0 commit comments

Comments
 (0)