/*
* ProActive Parallel Suite(TM):
* The Open Source library for parallel and distributed
* Workflows & Scheduling, Orchestration, Cloud Automation
* and Big Data Analysis on Enterprise Grids & Clouds.
*
* Copyright (c) 2007 - 2017 ActiveEon
* Contact: contact@activeeon.com
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation: version 3 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If needed, contact us to obtain a release under GPL Version 2 or 3
* or a different license than the AGPL.
*/
package org.ow2.proactive.resourcemanager.utils;
import org.ow2.proactive.resourcemanager.common.NodeState;
import org.ow2.proactive.resourcemanager.common.event.RMEvent;
import org.ow2.proactive.resourcemanager.common.event.RMEventType;
import org.ow2.proactive.resourcemanager.common.event.RMNodeEvent;
/**
* This class represents the statistics of the Resource Manager. Different kind of
* values are collected by interpreting incoming events from the Resource Manager.
* <p>
* An instance of this class must not be accessed and modified concurrently.
* The concurrency is handled by the {@link AtomicRMStatisticsHolder} class.
*
* @author The ProActive Team
* @since ProActive Scheduling 1.1
*/
public final class RMStatistics {
/** The state of the Resource Manager */
private RMEventType rmStatus;
/** The current available nodes count */
private int availableNodesCount;
/** The count of nodes in {@link NodeState#DEPLOYING} state */
private int deployingNodesCount;
/** The count of nodes in {@link NodeState#CONFIGURING} state */
private int configuringNodesCount;
/** The count of nodes in {@link NodeState#LOST} state */
private int lostNodesCount;
/** The count of nodes in {@link NodeState#FREE} state */
private int freeNodesCount;
/** The count of nodes in {@link NodeState#BUSY} state */
private int busyNodesCount;
/** The count of nodes in {@link NodeState#TO_BE_REMOVED} state */
private int toBeRemovedNodesCount;
/** The count of nodes in {@link NodeState#DOWN} state */
private int downNodesCount;
/** The maximum free nodes count */
private int maxFreeNodes;
/** The maximum free nodes count */
private int maxDeployingNodes;
/** The maximum configuring nodes count */
private int maxConfiguringNodes;
/** The maximum lost nodes count */
private int maxLostNodes;
/** The maximum busy nodes count */
private int maxBusyNodes;
/** The maximum to be released nodes count */
private int maxToBeRemovedNodes;
/** The maximum down nodes count */
private int maxDownNodes;
/** The cumulative activity time */
private long cumulativeActivityTime;
/** The cumulative inactivity time */
private long cumulativeInactivityTime;
/** A time stamp used for cumulative times computation */
private long previousTimeStamp;
/**
* Creates a new instance of the this class.
*/
public RMStatistics() {
// Set the initial status as shutdown
this.rmStatus = RMEventType.SHUTDOWN;
// Initialize all nodes related counts
this.availableNodesCount = 0;
this.configuringNodesCount = 0;
this.deployingNodesCount = 0;
this.lostNodesCount = 0;
this.freeNodesCount = 0;
this.busyNodesCount = 0;
this.toBeRemovedNodesCount = 0;
this.downNodesCount = 0;
this.maxFreeNodes = 0;
this.maxBusyNodes = 0;
this.maxToBeRemovedNodes = 0;
this.maxDownNodes = 0;
// Initialize all cumulative times
this.cumulativeInactivityTime = 0;
this.cumulativeActivityTime = 0;
// Initialize the time stamp
this.previousTimeStamp = System.nanoTime();
}
/**
* Copy constructor.
*/
public RMStatistics(final RMStatistics rmStatistics) {
this.updateFrom(rmStatistics);
}
/**
* Updates all fields of this class from an existing instance.
* @param rmStatistics existing instance of this class
* @return the current instance of this class
*/
public RMStatistics updateFrom(final RMStatistics rmStatistics) {
this.rmStatus = rmStatistics.rmStatus;
this.availableNodesCount = rmStatistics.availableNodesCount;
this.configuringNodesCount = rmStatistics.configuringNodesCount;
this.lostNodesCount = rmStatistics.lostNodesCount;
this.deployingNodesCount = rmStatistics.deployingNodesCount;
this.freeNodesCount = rmStatistics.freeNodesCount;
this.busyNodesCount = rmStatistics.busyNodesCount;
this.toBeRemovedNodesCount = rmStatistics.toBeRemovedNodesCount;
this.downNodesCount = rmStatistics.downNodesCount;
this.maxConfiguringNodes = rmStatistics.maxConfiguringNodes;
this.maxDeployingNodes = rmStatistics.maxDeployingNodes;
this.maxLostNodes = rmStatistics.maxLostNodes;
this.maxFreeNodes = rmStatistics.maxFreeNodes;
this.maxBusyNodes = rmStatistics.maxBusyNodes;
this.maxToBeRemovedNodes = rmStatistics.toBeRemovedNodesCount;
this.maxDownNodes = rmStatistics.maxDownNodes;
this.cumulativeInactivityTime = rmStatistics.cumulativeInactivityTime;
this.cumulativeActivityTime = rmStatistics.cumulativeActivityTime;
this.previousTimeStamp = rmStatistics.previousTimeStamp;
return this;
}
/**
* Handle incoming node events of the Resource Manager
* @param event incoming event
*/
public void nodeEvent(final RMNodeEvent event) {
// Update cumulative times based on activity and inactivity during the last time interval
final long currentTimeStamp = System.nanoTime();
final long timeInterval = currentTimeStamp - this.previousTimeStamp;
this.cumulativeActivityTime += this.busyNodesCount * timeInterval;
this.cumulativeInactivityTime += this.freeNodesCount * timeInterval;
// Update the previous time stamp to the current
this.previousTimeStamp = currentTimeStamp;
// Depending on the event type update nodes count
switch (event.getEventType()) {
case NODE_ADDED:
// Increment the available nodes count
this.availableNodesCount++;
// We define the state of the added node
final NodeState addNodeState = event.getNodeState();
switch (addNodeState) {
case FREE:
this.incrementFreeNodesCount();
break;
case CONFIGURING:
this.incrementConfiguringNodesCount();
break;
case DEPLOYING:
this.incrementDeployingNodesCount();
break;
case LOST:
this.incrementLostNodesCount();
break;
case BUSY:
this.incrementBusyNodesCount();
break;
case DOWN:
this.incrementDownNodesCount();
break;
case TO_BE_REMOVED:
this.incrementToBeRemovedNodesCount();
break;
default:
// Unknown NodeState
}
break;
case NODE_REMOVED:
// Get the state of the node before it was removed
final NodeState nodeState = event.getNodeState();
switch (nodeState) {
case FREE:
this.decrementFreeNodesCount();
break;
case BUSY:
this.decrementBusyNodesCount();
break;
case TO_BE_REMOVED:
this.decrementToBeRemovedNodesCount();
break;
case DOWN:
this.decrementDownNodesCount();
break;
case CONFIGURING:
this.decrementConfiguringNodesCount();
break;
case LOST:
this.decrementLostNodesCount();
break;
case DEPLOYING:
this.decrementDeployingNodesCount();
break;
default:
// Unknown NodeState
}
this.decrementAvailableNodesCount();
break;
case NODE_STATE_CHANGED:
// Depending on the previous state decrement counters
final NodeState previousNodeState = event.getPreviousNodeState();
if (previousNodeState != null) {
switch (previousNodeState) {
case FREE:
this.decrementFreeNodesCount();
break;
case BUSY:
this.decrementBusyNodesCount();
break;
case TO_BE_REMOVED:
this.decrementToBeRemovedNodesCount();
break;
case DOWN:
this.decrementDownNodesCount();
break;
case CONFIGURING:
this.decrementConfiguringNodesCount();
break;
case LOST:
this.decrementLostNodesCount();
break;
case DEPLOYING:
this.decrementDeployingNodesCount();
break;
default:
// Unknown NodeState
}
}
final NodeState currentNodeState = event.getNodeState(); // can't be null
// Depending on the current state increment counters
switch (currentNodeState) {
case FREE:
this.incrementFreeNodesCount();
break;
case BUSY:
this.incrementBusyNodesCount();
break;
case TO_BE_REMOVED:
this.incrementToBeRemovedNodesCount();
break;
case DOWN:
this.incrementDownNodesCount();
break;
case CONFIGURING:
this.incrementConfiguringNodesCount();
break;
case LOST:
this.incrementLostNodesCount();
break;
case DEPLOYING:
this.incrementDeployingNodesCount();
break;
default:
// Unknown NodeState
}
default:
// Unknown RMEventType
}
}
/**
* Handle incoming Resource Manager events
* @param event The Resource Manager event
*/
public void rmEvent(RMEvent event) {
this.rmStatus = event.getEventType();
}
////////////////////////////
// INTERNAL METHODS
////////////////////////////
private void incrementConfiguringNodesCount() {
// Increment and update configuring nodes max value
if (++this.configuringNodesCount > this.maxConfiguringNodes) {
this.maxConfiguringNodes = this.configuringNodesCount;
}
}
private void incrementDeployingNodesCount() {
// Increment and update deploying nodes max value
if (++this.deployingNodesCount > this.maxDeployingNodes) {
this.maxDeployingNodes = this.deployingNodesCount;
}
}
private void incrementLostNodesCount() {
// Increment and update lost nodes max value
if (++this.lostNodesCount > this.maxLostNodes) {
this.maxLostNodes = this.lostNodesCount;
}
}
private void incrementFreeNodesCount() {
// Increment and update free nodes max value
if (++this.freeNodesCount > this.maxFreeNodes) {
this.maxFreeNodes = this.freeNodesCount;
}
}
private void incrementBusyNodesCount() {
// Increment and update busy nodes max value
if (++this.busyNodesCount > this.maxBusyNodes) {
this.maxBusyNodes = this.busyNodesCount;
}
}
private void incrementToBeRemovedNodesCount() {
// Increment and update toBeReleased nodes max value
if (++this.toBeRemovedNodesCount > this.maxToBeRemovedNodes) {
this.maxToBeRemovedNodes = this.toBeRemovedNodesCount;
}
}
private void incrementDownNodesCount() {
// Increment and update down nodes max value
if (++this.downNodesCount > this.maxDownNodes) {
this.maxDownNodes = this.downNodesCount;
}
}
private void decrementAvailableNodesCount() {
// Decrement available nodes count (keep always >= 0)
if (this.availableNodesCount > 0) {
this.availableNodesCount--;
}
}
private void decrementConfiguringNodesCount() {
// Decrement configuring nodes count (keep always >= 0)
if (this.configuringNodesCount > 0) {
this.configuringNodesCount--;
}
}
private void decrementDeployingNodesCount() {
// Decrement deploying nodes count (keep always >= 0)
if (this.deployingNodesCount > 0) {
this.deployingNodesCount--;
}
}
private void decrementLostNodesCount() {
// Decrement lost nodes count (keep always >= 0)
if (this.lostNodesCount > 0) {
this.lostNodesCount--;
}
}
private void decrementFreeNodesCount() {
// Decrement free nodes count (keep always >= 0)
if (this.freeNodesCount > 0) {
this.freeNodesCount--;
}
}
private void decrementBusyNodesCount() {
// Decrement busy nodes count (keep always >= 0)
if (this.busyNodesCount > 0) {
this.busyNodesCount--;
}
}
private void decrementToBeRemovedNodesCount() {
// Decrement toBeReleased nodes count (keep always >= 0)
if (this.toBeRemovedNodesCount > 0) {
this.toBeRemovedNodesCount--;
}
}
private void decrementDownNodesCount() {
// Decrement down nodes count (keep always >= 0)
if (this.downNodesCount > 0) {
this.downNodesCount--;
}
}
///////////////////////////
// ACCESSORS
///////////////////////////
/**
* Returns the current status of the resource manager.
* @return the current status of the resource manager
*/
public String getRMStatus() {
return this.rmStatus.toString();
}
/**
* Returns the current number of available nodes.
* @return the current number of available nodes
*/
public int getAvailableNodesCount() {
return this.availableNodesCount;
}
/**
* Returns the current number of nodes in {@link NodeState#CONFIGURING} state.
* @return the current number of nodes in {@link NodeState#CONFIGURING} state.
*/
public int getConfiguringNodesCount() {
return this.configuringNodesCount;
}
/**
* Returns the current number of nodes in {@link NodeState#DEPLOYING} state.
* @return the current number of nodes in {@link NodeState#DEPLOYING} state.
*/
public int getDeployingNodesCount() {
return this.deployingNodesCount;
}
/**
* Returns the current number of nodes in {@link NodeState#LOST} state.
* @return the current number of nodes in {@link NodeState#LOST} state.
*/
public int getLostNodesCount() {
return this.lostNodesCount;
}
/**
* Returns the current number of nodes in {@link NodeState#FREE} state.
* @return the current number of free nodes
*/
public int getFreeNodesCount() {
return this.freeNodesCount;
}
/**
* Returns the current number of nodes in {@link NodeState#BUSY} state.
* @return the current number of busy nodes
*/
public int getBusyNodesCount() {
return this.busyNodesCount;
}
/**
* Returns the current number of nodes in {@link NodeState#TO_BE_REMOVED} state.
* @return the current number of busy nodes
*/
public int getToBeRemovedNodesCount() {
return this.toBeRemovedNodesCount;
}
/**
* Returns the current number of nodes in {@link NodeState#DOWN} state.
* @return the current number of down nodes
*/
public int getDownNodesCount() {
return this.downNodesCount;
}
/**
* Returns the maximum number of configuring nodes.
* @return the maximum number of configuring nodes.
*/
public int getMaxConfiguringNodes() {
return this.maxConfiguringNodes;
}
/**
* Returns the maximum number of deploying nodes.
* @return the maximum number of deploying nodes.
*/
public int getMaxDeployingNodes() {
return this.maxDeployingNodes;
}
/**
* Returns the maximum number of lost nodes.
* @return the maximum number of lost nodes.
*/
public int getMaxLostNodes() {
return this.maxLostNodes;
}
/**
* Returns the maximum number of free nodes.
* @return the maximum number of free nodes
*/
public int getMaxFreeNodes() {
return this.maxFreeNodes;
}
/**
* Returns the maximum number of busy nodes.
* @return the maximum number of busy nodes
*/
public int getMaxBusyNodes() {
return this.maxBusyNodes;
}
/**
* Returns the maximum number of toBeReleased nodes.
* @return the maximum number of toBeReleased nodes
*/
public int getMaxToBeReleasedNodes() {
return this.maxBusyNodes;
}
/**
* Returns the maximum number of down nodes.
* @return the maximum number of down nodes
*/
public int getMaxDownNodes() {
return this.maxDownNodes;
}
/**
* Returns the nodes activity time percentage.
* @return the nodes activity time percentage
*/
public double getActivityTimePercentage() {
final long lastInterval = System.nanoTime() - this.previousTimeStamp;
final long v1 = this.cumulativeActivityTime + (lastInterval * this.busyNodesCount);
final long v2 = this.cumulativeInactivityTime + (lastInterval * this.freeNodesCount);
final long total = v1 + v2;
if (total == 0) {
return 0;
}
return (((double) v1 / total) * 100);
}
/**
* Returns the nodes inactivity time percentage.
* @return the nodes inactivity time percentage
*/
public double getInactivityTimePercentage() {
final long lastInterval = System.nanoTime() - this.previousTimeStamp;
final long v1 = this.cumulativeActivityTime + (lastInterval * this.busyNodesCount);
final long v2 = this.cumulativeInactivityTime + (lastInterval * this.freeNodesCount);
final long total = v1 + v2;
if (total == 0) {
return 0;
}
return (((double) v2 / total) * 100);
}
}