From faef0a99c9fc805553b4a483dc1dfe0f6f7b3bfc Mon Sep 17 00:00:00 2001 From: Ben Johnson Date: Wed, 1 Feb 2017 10:40:58 -0700 Subject: [PATCH] Perform series tag iteration under lock. Adds a `tsdb.Series.ForEachTag()` function for safely iterating over a series' tags within the context of a lock. This preverts tags from being dereferenced during iteration which can cause a seg fault. --- CHANGELOG.md | 1 + tsdb/meta.go | 9 +++++++++ tsdb/store.go | 6 +++--- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0574eaeb91..00356b7cf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [#7877](https://github.com/influxdata/influxdb/issues/7877): Fix mapping of types when the measurement uses a regex - [#7888](https://github.com/influxdata/influxdb/pull/7888): Expand query dimensions from the subquery. - [#7910](https://github.com/influxdata/influxdb/issues/7910): Fix EvalType when a parenthesis expression is used. +- [#7929](https://github.com/influxdata/influxdb/issues/7929): Fix series tag iteration segfault. (#7922) ## v1.2.0 [2017-01-24] diff --git a/tsdb/meta.go b/tsdb/meta.go index 52427eeee0..0723f74f1f 100644 --- a/tsdb/meta.go +++ b/tsdb/meta.go @@ -1620,6 +1620,15 @@ func (s *Series) ShardN() int { return n } +// ForEachTag executes fn for every tag. Iteration occurs under lock. +func (s *Series) ForEachTag(fn func(models.Tag)) { + s.mu.RLock() + defer s.mu.RUnlock() + for _, t := range s.Tags { + fn(t) + } +} + // Dereference removes references to a byte slice. func (s *Series) Dereference(b []byte) { s.mu.Lock() diff --git a/tsdb/store.go b/tsdb/store.go index d42d815c37..579418c913 100644 --- a/tsdb/store.go +++ b/tsdb/store.go @@ -926,14 +926,14 @@ func (s *Store) TagValues(database string, cond influxql.Expr) ([]TagValues, err // Loop over all keys for each series. m := make(map[KeyValue]struct{}, len(ss)) for _, series := range ss { - for _, t := range series.Tags { + series.ForEachTag(func(t models.Tag) { if !ok { // nop } else if _, exists := keySet[string(t.Key)]; !exists { - continue + return } m[KeyValue{string(t.Key), string(t.Value)}] = struct{}{} - } + }) } // Return an empty slice if there are no key/value matches.