From f9ef704ab246337e9ed486b11f6b3cc77392d9b3 Mon Sep 17 00:00:00 2001 From: John Blum Date: Thu, 20 Sep 2018 18:23:49 -0700 Subject: [PATCH] Add additional details with configuration meta-data about Region eviction as well as entry idle timeout (TTI) and time-to-live (TTL) expiration policies. --- .../actuate/GeodeRegionsHealthIndicator.java | 59 +++++++++++++++++++ .../GeodeRegionsHealthIndicatorUnitTests.java | 33 +++++++++++ 2 files changed, 92 insertions(+) diff --git a/spring-geode-actuator/src/main/java/org/springframework/geode/boot/actuate/GeodeRegionsHealthIndicator.java b/spring-geode-actuator/src/main/java/org/springframework/geode/boot/actuate/GeodeRegionsHealthIndicator.java index df9bd672..d858cd72 100644 --- a/spring-geode-actuator/src/main/java/org/springframework/geode/boot/actuate/GeodeRegionsHealthIndicator.java +++ b/spring-geode-actuator/src/main/java/org/springframework/geode/boot/actuate/GeodeRegionsHealthIndicator.java @@ -47,6 +47,8 @@ public class GeodeRegionsHealthIndicator extends AbstractGeodeHealthIndicator { private final BiConsumer, Health.Builder> gemfireRegionHealthIndicatorConsumers = withRegionDetails() .andThen(withPartitionRegionDetails()) + .andThen(withRegionEvictionPolicyDetails()) + .andThen(withRegionExpirationDetails()) .andThen(withRegionStatisticsDetails()); /** @@ -142,6 +144,7 @@ public class GeodeRegionsHealthIndicator extends AbstractGeodeHealthIndicator { String regionName = region.getName(); Optional.of(region) + .filter(it -> it.getAttributes() != null) .map(Region::getAttributes) .map(RegionAttributes::getPartitionAttributes) .ifPresent(partitionAttributes -> builder @@ -153,6 +156,54 @@ public class GeodeRegionsHealthIndicator extends AbstractGeodeHealthIndicator { }; } + private BiConsumer, Health.Builder> withRegionEvictionPolicyDetails() { + + return (region, builder) -> { + + String regionName = region.getName(); + + Optional.of(region) + .filter(it -> it.getAttributes() != null) + .map(Region::getAttributes) + .map(RegionAttributes::getEvictionAttributes) + .ifPresent(evictionAttributes -> { + + builder.withDetail(cacheRegionEvictionKey(regionName, "action"), evictionAttributes.getAction()) + .withDetail(cacheRegionEvictionKey(regionName, "algorithm"), evictionAttributes.getAlgorithm()); + + // NOTE: Careful! Eviction Maximum does not apply when Algorithm is Heap LRU. + Optional.ofNullable(evictionAttributes.getAlgorithm()) + .filter(it -> !it.isLRUHeap()) + .ifPresent(it -> builder + .withDetail(cacheRegionEvictionKey(regionName,"maximum"), evictionAttributes.getMaximum())); + }); + }; + } + + private BiConsumer, Health.Builder> withRegionExpirationDetails() { + + return (region, builder) -> { + + String regionName = region.getName(); + + Optional.of(region) + .filter(it -> it.getAttributes() != null) + .map(Region::getAttributes) + .map(RegionAttributes::getEntryTimeToLive) + .ifPresent(expirationAttributes -> builder + .withDetail(cacheRegionExpirationKey(regionName, "entry.ttl.action"), expirationAttributes.getAction()) + .withDetail(cacheRegionExpirationKey(regionName, "entry.ttl.timeout"), expirationAttributes.getTimeout())); + + Optional.of(region) + .filter(it -> it.getAttributes() != null) + .map(Region::getAttributes) + .map(RegionAttributes::getEntryIdleTimeout) + .ifPresent(expirationAttributes -> builder + .withDetail(cacheRegionExpirationKey(regionName, "entry.tti.action"), expirationAttributes.getAction()) + .withDetail(cacheRegionExpirationKey(regionName, "entry.tti.timeout"), expirationAttributes.getTimeout())); + }; + } + private BiConsumer, Health.Builder> withRegionStatisticsDetails() { return (region, builder) -> { @@ -180,6 +231,14 @@ public class GeodeRegionsHealthIndicator extends AbstractGeodeHealthIndicator { return String.format("geode.cache.regions.%1$s.%2$s", regionName, suffix); } + private String cacheRegionEvictionKey(String regionName, String suffix) { + return cacheRegionKey(regionName, String.format("eviction.%s", suffix)); + } + + private String cacheRegionExpirationKey(String regionName, String suffix) { + return cacheRegionKey(regionName, String.format("expiration.%s", suffix)); + } + private String cacheRegionStatisticsKey(String regionName, String suffix) { return cacheRegionKey(regionName, String.format("statistics.%s", suffix)); } diff --git a/spring-geode-actuator/src/test/java/org/springframework/geode/boot/actuate/GeodeRegionsHealthIndicatorUnitTests.java b/spring-geode-actuator/src/test/java/org/springframework/geode/boot/actuate/GeodeRegionsHealthIndicatorUnitTests.java index 9f86a6eb..766ad41a 100644 --- a/spring-geode-actuator/src/test/java/org/springframework/geode/boot/actuate/GeodeRegionsHealthIndicatorUnitTests.java +++ b/spring-geode-actuator/src/test/java/org/springframework/geode/boot/actuate/GeodeRegionsHealthIndicatorUnitTests.java @@ -30,6 +30,11 @@ import java.util.Set; import org.apache.geode.cache.CacheStatistics; import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.EvictionAction; +import org.apache.geode.cache.EvictionAlgorithm; +import org.apache.geode.cache.EvictionAttributes; +import org.apache.geode.cache.ExpirationAction; +import org.apache.geode.cache.ExpirationAttributes; import org.apache.geode.cache.GemFireCache; import org.apache.geode.cache.PartitionAttributes; import org.apache.geode.cache.Region; @@ -96,6 +101,13 @@ public class GeodeRegionsHealthIndicatorUnitTests { when(mockPartitionAttributes.getTotalNumBuckets()).thenReturn(226); when(mockRegionOne.getAttributes().getPartitionAttributes()).thenReturn(mockPartitionAttributes); + EvictionAttributes mockEvictionAttributes = mock(EvictionAttributes.class); + + when(mockEvictionAttributes.getAction()).thenReturn(EvictionAction.LOCAL_DESTROY); + when(mockEvictionAttributes.getAlgorithm()).thenReturn(EvictionAlgorithm.LRU_ENTRY); + when(mockEvictionAttributes.getMaximum()).thenReturn(10000); + when(mockRegionOne.getAttributes().getEvictionAttributes()).thenReturn(mockEvictionAttributes); + Region mockRegionTwo = CacheMockObjects.mockRegion("MockRegionTwo", DataPolicy.EMPTY); when(mockRegionTwo.getAttributes().getCloningEnabled()).thenReturn(false); @@ -108,6 +120,20 @@ public class GeodeRegionsHealthIndicatorUnitTests { when(mockRegionTwo.getAttributes().getStatisticsEnabled()).thenReturn(true); when(mockRegionTwo.getAttributes().getValueConstraint()).thenReturn((Class) String.class); + ExpirationAttributes mockIdleTimeoutEntryExpirationAttributes = + mock(ExpirationAttributes.class, "Entry-TTI"); + + when(mockIdleTimeoutEntryExpirationAttributes.getAction()).thenReturn(ExpirationAction.INVALIDATE); + when(mockIdleTimeoutEntryExpirationAttributes.getTimeout()).thenReturn(600); + when(mockRegionTwo.getAttributes().getEntryIdleTimeout()).thenReturn(mockIdleTimeoutEntryExpirationAttributes); + + ExpirationAttributes mockTimeToLiveEntryExpirationAttributes = + mock(ExpirationAttributes.class, "Entry-TTL"); + + when(mockTimeToLiveEntryExpirationAttributes.getAction()).thenReturn(ExpirationAction.DESTROY); + when(mockTimeToLiveEntryExpirationAttributes.getTimeout()).thenReturn(900); + when(mockRegionTwo.getAttributes().getEntryTimeToLive()).thenReturn(mockTimeToLiveEntryExpirationAttributes); + CacheStatistics mockCacheStatistics = mock(CacheStatistics.class); when(mockCacheStatistics.getHitCount()).thenReturn(202408L); @@ -142,6 +168,9 @@ public class GeodeRegionsHealthIndicatorUnitTests { assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.load-factor", 0.75f); assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.key-constraint", Long.class.getName()); assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.off-heap", "Yes"); + assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.eviction.action", EvictionAction.LOCAL_DESTROY); + assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.eviction.algorithm", EvictionAlgorithm.LRU_ENTRY); + assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.eviction.maximum", 10000); assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.partition.collocated-with", "CollocatedRegion"); assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.partition.local-max-memory", 10240); assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionOne.partition.redundant-copies", 2); @@ -158,6 +187,10 @@ public class GeodeRegionsHealthIndicatorUnitTests { assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.off-heap", "No"); assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.pool-name", "TestPool"); assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.scope", Scope.DISTRIBUTED_NO_ACK); + assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.expiration.entry.tti.action", ExpirationAction.INVALIDATE); + assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.expiration.entry.tti.timeout", 600); + assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.expiration.entry.ttl.action", ExpirationAction.DESTROY); + assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.expiration.entry.ttl.timeout", 900); assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.statistics.hit-count", 202408L); assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.statistics.hit-ratio", 0.82f); assertThat(healthDetails).containsEntry("geode.cache.regions.MockRegionTwo.statistics.last-accessed-time", 1L);