This is an automated email from the ASF dual-hosted git repository. nnag pushed a commit to branch support/1.12 in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/support/1.12 by this push: new 4ea7a32 GEODE-9051: Added a feature to measure the Tenured heap consumption (#6176) 4ea7a32 is described below commit 4ea7a32f4bd8e77ac5752c8e4d467390267496f4 Author: geetrawat <gra...@pivotal.io> AuthorDate: Thu Apr 1 18:33:27 2021 -0400 GEODE-9051: Added a feature to measure the Tenured heap consumption (#6176) This feature prints out the tenured heap in the logs after the garbage collection. It works with JDK 1.8 build 212 and above. Co-authored-by: geet <gra...@vmware.com> (cherry picked from commit d79a3c78eab96a9e760db07fa42580e61586b9c5) --- .../internal/cache/control/HeapMemoryMonitor.java | 7 +- .../cache/control/InternalResourceManager.java | 5 +- .../control/TenuredHeapConsumptionMonitor.java | 70 +++++++++++++++ .../cache/control/HeapMemoryMonitorTest.java | 2 +- .../control/TenuredHeapConsumptionMonitorTest.java | 99 ++++++++++++++++++++++ 5 files changed, 179 insertions(+), 4 deletions(-) diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/control/HeapMemoryMonitor.java b/geode-core/src/main/java/org/apache/geode/internal/cache/control/HeapMemoryMonitor.java index 2b3ef17..438facf 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/control/HeapMemoryMonitor.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/control/HeapMemoryMonitor.java @@ -142,6 +142,7 @@ public class HeapMemoryMonitor implements NotificationListener, MemoryMonitor { private final ResourceAdvisor resourceAdvisor; private final InternalCache cache; private final ResourceManagerStats stats; + private final TenuredHeapConsumptionMonitor tenuredHeapConsumptionMonitor; @MutableForTesting private static boolean testDisableMemoryUpdates = false; @@ -153,6 +154,7 @@ public class HeapMemoryMonitor implements NotificationListener, MemoryMonitor { * names. * * Package private for testing. + * checkTenuredHeapConsumption * * @param memoryPoolMXBean The memory pool MXBean to check. * @return True if the pool name matches a known tenured pool name, false otherwise. @@ -177,11 +179,13 @@ public class HeapMemoryMonitor implements NotificationListener, MemoryMonitor { } HeapMemoryMonitor(final InternalResourceManager resourceManager, final InternalCache cache, - final ResourceManagerStats stats) { + final ResourceManagerStats stats, + TenuredHeapConsumptionMonitor tenuredHeapConsumptionMonitor) { this.resourceManager = resourceManager; this.resourceAdvisor = (ResourceAdvisor) cache.getDistributionAdvisor(); this.cache = cache; this.stats = stats; + this.tenuredHeapConsumptionMonitor = tenuredHeapConsumptionMonitor; } /** @@ -669,6 +673,7 @@ public class HeapMemoryMonitor implements NotificationListener, MemoryMonitor { // Not using the information given by the notification in favor // of constructing fresh information ourselves. if (!testDisableMemoryUpdates) { + tenuredHeapConsumptionMonitor.checkTenuredHeapConsumption(notification); updateStateAndSendEvent(); } } diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/control/InternalResourceManager.java b/geode-core/src/main/java/org/apache/geode/internal/cache/control/InternalResourceManager.java index 4d65521..6e345ed 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/control/InternalResourceManager.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/control/InternalResourceManager.java @@ -142,8 +142,9 @@ public class InternalResourceManager implements ResourceManager { 0, this.stats.getResourceEventQueueStatHelper()); // Create the monitors - Map<ResourceType, ResourceMonitor> tempMonitors = new HashMap<ResourceType, ResourceMonitor>(); - tempMonitors.put(ResourceType.HEAP_MEMORY, new HeapMemoryMonitor(this, cache, this.stats)); + Map<ResourceType, ResourceMonitor> tempMonitors = new HashMap<>(); + tempMonitors.put(ResourceType.HEAP_MEMORY, + new HeapMemoryMonitor(this, cache, stats, new TenuredHeapConsumptionMonitor())); tempMonitors.put(ResourceType.OFFHEAP_MEMORY, new OffHeapMemoryMonitor(this, cache, cache.getOffHeapStore(), this.stats)); this.resourceMonitors = Collections.unmodifiableMap(tempMonitors); diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/control/TenuredHeapConsumptionMonitor.java b/geode-core/src/main/java/org/apache/geode/internal/cache/control/TenuredHeapConsumptionMonitor.java new file mode 100644 index 0000000..07e2504 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/control/TenuredHeapConsumptionMonitor.java @@ -0,0 +1,70 @@ +/* + * 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.geode.internal.cache.control; + +import java.lang.management.MemoryNotificationInfo; +import java.lang.management.MemoryUsage; +import java.util.function.BiConsumer; +import java.util.function.Function; + +import javax.management.Notification; +import javax.management.openmbean.CompositeData; + +import org.apache.logging.log4j.Logger; + +import org.apache.geode.annotations.VisibleForTesting; +import org.apache.geode.logging.internal.log4j.api.LogService; + + +class TenuredHeapConsumptionMonitor { + + private static final Logger logger = LogService.getLogger(); + private final BiConsumer<String, Throwable> infoLogger; + private final Function<CompositeData, MemoryNotificationInfo> memoryNotificationInfoFactory; + + TenuredHeapConsumptionMonitor() { + this(logger::info, MemoryNotificationInfo::from); + } + + @VisibleForTesting + TenuredHeapConsumptionMonitor(BiConsumer<String, Throwable> infoLogger, + Function<CompositeData, MemoryNotificationInfo> memoryNotificationInfoFactory) { + this.infoLogger = infoLogger; + this.memoryNotificationInfoFactory = memoryNotificationInfoFactory; + } + + void checkTenuredHeapConsumption(Notification notification) { + try { + String type = notification.getType(); + if (type.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED) || + type.equals(MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED)) { + // retrieve the memory notification information + CompositeData compositeData = (CompositeData) notification.getUserData(); + MemoryNotificationInfo info = memoryNotificationInfoFactory.apply(compositeData); + MemoryUsage usage = info.getUsage(); + long usedBytes = usage.getUsed(); + infoLogger.accept( + "A tenured heap garbage collection has occurred. New tenured heap consumption: " + + + usedBytes, + null); + } + } catch (Exception e) { + infoLogger.accept( + "An Exception occurred while attempting to log tenured heap consumption", e); + } + } +} diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/control/HeapMemoryMonitorTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/control/HeapMemoryMonitorTest.java index 9dd8ab5..aa921ea 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/cache/control/HeapMemoryMonitorTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/cache/control/HeapMemoryMonitorTest.java @@ -68,7 +68,7 @@ public class HeapMemoryMonitorTest { when(internalCache.getMyId()).thenReturn(myself); heapMonitor = new HeapMemoryMonitor(mock(InternalResourceManager.class), internalCache, - mock(ResourceManagerStats.class)); + mock(ResourceManagerStats.class), mock(TenuredHeapConsumptionMonitor.class)); previousMemoryStateChangeTolerance = heapMonitor.getMemoryStateChangeTolerance(); heapMonitor.setMemoryStateChangeTolerance(memoryStateChangeTolerance); memberSet = new HashSet<>(); diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/control/TenuredHeapConsumptionMonitorTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/control/TenuredHeapConsumptionMonitorTest.java new file mode 100644 index 0000000..4c1ed1d --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/cache/control/TenuredHeapConsumptionMonitorTest.java @@ -0,0 +1,99 @@ +/* + * 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.geode.internal.cache.control; + +import static java.lang.management.MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED; +import static java.lang.management.MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.lang.management.MemoryNotificationInfo; +import java.lang.management.MemoryUsage; +import java.util.function.BiConsumer; +import java.util.function.Function; + +import javax.management.Notification; +import javax.management.openmbean.CompositeData; + +import org.junit.Before; +import org.junit.Test; + +public class TenuredHeapConsumptionMonitorTest { + + private BiConsumer<String, Throwable> infoLogger; + private Function<CompositeData, MemoryNotificationInfo> memoryNotificationInfoFactory; + private Notification notification; + private final long used = 50; + private TenuredHeapConsumptionMonitor monitor; + + @Before + public void setUp() { + notification = mock(Notification.class); + MemoryUsage usage = mock(MemoryUsage.class); + MemoryNotificationInfo memoryNotificationInfo = mock(MemoryNotificationInfo.class); + when(memoryNotificationInfo.getUsage()).thenReturn(usage); + when(usage.getUsed()).thenReturn(used); + memoryNotificationInfoFactory = mock(Function.class); + when(memoryNotificationInfoFactory.apply(any())).thenReturn(memoryNotificationInfo); + infoLogger = mock(BiConsumer.class); + monitor = new TenuredHeapConsumptionMonitor(infoLogger, memoryNotificationInfoFactory); + + } + + @Test + public void assertIfTenuredGCLogMessageIsPrintedAfterGCAndWhenMemoryThresholdExceeds() { + when(notification.getType()).thenReturn(MEMORY_THRESHOLD_EXCEEDED); + monitor.checkTenuredHeapConsumption(notification); + verify(infoLogger).accept( + eq("A tenured heap garbage collection has occurred. New tenured heap consumption: " + + used), + isNull()); + } + + @Test + public void assertIfTenuredGCLogMessageIsPrintedAfterGCAndWhenMemoryCollectionThresholdExceeds() { + when(notification.getType()).thenReturn(MEMORY_COLLECTION_THRESHOLD_EXCEEDED); + monitor.checkTenuredHeapConsumption(notification); + verify(infoLogger).accept( + eq("A tenured heap garbage collection has occurred. New tenured heap consumption: " + + used), + isNull()); + + + } + + @Test + public void assertThatNothingIsLoggedWhenNotificationTypeIsNotMemoryThresholdExceededOrMemoryCollectionThresholdExceeded() { + when(notification.getType()).thenReturn("FAKE_TYPE"); + monitor.checkTenuredHeapConsumption(notification); + verify(infoLogger, never()).accept(anyString(), any()); + } + + @Test + public void exceptionMessageIsLoggedWhenExceptionIsThrownInCheckTenuredHeapConsumption() { + IllegalArgumentException ex = new IllegalArgumentException("test message"); + when(memoryNotificationInfoFactory.apply(any())).thenThrow(ex); + when(notification.getType()).thenReturn(MEMORY_COLLECTION_THRESHOLD_EXCEEDED); + monitor.checkTenuredHeapConsumption(notification); + verify(infoLogger) + .accept("An Exception occurred while attempting to log tenured heap consumption", ex); + } +}