001package org.javasimon.callback.timeline;
002
003import org.javasimon.Split;
004import org.javasimon.Stopwatch;
005import org.javasimon.clock.SimonClock;
006
007/**
008 * Timeline for Stopwatches, historicize {@link Stopwatch} state on a rolling period of time.
009 *
010 * @author gerald
011 */
012public final class StopwatchTimeline extends Timeline<StopwatchTimeRange> {
013
014        /**
015         * Main constructor.
016         *
017         * @param capacity Number of time range.
018         * @param timeRangeWidth Width of each time range
019         */
020        public StopwatchTimeline(int capacity, long timeRangeWidth) {
021                super(capacity, timeRangeWidth);
022        }
023
024        /**
025         * Produces a {@link StopwatchTimeRange} object.
026         *
027         * @param startTimestamp Range beginning
028         * @param endTimestamp Range ending
029         * @return {@link StopwatchTimeRange} object
030         */
031        @Override
032        protected StopwatchTimeRange createTimeRange(long startTimestamp, long endTimestamp) {
033                return new StopwatchTimeRange(startTimestamp, endTimestamp);
034        }
035
036        /**
037         * Main method used to insert the split on the timeline: <ol>
038         * <li>Split start is used to determine in which time-range it should be split. A new time range may be created if needed.</li>
039         * <li>Split duration is added to time range statistics.
040         * </ol>
041         * The split might be drop if it's too old.
042         *
043         * @param split Split
044         */
045        public void addSplit(Split split) {
046                final long timestamp = split.getStartMillis();
047                StopwatchTimeRange timeRange;
048                synchronized (this) {
049                        timeRange = getOrCreateTimeRange(timestamp);
050                }
051                if (timeRange != null) {
052                        //noinspection SynchronizationOnLocalVariableOrMethodParameter
053                        synchronized (timeRange) {
054                                timeRange.addSplit(timestamp, split.runningFor());
055                        }
056                }
057        }
058
059        /**
060         * Take a snapshot of the timeline.
061         *
062         * @return Timeline sample
063         */
064        @Override
065        public TimelineSample<StopwatchTimeRange> sample() {
066                StopwatchTimeRange[] timeRangesCopy;
067                synchronized (this) {
068                        timeRangesCopy = timeRanges.toArray(new StopwatchTimeRange[timeRanges.size()]);
069                }
070                // TODO sample each time-range by making a copy of it
071                return new TimelineSample<>(timeRanges.getCapacity(), timeRangeWidth * SimonClock.NANOS_IN_MILLIS, timeRangesCopy);
072        }
073}