Add data extraction methods to operator types.

pull/84/head
Julius Volz 2013-03-13 14:05:58 -07:00 committed by Matt T. Proud
parent 1d5df867d1
commit 12a8863582
3 changed files with 246 additions and 174 deletions

View File

@ -15,6 +15,7 @@ package metric
import (
"fmt"
"github.com/prometheus/prometheus/model"
"math"
"sort"
"time"
@ -24,6 +25,11 @@ import (
type op interface {
// The time at which this operation starts.
StartsAt() time.Time
// Extract samples from stream of values and advance operation time.
ExtractSamples(in []model.SamplePair) (out []model.SamplePair)
// Get current operation time or nil if no subsequent work associated with
// this operator remains.
CurrentTime() *time.Time
}
// Provides a sortable collection of operations.
@ -43,7 +49,8 @@ func (o ops) Swap(i, j int) {
// Encapsulates getting values at or adjacent to a specific time.
type getValuesAtTimeOp struct {
time time.Time
time time.Time
consumed bool
}
func (o getValuesAtTimeOp) String() string {
@ -54,6 +61,33 @@ func (g getValuesAtTimeOp) StartsAt() time.Time {
return g.time
}
func (g *getValuesAtTimeOp) ExtractSamples(in []model.SamplePair) (out []model.SamplePair) {
extractValuesAroundTime(g.time, in, out)
g.consumed = true
return
}
func extractValuesAroundTime(t time.Time, in []model.SamplePair, out []model.SamplePair) {
i := sort.Search(len(in), func(i int) bool {
return in[i].Timestamp.After(t)
})
if i == len(in) {
panic("Searched past end of input")
}
if i == 0 {
out = append(out, in[0:1]...)
} else {
out = append(out, in[i-1:i+1]...)
}
}
func (g getValuesAtTimeOp) CurrentTime() (currentTime *time.Time) {
if !g.consumed {
currentTime = &g.time
}
return
}
// Encapsulates getting values at a given interval over a duration.
type getValuesAtIntervalOp struct {
from time.Time
@ -73,6 +107,28 @@ func (g getValuesAtIntervalOp) Through() time.Time {
return g.through
}
func (g *getValuesAtIntervalOp) ExtractSamples(in []model.SamplePair) (out []model.SamplePair) {
lastChunkTime := in[len(in)-1].Timestamp
for {
if g.from.After(lastChunkTime) {
break
}
if g.from.After(g.through) {
break
}
extractValuesAroundTime(g.from, in, out)
g.from = g.from.Add(g.interval)
}
return
}
func (g getValuesAtIntervalOp) CurrentTime() (currentTime *time.Time) {
if g.from.After(g.through) {
return
}
return &g.from
}
type getValuesAlongRangeOp struct {
from time.Time
through time.Time
@ -90,8 +146,21 @@ func (g getValuesAlongRangeOp) Through() time.Time {
return g.through
}
func (g *getValuesAlongRangeOp) ExtractSamples(in []model.SamplePair) (out []model.SamplePair) {
lastChunkTime := in[len(in)-1].Timestamp
g.from = lastChunkTime.Add(time.Duration(1))
return in
}
func (g getValuesAlongRangeOp) CurrentTime() (currentTime *time.Time) {
if g.from.After(g.through) {
return
}
return &g.from
}
// Provides a collection of getMetricRangeOperation.
type getMetricRangeOperations []getValuesAlongRangeOp
type getMetricRangeOperations []*getValuesAlongRangeOp
func (s getMetricRangeOperations) Len() int {
return len(s)
@ -136,7 +205,7 @@ func (o durationOperators) Swap(i, j int) {
}
// Contains getValuesAtIntervalOp operations.
type getValuesAtIntervalOps []getValuesAtIntervalOp
type getValuesAtIntervalOps []*getValuesAtIntervalOp
func (s getValuesAtIntervalOps) Len() int {
return len(s)
@ -177,7 +246,7 @@ func collectIntervals(ops ops) (intervals map[time.Duration]getValuesAtIntervalO
for _, operation := range ops {
switch t := operation.(type) {
case getValuesAtIntervalOp:
case *getValuesAtIntervalOp:
operations, _ := intervals[t.interval]
operations = append(operations, t)
@ -196,7 +265,7 @@ func collectIntervals(ops ops) (intervals map[time.Duration]getValuesAtIntervalO
func collectRanges(ops ops) (ranges getMetricRangeOperations) {
for _, operation := range ops {
switch t := operation.(type) {
case getValuesAlongRangeOp:
case *getValuesAlongRangeOp:
ranges = append(ranges, t)
}
}
@ -223,13 +292,13 @@ func optimizeForward(pending ops) (out ops) {
pending = pending[1:len(pending)]
switch t := firstOperation.(type) {
case getValuesAtTimeOp:
case *getValuesAtTimeOp:
out = ops{firstOperation}
tail := optimizeForward(pending)
return append(out, tail...)
case getValuesAtIntervalOp:
case *getValuesAtIntervalOp:
// If the last value was a scan at a given frequency along an interval,
// several optimizations may exist.
for _, peekOperation := range pending {
@ -239,11 +308,11 @@ func optimizeForward(pending ops) (out ops) {
// If the type is not a range request, we can't do anything.
switch next := peekOperation.(type) {
case getValuesAlongRangeOp:
case *getValuesAlongRangeOp:
if !next.Through().After(t.Through()) {
var (
before = getValuesAtIntervalOp(t)
after = getValuesAtIntervalOp(t)
before = getValuesAtIntervalOp(*t)
after = getValuesAtIntervalOp(*t)
)
before.through = next.from
@ -263,7 +332,7 @@ func optimizeForward(pending ops) (out ops) {
}
}
pending = append(ops{before, after}, pending...)
pending = append(ops{&before, &after}, pending...)
sort.Sort(pending)
return optimizeForward(pending)
@ -271,7 +340,7 @@ func optimizeForward(pending ops) (out ops) {
}
}
case getValuesAlongRangeOp:
case *getValuesAlongRangeOp:
for _, peekOperation := range pending {
if peekOperation.StartsAt().After(t.Through()) {
break
@ -279,10 +348,10 @@ func optimizeForward(pending ops) (out ops) {
switch next := peekOperation.(type) {
// All values at a specific time may be elided into the range query.
case getValuesAtTimeOp:
case *getValuesAtTimeOp:
pending = pending[1:len(pending)]
continue
case getValuesAlongRangeOp:
case *getValuesAlongRangeOp:
// Range queries should be concatenated if they overlap.
pending = pending[1:len(pending)]
@ -298,7 +367,7 @@ func optimizeForward(pending ops) (out ops) {
return optimizeForward(pending)
}
case getValuesAtIntervalOp:
case *getValuesAtIntervalOp:
pending = pending[1:len(pending)]
if next.through.After(t.Through()) {
@ -317,9 +386,12 @@ func optimizeForward(pending ops) (out ops) {
}
}
}
default:
panic("unknown operation type")
}
}
default:
panic("unknown operation type")
}
// Strictly needed?
@ -394,7 +466,7 @@ func optimizeTimeGroup(group ops) (out ops) {
} else if !containsRange && containsInterval {
intervalOperations := getValuesAtIntervalOps{}
for _, o := range greediestIntervals {
intervalOperations = append(intervalOperations, o.(getValuesAtIntervalOp))
intervalOperations = append(intervalOperations, o.(*getValuesAtIntervalOp))
}
sort.Sort(frequencySorter{intervalOperations})
@ -412,7 +484,7 @@ func optimizeTimeGroup(group ops) (out ops) {
// The range operation does not exceed interval. Leave a snippet of
// interval.
var (
truncated = op.(getValuesAtIntervalOp)
truncated = op.(*getValuesAtIntervalOp)
newIntervalOperation getValuesAtIntervalOp
// Refactor
remainingSlice = greediestRange.Through().Sub(greediestRange.StartsAt()) / time.Second
@ -425,7 +497,7 @@ func optimizeTimeGroup(group ops) (out ops) {
newIntervalOperation.through = truncated.Through()
// Added back to the pending because additional curation could be
// necessary.
out = append(out, newIntervalOperation)
out = append(out, &newIntervalOperation)
}
} else {
// Operation is OK as-is.

View File

@ -36,12 +36,12 @@ func testOptimizeTimeGroups(t test.Tester) {
// Single time; return single time.
{
in: ops{
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant,
},
},
out: ops{
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant,
},
},
@ -49,13 +49,13 @@ func testOptimizeTimeGroups(t test.Tester) {
// Single range; return single range.
{
in: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
},
@ -64,14 +64,14 @@ func testOptimizeTimeGroups(t test.Tester) {
// Single interval; return single interval.
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
},
out: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
@ -81,15 +81,15 @@ func testOptimizeTimeGroups(t test.Tester) {
// Duplicate points; return single point.
{
in: ops{
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant,
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant,
},
},
out: ops{
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant,
},
},
@ -97,17 +97,17 @@ func testOptimizeTimeGroups(t test.Tester) {
// Duplicate ranges; return single range.
{
in: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
},
@ -116,19 +116,19 @@ func testOptimizeTimeGroups(t test.Tester) {
// Duplicate intervals; return single interval.
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
},
out: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
@ -138,19 +138,19 @@ func testOptimizeTimeGroups(t test.Tester) {
// Subordinate interval; return master.
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 5,
},
},
out: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 5,
@ -160,17 +160,17 @@ func testOptimizeTimeGroups(t test.Tester) {
// Subordinate range; return master.
{
in: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
},
@ -179,24 +179,24 @@ func testOptimizeTimeGroups(t test.Tester) {
// Equal range with different interval; return both.
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 10,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
},
out: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 10,
@ -206,34 +206,34 @@ func testOptimizeTimeGroups(t test.Tester) {
// Different range with different interval; return best.
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 10,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 10,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 5,
},
},
out: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 5,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 10,
@ -243,27 +243,27 @@ func testOptimizeTimeGroups(t test.Tester) {
// Include Truncated Intervals with Range.
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 10,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 10,
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(30 * time.Second),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(30 * time.Second),
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant.Add(30 * time.Second),
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 10,
@ -273,22 +273,22 @@ func testOptimizeTimeGroups(t test.Tester) {
// Compacted Forward Truncation
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(3 * time.Minute),
interval: time.Second * 10,
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant.Add(2 * time.Minute),
through: testInstant.Add(3 * time.Minute),
interval: time.Second * 10,
@ -298,22 +298,22 @@ func testOptimizeTimeGroups(t test.Tester) {
// Compacted Tail Truncation
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(3 * time.Minute),
interval: time.Second * 10,
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant.Add(2 * time.Minute),
through: testInstant.Add(3 * time.Minute),
interval: time.Second * 10,
@ -335,9 +335,9 @@ func testOptimizeTimeGroups(t test.Tester) {
for j, op := range out {
if actual, ok := op.(getValuesAtTimeOp); ok {
if actual, ok := op.(*getValuesAtTimeOp); ok {
if expected, ok := scenario.out[j].(getValuesAtTimeOp); ok {
if expected, ok := scenario.out[j].(*getValuesAtTimeOp); ok {
if expected.time.Unix() != actual.time.Unix() {
t.Fatalf("%d.%d. expected time %s, got %s", i, j, expected.time, actual.time)
}
@ -345,9 +345,9 @@ func testOptimizeTimeGroups(t test.Tester) {
t.Fatalf("%d.%d. expected getValuesAtTimeOp, got %s", i, j, actual)
}
} else if actual, ok := op.(getValuesAtIntervalOp); ok {
} else if actual, ok := op.(*getValuesAtIntervalOp); ok {
if expected, ok := scenario.out[j].(getValuesAtIntervalOp); ok {
if expected, ok := scenario.out[j].(*getValuesAtIntervalOp); ok {
// Shaving off nanoseconds.
if expected.from.Unix() != actual.from.Unix() {
t.Fatalf("%d.%d. expected from %s, got %s", i, j, expected.from, actual.from)
@ -362,9 +362,9 @@ func testOptimizeTimeGroups(t test.Tester) {
t.Fatalf("%d.%d. expected getValuesAtIntervalOp, got %s", i, j, actual)
}
} else if actual, ok := op.(getValuesAlongRangeOp); ok {
} else if actual, ok := op.(*getValuesAlongRangeOp); ok {
if expected, ok := scenario.out[j].(getValuesAlongRangeOp); ok {
if expected, ok := scenario.out[j].(*getValuesAlongRangeOp); ok {
if expected.from.Unix() != actual.from.Unix() {
t.Fatalf("%d.%d. expected from %s, got %s", i, j, expected.from, actual.from)
}
@ -402,18 +402,18 @@ func testOptimizeForward(t test.Tester) {
// Compact Interval with Subservient Range
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant.Add(1 * time.Minute),
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 10,
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(3 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(3 * time.Minute),
},
@ -422,17 +422,17 @@ func testOptimizeForward(t test.Tester) {
// Compact Ranges with Subservient Range
{
in: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant.Add(1 * time.Minute),
through: testInstant.Add(2 * time.Minute),
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(3 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(3 * time.Minute),
},
@ -441,27 +441,27 @@ func testOptimizeForward(t test.Tester) {
// Carving Middle Elements
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(5 * time.Minute),
interval: time.Second * 10,
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant.Add(2 * time.Minute),
through: testInstant.Add(3 * time.Minute),
},
},
out: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 10,
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant.Add(2 * time.Minute),
through: testInstant.Add(3 * time.Minute),
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
// Since the range operation consumes Now() + 3 Minutes, we start
// an additional ten seconds later.
from: testInstant.Add(3 * time.Minute).Add(10 * time.Second),
@ -475,44 +475,44 @@ func testOptimizeForward(t test.Tester) {
// work.
{
in: ops{
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(1 * time.Minute).Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(2 * time.Minute).Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(3 * time.Minute).Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(4 * time.Minute).Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(5 * time.Minute).Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(6 * time.Minute).Add(30 * time.Second),
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant.Add(1 * time.Minute),
through: testInstant.Add(5 * time.Minute),
},
},
out: ops{
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(30 * time.Second),
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant.Add(1 * time.Minute),
through: testInstant.Add(5 * time.Minute),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(5 * time.Minute).Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(6 * time.Minute).Add(30 * time.Second),
},
},
@ -532,9 +532,9 @@ func testOptimizeForward(t test.Tester) {
for j, op := range out {
if actual, ok := op.(getValuesAtTimeOp); ok {
if actual, ok := op.(*getValuesAtTimeOp); ok {
if expected, ok := scenario.out[j].(getValuesAtTimeOp); ok {
if expected, ok := scenario.out[j].(*getValuesAtTimeOp); ok {
if expected.time.Unix() != actual.time.Unix() {
t.Fatalf("%d.%d. expected time %s, got %s", i, j, expected.time, actual.time)
}
@ -542,9 +542,9 @@ func testOptimizeForward(t test.Tester) {
t.Fatalf("%d.%d. expected getValuesAtTimeOp, got %s", i, j, actual)
}
} else if actual, ok := op.(getValuesAtIntervalOp); ok {
} else if actual, ok := op.(*getValuesAtIntervalOp); ok {
if expected, ok := scenario.out[j].(getValuesAtIntervalOp); ok {
if expected, ok := scenario.out[j].(*getValuesAtIntervalOp); ok {
// Shaving off nanoseconds.
if expected.from.Unix() != actual.from.Unix() {
t.Fatalf("%d.%d. expected from %s, got %s", i, j, expected.from, actual.from)
@ -559,9 +559,9 @@ func testOptimizeForward(t test.Tester) {
t.Fatalf("%d.%d. expected getValuesAtIntervalOp, got %s", i, j, actual)
}
} else if actual, ok := op.(getValuesAlongRangeOp); ok {
} else if actual, ok := op.(*getValuesAlongRangeOp); ok {
if expected, ok := scenario.out[j].(getValuesAlongRangeOp); ok {
if expected, ok := scenario.out[j].(*getValuesAlongRangeOp); ok {
if expected.from.Unix() != actual.from.Unix() {
t.Fatalf("%d.%d. expected from %s, got %s", i, j, expected.from, actual.from)
}
@ -604,12 +604,12 @@ func testOptimize(t test.Tester) {
// Single time; return single time.
{
in: ops{
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant,
},
},
out: ops{
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant,
},
},
@ -617,13 +617,13 @@ func testOptimize(t test.Tester) {
// Single range; return single range.
{
in: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
},
@ -632,14 +632,14 @@ func testOptimize(t test.Tester) {
// Single interval; return single interval.
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
},
out: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
@ -649,15 +649,15 @@ func testOptimize(t test.Tester) {
// Duplicate points; return single point.
{
in: ops{
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant,
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant,
},
},
out: ops{
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant,
},
},
@ -665,17 +665,17 @@ func testOptimize(t test.Tester) {
// Duplicate ranges; return single range.
{
in: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
},
@ -684,19 +684,19 @@ func testOptimize(t test.Tester) {
// Duplicate intervals; return single interval.
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
},
out: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
@ -706,19 +706,19 @@ func testOptimize(t test.Tester) {
// Subordinate interval; return master.
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 5,
},
},
out: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 5,
@ -728,17 +728,17 @@ func testOptimize(t test.Tester) {
// Subordinate range; return master.
{
in: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
},
@ -747,24 +747,24 @@ func testOptimize(t test.Tester) {
// Equal range with different interval; return both.
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 10,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
},
out: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 10,
@ -774,34 +774,34 @@ func testOptimize(t test.Tester) {
// Different range with different interval; return best.
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 10,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 10,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 5,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 5,
},
},
out: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 5,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 10,
@ -811,27 +811,27 @@ func testOptimize(t test.Tester) {
// Include Truncated Intervals with Range.
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 10,
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(1 * time.Minute),
interval: time.Second * 10,
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(30 * time.Second),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(30 * time.Second),
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant.Add(30 * time.Second),
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 10,
@ -841,22 +841,22 @@ func testOptimize(t test.Tester) {
// Compacted Forward Truncation
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(3 * time.Minute),
interval: time.Second * 10,
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant.Add(2 * time.Minute),
through: testInstant.Add(3 * time.Minute),
interval: time.Second * 10,
@ -866,22 +866,22 @@ func testOptimize(t test.Tester) {
// Compacted Tail Truncation
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(3 * time.Minute),
interval: time.Second * 10,
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant.Add(2 * time.Minute),
through: testInstant.Add(3 * time.Minute),
interval: time.Second * 10,
@ -891,18 +891,18 @@ func testOptimize(t test.Tester) {
// Compact Interval with Subservient Range
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant.Add(1 * time.Minute),
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 10,
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(3 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(3 * time.Minute),
},
@ -911,17 +911,17 @@ func testOptimize(t test.Tester) {
// Compact Ranges with Subservient Range
{
in: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant.Add(1 * time.Minute),
through: testInstant.Add(2 * time.Minute),
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(3 * time.Minute),
},
},
out: ops{
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant,
through: testInstant.Add(3 * time.Minute),
},
@ -930,27 +930,27 @@ func testOptimize(t test.Tester) {
// Carving Middle Elements
{
in: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(5 * time.Minute),
interval: time.Second * 10,
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant.Add(2 * time.Minute),
through: testInstant.Add(3 * time.Minute),
},
},
out: ops{
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
from: testInstant,
through: testInstant.Add(2 * time.Minute),
interval: time.Second * 10,
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant.Add(2 * time.Minute),
through: testInstant.Add(3 * time.Minute),
},
getValuesAtIntervalOp{
&getValuesAtIntervalOp{
// Since the range operation consumes Now() + 3 Minutes, we start
// an additional ten seconds later.
from: testInstant.Add(3 * time.Minute).Add(10 * time.Second),
@ -964,44 +964,44 @@ func testOptimize(t test.Tester) {
// work.
{
in: ops{
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(1 * time.Minute).Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(2 * time.Minute).Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(3 * time.Minute).Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(4 * time.Minute).Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(5 * time.Minute).Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(6 * time.Minute).Add(30 * time.Second),
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant.Add(1 * time.Minute),
through: testInstant.Add(5 * time.Minute),
},
},
out: ops{
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(30 * time.Second),
},
getValuesAlongRangeOp{
&getValuesAlongRangeOp{
from: testInstant.Add(1 * time.Minute),
through: testInstant.Add(5 * time.Minute),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(5 * time.Minute).Add(30 * time.Second),
},
getValuesAtTimeOp{
&getValuesAtTimeOp{
time: testInstant.Add(6 * time.Minute).Add(30 * time.Second),
},
},
@ -1021,9 +1021,9 @@ func testOptimize(t test.Tester) {
for j, op := range out {
if actual, ok := op.(getValuesAtTimeOp); ok {
if actual, ok := op.(*getValuesAtTimeOp); ok {
if expected, ok := scenario.out[j].(getValuesAtTimeOp); ok {
if expected, ok := scenario.out[j].(*getValuesAtTimeOp); ok {
if expected.time.Unix() != actual.time.Unix() {
t.Fatalf("%d.%d. expected time %s, got %s", i, j, expected.time, actual.time)
}
@ -1031,9 +1031,9 @@ func testOptimize(t test.Tester) {
t.Fatalf("%d.%d. expected getValuesAtTimeOp, got %s", i, j, actual)
}
} else if actual, ok := op.(getValuesAtIntervalOp); ok {
} else if actual, ok := op.(*getValuesAtIntervalOp); ok {
if expected, ok := scenario.out[j].(getValuesAtIntervalOp); ok {
if expected, ok := scenario.out[j].(*getValuesAtIntervalOp); ok {
// Shaving off nanoseconds.
if expected.from.Unix() != actual.from.Unix() {
t.Fatalf("%d.%d. expected from %s, got %s", i, j, expected.from, actual.from)
@ -1048,9 +1048,9 @@ func testOptimize(t test.Tester) {
t.Fatalf("%d.%d. expected getValuesAtIntervalOp, got %s", i, j, actual)
}
} else if actual, ok := op.(getValuesAlongRangeOp); ok {
} else if actual, ok := op.(*getValuesAlongRangeOp); ok {
if expected, ok := scenario.out[j].(getValuesAlongRangeOp); ok {
if expected, ok := scenario.out[j].(*getValuesAlongRangeOp); ok {
if expected.from.Unix() != actual.from.Unix() {
t.Fatalf("%d.%d. expected from %s, got %s", i, j, expected.from, actual.from)
}

View File

@ -55,7 +55,7 @@ func NewViewRequestBuilder() viewRequestBuilder {
// match or the one or two values adjacent thereto.
func (v viewRequestBuilder) GetMetricAtTime(fingerprint model.Fingerprint, time time.Time) {
ops := v.operations[fingerprint]
ops = append(ops, getValuesAtTimeOp{
ops = append(ops, &getValuesAtTimeOp{
time: time,
})
v.operations[fingerprint] = ops
@ -66,7 +66,7 @@ func (v viewRequestBuilder) GetMetricAtTime(fingerprint model.Fingerprint, time
// for each point.
func (v viewRequestBuilder) GetMetricAtInterval(fingerprint model.Fingerprint, from, through time.Time, interval time.Duration) {
ops := v.operations[fingerprint]
ops = append(ops, getValuesAtIntervalOp{
ops = append(ops, &getValuesAtIntervalOp{
from: from,
through: through,
interval: interval,
@ -78,7 +78,7 @@ func (v viewRequestBuilder) GetMetricAtInterval(fingerprint model.Fingerprint, f
// From through Through.
func (v viewRequestBuilder) GetMetricRange(fingerprint model.Fingerprint, from, through time.Time) {
ops := v.operations[fingerprint]
ops = append(ops, getValuesAlongRangeOp{
ops = append(ops, &getValuesAlongRangeOp{
from: from,
through: through,
})