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

jbarrett pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new 23e554bbe6 GEODE-10249: Adds BufferPoolMXBean stats. (#7607)
23e554bbe6 is described below

commit 23e554bbe633c7fca189c788d34c85778924bafb
Author: Jacob Barrett <jbarr...@pivotal.io>
AuthorDate: Mon Apr 25 12:54:01 2022 -0700

    GEODE-10249: Adds BufferPoolMXBean stats. (#7607)
    
    * Adds new class for BufferPoolMXBean.
    * Adds tests for BufferPoolStats.
    * Cleanup VMStats50.
---
 .../stats50/BufferPoolStatsIntegrationTest.java    |  95 +++++++++++
 .../geode/internal/stats50/BufferPoolStats.java    |  86 ++++++++++
 .../apache/geode/internal/stats50/VMStats50.java   |  68 ++++----
 .../internal/stats50/BufferPoolStatsTest.java      | 174 +++++++++++++++++++++
 4 files changed, 382 insertions(+), 41 deletions(-)

diff --git 
a/geode-core/src/integrationTest/java/org/apache/geode/internal/stats50/BufferPoolStatsIntegrationTest.java
 
b/geode-core/src/integrationTest/java/org/apache/geode/internal/stats50/BufferPoolStatsIntegrationTest.java
new file mode 100644
index 0000000000..9383d938be
--- /dev/null
+++ 
b/geode-core/src/integrationTest/java/org/apache/geode/internal/stats50/BufferPoolStatsIntegrationTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.stats50;
+
+import static java.lang.management.ManagementFactory.getPlatformMXBeans;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.contains;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.management.BufferPoolMXBean;
+import java.nio.ByteBuffer;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+
+import org.apache.geode.Statistics;
+import org.apache.geode.StatisticsFactory;
+import org.apache.geode.StatisticsType;
+import org.apache.geode.StatisticsTypeFactory;
+
+class BufferPoolStatsIntegrationTest {
+
+  @Test
+  void refreshAfterDirectBufferAllocationChangesStatistics() {
+    assumeThat(getPlatformMXBeans(BufferPoolMXBean.class))
+        .anySatisfy(p -> assertThat(p.getName()).contains("direct"));
+
+    final StatisticsTypeFactory statisticsTypeFactory = 
mock(StatisticsTypeFactory.class);
+    final StatisticsType statisticsType = mock(StatisticsType.class);
+    when(statisticsTypeFactory.createType(anyString(), anyString(), any()))
+        .thenReturn(statisticsType);
+    when(statisticsType.nameToId(eq("count"))).thenReturn(0);
+    when(statisticsType.nameToId(eq("totalCapacity"))).thenReturn(1);
+    when(statisticsType.nameToId(eq("memoryUsed"))).thenReturn(2);
+    final StatisticsFactory statisticsFactory = mock(StatisticsFactory.class);
+    final Statistics statistics = mock(Statistics.class);
+    when(statisticsFactory.createStatistics(any(), contains("direct"), 
anyLong()))
+        .thenReturn(statistics);
+
+    final BufferPoolStats bufferPoolStats = new 
BufferPoolStats(statisticsTypeFactory);
+    bufferPoolStats.init(statisticsFactory, 42);
+
+    bufferPoolStats.refresh();
+
+    final ArgumentCaptor<Long> count = ArgumentCaptor.forClass(Long.class);
+    verify(statistics).setLong(eq(0), count.capture());
+    final ArgumentCaptor<Long> totalCapacity = 
ArgumentCaptor.forClass(Long.class);
+    verify(statistics).setLong(eq(1), totalCapacity.capture());
+    final ArgumentCaptor<Long> memoryUsed = 
ArgumentCaptor.forClass(Long.class);
+    verify(statistics).setLong(eq(2), memoryUsed.capture());
+
+    clearInvocations(statistics);
+
+    final ByteBuffer directBuffer = ByteBuffer.allocateDirect(1000);
+
+    bufferPoolStats.refresh();
+
+    final ArgumentCaptor<Long> countAfterAllocate = 
ArgumentCaptor.forClass(Long.class);
+    verify(statistics).setLong(eq(0), countAfterAllocate.capture());
+    final ArgumentCaptor<Long> totalCapacityAfterAllocate = 
ArgumentCaptor.forClass(Long.class);
+    verify(statistics).setLong(eq(1), totalCapacityAfterAllocate.capture());
+    final ArgumentCaptor<Long> memoryUsedAfterAllocate = 
ArgumentCaptor.forClass(Long.class);
+    verify(statistics).setLong(eq(2), memoryUsedAfterAllocate.capture());
+
+    assertThat(countAfterAllocate.getValue()).isGreaterThan(count.getValue());
+    
assertThat(totalCapacityAfterAllocate.getValue()).isGreaterThan(totalCapacity.getValue());
+    
assertThat(memoryUsedAfterAllocate.getValue()).isGreaterThan(memoryUsed.getValue());
+
+    // Used only to prevent GC of directBuffer during test
+    assertThat(directBuffer).isNotNull();
+  }
+
+
+}
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/stats50/BufferPoolStats.java
 
b/geode-core/src/main/java/org/apache/geode/internal/stats50/BufferPoolStats.java
new file mode 100644
index 0000000000..1de05fb293
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/stats50/BufferPoolStats.java
@@ -0,0 +1,86 @@
+/*
+ * 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.stats50;
+
+import static java.lang.management.ManagementFactory.getPlatformMXBeans;
+
+import java.lang.management.BufferPoolMXBean;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jetbrains.annotations.NotNull;
+
+import org.apache.geode.StatisticDescriptor;
+import org.apache.geode.Statistics;
+import org.apache.geode.StatisticsFactory;
+import org.apache.geode.StatisticsType;
+import org.apache.geode.StatisticsTypeFactory;
+
+/**
+ * Polls Java platform buffer pool statistics from {@link BufferPoolMXBean}.
+ */
+public class BufferPoolStats {
+
+  private final StatisticsType bufferPoolType;
+  private final int bufferPoolCountId;
+  private final int bufferPoolTotalCapacityId;
+  private final int bufferPoolMemoryUsedId;
+
+  private final Map<BufferPoolMXBean, Statistics> bufferPoolStatistics =
+      new IdentityHashMap<>();
+
+  BufferPoolStats(final @NotNull StatisticsTypeFactory typeFactory) {
+    bufferPoolType =
+        typeFactory.createType("PlatformBufferPoolStats", "Java platform 
buffer pools.",
+            new StatisticDescriptor[] {
+                typeFactory.createLongGauge("count",
+                    "An estimate of the number of buffers in this pool.", 
"buffers"),
+                typeFactory.createLongGauge("totalCapacity",
+                    "An estimate of the total capacity of the buffers in this 
pool in bytes.",
+                    "bytes"),
+                typeFactory.createLongGauge("memoryUsed",
+                    "An estimate of the memory that the Java virtual machine 
is using for this buffer pool in bytes, or -1L if an estimate of the memory 
usage is not available.",
+                    "bytes")});
+    bufferPoolCountId = bufferPoolType.nameToId("count");
+    bufferPoolTotalCapacityId = bufferPoolType.nameToId("totalCapacity");
+    bufferPoolMemoryUsedId = bufferPoolType.nameToId("memoryUsed");
+  }
+
+  void init(final @NotNull StatisticsFactory statisticsFactory, final long id) 
{
+    init(statisticsFactory, id, getPlatformMXBeans(BufferPoolMXBean.class));
+  }
+
+  void init(final StatisticsFactory statisticsFactory, final long id,
+      final List<BufferPoolMXBean> platformMXBeans) {
+    platformMXBeans.forEach(
+        pool -> bufferPoolStatistics.computeIfAbsent(pool,
+            k -> statisticsFactory.createStatistics(bufferPoolType, 
k.getName() + " buffer pool",
+                id)));
+  }
+
+  void refresh() {
+    bufferPoolStatistics.forEach((bufferPool, statistics) -> {
+      statistics.setLong(bufferPoolCountId, bufferPool.getCount());
+      statistics.setLong(bufferPoolTotalCapacityId, 
bufferPool.getTotalCapacity());
+      statistics.setLong(bufferPoolMemoryUsedId, bufferPool.getMemoryUsed());
+    });
+  }
+
+  public void close() {
+    bufferPoolStatistics.values().forEach(Statistics::close);
+  }
+}
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/stats50/VMStats50.java 
b/geode-core/src/main/java/org/apache/geode/internal/stats50/VMStats50.java
index a2d25dadeb..10e7c36509 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/stats50/VMStats50.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/stats50/VMStats50.java
@@ -113,10 +113,7 @@ public class VMStats50 implements VMStatsContract {
   private static final int mp_l_maxMemoryId;
   private static final int mp_l_usedMemoryId;
   private static final int mp_l_committedMemoryId;
-  // private static final int mp_gc_initMemoryId;
-  // private static final int mp_gc_maxMemoryId;
   private static final int mp_gc_usedMemoryId;
-  // private static final int mp_gc_committedMemoryId;
   private static final int mp_usageThresholdId;
   private static final int mp_collectionUsageThresholdId;
   private static final int mp_usageExceededId;
@@ -128,7 +125,6 @@ public class VMStats50 implements VMStatsContract {
   private static final int unix_fdLimitId;
   private static final int unix_fdsOpenId;
   private static final int processCpuTimeId;
-
   private long threadStartCount = 0;
   private long[] allThreadIds = null;
   private static final boolean THREAD_STATS_ENABLED =
@@ -147,6 +143,9 @@ public class VMStats50 implements VMStatsContract {
   private static final int thread_cpuTimeId;
   private static final int thread_userTimeId;
 
+  @Immutable
+  private static final BufferPoolStats bufferPoolStats;
+
   static {
     clBean = ManagementFactory.getClassLoadingMXBean();
     memBean = ManagementFactory.getMemoryMXBean();
@@ -157,20 +156,17 @@ public class VMStats50 implements VMStatsContract {
       Method m3 = null;
       Object bean = null;
       try {
-        Class c =
+        Class<?> c =
             
ClassPathLoader.getLatest().forName("com.sun.management.UnixOperatingSystemMXBean");
         if (c.isInstance(osBean)) {
           m1 = c.getMethod("getMaxFileDescriptorCount");
           m2 = c.getMethod("getOpenFileDescriptorCount");
           bean = osBean;
-        } else {
-          // leave them null
         }
+
         // Always set ProcessCpuTime
         m3 = osBean.getClass().getMethod("getProcessCpuTime");
-        if (m3 != null) {
-          m3.setAccessible(true);
-        }
+        m3.setAccessible(true);
       } catch (VirtualMachineError err) {
         SystemFailure.initiateFailure(err);
         // If this ever returns, rethrow the error. We're poisoned
@@ -215,17 +211,17 @@ public class VMStats50 implements VMStatsContract {
     }
     StatisticsTypeFactory f = StatisticsTypeFactoryImpl.singleton();
     List<StatisticDescriptor> sds = new ArrayList<>();
-    sds.add(f.createIntGauge("pendingFinalization",
+    sds.add(f.createLongGauge("pendingFinalization",
         "Number of objects that are pending finalization in the java VM.", 
"objects"));
-    sds.add(f.createIntGauge("daemonThreads", "Current number of live daemon 
threads in this VM.",
+    sds.add(f.createLongGauge("daemonThreads", "Current number of live daemon 
threads in this VM.",
         "threads"));
-    sds.add(f.createIntGauge("threads",
+    sds.add(f.createLongGauge("threads",
         "Current number of live threads (both daemon and non-daemon) in this 
VM.", "threads"));
     sds.add(
-        f.createIntGauge("peakThreads", "High water mark of live threads in 
this VM.", "threads"));
+        f.createLongGauge("peakThreads", "High water mark of live threads in 
this VM.", "threads"));
     sds.add(f.createLongCounter("threadStarts",
         "Total number of times a thread has been started since this vm 
started.", "threads"));
-    sds.add(f.createIntGauge("cpus", "Number of cpus available to the java VM 
on its machine.",
+    sds.add(f.createLongGauge("cpus", "Number of cpus available to the java VM 
on its machine.",
         "cpus", true));
     sds.add(f.createLongCounter("loadedClasses", "Total number of classes 
loaded since vm started.",
         "classes"));
@@ -350,8 +346,8 @@ public class VMStats50 implements VMStatsContract {
                   "milliseconds"),
               f.createLongGauge("lockOwner",
                   "The thread id that owns the lock that this thread is 
blocking on.", "threadId"),
-              f.createIntGauge("inNative", "1 if the thread is in native 
code.", "boolean"),
-              f.createIntGauge("suspended", "1 if this thread is suspended", 
"boolean"),
+              f.createLongGauge("inNative", "1 if the thread is in native 
code.", "boolean"),
+              f.createLongGauge("suspended", "1 if this thread is suspended", 
"boolean"),
               f.createLongCounter("waited",
                   "Total number of times this thread waited for 
notification.", "operations"),
               f.createLongCounter("waitedTime",
@@ -384,6 +380,8 @@ public class VMStats50 implements VMStatsContract {
       thread_cpuTimeId = -1;
       thread_userTimeId = -1;
     }
+
+    bufferPoolStats = new BufferPoolStats(f);
   }
 
   private final Statistics vmStats;
@@ -399,7 +397,8 @@ public class VMStats50 implements VMStatsContract {
     vmStats = f.createStatistics(vmType, "vmStats", id);
     heapMemStats = f.createStatistics(memoryUsageType, "vmHeapMemoryStats", 
id);
     nonHeapMemStats = f.createStatistics(memoryUsageType, 
"vmNonHeapMemoryStats", id);
-    initMemoryPools(); // Fix for #40424
+    initMemoryPools();
+    bufferPoolStats.init(f, id);
     initGC();
   }
 
@@ -443,8 +442,8 @@ public class VMStats50 implements VMStatsContract {
       s.setLong(thread_blockedId, ti.getBlockedCount());
       s.setLong(thread_lockOwnerId, ti.getLockOwnerId());
       s.setLong(thread_waitedId, ti.getWaitedCount());
-      s.setInt(thread_inNativeId, ti.isInNative() ? 1 : 0);
-      s.setInt(thread_suspendedId, ti.isSuspended() ? 1 : 0);
+      s.setLong(thread_inNativeId, ti.isInNative() ? 1 : 0);
+      s.setLong(thread_suspendedId, ti.isSuspended() ? 1 : 0);
       if (threadBean.isThreadContentionMonitoringSupported()
           && threadBean.isThreadContentionMonitoringEnabled()) {
         s.setLong(thread_blockedTimeId, ti.getBlockedTime());
@@ -499,7 +498,7 @@ public class VMStats50 implements VMStatsContract {
         it.remove();
         reInitPools = true;
       } else {
-        MemoryUsage mu = null;
+        MemoryUsage mu;
         try {
           mu = mp.getUsage();
         } catch (IllegalArgumentException ex) {
@@ -584,11 +583,11 @@ public class VMStats50 implements VMStatsContract {
   @Override
   public void refresh() {
     Runtime rt = Runtime.getRuntime();
-    vmStats.setInt(pendingFinalizationCountId, 
memBean.getObjectPendingFinalizationCount());
-    vmStats.setInt(cpusId, osBean.getAvailableProcessors());
-    vmStats.setInt(threadsId, threadBean.getThreadCount());
-    vmStats.setInt(daemonThreadsId, threadBean.getDaemonThreadCount());
-    vmStats.setInt(peakThreadsId, threadBean.getPeakThreadCount());
+    vmStats.setLong(pendingFinalizationCountId, 
memBean.getObjectPendingFinalizationCount());
+    vmStats.setLong(cpusId, osBean.getAvailableProcessors());
+    vmStats.setLong(threadsId, threadBean.getThreadCount());
+    vmStats.setLong(daemonThreadsId, threadBean.getDaemonThreadCount());
+    vmStats.setLong(peakThreadsId, threadBean.getPeakThreadCount());
     vmStats.setLong(threadStartsId, threadBean.getTotalStartedThreadCount());
     vmStats.setLong(loadedClassesId, clBean.getTotalLoadedClassCount());
     vmStats.setLong(unloadedClassesId, clBean.getUnloadedClassCount());
@@ -641,6 +640,7 @@ public class VMStats50 implements VMStatsContract {
     refresh(nonHeapMemStats, getNonHeapMemoryUsage(memBean));
     refreshGC();
     refreshMemoryPools();
+    bufferPoolStats.refresh();
     refreshThreads();
   }
 
@@ -693,6 +693,7 @@ public class VMStats50 implements VMStatsContract {
     vmStats.close();
     closeStatsMap(mpMap);
     closeStatsMap(gcMap);
+    bufferPoolStats.close();
   }
 
   private void closeStatsMap(Map<?, Statistics> map) {
@@ -723,23 +724,8 @@ public class VMStats50 implements VMStatsContract {
     return heapMemStats;
   }
 
-  public Statistics getVMNonHeapStats() {
-    return nonHeapMemStats;
-  }
-
   public static StatisticsType getGCType() {
     return gcType;
   }
 
-  public static StatisticsType getMemoryPoolType() {
-    return mpType;
-  }
-
-  public static StatisticsType getThreadType() {
-    return threadType;
-  }
-
-  public static StatisticsType getMemoryUsageType() {
-    return memoryUsageType;
-  }
 }
diff --git 
a/geode-core/src/test/java/org/apache/geode/internal/stats50/BufferPoolStatsTest.java
 
b/geode-core/src/test/java/org/apache/geode/internal/stats50/BufferPoolStatsTest.java
new file mode 100644
index 0000000000..9f8fd45d91
--- /dev/null
+++ 
b/geode-core/src/test/java/org/apache/geode/internal/stats50/BufferPoolStatsTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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.stats50;
+
+import static java.util.Arrays.asList;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.contains;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import java.lang.management.BufferPoolMXBean;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import org.apache.geode.Statistics;
+import org.apache.geode.StatisticsFactory;
+import org.apache.geode.StatisticsType;
+import org.apache.geode.StatisticsTypeFactory;
+
+class BufferPoolStatsTest {
+
+  @Test
+  void constructorCreatesStatisticsType() {
+    final StatisticsTypeFactory statisticsTypeFactory = 
mock(StatisticsTypeFactory.class);
+    when(statisticsTypeFactory.createType(anyString(), anyString(), any()))
+        .thenReturn(mock(StatisticsType.class));
+
+    new BufferPoolStats(statisticsTypeFactory);
+
+    verify(statisticsTypeFactory).createType(eq("PlatformBufferPoolStats"), 
anyString(), any());
+    verify(statisticsTypeFactory).createLongGauge(eq("count"), anyString(), 
eq("buffers"));
+    verify(statisticsTypeFactory).createLongGauge(eq("totalCapacity"), 
anyString(), eq("bytes"));
+    verify(statisticsTypeFactory).createLongGauge(eq("memoryUsed"), 
anyString(), eq("bytes"));
+    verifyNoMoreInteractions(statisticsTypeFactory);
+  }
+
+  @Test
+  void initCreatesStatistics() {
+    final StatisticsTypeFactory statisticsTypeFactory = 
mock(StatisticsTypeFactory.class);
+    final StatisticsType statisticsType = mock(StatisticsType.class);
+    when(statisticsTypeFactory.createType(anyString(), anyString(), any()))
+        .thenReturn(statisticsType);
+    final StatisticsFactory statisticsFactory = mock(StatisticsFactory.class);
+    when(statisticsFactory.createStatistics(any(), anyString(), anyLong()))
+        .thenReturn(mock(Statistics.class), mock(Statistics.class));
+    final BufferPoolMXBean bufferPoolMXBean1 = mock(BufferPoolMXBean.class);
+    when(bufferPoolMXBean1.getName()).thenReturn("mocked1");
+    final BufferPoolMXBean bufferPoolMXBean2 = mock(BufferPoolMXBean.class);
+    when(bufferPoolMXBean2.getName()).thenReturn("mocked2");
+    final List<BufferPoolMXBean> platformMXBeans = asList(bufferPoolMXBean1, 
bufferPoolMXBean2);
+
+    final BufferPoolStats bufferPoolStats = new 
BufferPoolStats(statisticsTypeFactory);
+    bufferPoolStats.init(statisticsFactory, 42, platformMXBeans);
+
+    verify(bufferPoolMXBean1).getName();
+    verify(bufferPoolMXBean2).getName();
+    verify(statisticsFactory).createStatistics(same(statisticsType), 
contains("mocked1"), eq(42L));
+    verify(statisticsFactory).createStatistics(same(statisticsType), 
contains("mocked2"), eq(42L));
+    verifyNoMoreInteractions(bufferPoolMXBean1, bufferPoolMXBean2, 
statisticsFactory);
+  }
+
+  @Test
+  void initCreatesStatisticsOnceIfCalledTwice() {
+    final StatisticsTypeFactory statisticsTypeFactory = 
mock(StatisticsTypeFactory.class);
+    final StatisticsType statisticsType = mock(StatisticsType.class);
+    when(statisticsTypeFactory.createType(anyString(), anyString(), any()))
+        .thenReturn(statisticsType);
+    final StatisticsFactory statisticsFactory = mock(StatisticsFactory.class);
+    when(statisticsFactory.createStatistics(any(), anyString(), anyLong()))
+        .thenReturn(mock(Statistics.class), mock(Statistics.class));
+    final BufferPoolMXBean bufferPoolMXBean1 = mock(BufferPoolMXBean.class);
+    when(bufferPoolMXBean1.getName()).thenReturn("mocked1");
+    final BufferPoolMXBean bufferPoolMXBean2 = mock(BufferPoolMXBean.class);
+    when(bufferPoolMXBean2.getName()).thenReturn("mocked2");
+    final List<BufferPoolMXBean> platformMXBeans = asList(bufferPoolMXBean1, 
bufferPoolMXBean2);
+
+    final BufferPoolStats bufferPoolStats = new 
BufferPoolStats(statisticsTypeFactory);
+    bufferPoolStats.init(statisticsFactory, 42, platformMXBeans);
+    bufferPoolStats.init(statisticsFactory, 42, platformMXBeans);
+
+    verify(bufferPoolMXBean1).getName();
+    verify(bufferPoolMXBean2).getName();
+    verify(statisticsFactory).createStatistics(same(statisticsType), 
contains("mocked1"), eq(42L));
+    verify(statisticsFactory).createStatistics(same(statisticsType), 
contains("mocked2"), eq(42L));
+    verifyNoMoreInteractions(bufferPoolMXBean1, bufferPoolMXBean2, 
statisticsFactory);
+  }
+
+  @Test
+  void refreshUpdatesStatistics() {
+    final StatisticsTypeFactory statisticsTypeFactory = 
mock(StatisticsTypeFactory.class);
+    when(statisticsTypeFactory.createType(anyString(), anyString(), any()))
+        .thenReturn(mock(StatisticsType.class));
+    final StatisticsFactory statisticsFactory = mock(StatisticsFactory.class);
+    final Statistics statistics1 = mock(Statistics.class);
+    final Statistics statistics2 = mock(Statistics.class);
+    when(statisticsFactory.createStatistics(any(), anyString(), anyLong()))
+        .thenReturn(statistics1, statistics2);
+    final BufferPoolMXBean bufferPoolMXBean1 = mock(BufferPoolMXBean.class);
+    when(bufferPoolMXBean1.getName()).thenReturn("mocked1");
+    when(bufferPoolMXBean1.getCount()).thenReturn(1200L);
+    when(bufferPoolMXBean1.getTotalCapacity()).thenReturn(2400L);
+    when(bufferPoolMXBean1.getMemoryUsed()).thenReturn(9600L);
+    final BufferPoolMXBean bufferPoolMXBean2 = mock(BufferPoolMXBean.class);
+    when(bufferPoolMXBean2.getName()).thenReturn("mocked2");
+    when(bufferPoolMXBean2.getCount()).thenReturn(1L);
+    when(bufferPoolMXBean2.getTotalCapacity()).thenReturn(2L);
+    when(bufferPoolMXBean2.getMemoryUsed()).thenReturn(3L);
+    final List<BufferPoolMXBean> platformMXBeans = asList(bufferPoolMXBean1, 
bufferPoolMXBean2);
+
+    final BufferPoolStats bufferPoolStats = new 
BufferPoolStats(statisticsTypeFactory);
+    bufferPoolStats.init(statisticsFactory, 42, platformMXBeans);
+    bufferPoolStats.refresh();
+
+    verify(bufferPoolMXBean1).getName();
+    verify(bufferPoolMXBean2).getName();
+    verify(bufferPoolMXBean1).getCount();
+    verify(bufferPoolMXBean1).getTotalCapacity();
+    verify(bufferPoolMXBean1).getMemoryUsed();
+    verify(bufferPoolMXBean2).getCount();
+    verify(bufferPoolMXBean2).getTotalCapacity();
+    verify(bufferPoolMXBean2).getMemoryUsed();
+    verify(statistics1).setLong(anyInt(), eq(1200L));
+    verify(statistics1).setLong(anyInt(), eq(2400L));
+    verify(statistics1).setLong(anyInt(), eq(9600L));
+    verify(statistics2).setLong(anyInt(), eq(1L));
+    verify(statistics2).setLong(anyInt(), eq(2L));
+    verify(statistics2).setLong(anyInt(), eq(3L));
+    verifyNoMoreInteractions(bufferPoolMXBean1, bufferPoolMXBean2, 
statistics1, statistics2);
+  }
+
+  @Test
+  void closeClosesAllStatistics() {
+    final StatisticsTypeFactory statisticsTypeFactory = 
mock(StatisticsTypeFactory.class);
+    when(statisticsTypeFactory.createType(anyString(), anyString(), any()))
+        .thenReturn(mock(StatisticsType.class));
+    final StatisticsFactory statisticsFactory = mock(StatisticsFactory.class);
+    final Statistics statistics1 = mock(Statistics.class);
+    final Statistics statistics2 = mock(Statistics.class);
+    when(statisticsFactory.createStatistics(any(), anyString(), anyLong()))
+        .thenReturn(statistics1, statistics2);
+    final List<BufferPoolMXBean> platformMXBeans =
+        asList(mock(BufferPoolMXBean.class), mock(BufferPoolMXBean.class));
+
+    final BufferPoolStats bufferPoolStats = new 
BufferPoolStats(statisticsTypeFactory);
+    bufferPoolStats.init(statisticsFactory, 42, platformMXBeans);
+    bufferPoolStats.close();
+
+    verify(statistics1).close();
+    verify(statistics2).close();
+    verifyNoMoreInteractions(statistics1, statistics2);
+  }
+
+}

Reply via email to