com.gemstone.gemfire.internal.GemFireStatSampler Maven / Gradle / Ivy
/*
* Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
*
* Licensed 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. See accompanying
* LICENSE file.
*/
package com.gemstone.gemfire.internal;
import com.gemstone.gemfire.Statistics;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
import com.gemstone.gemfire.distributed.internal.membership.InternalDistributedMember;
import com.gemstone.gemfire.internal.admin.ListenerIdMap;
import com.gemstone.gemfire.internal.admin.remote.StatListenerMessage;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* GemFireStatSampler adds listeners and rolling archives to HostStatSampler.
*
* The StatisticsManager is implemented by DistributedSystem.
*
* @author Darrel Schneider
* @author Kirk Lund
* @author Swapnil Bawaskar
*/
public final class GemFireStatSampler extends HostStatSampler {
private final ListenerIdMap listeners = new ListenerIdMap();
// TODO: change the listener maps to be copy-on-write
private final Map localListeners =
new ConcurrentHashMap();
private final Map> recipientToListeners =
new HashMap>();
private final InternalDistributedSystem con;
private int nextListenerId = 1;
private ProcessStats processStats = null;
////////////////////// Constructors //////////////////////
public GemFireStatSampler(InternalDistributedSystem con) {
super(con.getCancelCriterion(), con.getLogWriterI18n(), new StatSamplerStats(con, con.getId()));
this.con = con;
}
/**
* Returns the ProcessStats
for this Java VM. Note
* that null
will be returned if operating statistics
* are disabled.
*
* @since 3.5
*/
public final ProcessStats getProcessStats() {
return this.processStats;
}
@Override
public String getProductDescription() {
return "GemFire " + GemFireVersion.getGemFireVersion()
+ " #" + GemFireVersion.getBuildId()
+ " as of " + GemFireVersion.getSourceDate();
}
public int addListener(InternalDistributedMember recipient, long resourceId, String statName) {
int result = getNextListenerId();
synchronized (listeners) {
while (listeners.get(result) != null) {
// previous one was still being used
result = getNextListenerId();
}
RemoteStatListenerImpl sl = RemoteStatListenerImpl.create(result, recipient,
resourceId, statName, this);
listeners.put(result, sl);
List l = recipientToListeners.get(recipient);
if (l == null) {
l = new ArrayList();
recipientToListeners.put(recipient, l);
}
l.add(sl);
}
return result;
}
public boolean removeListener(int listenerId) {
synchronized (listeners) {
RemoteStatListenerImpl sl = (RemoteStatListenerImpl)listeners.remove(listenerId);
if (sl != null) {
List l = recipientToListeners.get(sl.getRecipient());
l.remove(sl);
}
return sl != null;
}
}
public void removeListenersByRecipient(InternalDistributedMember recipient) {
synchronized (listeners) {
List l = recipientToListeners.get(recipient);
if (l != null && l.size() != 0) {
for (RemoteStatListenerImpl sl : l) {
listeners.remove(sl.getListenerId());
}
recipientToListeners.remove(recipient);
}
}
}
public void addLocalStatListener(LocalStatListener l, Statistics stats, String statName) {
LocalStatListenerImpl sl = null;
synchronized (LocalStatListenerImpl.class) {
sl = LocalStatListenerImpl.create(l, stats, statName);
}
this.localListeners.put(sl, Boolean.TRUE);
}
public boolean removeLocalStatListener(LocalStatListener listener) {
Iterator> it =
this.localListeners.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
if (listener.equals(entry.getKey().getListener())) {
it.remove();
return true;
}
}
return false;
}
public Set getLocalListeners() {
return this.localListeners.keySet();
}
@Override
public final File getArchiveFileName() {
return this.con.getConfig().getStatisticArchiveFile();
}
@Override
public final long getArchiveFileSizeLimit() {
if (fileSizeLimitInKB()) {
// use KB instead of MB to speed up rolling for testing
return ((long)this.con.getConfig().getArchiveFileSizeLimit()) * (1024);
} else {
return ((long)this.con.getConfig().getArchiveFileSizeLimit()) * (1024*1024);
}
}
@Override
public final long getArchiveDiskSpaceLimit() {
if (fileSizeLimitInKB()) {
// use KB instead of MB to speed up removal for testing
return ((long)this.con.getConfig().getArchiveDiskSpaceLimit()) * (1024);
} else {
return ((long)this.con.getConfig().getArchiveDiskSpaceLimit()) * (1024*1024);
}
}
@Override
protected void checkListeners() {
checkLocalListeners();
synchronized (listeners) {
if (listeners.size() == 0) {
return;
}
long timeStamp = System.currentTimeMillis();
Iterator>> it1 =
recipientToListeners.entrySet().iterator();
while (it1.hasNext()) {
if (stopRequested()) return;
Map.Entry> me =
it1.next();
List l = me.getValue();
if (l.size() > 0) {
InternalDistributedMember recipient = (InternalDistributedMember)me.getKey();
StatListenerMessage msg =
StatListenerMessage.create(timeStamp, l.size());
msg.setRecipient(recipient);
for (RemoteStatListenerImpl statListener : l) {
if (getStatisticsManager().statisticsExists(statListener.getStatId())) {
statListener.checkForChange(msg);
} else {
// its stale; indicate this with a negative listener id
// fix for bug 29405
msg.addChange(-statListener.getListenerId(), 0);
}
}
this.con.getDistributionManager().putOutgoing(msg);
}
}
}
}
@Override
protected final int getSampleRate() {
return this.con.getConfig().getStatisticSampleRate();
}
@Override
public final boolean isSamplingEnabled() {
return this.con.getConfig().getStatisticSamplingEnabled();
}
@Override
protected final StatisticsManager getStatisticsManager() {
return this.con;
}
@Override
protected final OsStatisticsFactory getOsStatisticsFactory() {
return this.con;
}
@Override
protected final long getSpecialStatsId() {
long statId = OSProcess.getId();
if (statId == 0 || statId == -1) {
statId = getStatisticsManager().getId();
}
return statId;
}
@Override
protected final void initProcessStats(long id) {
if (PureJavaMode.osStatsAreAvailable()) {
if (osStatsDisabled()) {
getLogger().info(LocalizedStrings.GemFireStatSampler_OS_STATISTIC_COLLECTION_DISABLED_BY_OSSTATSDISABLED_SYSTEM_PROPERTY);
} else {
int retVal = HostStatHelper.initOSStats();
if ( retVal != 0 ) {
getLogger().error(LocalizedStrings.GemFireStatSampler_OS_STATISTICS_FAILED_TO_INITIALIZE_PROPERLY_SOME_STATS_MAY_BE_MISSING_SEE_BUGNOTE_37160);
}
HostStatHelper.newSystem(getOsStatisticsFactory());
String statName = getStatisticsManager().getName();
if (statName == null || statName.length() == 0) {
statName = "javaApp" + getStatisticsManager().getId();
}
Statistics stats = HostStatHelper.newProcess(getOsStatisticsFactory(), id, statName + "-proc");
this.processStats = HostStatHelper.newProcessStats(stats);
}
}
}
@Override
protected final void sampleProcessStats(boolean prepareOnly) {
if (prepareOnly || osStatsDisabled() || !PureJavaMode.osStatsAreAvailable()) {
return;
}
List l = getStatisticsManager().getStatsList();
if (l == null) {
return;
}
if (stopRequested()) return;
HostStatHelper.readyRefreshOSStats();
synchronized (l) {
Iterator it = l.iterator();
while (it.hasNext()) {
if (stopRequested()) return;
StatisticsImpl s = (StatisticsImpl)it.next();
if (s.usesSystemCalls()) {
HostStatHelper.refresh((LocalStatisticsImpl)s);
}
}
}
}
@Override
protected final void closeProcessStats() {
if (PureJavaMode.osStatsAreAvailable()) {
if (!osStatsDisabled()) {
if (this.processStats != null) {
this.processStats.close();
}
HostStatHelper.closeOSStats();
}
}
}
private void checkLocalListeners() {
for (LocalStatListenerImpl st : this.localListeners.keySet()) {
if (getStatisticsManager().statisticsExists(st.getStatId())) {
st.checkForChange();
}
}
}
private int getNextListenerId() {
int result = nextListenerId++;
if (nextListenerId < 0) {
nextListenerId = 1;
}
return result;
}
protected static abstract class StatListenerImpl {
protected Statistics stats;
protected StatisticDescriptorImpl stat;
protected boolean oldValueInitialized = false;
protected long oldValue;
public long getStatId() {
if (this.stats.isClosed()) {
return -1;
} else {
return this.stats.getUniqueId();
}
}
protected abstract double getBitsAsDouble(long bits);
}
protected static abstract class LocalStatListenerImpl extends StatListenerImpl {
private LocalStatListener listener;
public LocalStatListener getListener() {
return this.listener;
}
static LocalStatListenerImpl create(LocalStatListener l, Statistics stats, String statName) {
LocalStatListenerImpl result = null;
StatisticDescriptorImpl stat = (StatisticDescriptorImpl)stats.nameToDescriptor(statName);
switch (stat.getTypeCode()) {
case StatisticDescriptorImpl.BYTE:
case StatisticDescriptorImpl.SHORT:
case StatisticDescriptorImpl.INT:
case StatisticDescriptorImpl.LONG:
result = new LocalLongStatListenerImpl();
break;
case StatisticDescriptorImpl.FLOAT:
result = new LocalFloatStatListenerImpl();
break;
case StatisticDescriptorImpl.DOUBLE:
result = new LocalDoubleStatListenerImpl();
break;
default:
throw new RuntimeException("Illegal field type " + stats.getType() + " for statistic");
}
result.stats = stats;
result.stat = stat;
result.listener = l;
return result;
}
/**
* Checks to see if the value of the stat has changed. If it has then
* the local listener is fired
*/
public void checkForChange() {
long currentValue = stats.getRawBits(stat);
if (oldValueInitialized) {
if (currentValue == oldValue) {
return;
}
} else {
oldValueInitialized = true;
}
oldValue = currentValue;
listener.statValueChanged(getBitsAsDouble(currentValue));
}
}
protected static class LocalLongStatListenerImpl extends LocalStatListenerImpl {
@Override
protected double getBitsAsDouble(long bits) {
return bits;
}
}
protected static class LocalFloatStatListenerImpl extends LocalStatListenerImpl {
@Override
protected double getBitsAsDouble(long bits) {
return Float.intBitsToFloat((int)bits);
}
}
protected static class LocalDoubleStatListenerImpl extends LocalStatListenerImpl {
@Override
protected double getBitsAsDouble(long bits) {
return Double.longBitsToDouble(bits);
}
}
/**
* Used to register a StatListener.
*/
protected static abstract class RemoteStatListenerImpl extends StatListenerImpl{
private int listenerId;
private InternalDistributedMember recipient;
@Override
public final int hashCode() {
return listenerId;
}
@Override
public final boolean equals(Object o) {
if (o == null) {
return false;
}
if (o instanceof RemoteStatListenerImpl) {
return listenerId == ((RemoteStatListenerImpl)o).listenerId;
} else {
return false;
}
}
public int getListenerId() {
return this.listenerId;
}
public InternalDistributedMember getRecipient() {
return this.recipient;
}
static RemoteStatListenerImpl create(int listenerId, InternalDistributedMember recipient, long resourceId, String statName, HostStatSampler sampler) {
RemoteStatListenerImpl result = null;
Statistics stats = sampler.getStatisticsManager().findStatistics(resourceId);
StatisticDescriptorImpl stat = (StatisticDescriptorImpl)stats.nameToDescriptor(statName);
switch (stat.getTypeCode()) {
case StatisticDescriptorImpl.BYTE:
case StatisticDescriptorImpl.SHORT:
case StatisticDescriptorImpl.INT:
case StatisticDescriptorImpl.LONG:
result = new LongStatListenerImpl();
break;
case StatisticDescriptorImpl.FLOAT:
result = new FloatStatListenerImpl();
break;
case StatisticDescriptorImpl.DOUBLE:
result = new DoubleStatListenerImpl();
break;
default:
throw new RuntimeException(LocalizedStrings.GemFireStatSampler_ILLEGAL_FIELD_TYPE_0_FOR_STATISTIC.toLocalizedString(stats.getType()));
}
result.stats = stats;
result.stat = stat;
result.listenerId = listenerId;
result.recipient = recipient;
return result;
}
/**
* Checks to see if the value of the stat has changed. If it has then it
* adds that change to the specified message.
*/
public void checkForChange(StatListenerMessage msg) {
long currentValue = stats.getRawBits(stat);
if (oldValueInitialized) {
if (currentValue == oldValue) {
return;
}
} else {
oldValueInitialized = true;
}
oldValue = currentValue;
msg.addChange(listenerId, getBitsAsDouble(currentValue));
}
}
protected static class LongStatListenerImpl extends RemoteStatListenerImpl {
@Override
protected double getBitsAsDouble(long bits) {
return bits;
}
}
protected static class FloatStatListenerImpl extends RemoteStatListenerImpl {
@Override
protected double getBitsAsDouble(long bits) {
return Float.intBitsToFloat((int)bits);
}
}
protected static class DoubleStatListenerImpl extends RemoteStatListenerImpl {
@Override
protected double getBitsAsDouble(long bits) {
return Double.longBitsToDouble(bits);
}
}
}