
com.jamonapi.FactoryEnabled Maven / Gradle / Ivy
package com.jamonapi;
import com.jamonapi.utils.DetailData;
import com.jamonapi.utils.Misc;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
/** Factory that creates Monitors. Main workhorse for creating monitors. This can be created directly. {@code MonitorFactory} is simply
* a wrapper that makes calling this class simpler. {@code MonitorFactory} contains a static reference to
* a {@code FactoryEnabled} class.
*
* @author steve souza
*
*/
public class FactoryEnabled implements MonitorFactoryInterface {
/** Creates a new instance of MonFactoryEnabled. Also initializes the standard
* JAMon time monitor range (ms.)
*/
public FactoryEnabled() {
initialize();
}
// note the default capacity for a HashMap is 16 elements with a load factor of
// .75. This means that after 12 elements have been loaded the HashMap doubles,
// and doubles again at 24 etc. By setting the HashMap to a higher value it need not
// grow as often. You can also have jamon use a different map type via the setMap method.
private Map map;
private Counter allActive;
private Counter primaryActive;
private boolean activityTracking=false;
private RangeFactory rangeFactory;// Builds Range objects
private GetMonitor getMonitor;
private int maxMonitors;
private AtomicLong totalKeySize;
private int maxSqlSize;
private static final boolean PRIMARY=true;
private static final boolean NOT_PRIMARY=false;
private static final boolean TIME_MONITOR=true;
private static final boolean NOT_TIME_MONITOR=false;
private static final int DEFAULT_MAP_SIZE=500;
private static final NullMonitor NULL_MON=new NullMonitor();// used when disabled
private synchronized void initialize() {
allActive=new Counter();
primaryActive=new Counter();
rangeFactory=new RangeFactory();// Builds Range objects
activityTracking=false;
setRangeDefault("ms.", RangeHolder.getMSHolder());
setRangeDefault("percent", RangeHolder.getPercentHolder());
setMap(Misc.createConcurrentMap(DEFAULT_MAP_SIZE));
if (isTotalKeySizeTrackingEnabled()) {
enableTotalKeySizeTracking();
}
}
public Monitor add(MonKey key, double value) {
return getMonitor(key).add(value);
}
public Monitor add(String label, String units, double value) {
return getMonitor(new MonKeyImp(label, units)).add(value);
}
public Monitor start(MonKey key) {
return getTimeMonitor(key, NOT_PRIMARY).start();
}
public Monitor start(String label) {
return getTimeMonitor(new MonKeyImp(label, "ms."), NOT_PRIMARY).start();
}
public Monitor startNano(String label) {
return getNanoMonitor(new MonKeyImp(label, "ns.")).start();
}
public Monitor startNano(MonKey key) {
return getNanoMonitor(key).start();
}
public Monitor startPrimary(MonKey key) {
return getTimeMonitor(key, PRIMARY).start();
}
public Monitor startPrimary(String label) {
return getTimeMonitor(new MonKeyImp(label, "ms."), PRIMARY).start();
}
public Monitor start() {
return new TimeMon2().start();
}
public Monitor getMonitor() {
return new MonitorImp(new MonKeyImp("defaultMon","defaultMon"), null, new ActivityStats(), false);
}
/** allows for using a faster/open source map. */
public void setMap(Map map) {
// assign this map first. As there could be synchronization problems if the map is first assigned
// and the ConcurrentHashMap's GetMonitor is used for a standard map. If the object is a ConcurrentHashMap
// then the GetMonitor will be reassigned below. GetMonitorMap works with any kind of map whereas
// GetMonitor only works with a ConcurrentHashMap
getMonitor=new GetMonitorMap();
this.map=map;
// If a ConcurrentHashMap is used the GetMonitor class has better concurrency as it does not need to be
// synchronized.
if (map instanceof ConcurrentHashMap)
getMonitor=new GetMonitor();
}
public Monitor getMonitor(MonKey key) {
return getMonitor(key, NOT_PRIMARY, NOT_TIME_MONITOR);
}
public Monitor getMonitor(String label, String units) {
return getMonitor(new MonKeyImp(label, units));
}
public Monitor getTimeMonitor(MonKey key) {
return getTimeMonitor(key, NOT_PRIMARY);
}
public Monitor getTimeMonitor(String label) {
return getTimeMonitor(new MonKeyImp(label, "ms."), NOT_PRIMARY);
}
// Range methods
// logical should be < or <= to determine how to use range values.
// if it is neither it defaults to <=
/** Note if a null is passed in it will have the same effect as an empty
* RangeHolder (i.e. it will perform null operations)
*/
public void setRangeDefault(String key, RangeHolder rangeHolder) {
RangeImp range=null;
if (rangeHolder!=null && rangeHolder.getSize()>0)
range=new RangeBase(rangeHolder);
rangeFactory.setRangeDefault(key, range );
}
public String[] getRangeHeader() {
return rangeFactory.getHeader();
}
public Object[][] getRangeNames() {
return rangeFactory.getData();
}
public void remove(MonKey key) {
map.remove(key);
if (totalKeySize!=null) {
decrementKeySize(key.getSize());
}
}
public void remove(String label, String units) {
remove(new MonKeyImp(label, units));
}
public boolean exists(MonKey key) {
return map.containsKey(key);
}
public boolean exists(String label, String units) {
return map.containsKey(new MonKeyImp(label, units));
}
public int getNumRows() {
return map.size();
}
// MonitorComposite methods
/** getComposite("AllMonitors") is the same as getRootMonitor() */
public MonitorComposite getRootMonitor() {
return new MonitorComposite(getMonitors());
}
/** Pass in the units (or range type) and return all monitors of that
* type. 'AllMonitors' is a special argument returns a composite of surprise surprise all monitors
*getComposite("AllMonitors") is the same as getRootMonitor() ;
**/
public MonitorComposite getComposite(String units) {
return new MonitorComposite(getMonitors(units));
}
public String getVersion() {
return VERSION;
}
/** Returns the total of all keys in the monitor map. If there are no entries or if tracking
* is disabled then 0 is returned
*/
public long getTotalKeySize() {
return isTotalKeySizeTrackingEnabled() ? totalKeySize.get() : 0;
}
// INTERNALS/PRIVATES FOLLOW
private MonitorImp getTimeMonitor(MonKey key, boolean isPrimary) {
return getMonitor(key, isPrimary, TIME_MONITOR);
}
/***This was changed 11/24/06 to fix syncronization problems reported as bug */
private MonitorImp getMonitor(MonKey key, boolean isPrimary, boolean isTimeMonitor) {
MonitorImp mon=getMonitor.getMon(key, isPrimary, isTimeMonitor);
if (mon.isEnabled()) {
mon = (isTimeMonitor) ? new TimeMon(key, mon.getMonInternals()) : new DecoMon(key, mon.getMonInternals());
}
return mon;
}
private MonitorImp getNanoMonitor(MonKey key) {
boolean isPrimary=false;
boolean isTimeMon=true;
MonitorImp mon=getMonitor.getMon(key, isPrimary, isTimeMon);
if (mon.isEnabled()) {
mon = new TimeMonNano(key, mon.getMonInternals());
}
return mon;
}
private MonitorImp createMon(MonKey key, boolean isPrimary, boolean isTimeMonitor) {
ActivityStats activityStats=new ActivityStats(new Counter(), primaryActive, allActive);
// get default range for this type and assign it to the monitor
RangeImp range=rangeFactory.getRangeDefault(key.getRangeKey(), activityStats);
MonitorImp mon=new MonitorImp(key, range, activityStats, isTimeMonitor);
// activity tracking is off by default.
if (isTotalKeySizeTrackingEnabled()) {
incrementKeySize(key.getSize());
}
if (activityTracking) {
mon.setActivityTracking(activityTracking);
}
mon.setPrimary(isPrimary);
return mon;
}
private void incrementKeySize(int keySize) {
totalKeySize.addAndGet(keySize);
}
private void decrementKeySize(int keySize) {
totalKeySize.addAndGet(-keySize);
}
private MonitorImp[] getMonitors(String units) {
MonitorImp[] monitors=getMonitors();
if (monitors==null || units==null)
return null;
else if ("AllMonitors".equalsIgnoreCase(units))
return monitors;
List rows=new ArrayList(500);
int size=monitors.length;
for (int i=0;i0 && map.size()>=maxMonitors);
}
// class used to get data from a ConcurrentHashMap need not be synchronized
private class GetMonitor {
protected MonitorImp getMon(MonKey key, boolean isPrimary, boolean isTimeMonitor) {
// note using MonKey over String concatenation doubled the speed
// of the code, and was only slightly slower than using just the label
// as the key
MonitorImp mon=getExistingMonitor(key);
// There is a chance of 2 threads going into the next code simultaneously, but this can be handled in
// a thread safe manner via the following code with a ConcurrentHashMap
if (mon==null) {
if (monitorThresholdReached()) {
return NULL_MON;
}
// create the monitor. There is a chance that between the check for mon==null above and
// the call to putIfAbsent that another thread created the monitor already. If so then
// a nonnull value will be returned by putIfAbsent. In this case (rare) use the value
// returned by putIfAbsent and not the monitor returned by createMon.
mon=createMon(key, isPrimary, isTimeMonitor);
MonitorImp tempMon=(MonitorImp) ((ConcurrentHashMap) map).putIfAbsent(key, mon);
if (tempMon!=null)
mon=tempMon;
}
return mon;
}
}
// Note the method must be synchronized due to the use of a regular map. It is better to use the
// concurrentMap implementation above.
private class GetMonitorMap extends GetMonitor {
@Override
protected synchronized MonitorImp getMon(MonKey key, boolean isPrimary, boolean isTimeMonitor) {
// note using MonKey over String concatenation doubled the speed
// of the code, and was only slightly slower than using just the label
// as the key
MonitorImp mon=getExistingMonitor(key);
// chance of 2 threads going into the next code simultaneously
if (mon==null) {
if (monitorThresholdReached()) {
return NULL_MON;
}
mon=createMon(key, isPrimary, isTimeMonitor);
putMon(key, mon);
}
return mon;
}
}
public void enableTotalKeySizeTracking() {
totalKeySize=new AtomicLong();
}
public void disableTotalKeySizeTracking() {
totalKeySize=null;
}
public boolean isTotalKeySizeTrackingEnabled() {
return totalKeySize!=null;
}
public int getMaxSqlSize() {
return maxSqlSize;
}
public void setMaxSqlSize(int size) {
this.maxSqlSize=size;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy