Skip to content

Commit

Permalink
GEODE-5314: Cleanup and document MBeanStatsMonitor child classes
Browse files Browse the repository at this point in the history
- Fixed minor warnings.
- Added JUnit Tests for all modified classes.
- There's only one thread updating the mutable values so it's been
  decided to keep volatiles instead of moving to atomics.
- Documentation improved to better explain the thread-safety of the
  classes.
  • Loading branch information
jujoramos authored and galen-pivotal committed Sep 21, 2018
1 parent 1998a21 commit be52507
Show file tree
Hide file tree
Showing 10 changed files with 1,445 additions and 477 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -15,72 +15,91 @@
package org.apache.geode.management.internal.beans.stats;

import org.apache.geode.StatisticDescriptor;
import org.apache.geode.distributed.ConfigurationProperties;
import org.apache.geode.internal.statistics.StatisticId;
import org.apache.geode.internal.statistics.StatisticNotFoundException;
import org.apache.geode.internal.statistics.StatisticsNotification;

/**
* This class acts as a monitor and listen for GC statistics updates on behalf of MemberMBean.
* <p>
* There's only one dedicated thread that wakes up at the
* {@link ConfigurationProperties#STATISTIC_SAMPLE_RATE} configured, samples all the statistics,
* writes them to the {@link ConfigurationProperties#STATISTIC_ARCHIVE_FILE} configured (if any) and
* notifies listeners of changes. The mutable fields are declared as {@code volatile} to make sure
* readers of the statistics get the latest recorded value.
* <p>
* This class is conditionally thread-safe, there can be multiple concurrent readers accessing a
* instance, but concurrent writers need to be synchronized externally.
*
* @see org.apache.geode.internal.statistics.HostStatSampler
* @see org.apache.geode.distributed.ConfigurationProperties
* @see org.apache.geode.management.internal.beans.stats.MBeanStatsMonitor
*/
public class GCStatsMonitor extends MBeanStatsMonitor {

private volatile long collections = 0;

private volatile long collectionTime = 0;

long getCollections() {
return collections;
}

long getCollectionTime() {
return collectionTime;
}

public GCStatsMonitor(String name) {
super(name);
}

void decreasePrevValues(DefaultHashMap statsMap) {
collections -= statsMap.get(StatsKey.VM_GC_STATS_COLLECTIONS).longValue();
collectionTime -= statsMap.get(StatsKey.VM_GC_STATS_COLLECTION_TIME).longValue();
}

void increaseStats(String name, Number value) {
if (name.equals(StatsKey.VM_GC_STATS_COLLECTIONS)) {
collections += value.longValue();
return;
}

if (name.equals(StatsKey.VM_GC_STATS_COLLECTION_TIME)) {
collectionTime += value.longValue();
return;
}
}

@Override
public Number getStatistic(String statName) {
if (statName.equals(StatsKey.VM_GC_STATS_COLLECTIONS)) {
return getCollections();
}

if (statName.equals(StatsKey.VM_GC_STATS_COLLECTION_TIME)) {
return getCollectionTime();
}

return 0;
}


@Override
public void handleNotification(StatisticsNotification notification) {
decreasePrevValues(statsMap);

for (StatisticId statId : notification) {
StatisticDescriptor descriptor = statId.getStatisticDescriptor();
String name = descriptor.getName();
Number value;

try {
value = notification.getValue(statId);
} catch (StatisticNotFoundException e) {
value = 0;
}

log(name, value);
increaseStats(name, value);
statsMap.put(name, value);
}
}

private void decreasePrevValues(DefaultHashMap statsMap) {
collections -= statsMap.get(StatsKey.VM_GC_STATS_COLLECTIONS).intValue();
collectionTime -= statsMap.get(StatsKey.VM_GC_STATS_COLLECTION_TIME).intValue();
}

private void increaseStats(String name, Number value) {
if (name.equals(StatsKey.VM_GC_STATS_COLLECTIONS)) {
collections += value.longValue();
return;
}
if (name.equals(StatsKey.VM_GC_STATS_COLLECTION_TIME)) {
collectionTime += value.longValue();
return;
}
}

public long getCollections() {
return collections;
}

public long getCollectionTime() {
return collectionTime;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,71 +19,143 @@

import org.apache.geode.StatisticDescriptor;
import org.apache.geode.Statistics;
import org.apache.geode.distributed.ConfigurationProperties;
import org.apache.geode.internal.statistics.StatisticId;
import org.apache.geode.internal.statistics.StatisticNotFoundException;
import org.apache.geode.internal.statistics.StatisticsListener;
import org.apache.geode.internal.statistics.StatisticsNotification;
import org.apache.geode.internal.statistics.ValueMonitor;

/**
* This class acts as a monitor and listen for Gateway Sender Overflow statistics updates on
* behalf of MemberMBean.
* <p>
* There's only one dedicated thread that wakes up at the
* {@link ConfigurationProperties#STATISTIC_SAMPLE_RATE} configured, samples all the statistics,
* writes them to the {@link ConfigurationProperties#STATISTIC_ARCHIVE_FILE} configured (if any) and
* notifies listeners of changes. The mutable fields are declared as {@code volatile} to make sure
* readers of the statistics get the latest recorded value.
* <p>
* This class is conditionally thread-safe, there can be multiple concurrent readers accessing a
* instance, but concurrent writers need to be synchronized externally.
*
* @see org.apache.geode.internal.statistics.HostStatSampler
* @see org.apache.geode.distributed.ConfigurationProperties
* @see org.apache.geode.management.internal.beans.stats.MBeanStatsMonitor
*/
public class GatewaySenderOverflowMonitor extends MBeanStatsMonitor {

private volatile long lruEvictions = 0;
private volatile long bytesOverflowedToDisk = 0;
private volatile long entriesOverflowedToDisk = 0;
private final Map<Statistics, ValueMonitor> monitors;
private final Map<Statistics, StatisticsListener> listeners;

private volatile long bytesOverflowedToDisk = 0;
public long getLruEvictions() {
return lruEvictions;
}

private volatile long lruEvictions = 0;
public long getBytesOverflowedToDisk() {
return bytesOverflowedToDisk;
}

private Map<Statistics, ValueMonitor> monitors;
public long getEntriesOverflowedToDisk() {
return entriesOverflowedToDisk;
}

private Map<Statistics, StatisticsListener> listeners;
Map<Statistics, ValueMonitor> getMonitors() {
return monitors;
}

Map<Statistics, StatisticsListener> getListeners() {
return listeners;
}

public GatewaySenderOverflowMonitor(String name) {
super(name);
monitors = new HashMap<>();
listeners = new HashMap<>();
}

Number computeDelta(DefaultHashMap statsMap, String name, Number currentValue) {
if (name.equals(StatsKey.GATEWAYSENDER_LRU_EVICTIONS)) {
Number prevValue = statsMap.get(StatsKey.GATEWAYSENDER_LRU_EVICTIONS);
return currentValue.longValue() - prevValue.longValue();
}

if (name.equals(StatsKey.GATEWAYSENDER_ENTRIES_OVERFLOWED_TO_DISK)) {
Number prevValue = statsMap.get(StatsKey.GATEWAYSENDER_ENTRIES_OVERFLOWED_TO_DISK);
return currentValue.longValue() - prevValue.longValue();
}

if (name.equals(StatsKey.GATEWAYSENDER_BYTES_OVERFLOWED_TO_DISK)) {
Number prevValue = statsMap.get(StatsKey.GATEWAYSENDER_BYTES_OVERFLOWED_TO_DISK);
return currentValue.longValue() - prevValue.longValue();
}

return 0;
}

void increaseStats(String name, Number value) {
if (name.equals(StatsKey.GATEWAYSENDER_LRU_EVICTIONS)) {
lruEvictions += value.longValue();
return;
}

if (name.equals(StatsKey.GATEWAYSENDER_ENTRIES_OVERFLOWED_TO_DISK)) {
entriesOverflowedToDisk += value.longValue();
return;
}

if (name.equals(StatsKey.GATEWAYSENDER_BYTES_OVERFLOWED_TO_DISK)) {
bytesOverflowedToDisk += value.longValue();
return;
}
}

@Override
public Number getStatistic(String name) {
if (name.equals(StatsKey.GATEWAYSENDER_LRU_EVICTIONS)) {
return getLruEvictions();
}

if (name.equals(StatsKey.GATEWAYSENDER_ENTRIES_OVERFLOWED_TO_DISK)) {
return getEntriesOverflowedToDisk();
}

if (name.equals(StatsKey.GATEWAYSENDER_BYTES_OVERFLOWED_TO_DISK)) {
return getBytesOverflowedToDisk();
}

return 0;
}

@Override
public void addStatisticsToMonitor(Statistics stats) {
ValueMonitor overflowMonitor = new ValueMonitor();
StatisticsListener listener = new GatewaySenderOverflowStatisticsListener();
overflowMonitor.addListener(listener);
overflowMonitor.addStatistics(stats);

monitors.put(stats, overflowMonitor);
listeners.put(stats, listener);
}

@Override
public void removeStatisticsFromMonitor(Statistics stats) {}

@Override
public void stopListener() {
for (Statistics stat : listeners.keySet()) {
ValueMonitor monitor = monitors.get(stat);
monitor.removeListener(listeners.get(stat));
monitor.removeStatistics(stat);
}

listeners.clear();
monitors.clear();
}

@Override
public Number getStatistic(String name) {
if (name.equals(StatsKey.GATEWAYSENDER_LRU_EVICTIONS)) {
return getLruEvictions();
}
if (name.equals(StatsKey.GATEWAYSENDER_ENTRIES_OVERFLOWED_TO_DISK)) {
return getEntriesOverflowedToDisk();
}
if (name.equals(StatsKey.GATEWAYSENDER_BYTES_OVERFLOWED_TO_DISK)) {
return getBytesOverflowedToDisk();
}
return 0;
}


private class GatewaySenderOverflowStatisticsListener implements StatisticsListener {
public void removeStatisticsFromMonitor(Statistics stats) {}

class GatewaySenderOverflowStatisticsListener implements StatisticsListener {
DefaultHashMap statsMap = new DefaultHashMap();

@Override
Expand All @@ -93,65 +165,19 @@ public void handleNotification(StatisticsNotification notification) {
StatisticDescriptor descriptor = statId.getStatisticDescriptor();
String name = descriptor.getName();
Number value;

try {
value = notification.getValue(statId);
} catch (StatisticNotFoundException e) {
value = 0;
}
log(name, value);

log(name, value);
Number deltaValue = computeDelta(statsMap, name, value);
statsMap.put(name, value);
increaseStats(name, deltaValue);
}
}
}
};

private Number computeDelta(DefaultHashMap statsMap, String name, Number currentValue) {
if (name.equals(StatsKey.GATEWAYSENDER_LRU_EVICTIONS)) {
Number prevValue = statsMap.get(StatsKey.GATEWAYSENDER_LRU_EVICTIONS).longValue();
Number deltaValue = currentValue.longValue() - prevValue.longValue();
return deltaValue;
}
if (name.equals(StatsKey.GATEWAYSENDER_ENTRIES_OVERFLOWED_TO_DISK)) {
Number prevValue =
statsMap.get(StatsKey.GATEWAYSENDER_ENTRIES_OVERFLOWED_TO_DISK).longValue();
Number deltaValue = currentValue.longValue() - prevValue.longValue();
return deltaValue;
}
if (name.equals(StatsKey.GATEWAYSENDER_BYTES_OVERFLOWED_TO_DISK)) {
Number prevValue = statsMap.get(StatsKey.GATEWAYSENDER_BYTES_OVERFLOWED_TO_DISK).longValue();
Number deltaValue = currentValue.longValue() - prevValue.longValue();
return deltaValue;
}
return 0;
}

private void increaseStats(String name, Number value) {
if (name.equals(StatsKey.GATEWAYSENDER_LRU_EVICTIONS)) {
lruEvictions += value.longValue();
return;
}
if (name.equals(StatsKey.GATEWAYSENDER_ENTRIES_OVERFLOWED_TO_DISK)) {
entriesOverflowedToDisk += value.longValue();
return;
}
if (name.equals(StatsKey.GATEWAYSENDER_BYTES_OVERFLOWED_TO_DISK)) {
bytesOverflowedToDisk += value.longValue();
return;
}
}

public long getLruEvictions() {
return lruEvictions;
}

public long getEntriesOverflowedToDisk() {
return entriesOverflowedToDisk;
}

public long getBytesOverflowedToDisk() {
return bytesOverflowedToDisk;
}
}
Loading

0 comments on commit be52507

Please sign in to comment.