/******************************************************************************* * 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.admin.internal.pu; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openspaces.admin.internal.pu.statistics.InstancesStatisticsCalculator; import org.openspaces.admin.internal.pu.statistics.InternalProcessingUnitStatistics; import org.openspaces.admin.internal.pu.statistics.InternalProcessingUnitStatisticsCalculator; import org.openspaces.admin.internal.pu.statistics.StatisticsObjectListFunction; import org.openspaces.admin.internal.pu.statistics.TimeWindowStatisticsCalculator; import org.openspaces.admin.internal.pu.statistics.ZoneStatisticsCalculator; import org.openspaces.admin.pu.statistics.InstancesStatisticsConfig; import org.openspaces.admin.pu.statistics.ProcessingUnitStatisticsId; import org.openspaces.admin.pu.statistics.SingleInstanceStatisticsConfig; import org.openspaces.admin.zone.config.ExactZonesConfig; import org.openspaces.admin.zone.config.ZonesConfig; /** * This class performs 3 calculations on raw statistics: timeWindow, agentZones and instances calculations * in order to transform the raw statisticsId into the requested statisticsId * * raw statisticsid read from pu instance (timestamp = now): * ["mybean", "memory" , LastSampleTimeWindowStatisticsConfig, SingleInstanceStatisticsConfig("instance1"), ExactZoneConfig("zone1")] * * time calculated statisticsId (timestamp = now, but the calculator averaged the last 60 seconds): * ["mybean", "memory" , AverageTimeWindowStatisticsConfig(60), SingleInstanceStatisticsConfig("instance1"), ExactZoneConfig("zone1")] * * zone calculated statisticsId (the zone is changed to reflect the requested statisticsId): * ["mybean", "memory" , AverageTimeWindowStatisticsConfig(60), SingleInstanceStatisticsConfig("instance1"), AtLeastOneZoneConfig("zone1")] * * instances calculated statisticsId (the instances changed to reflect the average across all instances) * This is also the requested statisticId: * ["mybean", "memory" , AverageTimeWindowStatisticsConfig(60), AverageInstancesStatisticsConfig , AtLeastOneZoneConfig("zone1")] * * @author Itai Frenkel * */ public class DefaultProcessingUnitStatistics implements InternalProcessingUnitStatistics { private volatile ProcessingUnitStatistics previous; private final long adminTimestamp; private final Map<ProcessingUnitStatisticsId, Object> statistics; private final InternalProcessingUnitStatisticsCalculator timeWindowStatisticsCalculator = new TimeWindowStatisticsCalculator(); private final InternalProcessingUnitStatisticsCalculator instancesStatisticsCalculator = new InstancesStatisticsCalculator(); private final InternalProcessingUnitStatisticsCalculator zoneStatisticsCalculator = new ZoneStatisticsCalculator(); private Log logger = LogFactory.getLog(this.getClass()); public DefaultProcessingUnitStatistics( long adminTimestamp, ProcessingUnitStatistics lastStatistics, int historySize) { this.statistics = new HashMap<ProcessingUnitStatisticsId, Object>(); this.adminTimestamp = adminTimestamp; this.previous = lastStatistics; if (lastStatistics != null) { for (int i = 0; i < historySize; i++) { if (lastStatistics.getPrevious() == null) { break; } lastStatistics = lastStatistics.getPrevious(); } ((DefaultProcessingUnitStatistics)lastStatistics).previous = null; } } @Override public long getAdminTimestamp() { return this.adminTimestamp; } @Override public ProcessingUnitStatistics getPrevious() { return this.previous; } @Override public Map<ProcessingUnitStatisticsId, Object> getStatistics() { return Collections.unmodifiableMap(statistics); } @Override public void addStatistics(ProcessingUnitStatisticsId statisticsId, Object statisticsValue) { statisticsId.validate(); statistics.put(statisticsId, statisticsValue); } /** * @see #DefaultProcessingUnitStatistics(long, ProcessingUnitStatistics, int) documentation */ @Override public void calculateStatistics(Iterable<ProcessingUnitStatisticsId> statisticsIds) { if (logger.isTraceEnabled()) { logger.trace("statisticsIds before calculating new statistics is = "+ statistics); } calculateTimeWindowStatistics(statisticsIds); calculateZoneStatistics(statisticsIds); calculateInstancesStatistics(statisticsIds); if (logger.isTraceEnabled()) { logger.trace("statisticsIds after calculation finished = "+ statistics); } } private void calculateInstancesStatistics(Iterable<ProcessingUnitStatisticsId> statisticsIds) { final List<ProcessingUnitStatisticsId> instancesCalculatedStatistics = new ArrayList<ProcessingUnitStatisticsId>(); for (final ProcessingUnitStatisticsId statisticsId : statisticsIds) { if (statisticsId.getInstancesStatistics() instanceof StatisticsObjectListFunction) { instancesCalculatedStatistics.add(statisticsId); } } instancesStatisticsCalculator.calculateNewStatistics(this, instancesCalculatedStatistics); } private void calculateZoneStatistics(Iterable<ProcessingUnitStatisticsId> statisticIds) { List<ProcessingUnitStatisticsId> zoneCalculatedStatistics = new ArrayList<ProcessingUnitStatisticsId>(); for (final ProcessingUnitStatisticsId statisticsId : statisticIds) { statisticsId.validate(); zoneCalculatedStatistics.add(statisticsId); } zoneStatisticsCalculator.calculateNewStatistics(this, zoneCalculatedStatistics); } private void calculateTimeWindowStatistics(Iterable<ProcessingUnitStatisticsId> statisticsIdsToCalculate) { Map<SingleInstanceStatisticsConfig,ExactZonesConfig> instances = new HashMap<SingleInstanceStatisticsConfig, ExactZonesConfig>(); // construct a set containing all instances UIDS for the current processing unit for (ProcessingUnitStatisticsId processingUnitStatisticsId : statistics.keySet()) { InstancesStatisticsConfig instancesStatistics = processingUnitStatisticsId.getInstancesStatistics(); ZonesConfig zoneStatistics = processingUnitStatisticsId.getAgentZones(); if (instancesStatistics instanceof SingleInstanceStatisticsConfig && zoneStatistics instanceof ExactZonesConfig) { instances.put( (SingleInstanceStatisticsConfig) instancesStatistics, (ExactZonesConfig) processingUnitStatisticsId.getAgentZones()); } } final List<ProcessingUnitStatisticsId> singleInstanceCalculatedStatistics = new ArrayList<ProcessingUnitStatisticsId>(); // iterate over every existing processingUnitStatisticsId to create requests that have matching zone statistics id's. for (final ProcessingUnitStatisticsId statisticsId : statisticsIdsToCalculate) { if (statisticsId.getInstancesStatistics() instanceof SingleInstanceStatisticsConfig) { // instance UID is already specified. Just check that it is still discovered and has correct zones SingleInstanceStatisticsConfig instancesStatistics = (SingleInstanceStatisticsConfig)(statisticsId.getInstancesStatistics()); if (!instances.containsKey(instancesStatistics)) { if (logger.isDebugEnabled()) { logger.debug("Failed to find instance UID " + instancesStatistics.getInstanceUid()); } continue; } ExactZonesConfig zoneStatistics = instances.get(instancesStatistics); if (!statisticsId.getAgentZones().isSatisfiedBy(zoneStatistics)) { if (logger.isDebugEnabled()) { logger.debug("Failed to find instance UID " + instancesStatistics.getInstanceUid() + " with zones " + zoneStatistics.getZones() + " which satisfies zones " + statisticsId.getAgentZones()); } continue; } // fix zone statistics for timewindow calculator so it finds the instance ProcessingUnitStatisticsId fixedStatisticsId = statisticsId.shallowClone(); zoneStatistics.validate(); fixedStatisticsId.setAgentZones(zoneStatistics); singleInstanceCalculatedStatistics.add(fixedStatisticsId); } else { //expand to all instance UIDs for (Entry<SingleInstanceStatisticsConfig, ExactZonesConfig> pair : instances.entrySet()) { ProcessingUnitStatisticsId fixedStatisticsId = statisticsId.shallowClone(); fixedStatisticsId.setInstancesStatistics(pair.getKey()); fixedStatisticsId.setAgentZones(pair.getValue()); singleInstanceCalculatedStatistics.add(fixedStatisticsId); } } } timeWindowStatisticsCalculator.calculateNewStatistics(this, singleInstanceCalculatedStatistics); } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "ProcessingUnitStatistics {adminTimestamp=" + adminTimestamp + ", statistics=" + statistics + "}"; } }