Fix interval op special case.

In the case that a getValuesAtIntervalOp's ExtractSamples() is called
with a current time after the last chunk time, we return without
extracting any further values beyond the last one in the chunk
(correct), but also without advancing the op's time (incorrect). This
leads to an infinite loop in renderView(), since the op is called
repeatedly without ever being advanced and consumed.

This adds handling for this special case. When detecting this case, we
immediately set the op to be consumed, since we would always get a value
after the current time passed in if there was one.

Change-Id: Id99149e07b5188d655331382b8b6a461b677005c
This commit is contained in:
Julius Volz 2014-03-25 19:07:27 +01:00
parent 257b720e87
commit 7a577b86b7
2 changed files with 73 additions and 0 deletions

View file

@ -203,7 +203,14 @@ func (g *getValuesAtIntervalOp) ExtractSamples(in Values) (out Values) {
if len(in) == 0 {
return
}
lastChunkTime := in[len(in)-1].Timestamp
if g.current.After(lastChunkTime) {
g.current = g.through.Add(clientmodel.MinimumTick)
return Values{in[len(in)-1]}
}
for len(in) > 0 {
out = append(out, extractValuesAroundTime(g.current, in)...)
if g.current.After(lastChunkTime) {

View file

@ -524,6 +524,72 @@ func testMakeView(t test.Tester, flushToDisk bool) {
// extracted value at the end of the second chunk.
diskOnly: true,
},
// Single sample, getValuesAtIntervalOp starting after the sample.
{
data: clientmodel.Samples{
{
Metric: metric,
Value: 0,
Timestamp: instant,
},
},
in: in{
atInterval: []getValuesAtIntervalOp{
{
getValuesAlongRangeOp: getValuesAlongRangeOp{
baseOp: baseOp{current: instant.Add(time.Second)},
through: instant.Add(time.Second * 2),
},
interval: time.Second,
},
},
},
out: out{
atInterval: []Values{
{
{
Timestamp: instant,
Value: 0,
},
},
},
},
},
// Single sample, getValuesAtIntervalOp starting before the sample.
{
data: clientmodel.Samples{
{
Metric: metric,
Value: 0,
Timestamp: instant.Add(time.Second),
},
},
in: in{
atInterval: []getValuesAtIntervalOp{
{
getValuesAlongRangeOp: getValuesAlongRangeOp{
baseOp: baseOp{current: instant},
through: instant.Add(time.Second * 2),
},
interval: time.Second,
},
},
},
out: out{
atInterval: []Values{
{
{
Timestamp: instant.Add(time.Second),
Value: 0,
},
{
Timestamp: instant.Add(time.Second),
Value: 0,
},
},
},
},
},
}
)