mirror of
https://github.com/prometheus/prometheus
synced 2024-12-27 17:13:22 +00:00
Update package storage/remote for new labels.Labels type
`QueueManager.externalLabels` becomes a slice rather than a `Labels` so we can index into it when doing the merge operation. Note we avoid calling `Labels.Len()` in `labelProtosToLabels()`. It isn't necessary - `append()` will enlarge the buffer and we're expecting to re-use it many times. Also, we now validate protobuf input before converting to Labels. This way we can detect errors first, and we don't place unnecessary requirements on the Labels structure. Re-do seriesFilter using labels.Builder (albeit N^2). Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
This commit is contained in:
parent
9bc6d7a7db
commit
abd9909595
@ -153,10 +153,10 @@ func ToQueryResult(ss storage.SeriesSet, sampleLimit int) (*prompb.QueryResult,
|
||||
func FromQueryResult(sortSeries bool, res *prompb.QueryResult) storage.SeriesSet {
|
||||
series := make([]storage.Series, 0, len(res.Timeseries))
|
||||
for _, ts := range res.Timeseries {
|
||||
lbls := labelProtosToLabels(ts.Labels)
|
||||
if err := validateLabelsAndMetricName(lbls); err != nil {
|
||||
if err := validateLabelsAndMetricName(ts.Labels); err != nil {
|
||||
return errSeriesSet{err: err}
|
||||
}
|
||||
lbls := labelProtosToLabels(ts.Labels)
|
||||
series = append(series, &concreteSeries{labels: lbls, samples: ts.Samples})
|
||||
}
|
||||
|
||||
@ -346,7 +346,7 @@ type concreteSeries struct {
|
||||
}
|
||||
|
||||
func (c *concreteSeries) Labels() labels.Labels {
|
||||
return labels.New(c.labels...)
|
||||
return c.labels.Copy()
|
||||
}
|
||||
|
||||
func (c *concreteSeries) Iterator(it chunkenc.Iterator) chunkenc.Iterator {
|
||||
@ -441,7 +441,7 @@ func (c *concreteSeriesIterator) Err() error {
|
||||
|
||||
// validateLabelsAndMetricName validates the label names/values and metric names returned from remote read,
|
||||
// also making sure that there are no labels with duplicate names
|
||||
func validateLabelsAndMetricName(ls labels.Labels) error {
|
||||
func validateLabelsAndMetricName(ls []prompb.Label) error {
|
||||
for i, l := range ls {
|
||||
if l.Name == labels.MetricName && !model.IsValidMetricName(model.LabelValue(l.Value)) {
|
||||
return fmt.Errorf("invalid metric name: %v", l.Value)
|
||||
@ -581,30 +581,24 @@ func LabelProtosToMetric(labelPairs []*prompb.Label) model.Metric {
|
||||
}
|
||||
|
||||
func labelProtosToLabels(labelPairs []prompb.Label) labels.Labels {
|
||||
result := make(labels.Labels, 0, len(labelPairs))
|
||||
b := labels.ScratchBuilder{}
|
||||
for _, l := range labelPairs {
|
||||
result = append(result, labels.Label{
|
||||
Name: l.Name,
|
||||
Value: l.Value,
|
||||
})
|
||||
b.Add(l.Name, l.Value)
|
||||
}
|
||||
sort.Sort(result)
|
||||
return result
|
||||
b.Sort()
|
||||
return b.Labels()
|
||||
}
|
||||
|
||||
// labelsToLabelsProto transforms labels into prompb labels. The buffer slice
|
||||
// will be used to avoid allocations if it is big enough to store the labels.
|
||||
func labelsToLabelsProto(labels labels.Labels, buf []prompb.Label) []prompb.Label {
|
||||
func labelsToLabelsProto(lbls labels.Labels, buf []prompb.Label) []prompb.Label {
|
||||
result := buf[:0]
|
||||
if cap(buf) < len(labels) {
|
||||
result = make([]prompb.Label, 0, len(labels))
|
||||
}
|
||||
for _, l := range labels {
|
||||
lbls.Range(func(l labels.Label) {
|
||||
result = append(result, prompb.Label{
|
||||
Name: l.Name,
|
||||
Value: l.Value,
|
||||
})
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -396,7 +396,7 @@ type QueueManager struct {
|
||||
flushDeadline time.Duration
|
||||
cfg config.QueueConfig
|
||||
mcfg config.MetadataConfig
|
||||
externalLabels labels.Labels
|
||||
externalLabels []labels.Label
|
||||
relabelConfigs []*relabel.Config
|
||||
sendExemplars bool
|
||||
sendNativeHistograms bool
|
||||
@ -454,13 +454,19 @@ func NewQueueManager(
|
||||
logger = log.NewNopLogger()
|
||||
}
|
||||
|
||||
// Copy externalLabels into slice which we need for processExternalLabels.
|
||||
extLabelsSlice := make([]labels.Label, 0, externalLabels.Len())
|
||||
externalLabels.Range(func(l labels.Label) {
|
||||
extLabelsSlice = append(extLabelsSlice, l)
|
||||
})
|
||||
|
||||
logger = log.With(logger, remoteName, client.Name(), endpoint, client.Endpoint())
|
||||
t := &QueueManager{
|
||||
logger: logger,
|
||||
flushDeadline: flushDeadline,
|
||||
cfg: cfg,
|
||||
mcfg: mCfg,
|
||||
externalLabels: externalLabels,
|
||||
externalLabels: extLabelsSlice,
|
||||
relabelConfigs: relabelConfigs,
|
||||
storeClient: client,
|
||||
sendExemplars: enableExemplarRemoteWrite,
|
||||
@ -769,8 +775,8 @@ func (t *QueueManager) StoreSeries(series []record.RefSeries, index int) {
|
||||
t.seriesSegmentIndexes[s.Ref] = index
|
||||
|
||||
ls := processExternalLabels(s.Labels, t.externalLabels)
|
||||
lbls := relabel.Process(ls, t.relabelConfigs...)
|
||||
if len(lbls) == 0 {
|
||||
lbls, keep := relabel.Process(ls, t.relabelConfigs...)
|
||||
if !keep || lbls.IsEmpty() {
|
||||
t.droppedSeries[s.Ref] = struct{}{}
|
||||
continue
|
||||
}
|
||||
@ -831,44 +837,33 @@ func (t *QueueManager) client() WriteClient {
|
||||
}
|
||||
|
||||
func (t *QueueManager) internLabels(lbls labels.Labels) {
|
||||
for i, l := range lbls {
|
||||
lbls[i].Name = t.interner.intern(l.Name)
|
||||
lbls[i].Value = t.interner.intern(l.Value)
|
||||
}
|
||||
lbls.InternStrings(t.interner.intern)
|
||||
}
|
||||
|
||||
func (t *QueueManager) releaseLabels(ls labels.Labels) {
|
||||
for _, l := range ls {
|
||||
t.interner.release(l.Name)
|
||||
t.interner.release(l.Value)
|
||||
}
|
||||
ls.ReleaseStrings(t.interner.release)
|
||||
}
|
||||
|
||||
// processExternalLabels merges externalLabels into ls. If ls contains
|
||||
// a label in externalLabels, the value in ls wins.
|
||||
func processExternalLabels(ls, externalLabels labels.Labels) labels.Labels {
|
||||
i, j, result := 0, 0, make(labels.Labels, 0, len(ls)+len(externalLabels))
|
||||
for i < len(ls) && j < len(externalLabels) {
|
||||
if ls[i].Name < externalLabels[j].Name {
|
||||
result = append(result, labels.Label{
|
||||
Name: ls[i].Name,
|
||||
Value: ls[i].Value,
|
||||
})
|
||||
i++
|
||||
} else if ls[i].Name > externalLabels[j].Name {
|
||||
result = append(result, externalLabels[j])
|
||||
j++
|
||||
} else {
|
||||
result = append(result, labels.Label{
|
||||
Name: ls[i].Name,
|
||||
Value: ls[i].Value,
|
||||
})
|
||||
i++
|
||||
func processExternalLabels(ls labels.Labels, externalLabels []labels.Label) labels.Labels {
|
||||
b := labels.NewScratchBuilder(ls.Len() + len(externalLabels))
|
||||
j := 0
|
||||
ls.Range(func(l labels.Label) {
|
||||
for j < len(externalLabels) && l.Name > externalLabels[j].Name {
|
||||
b.Add(externalLabels[j].Name, externalLabels[j].Value)
|
||||
j++
|
||||
}
|
||||
if j < len(externalLabels) && l.Name == externalLabels[j].Name {
|
||||
j++
|
||||
}
|
||||
b.Add(l.Name, l.Value)
|
||||
})
|
||||
for ; j < len(externalLabels); j++ {
|
||||
b.Add(externalLabels[j].Name, externalLabels[j].Value)
|
||||
}
|
||||
|
||||
return append(append(result, ls[i:]...), externalLabels[j:]...)
|
||||
return b.Labels()
|
||||
}
|
||||
|
||||
func (t *QueueManager) updateShardsLoop() {
|
||||
|
@ -180,9 +180,11 @@ func (q *querier) Select(sortSeries bool, hints *storage.SelectHints, matchers .
|
||||
// We return the new set of matchers, along with a map of labels for which
|
||||
// matchers were added, so that these can later be removed from the result
|
||||
// time series again.
|
||||
func (q querier) addExternalLabels(ms []*labels.Matcher) ([]*labels.Matcher, labels.Labels) {
|
||||
el := make(labels.Labels, len(q.externalLabels))
|
||||
copy(el, q.externalLabels)
|
||||
func (q querier) addExternalLabels(ms []*labels.Matcher) ([]*labels.Matcher, []string) {
|
||||
el := make([]labels.Label, 0, q.externalLabels.Len())
|
||||
q.externalLabels.Range(func(l labels.Label) {
|
||||
el = append(el, l)
|
||||
})
|
||||
|
||||
// ms won't be sorted, so have to O(n^2) the search.
|
||||
for _, m := range ms {
|
||||
@ -202,7 +204,11 @@ func (q querier) addExternalLabels(ms []*labels.Matcher) ([]*labels.Matcher, lab
|
||||
}
|
||||
ms = append(ms, m)
|
||||
}
|
||||
return ms, el
|
||||
names := make([]string, len(el))
|
||||
for i := range el {
|
||||
names[i] = el[i].Name
|
||||
}
|
||||
return ms, names
|
||||
}
|
||||
|
||||
// LabelValues implements storage.Querier and is a noop.
|
||||
@ -234,7 +240,8 @@ func (q *chunkQuerier) Select(sortSeries bool, hints *storage.SelectHints, match
|
||||
return storage.NewSeriesSetToChunkSet(q.querier.Select(sortSeries, hints, matchers...))
|
||||
}
|
||||
|
||||
func newSeriesSetFilter(ss storage.SeriesSet, toFilter labels.Labels) storage.SeriesSet {
|
||||
// Note strings in toFilter must be sorted.
|
||||
func newSeriesSetFilter(ss storage.SeriesSet, toFilter []string) storage.SeriesSet {
|
||||
return &seriesSetFilter{
|
||||
SeriesSet: ss,
|
||||
toFilter: toFilter,
|
||||
@ -243,7 +250,7 @@ func newSeriesSetFilter(ss storage.SeriesSet, toFilter labels.Labels) storage.Se
|
||||
|
||||
type seriesSetFilter struct {
|
||||
storage.SeriesSet
|
||||
toFilter labels.Labels
|
||||
toFilter []string // Label names to remove from result
|
||||
querier storage.Querier
|
||||
}
|
||||
|
||||
@ -264,20 +271,12 @@ func (ssf seriesSetFilter) At() storage.Series {
|
||||
|
||||
type seriesFilter struct {
|
||||
storage.Series
|
||||
toFilter labels.Labels
|
||||
toFilter []string // Label names to remove from result
|
||||
}
|
||||
|
||||
func (sf seriesFilter) Labels() labels.Labels {
|
||||
labels := sf.Series.Labels()
|
||||
for i, j := 0, 0; i < len(labels) && j < len(sf.toFilter); {
|
||||
if labels[i].Name < sf.toFilter[j].Name {
|
||||
i++
|
||||
} else if labels[i].Name > sf.toFilter[j].Name {
|
||||
j++
|
||||
} else {
|
||||
labels = labels[:i+copy(labels[i:], labels[i+1:])]
|
||||
j++
|
||||
}
|
||||
}
|
||||
return labels
|
||||
b := labels.NewBuilder(sf.Series.Labels())
|
||||
// todo: check if this is too inefficient.
|
||||
b.Del(sf.toFilter...)
|
||||
return b.Labels(labels.EmptyLabels())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user