1 /* ============================================================
2 * JRobin : Pure java implementation of RRDTool's functionality
3 * ============================================================
4 *
5 * Project Info: http://www.jrobin.org
6 * Project Lead: Sasa Markovic (saxon@jrobin.org);
7 *
8 * (C) Copyright 2003-2005, by Sasa Markovic.
9 *
10 * Developers: Sasa Markovic (saxon@jrobin.org)
11 *
12 *
13 * This library is free software; you can redistribute it and/or modify it under the terms
14 * of the GNU Lesser General Public License as published by the Free Software Foundation;
15 * either version 2.1 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 * See the GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License along with this
22 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23 * Boston, MA 02111-1307, USA.
24 */
25
26 package org.jrobin.data;
27
28 import org.jrobin.core.ConsolFuns;
29 import org.jrobin.core.Util;
30
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.List;
34
35 class Aggregator implements ConsolFuns {
36 private long timestamps[], step;
37 private double[] values;
38
39 Aggregator(long[] timestamps, double[] values) {
40 assert timestamps.length == values.length: "Incompatible timestamps/values arrays (unequal lengths)";
41 assert timestamps.length >= 2: "At least two timestamps must be supplied";
42 this.timestamps = timestamps;
43 this.values = values;
44 this.step = timestamps[1] - timestamps[0];
45 }
46
47 Aggregates getAggregates(long tStart, long tEnd) {
48 Aggregates agg = new Aggregates();
49 long totalSeconds = 0;
50 boolean firstFound = false;
51 for (int i = 0; i < timestamps.length; i++) {
52 long left = Math.max(timestamps[i] - step, tStart);
53 long right = Math.min(timestamps[i], tEnd);
54 long delta = right - left;
55
56 // delta is only > 0 when the timestamp for a given buck is within the range of tStart and tEnd
57 if (delta > 0) {
58 double value = values[i];
59 agg.min = Util.min(agg.min, value);
60 agg.max = Util.max(agg.max, value);
61 if (!firstFound) {
62 agg.first = value;
63 firstFound = true;
64 agg.last = value;
65 } else if (delta >= step) { // an entire bucket is included in this range
66 agg.last = value;
67
68 /*
69 * Algorithmically, we're only updating last if it's either the first
70 * bucket encountered, or it's a "full" bucket.
71
72 if ( !isInRange(tEnd, left, right) ||
73 (isInRange(tEnd, left, right) && !Double.isNaN(value))
74 ) {
75 agg.last = value;
76 }
77 */
78
79 }
80 if (!Double.isNaN(value)) {
81 agg.total = Util.sum(agg.total, delta * value);
82 totalSeconds += delta;
83 }
84 }
85 }
86 agg.average = totalSeconds > 0 ? (agg.total / totalSeconds) : Double.NaN;
87 return agg;
88 }
89
90 double getPercentile(long tStart, long tEnd, double percentile) {
91 List<Double> valueList = new ArrayList<Double>();
92 // create a list of included datasource values (different from NaN)
93 for (int i = 0; i < timestamps.length; i++) {
94 long left = Math.max(timestamps[i] - step, tStart);
95 long right = Math.min(timestamps[i], tEnd);
96 if (right > left && !Double.isNaN(values[i])) {
97 valueList.add(values[i]);
98 }
99 }
100 // create an array to work with
101 int count = valueList.size();
102 if (count > 1) {
103 double[] valuesCopy = new double[count];
104 for (int i = 0; i < count; i++) {
105 valuesCopy[i] = valueList.get(i);
106 }
107 // sort array
108 Arrays.sort(valuesCopy);
109 // skip top (100% - percentile) values
110 double topPercentile = (100.0 - percentile) / 100.0;
111 count -= (int) Math.ceil(count * topPercentile);
112 // if we have anything left...
113 if (count > 0) {
114 return valuesCopy[count - 1];
115 }
116 }
117 // not enough data available
118 return Double.NaN;
119 }
120 }
121