Package org.springframework.xd.analytics.metrics.memory

Source Code of org.springframework.xd.analytics.metrics.memory.InMemoryAggregateCounter

/*
* Copyright 2002-2013 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.springframework.xd.analytics.metrics.memory;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.joda.time.Chronology;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.Duration;
import org.joda.time.Interval;

import org.joda.time.Months;
import org.joda.time.Years;
import org.springframework.util.Assert;
import org.springframework.xd.analytics.metrics.core.AggregateCount;
import org.springframework.xd.analytics.metrics.core.AggregateCountResolution;
import org.springframework.xd.analytics.metrics.core.Counter;
import org.springframework.xd.analytics.metrics.core.MetricUtils;

/**
* A counter that tracks integral values but also remembers how its value was distributed over time.
*
* <p>
* This core class only holds data structures. Depending on backing stores, logic for computing totals may be
* implemented in a specialization of this class or at the repository level.
* </p>
*
* @author Luke Taylor
* @author Eric Bottard
*/
class InMemoryAggregateCounter extends Counter {
  private Map<Integer, long[]> monthCountsByYear = new HashMap<Integer, long[]>();

  private Map<Integer, long[]> dayCountsByYear = new HashMap<Integer, long[]>();

  private Map<Integer, long[]> hourCountsByDay = new HashMap<Integer, long[]>();

  private Map<Integer, long[]> minuteCountsByDay = new HashMap<Integer, long[]>();

  public InMemoryAggregateCounter(String name, long value) {
    super(name, value);
  }

  public InMemoryAggregateCounter(String name) {
    super(name);
  }

  public AggregateCount getCounts(int nCounts, DateTime endDate, AggregateCountResolution resolution) {
    Assert.notNull(endDate, "endDate must not be null");

    return getCounts(new Interval(resolution.minus(endDate, nCounts-1), endDate), resolution);
  }

  public AggregateCount getCounts(Interval interval, AggregateCountResolution resolution) {
    DateTime start = interval.getStart();
    DateTime end = interval.getEnd();
    Chronology c = interval.getChronology();

    long[] counts;
    if (resolution == AggregateCountResolution.minute) {
      List<long[]> days = accumulateDayCounts(minuteCountsByDay, start, end, 60 * 24);

      counts = MetricUtils.concatArrays(days, interval.getStart().getMinuteOfDay(),
          interval.toPeriod().toStandardMinutes().getMinutes() + 1);
    }
    else if (resolution == AggregateCountResolution.hour) {
      List<long[]> days = accumulateDayCounts(hourCountsByDay, start, end, 24);

      counts = MetricUtils.concatArrays(days, interval.getStart().getHourOfDay(),
          interval.toPeriod().toStandardHours().getHours() + 1);
    }
    else if (resolution == AggregateCountResolution.day) {
      DateTime startDay = new DateTime(c.dayOfYear().roundFloor(start.getMillis()));
      DateTime endDay = new DateTime(c.dayOfYear().roundFloor(end.plusDays(1).getMillis()));
      int nDays = Days.daysBetween(startDay, endDay).getDays();
      DateTime cursor = new DateTime(c.year().roundFloor(interval.getStartMillis()));
      List<long[]> yearDays = new ArrayList<long[]>();
      DateTime endYear = new DateTime(c.year().roundCeiling(end.getMillis()));

      while (cursor.isBefore(endYear)) {
        long[] dayCounts = dayCountsByYear.get(cursor.getYear());
        if (dayCounts == null) {
          // Querying where we have no data
          dayCounts = new long[daysInYear(cursor.getYear())];
        }
        yearDays.add(dayCounts);
        cursor = cursor.plusYears(1);
      }

      counts = MetricUtils.concatArrays(yearDays, startDay.getDayOfYear() - 1, nDays);

    }
    else if (resolution == AggregateCountResolution.month) {
      DateTime startMonth = new DateTime(c.monthOfYear().roundFloor(interval.getStartMillis()));
      DateTime endMonth = new DateTime(c.monthOfYear().roundFloor(end.plusMonths(1).getMillis()));
      int nMonths = Months.monthsBetween(startMonth, endMonth).getMonths();
      DateTime cursor = new DateTime(c.year().roundFloor(interval.getStartMillis()));
      List<long[]> yearMonths = new ArrayList<long[]>();
      DateTime endYear = new DateTime(c.year().roundCeiling(end.getMillis()));

      while (cursor.isBefore(endYear)) {
        long[] monthCounts = monthCountsByYear.get(cursor.getYear());
        if (monthCounts == null) {
          monthCounts = new long[12];
        }
        yearMonths.add(monthCounts);
        cursor = cursor.plusYears(1);
      }

      counts = MetricUtils.concatArrays(yearMonths, startMonth.getMonthOfYear() - 1 , nMonths);
    }
    else if (resolution == AggregateCountResolution.year) {
      DateTime startYear = new DateTime(interval.getStart().getYear(), 1, 1, 0, 0);
      DateTime endYear   =  new DateTime(end.getYear() + 1, 1, 1, 0, 0);
      int nYears = Years.yearsBetween(startYear, endYear).getYears();
      counts = new long[nYears];

      for (int i = 0; i < nYears; i++) {
        long[] monthCounts = monthCountsByYear.get(startYear.plusYears(i).getYear());
        counts[i] = MetricUtils.sum(monthCounts);
      }

    }
    else {
      throw new IllegalStateException("Shouldn't happen. Unhandled resolution: " + resolution);
    }
    return new AggregateCount(getName(), interval, counts, resolution);
  }

  private static List<long[]> accumulateDayCounts(Map<Integer, long[]> fromDayCounts, DateTime start, DateTime end,
      int subSize) {
    List<long[]> days = new ArrayList<long[]>();
    Duration step = Duration.standardDays(1);
    long[] emptySubArray = new long[subSize];
    end = end.plusDays(1); // Need to account for an interval which crosses days

    for (DateTime now = start; now.isBefore(end); now = now.plus(step)) {
      int countsByDayKey = now.getYear() * 1000 + now.getDayOfYear();
      long[] dayCounts = fromDayCounts.get(countsByDayKey);

      if (dayCounts == null) {
        // Use an empty array if we don't have data
        dayCounts = emptySubArray;
      }
      days.add(dayCounts);
    }
    return days;
  }

  private int daysInYear(int year) {
    Duration d = new Duration(new DateTime(year, 1, 1, 0, 0), new DateTime(year + 1, 1, 1, 0, 0));
    return (int)d.getStandardDays();
  }

  synchronized long increment(long amount, DateTime dateTime) {
    int year = dateTime.getYear();
    int month = dateTime.getMonthOfYear();
    int day = dateTime.getDayOfYear();
    int hour = dateTime.getHourOfDay();
    int minute = dateTime.getMinuteOfDay();

    long[] monthCounts = monthCountsByYear.get(year);
    long[] dayCounts = dayCountsByYear.get(year);

    if (monthCounts == null) {
      monthCounts = new long[12];
      monthCountsByYear.put(year, monthCounts);
      dayCounts = new long[daysInYear(year)];
      dayCountsByYear.put(year, dayCounts);
    }

    int countsByDayKey = year * 1000 + day;
    long[] hourCounts = hourCountsByDay.get(countsByDayKey);

    if (hourCounts == null) {
      hourCounts = new long[24];
      hourCountsByDay.put(countsByDayKey, hourCounts);
    }

    long[] minuteCounts = minuteCountsByDay.get(countsByDayKey);

    if (minuteCounts == null) {
      minuteCounts = new long[60 * 24];
      minuteCountsByDay.put(countsByDayKey, minuteCounts);
    }

    minuteCounts[minute] += amount;
    monthCounts[month-1] += amount;
    dayCounts[day-1] += amount;
    hourCounts[hour] += amount;

    return increment(amount);
  }

}
TOP

Related Classes of org.springframework.xd.analytics.metrics.memory.InMemoryAggregateCounter

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.