diff --git a/querier.go b/querier.go index 68c35a918..523a67398 100644 --- a/querier.go +++ b/querier.go @@ -15,7 +15,6 @@ package tsdb import ( "fmt" - "sort" "strings" "github.com/prometheus/tsdb/chunks" @@ -671,25 +670,13 @@ func (it *chunkSeriesIterator) Seek(t int64) (ok bool) { t = it.mint } - // Only do binary search forward to stay in line with other iterators - // that can only move forward. - x := sort.Search(len(it.chunks[it.i:]), func(i int) bool { - return it.chunks[it.i+i].MinTime >= t - }) - x += it.i - - // If the timestamp was not found, it might be in the last chunk. - if x == len(it.chunks) { - x-- - - // Go to previous chunk if the chunk doesn't exactly start with t. - // If we are already at the first chunk, we use it as it's the best we have. - } else if x > 0 && it.chunks[x].MinTime > t { - x-- + for ; it.chunks[it.i].MaxTime < t; it.i++ { + if it.i == len(it.chunks)-1 { + return false + } } - it.i = x - it.cur = it.chunks[x].Chunk.Iterator() + it.cur = it.chunks[it.i].Chunk.Iterator() if len(it.intervals) > 0 { it.cur = &deletedIterator{it: it.cur, intervals: it.intervals} } diff --git a/querier_test.go b/querier_test.go index ed504da39..572a281e8 100644 --- a/querier_test.go +++ b/querier_test.go @@ -1028,7 +1028,7 @@ func TestSeriesIterator(t *testing.T) { } // Regression for: https://github.com/prometheus/tsdb/pull/97 -func TestCSIteratorDoubleSeek(t *testing.T) { +func TestChunkSeriesIterator_DoubleSeek(t *testing.T) { chkMetas := []*ChunkMeta{ chunkFromSamples([]sample{}), chunkFromSamples([]sample{{1, 1}, {2, 2}, {3, 3}}), @@ -1043,6 +1043,28 @@ func TestCSIteratorDoubleSeek(t *testing.T) { require.Equal(t, float64(2), v) } +// Regression when seeked chunks were still found via binary search and we always +// skipped to the end when seeking a value in the current chunk. +func TestChunkSeriesIterator_SeekInCurrentChunk(t *testing.T) { + metas := []*ChunkMeta{ + chunkFromSamples([]sample{}), + chunkFromSamples([]sample{{1, 2}, {3, 4}, {5, 6}, {7, 8}}), + chunkFromSamples([]sample{}), + } + + it := newChunkSeriesIterator(metas, nil, 1, 7) + + require.True(t, it.Next()) + ts, v := it.At() + require.Equal(t, int64(1), ts) + require.Equal(t, float64(2), v) + + require.True(t, it.Seek(4)) + ts, v = it.At() + require.Equal(t, int64(5), ts) + require.Equal(t, float64(6), v) +} + func TestPopulatedCSReturnsValidChunkSlice(t *testing.T) { lbls := []labels.Labels{labels.New(labels.Label{"a", "b"})} chunkMetas := [][]*ChunkMeta{