Package org.perf4j.helpers

Source Code of org.perf4j.helpers.GroupingStatisticsIterator

/* Copyright (c) 2008-2009 HomeAway, Inc.
* All rights reserved.  http://www.perf4j.org
*
* 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.perf4j.helpers;

import org.perf4j.GroupedTimingStatistics;
import org.perf4j.StopWatch;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
* This Iterator wraps a {@link StopWatchLogIterator} to return a single {@link GroupedTimingStatistics} object for
* each time slice detected. Thus, this iterator is a "gearing" iterator - if there are on average 100 StopWatches
* logged during each time slice, the underlying StopWatchLogIterator will return 100 StopWatches for each single
* GroupedTimingStatistics object returned by this Iterator.
* <p/>
* Note that it's assumed that the StopWatch Iterator is ordered according to start time. If this is not true, then
* this class will create GroupedTimingStatistics that may reflect StopWatch data from a previous time slice.
*
* @author Alex Devine
*/
public class
        GroupingStatisticsIterator implements Iterator<GroupedTimingStatistics> {
    /**
     * The underlying StopWatch iterator
     */
    private Iterator<StopWatch> stopWatchIterator;
    /**
     * The length of each time slice, in milliseconds.
     */
    private long timeSlice;
    /**
     * Whether or not entries for "rollup" tags should be created in each GroupedTimingStatistics returned.
     */
    private boolean createRollupStatistics;

    /**
     * This hasNext is really a tri-state var - null indicates I don't know if there's a next one or not.
     */
    private Boolean hasNext = null;
    /**
     * The next GroupedTimingStatistics to be returned.
     */
    private GroupedTimingStatistics nextGroupedTimingStatistics = null;
    /**
     * Keeps track of the CURRENT GroupedTimingStatistics while we iterate over the underlying StopWatches
     */
    private GroupedTimingStatistics currentGroupedTimingStatistics = new GroupedTimingStatistics();
    /**
     * The end time, in milliseconds since the epoch, of the next time slice.
     */
    private long nextTimeSliceEndTime = 0L;

    /**
     * Creates a GroupingStatisticsIterator that groups StopWatch instances pulled from the specified
     * stopWatchIterator into GroupedTimingStatistics. A timeslice of 30 seconds is used and rollup statistics are not
     * created.
     *
     * @param stopWatchIterator The StopWatch Iterator that provides the StopWatch instances. If stopWatchIterator
     *                          returns a null value, will check to see if a timeslice is over and return
     *                          GroupedTimingStatistics if necessary.
     */
    public GroupingStatisticsIterator(Iterator<StopWatch> stopWatchIterator) {
        this(stopWatchIterator, 30000L, false);
    }

    /**
     * Creates a GroupingStatisticsIterator that groups StopWatch instances pulled from the specified
     * stopWatchIterator into GroupedTimingStatistics.
     *
     * @param stopWatchIterator      The StopWatch Iterator that provides the StopWatch instances. If stopWatchIterator
     *                  returns a null value, will check to see if a timeslice is over and return
     *                  GroupedTimingStatistics if necessary.
     * @param timeSlice              The length of each time slice, in milliseconds.
     * @param createRollupStatistics Whether or not entries for "rollup" tags should be created
     */
    public GroupingStatisticsIterator(Iterator<StopWatch> stopWatchIterator,
                                      long timeSlice,
                                      boolean createRollupStatistics) {
        this.stopWatchIterator = stopWatchIterator;
        this.timeSlice = timeSlice;
        this.createRollupStatistics = createRollupStatistics;
        this.currentGroupedTimingStatistics.setCreateRollupStatistics(createRollupStatistics);
    }

    public boolean hasNext() {
        //if I don't know the state of next, pull the next statistics to determine the state of next
        if (hasNext == null) {
            nextGroupedTimingStatistics = getNext();
            hasNext = (nextGroupedTimingStatistics != null);
        }
        return hasNext;
    }

    public GroupedTimingStatistics next() {
        //if I already determined I don't have a next, throw an exception
        if (Boolean.FALSE.equals(hasNext)) {
            throw new NoSuchElementException();
        }

        //if I don't know what to return yet, find out - note this only happens if I call next() before a call
        //to hasNext().
        if (nextGroupedTimingStatistics == null) {
            nextGroupedTimingStatistics = getNext();

            //if there's still nothing I'm done
            if (nextGroupedTimingStatistics == null) {
                hasNext = false;
                throw new NoSuchElementException();
            }
        }

        //before I return, clear the state of the variables used to determine the next value.
        GroupedTimingStatistics retVal = nextGroupedTimingStatistics;
        hasNext = null;
        nextGroupedTimingStatistics = null;
        return retVal;
    }

    /**
     * Remove is not supported.
     *
     * @throws UnsupportedOperationException Always thrown.
     */
    public void remove() {
        throw new UnsupportedOperationException();
    }

    /**
     * Helper method runs over the StopWatch Iterator to group the StopWatches into GroupedTimingStatistics.
     *
     * @return The next GroupedTimingStatistics from the underlying StopWatch Iterator, or null if there are no
     *         StopWatch instances left.
     */
    private GroupedTimingStatistics getNext() {
        while (stopWatchIterator.hasNext()) {
            StopWatch stopWatch = stopWatchIterator.next();
           
            // if stopwatch is null, then the timeslice might be over (use current time)
            long startTime = stopWatch == null ? System.currentTimeMillis() : stopWatch.getStartTime();
           
            //the first time we pull a stop watch we need to set the first end time
            if (nextTimeSliceEndTime == 0L) {
                nextTimeSliceEndTime = ((startTime / timeSlice) * timeSlice) + timeSlice;
            }

            if (startTime >= nextTimeSliceEndTime) {
                //then we're over a new time boundary, so update the current timing statistics and return it.
                currentGroupedTimingStatistics.setStartTime(nextTimeSliceEndTime - timeSlice);
                currentGroupedTimingStatistics.setStopTime(nextTimeSliceEndTime);
                GroupedTimingStatistics retVal = currentGroupedTimingStatistics;

                //set the state for the next slice
                currentGroupedTimingStatistics = new GroupedTimingStatistics();
                currentGroupedTimingStatistics.setCreateRollupStatistics(createRollupStatistics);
                if (stopWatch != null) {
                  // only add if we got a new stopwatch, not if timeslice just expired
                  currentGroupedTimingStatistics.addStopWatch(stopWatch);
                }               
                nextTimeSliceEndTime = ((startTime / timeSlice) * timeSlice) + timeSlice;
                return retVal;
            } else if (stopWatch != null) {
                currentGroupedTimingStatistics.addStopWatch(stopWatch);
            }
        }

        //if here then there are no more stopwatches left, so clean up the last batch
        if (!currentGroupedTimingStatistics.getStatisticsByTag().isEmpty()) {
            currentGroupedTimingStatistics.setStartTime(nextTimeSliceEndTime - timeSlice);
            currentGroupedTimingStatistics.setStopTime(nextTimeSliceEndTime);
            GroupedTimingStatistics retVal = currentGroupedTimingStatistics;

            //create an empty GroupedTimingStatistics so we know to return null in the next call to this method.
            currentGroupedTimingStatistics = new GroupedTimingStatistics();
            currentGroupedTimingStatistics.setCreateRollupStatistics(createRollupStatistics);

            return retVal;
        } else {
            //The StopWatch iterator is done and we already printed the last GroupedTimingStatistics batch
            return null;
        }
    }
}
TOP

Related Classes of org.perf4j.helpers.GroupingStatisticsIterator

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.