Java tutorial
/******************************************************************************* * Copyright (c) 2012 GigaSpaces Technologies Ltd. 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. *******************************************************************************/ package org.openspaces.grid.gsm.autoscaling; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openspaces.admin.internal.pu.InternalProcessingUnit; import org.openspaces.admin.pu.ProcessingUnit; import org.openspaces.admin.pu.ProcessingUnitInstance; import org.openspaces.admin.pu.statistics.LastSampleTimeWindowStatisticsConfig; import org.openspaces.admin.pu.statistics.ProcessingUnitStatisticsId; import org.openspaces.admin.pu.statistics.SingleInstanceStatisticsConfig; import org.openspaces.admin.pu.statistics.SingleInstanceStatisticsConfigurer; import org.openspaces.admin.zone.config.ExactZonesConfig; import org.openspaces.admin.zone.config.ZonesConfig; import org.openspaces.grid.gsm.autoscaling.exceptions.AutoScalingInstanceStatisticsException; import org.openspaces.grid.gsm.autoscaling.exceptions.AutoScalingSlaEnforcementInProgressException; import org.openspaces.grid.gsm.autoscaling.exceptions.AutoScalingStatisticsException; import org.openspaces.grid.gsm.capacity.CapacityRequirements; import org.openspaces.grid.gsm.capacity.CapacityRequirementsPerZones; /** * @author itaif * */ public class AutoScalingSlaUtils { private static Log logger = LogFactory.getLog(AutoScalingSlaUtils.class.getName()); @SuppressWarnings("unchecked") public static int compare(Comparable<?> threshold, Object value) throws NumberFormatException { if (threshold.getClass().equals(value.getClass())) { return ((Comparable<Object>) threshold).compareTo(value); } return toDouble(threshold).compareTo(toDouble(value)); } private static Double toDouble(Object x) throws NumberFormatException { if (x instanceof Number) { return ((Number) x).doubleValue(); } return Double.valueOf(x.toString()); } /** * Calculates the maximum capacity for the specified zones. * * The algorithm tries to be very conservative and may return a smaller value than maxPerZones. * otherCapacity = sum (foreach otherZones!=zones --> min(maxPerZone,max(last[otherZones],newPlanned[otherZones])) * return min(maxPerZones, totalMax - otherCapacity) * * @param totalMax - the maximum capacity when adding up all zones * @param maxPerZone - the maximum capacity per zone * @param enforced - the last enforced (allocated) capacity per zone * @param newPlanned - the new (planned) capacity per zone (could be zero if no plan yet) * @param zones - the zone for which the maximum capacity is requested * @param zoness - the complete list of zones */ public static CapacityRequirements getMaximumCapacity(CapacityRequirements totalMax, CapacityRequirements maxPerZone, CapacityRequirementsPerZones enforced, CapacityRequirementsPerZones newPlanned, ZonesConfig zones) { Set<ZonesConfig> zoness = new HashSet<ZonesConfig>(); zoness.addAll(enforced.getZones()); zoness.addAll(newPlanned.getZones()); zoness.add(zones); CapacityRequirements maximumCapacity = totalMax; // initial for (ZonesConfig otherZone : zoness) { if (!zones.equals(otherZone)) { CapacityRequirements otherLastEnforced = enforced.getZonesCapacityOrZero(otherZone); CapacityRequirements otherNewPlanned = newPlanned.getZonesCapacityOrZero(otherZone); CapacityRequirements otherMaximumCapacity = otherLastEnforced.max(otherNewPlanned).min(maxPerZone); maximumCapacity = maximumCapacity.subtractOrZero(otherMaximumCapacity); } } maximumCapacity = maximumCapacity.min(maxPerZone); return maximumCapacity; } /** * Calculates the minimum capacity for the specified zones. * * The algorithm tries to be very conservative and may return a bigger value than minPerZones. * * otherCapacity = sum (foreach otherZones!=zones --> max(minPerZone,min(last[otherZones], newPlanned[otherZones])) * return min(maxPerZones, totalMin - otherCapacity) * * @param totalMin - the minimum capacity when adding up all zones * @param minPerZone - the minimum capacity per zone * @param enforced - the last enforced (allocated) capacity per zone * @param newPlanned - the new (planned) capacity per zone (could be zero if no plan yet, in that case it is ignored) * @param zones - the zone for which the maximum capacity is requested * @param zoness - the complete list of zones */ public static CapacityRequirements getMinimumCapacity(CapacityRequirements totalMin, CapacityRequirements minPerZone, CapacityRequirementsPerZones enforced, CapacityRequirementsPerZones newPlanned, ZonesConfig zones) { Set<ZonesConfig> zoness = new HashSet<ZonesConfig>(); zoness.addAll(enforced.getZones()); zoness.addAll(newPlanned.getZones()); zoness.add(zones); CapacityRequirements minimumRequierements = totalMin; // initial for (ZonesConfig otherZone : zoness) { if (!zones.equals(otherZone)) { CapacityRequirements otherLastEnforced = enforced.getZonesCapacityOrZero(otherZone); CapacityRequirements otherNewPlanned = newPlanned.getZonesCapacityOrZero(otherZone); CapacityRequirements otherMinimumCapacity = null; if (otherNewPlanned.equalsZero()) { // autoscaling did not calculate new capacity for 'otherZone' yet. otherMinimumCapacity = otherLastEnforced.max(minPerZone); } else { otherMinimumCapacity = otherLastEnforced.min(otherNewPlanned).max(minPerZone); } minimumRequierements = minimumRequierements.subtractOrZero(otherMinimumCapacity); } } // enforce minimum capacity per zone to be at least the pre-defince minimum capacity per // zone minimumRequierements = minimumRequierements.max(minPerZone); return minimumRequierements; } /** * Validates that the specified statisticsId defined in the rule */ public static Object getStatisticsValue(ProcessingUnit pu, Map<ProcessingUnitStatisticsId, Object> statistics, ProcessingUnitStatisticsId ruleStatisticsId) throws AutoScalingSlaEnforcementInProgressException { ruleStatisticsId.validate(); for (final ProcessingUnitInstance instance : pu) { ExactZonesConfig puInstanceExactZones = ((InternalProcessingUnit) pu) .getHostingGridServiceAgentZones(instance); if (puInstanceExactZones.isStasfies(ruleStatisticsId.getAgentZones())) { SingleInstanceStatisticsConfig singleInstanceStatistics = new SingleInstanceStatisticsConfigurer() .instance(instance).create(); //check original measured statistics exists final ProcessingUnitStatisticsId singleInstanceLastSampleStatisticsId = ruleStatisticsId .shallowClone(); singleInstanceLastSampleStatisticsId.setInstancesStatistics(singleInstanceStatistics); singleInstanceLastSampleStatisticsId.setAgentZones(puInstanceExactZones); singleInstanceLastSampleStatisticsId .setTimeWindowStatistics(new LastSampleTimeWindowStatisticsConfig()); singleInstanceLastSampleStatisticsId.validate(); if (!statistics.containsKey(singleInstanceLastSampleStatisticsId)) { AutoScalingInstanceStatisticsException exception = new AutoScalingInstanceStatisticsException( instance, singleInstanceLastSampleStatisticsId.getMetric()); if (logger.isTraceEnabled()) { logger.trace( "Failed to find statistics id = " + singleInstanceLastSampleStatisticsId + " in pu statistics. current statistics key set = " + statistics.keySet(), exception); } throw exception; } //check time calculated statistics exists final ProcessingUnitStatisticsId singleInstanceStatisticsId = ruleStatisticsId.shallowClone(); singleInstanceStatisticsId.setInstancesStatistics(singleInstanceStatistics); singleInstanceLastSampleStatisticsId.setAgentZones(puInstanceExactZones); singleInstanceStatisticsId.validate(); if (!statistics.containsKey(singleInstanceStatisticsId)) { AutoScalingStatisticsException exception = new AutoScalingInstanceStatisticsException(instance, singleInstanceStatisticsId.getMetric()); if (logger.isTraceEnabled()) { logger.trace( "Failed to find statistics id = " + singleInstanceStatisticsId + " in pu statistics. current statistics key set = " + statistics.keySet(), exception); } throw exception; } //check zone calculated statistics exists final ProcessingUnitStatisticsId singleInstanceTimeWindowZoneStatisticsId = ruleStatisticsId .shallowClone(); singleInstanceTimeWindowZoneStatisticsId.setInstancesStatistics(singleInstanceStatistics); singleInstanceTimeWindowZoneStatisticsId.validate(); if (!statistics.containsKey(singleInstanceTimeWindowZoneStatisticsId)) { AutoScalingStatisticsException exception = new AutoScalingInstanceStatisticsException(instance, singleInstanceTimeWindowZoneStatisticsId.getMetric()); if (logger.isTraceEnabled()) { logger.trace( "Failed to find statistics id = " + singleInstanceTimeWindowZoneStatisticsId + " in pu statistics. current statistics key set = " + statistics.keySet(), exception); } throw exception; } } } Object value = statistics.get(ruleStatisticsId); //check instances calculated statistics exists if (value == null) { logger.debug("statistics value for " + ruleStatisticsId + " was null."); throw new AutoScalingStatisticsException(pu, ruleStatisticsId); } return value; } private static final DecimalFormat decimalFormat = initDecimalFormat(); private static DecimalFormat initDecimalFormat() { DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(); decimalFormatSymbols.setDecimalSeparator('.'); decimalFormatSymbols.setGroupingSeparator(','); return new DecimalFormat("#,##0.##", decimalFormatSymbols); } public static String formatMetricValue(Object value) { if (value == null) { return "null"; } if (value instanceof Double) { return formatDouble(value); } return value.toString(); } private static String formatDouble(Object value) { return decimalFormat.format((Double) value); } }