diff --git a/chunks/chunk.go b/chunks/chunk.go index 181693fae..4d298041e 100644 --- a/chunks/chunk.go +++ b/chunks/chunk.go @@ -69,6 +69,17 @@ type Iterator interface { Next() bool } +// NewNopIterator returns a new chunk iterator that does not hold any data. +func NewNopIterator() Iterator { + return nopIterator{} +} + +type nopIterator struct{} + +func (nopIterator) At() (int64, float64) { return 0, 0 } +func (nopIterator) Next() bool { return false } +func (nopIterator) Err() error { return nil } + type Pool interface { Put(Chunk) error Get(e Encoding, b []byte) (Chunk, error) diff --git a/head.go b/head.go index 0aeaef5a6..8182fb4b5 100644 --- a/head.go +++ b/head.go @@ -1270,6 +1270,12 @@ func computeChunkEndTime(start, cur, max int64) int64 { func (s *memSeries) iterator(id int) chunks.Iterator { c := s.chunk(id) + // TODO(fabxc): Work around! A querier may have retrieved a pointer to a series' chunk, + // which got then garbage collected before it got accessed. + // We must ensure to not garbage collect as long as any readers still hold a reference. + if c == nil { + return chunks.NewNopIterator() + } if id-s.firstChunkID < len(s.chunks)-1 { return c.chunk.Iterator()