package org.radargun.sysmonitor; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.radargun.logging.Log; import org.radargun.logging.LogFactory; import org.radargun.state.StateBase; import org.radargun.state.StateListener; /** * Base class for holding and maintaining various slave and master state * monitors, extending classes have to implement interface extending * {@link StateListener} * * @author zhostasa * * @param <S> * {@link StateBase} implementation to store * @param <T> * {@link StateListener} implementation shared with {@link StateBase} */ public abstract class AbstractMonitors<S extends StateBase<T>, T extends StateListener> implements StateListener { protected final long period; protected ScheduledExecutorService exec; protected List<Monitor> monitors = new ArrayList<>(); private static Log log = LogFactory.getLog(AbstractMonitors.class); protected S state; /** * Registers {@link StateBase} and monitor execution period * * @param state * {@link StateBase} implementation of the node * @param period * Monitor execution period in milliseconds */ public AbstractMonitors(S state, long period) { this.state = state; this.period = period; } /** * Retrieves {@link ScheduledExecutorService} and registers monitors to * execute periodically */ protected synchronized void startInternal() { exec = Executors.newScheduledThreadPool(1, new ThreadFactory() { AtomicInteger counter = new AtomicInteger(); @Override public Thread newThread(Runnable r) { return new Thread(r, "MonitorThread-" + counter.getAndIncrement()); } }); for (Monitor m : monitors) { m.start(); exec.scheduleAtFixedRate(m, 0, period, TimeUnit.MILLISECONDS); } log.infof("Gathering statistics every %d ms", period); } /** * Stops monitors and {@link ScheduledExecutorService} */ protected synchronized void stopInternal() { if (exec == null) return; for (Monitor m : monitors) { m.stop(); } exec.shutdownNow(); try { exec.awaitTermination(2 * period, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { log.error("Failed to terminate local monitoring."); } this.exec = null; } /** * Stores monitor (unles already stored) and executes it if monitors are * started * * @param monitor */ public synchronized void addMonitor(Monitor monitor) { if (monitors.contains(monitor)) { log.warnf("Monitor %s is already registered, ignoring", monitor); return; } monitors.add(monitor); if (exec != null) { exec.scheduleAtFixedRate(monitor, 0, period, TimeUnit.MILLISECONDS); } } /** * Adds itself to node state and listeners and starts monitors */ public synchronized void start() { state.addListener((T) this); state.put(getName(), this); startInternal(); } /** * Removes itself from node state and listeners and stops monitors */ public synchronized void stop() { state.removeListener((T) this); state.remove(getName()); stopInternal(); } public abstract String getName(); }