Package org.rioproject.impl.system.measurable.memory

Source Code of org.rioproject.impl.system.measurable.memory.Memory$JMXNotificationListener

/*
* Copyright to the original author or authors.
*
* 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.
*/
package org.rioproject.impl.system.measurable.memory;

import com.sun.jini.config.Config;
import net.jini.config.Configuration;
import net.jini.config.ConfigurationException;
import org.rioproject.costmodel.ResourceCostModel;
import org.rioproject.costmodel.ZeroCostModel;
import org.rioproject.impl.system.measurable.MeasurableCapability;
import org.rioproject.impl.system.measurable.MeasurableMonitor;
import org.rioproject.system.MeasuredResource;
import org.rioproject.system.SystemWatchID;
import org.rioproject.system.measurable.memory.CalculableMemory;
import org.rioproject.system.measurable.memory.ProcessMemoryUtilization;
import org.rioproject.watch.ThresholdValues;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.management.Notification;
import javax.management.NotificationEmitter;
import javax.management.NotificationListener;
import java.lang.management.MemoryNotificationInfo;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

/**
* The Memory object is a MeasurableCapability that measures the amount of
* memory available for the JVM
*
* @author Dennis Reedy
*/

/* Suppress PMD warnings for the invocation of getComponentName() and createMeasurableMonitor() during object
* construction. This is by design. */
@SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
public class Memory extends MeasurableCapability {
    /** Iteration value for calculating utilization of sampleSize >1 */
    private int count;
    /** Temporary utilization value */
    private double tempUtilization;
    /** Computed utilization value */
    private double utilization;
    private static final String VIEW = "org.rioproject.system.memory.CalculableMemoryView";
    /** Total memory arena */
    double totalArena;
    /** Component for Configuration and Logging */
    private static final String COMPONENT = "org.rioproject.system.measurable.memory";
    private JMXNotificationListener jmxListener;
    /** For handling JX event notifications */
    private final BlockingQueue<Notification> eventQ = new LinkedBlockingQueue<Notification>();
    /** A Logger for this class */
    static Logger logger = LoggerFactory.getLogger(COMPONENT);

    /**
     * Construct a Memory object
     *
     * @param config Configuration object
     */
    public Memory(Configuration config) {
        this(SystemWatchID.JVM_MEMORY, config);
    }

    /**
     * Construct a Memory object
     *
     * @param id Identifier to use
     * @param config Configuration object
     */
    public Memory(String id, Configuration config) {
        this(id, COMPONENT, config);
    }

    /**
     * Construct a Memory object
     *
     * @param id Identifier to use
     * @param componentName The configuration component name
     * @param config Configuration object
     */
    public Memory(String id, String componentName, Configuration config) {
        super(id, componentName, config);
        if(!isEnabled())
            return;
        setView(VIEW);
        try {          
            ThresholdValues tVals = (ThresholdValues)config.getEntry(getComponentName(),
                                                                     "thresholdValues",
                                                                     ThresholdValues.class,
                                                                     new ThresholdValues(0.0, 1.0));
            logger.trace("{} threshold values: {}", getId(), tVals.toString());
            setThresholdValues(tVals);
           
            ResourceCostModel rCostModel = (ResourceCostModel)config.getEntry(getComponentName(),
                                                                              "resourceCost",
                                                                              ResourceCostModel.class,
                                                                              new ZeroCostModel());
            setResourceCostModel(rCostModel);
            sampleSize = Config.getIntEntry(config,
                                            getComponentName(),
                                            "sampleSize",
                                            1,   /* default */
                                            1,   /* min */
                                            10); /* max */
            setSampleSize(sampleSize);

            setMeasurableMonitor(createMeasurableMonitor(config));

            long reportRate = Config.getLongEntry(config,
                                                  getComponentName(),
                                                  "reportRate",
                                                  DEFAULT_PERIOD,     /* default */
                                                  5000,               /* min */
                                                  Integer.MAX_VALUE); /* max */
            setPeriod(reportRate);
           
            totalArena = Runtime.getRuntime().maxMemory();
           
        } catch (ConfigurationException e) {
            logger.warn("Getting Memory Configuration", e);
        }
    }

    protected String getComponentName() {
        return COMPONENT;
    }

    protected MeasurableMonitor createMeasurableMonitor(Configuration config) throws ConfigurationException {
        MeasurableMonitor mMon = (MeasurableMonitor)config.getEntry(getComponentName(),
                                                                    "monitor",
                                                                    MeasurableMonitor.class,
                                                                    new ProcessMemoryMonitor());
        if(mMon instanceof ProcessMemoryMonitor) {
            NotificationEmitter emitter = (NotificationEmitter)((ProcessMemoryMonitor)mMon).getMXBean();
            jmxListener = new JMXNotificationListener();
            emitter.addNotificationListener(jmxListener, null, null);
        }
        return mMon;
    }

    public MeasurableMonitor getMeasurableMonitor() {
        return monitor;
    }

    /**
     * Override PeriodicWatch.start() to get an initial reading prior to
     * scheduling
     */
    public void start() {
        checkValue();
        super.start();
    }


    @Override
    public void stop() {
        super.stop();
        if(jmxListener!=null)
            jmxListener.getExecutorService().shutdownNow();
    }

    /**
     * Get the computed utilization for this Memory object
     *
     * @return The utilization computed for this component
     */
    public double getUtilization() {
        return(utilization);
    }
       
   
    /* (non-Javadoc)
     * @see org.rioproject.watch.PeriodicWatch#checkValue()
     */
    public void checkValue() {
        addWatchRecord(createCalculableMemory());
    }

    protected double calculateUtilization(MeasuredResource mRes) {
        count++;
        tempUtilization += mRes.getValue();
        if(count==sampleSize) {
            utilization = tempUtilization/sampleSize;
            count = 0;
            tempUtilization = 0;
        }
        logger.trace("Memory : {} utilization={}", getComponentName(), utilization);

        return utilization;
    }

    private CalculableMemory createCalculableMemory() {
        CalculableMemory  calculableMemory ;
        MeasuredResource mRes = monitor.getMeasuredResource();
        utilization = calculateUtilization(mRes);
        long now = System.currentTimeMillis();
        if(mRes instanceof ProcessMemoryUtilization)
            calculableMemory = new CalculableMemory(getId(),
                                                utilization,
                                                (ProcessMemoryUtilization)mRes,
                                                now);
        else
            calculableMemory = new CalculableMemory(getId(), utilization, now);
        setLastMeasuredResource(mRes);
        return calculableMemory;
    }

    class JMXNotificationListener implements NotificationListener {
        private final ExecutorService execService = Executors.newSingleThreadExecutor();

        JMXNotificationListener() {
            execService.submit(new JMXNotificationHandler());
        }

        ExecutorService getExecutorService() {
            return execService;
        }

        public void handleNotification(Notification notification, Object handback) {
            eventQ.add(notification);
        }
    }

    class JMXNotificationHandler implements Runnable {
        public void run() {
            while (true) {
                Notification notification;
                try {
                    notification = eventQ.take();
                } catch (InterruptedException e) {
                    logger.debug("JMXNotificationHandler breaking out of main loop");
                    break;
                }
                if (notification.getType().equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) {
                    CalculableMemory calculableMemory = createCalculableMemory();
                    /* We may have a reading that lags behind the notification memory threshold notification.
                     * Force the value to be greater than the high threshold */
                    if(calculableMemory.getValue()<=getThresholdValues().getCurrentHighThreshold()) {
                        logger.info("JMX MEMORY_THRESHOLD_EXCEEDED, adjusting CalculableMemory value " +
                                    "from [{}] to [{}] to enforce SLA actions to occur.",
                                    calculableMemory.getValue(),
                                    (getThresholdValues().getCurrentHighThreshold()+0.01));
                        calculableMemory.setValue(getThresholdValues().getCurrentHighThreshold()+0.01);
                    }
                    addWatchRecord(createCalculableMemory());
                }
            }
        }
    }

}
TOP

Related Classes of org.rioproject.impl.system.measurable.memory.Memory$JMXNotificationListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.