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 <[email protected]>
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);
+ }
+
+}