package org.rhq.server.metrics; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.SortedMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.TreeBasedTable; import org.joda.time.DateTime; import org.rhq.server.metrics.domain.AggregateNumericMetric; import org.rhq.server.metrics.domain.Bucket; import org.rhq.server.metrics.domain.NumericMetric; import org.rhq.server.metrics.domain.RawNumericMetric; /** * @author John Sanda */ public class InMemoryMetricsDB { private TreeBasedTable<Integer, DateTime, NumericMetric> rawData = TreeBasedTable.create(); private TreeBasedTable<Integer, DateTime, AggregateNumericMetric> oneHourData = TreeBasedTable.create(); private TreeBasedTable<Integer, DateTime, AggregateNumericMetric> sixHourData = TreeBasedTable.create(); private TreeBasedTable<Integer, DateTime, AggregateNumericMetric> twentyFourHourData = TreeBasedTable.create(); public void putRawData(RawNumericMetric raw) { rawData.put(raw.getScheduleId(), new DateTime(raw.getTimestamp()), raw); } public AggregateNumericMetric get1HourData(DateTime timeSlice, int scheduleId) { return oneHourData.get(scheduleId, timeSlice); } public List<AggregateNumericMetric> get1HourData(int scheduleId) { return ImmutableList.copyOf(oneHourData.row(scheduleId).values()); } public List<AggregateNumericMetric> get1HourData(DateTime timeSlice) { Map<Integer, AggregateNumericMetric> data = oneHourData.column(timeSlice); return ImmutableList.copyOf(data.values()); } public List<AggregateNumericMetric> get1HourData(int... scheduleIds) { return getAllDataForBucket(oneHourData, scheduleIds); } public AggregateNumericMetric get6HourData(DateTime timeSlice, int scheduleId) { return sixHourData.get(scheduleId, timeSlice); } public List<AggregateNumericMetric> get6HourData(int... scheduleIds) { return getAllDataForBucket(sixHourData, scheduleIds); } public List<AggregateNumericMetric> get24HourData(int... scheduleIds) { return getAllDataForBucket(twentyFourHourData, scheduleIds); } private List<AggregateNumericMetric> getAllDataForBucket( TreeBasedTable<Integer, DateTime, AggregateNumericMetric> table, int... scheduleIds) { List<AggregateNumericMetric> metrics = new ArrayList<AggregateNumericMetric>(scheduleIds.length); for (Integer scheduleId : scheduleIds) { SortedMap<DateTime, AggregateNumericMetric> dataForSchedule = table.row(scheduleId); metrics.addAll(dataForSchedule.values()); } return metrics; } public void aggregateRawData(DateTime startTime, DateTime endTime) { aggregateData(startTime, endTime, rawData, oneHourData, Bucket.ONE_HOUR); } public void aggregate1HourData(DateTime startTime, DateTime endTime) { aggregateData(startTime, endTime, oneHourData, sixHourData, Bucket.SIX_HOUR); } public void aggregate6HourData(DateTime startTime, DateTime endTime) { aggregateData(startTime, endTime, sixHourData, twentyFourHourData, Bucket.TWENTY_FOUR_HOUR); } private void aggregateData(DateTime startTime, DateTime endTime, TreeBasedTable<Integer, DateTime, ? extends NumericMetric> from, TreeBasedTable<Integer, DateTime, AggregateNumericMetric> to, Bucket bucket) { for (Integer scheduleId : from.rowKeySet()) { SortedMap<DateTime, ? extends NumericMetric> row = from.row(scheduleId); Collection<? extends NumericMetric> dataForTimeSlice = row.subMap(startTime, endTime).values(); if (!dataForTimeSlice.isEmpty()) { AggregateNumericMetric aggregate = computeAggregate(startTime, row.subMap(startTime, endTime).values(), bucket); to.put(scheduleId, startTime, aggregate); } } } private AggregateNumericMetric computeAggregate(DateTime timestamp, Collection<? extends NumericMetric> values, Bucket bucket) { Double min = Double.NaN; Double max = Double.NaN; ArithmeticMeanCalculator mean = new ArithmeticMeanCalculator(); int scheduleId = 0; for (NumericMetric metric : values) { mean.add(metric.getAvg()); if (Double.isNaN(min)) { scheduleId = metric.getScheduleId(); min = metric.getMin(); max = metric.getMax(); } else { if (metric.getMin() < min) { min = metric.getMin(); } if (metric.getMax() > max) { max = metric.getMax(); } } } return new AggregateNumericMetric(scheduleId, bucket, mean.getArithmeticMean(), min, max, timestamp.getMillis()); } }