github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/storage/stores/tsdb/multitenant.go (about)

     1  package tsdb
     2  
     3  import (
     4  	"context"
     5  	"sort"
     6  
     7  	"github.com/prometheus/common/model"
     8  	"github.com/prometheus/prometheus/model/labels"
     9  
    10  	"github.com/grafana/loki/pkg/storage/chunk"
    11  	"github.com/grafana/loki/pkg/storage/stores/index/stats"
    12  	"github.com/grafana/loki/pkg/storage/stores/tsdb/index"
    13  )
    14  
    15  // TenantLabel is part of the reserved label namespace (__ prefix)
    16  // It's used to create multi-tenant TSDBs (which do not have a tenancy concept)
    17  // These labels are stripped out during compaction to single-tenant TSDBs
    18  const TenantLabel = "__loki_tenant__"
    19  
    20  // MultiTenantIndex will inject a tenant label to it's queries
    21  // This works with pre-compacted TSDBs which aren't yet per tenant.
    22  type MultiTenantIndex struct {
    23  	idx Index
    24  }
    25  
    26  func NewMultiTenantIndex(idx Index) *MultiTenantIndex {
    27  	return &MultiTenantIndex{idx: idx}
    28  }
    29  
    30  func withTenantLabelMatcher(userID string, matchers []*labels.Matcher) []*labels.Matcher {
    31  	cpy := make([]*labels.Matcher, len(matchers)+1)
    32  	cpy[0] = labels.MustNewMatcher(labels.MatchEqual, TenantLabel, userID)
    33  	copy(cpy[1:], matchers)
    34  	return cpy
    35  }
    36  
    37  func withoutTenantLabel(ls labels.Labels) labels.Labels {
    38  	for i, l := range ls {
    39  		if l.Name == TenantLabel {
    40  			ls = append(ls[:i], ls[i+1:]...)
    41  			break
    42  		}
    43  	}
    44  	return ls
    45  }
    46  
    47  func (m *MultiTenantIndex) Bounds() (model.Time, model.Time) { return m.idx.Bounds() }
    48  
    49  func (m *MultiTenantIndex) SetChunkFilterer(chunkFilter chunk.RequestChunkFilterer) {
    50  	m.idx.SetChunkFilterer(chunkFilter)
    51  }
    52  
    53  func (m *MultiTenantIndex) Close() error { return m.idx.Close() }
    54  
    55  func (m *MultiTenantIndex) GetChunkRefs(ctx context.Context, userID string, from, through model.Time, res []ChunkRef, shard *index.ShardAnnotation, matchers ...*labels.Matcher) ([]ChunkRef, error) {
    56  	return m.idx.GetChunkRefs(ctx, userID, from, through, res, shard, withTenantLabelMatcher(userID, matchers)...)
    57  }
    58  
    59  func (m *MultiTenantIndex) Series(ctx context.Context, userID string, from, through model.Time, res []Series, shard *index.ShardAnnotation, matchers ...*labels.Matcher) ([]Series, error) {
    60  	xs, err := m.idx.Series(ctx, userID, from, through, res, shard, withTenantLabelMatcher(userID, matchers)...)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	for i := range xs {
    65  		xs[i].Labels = withoutTenantLabel(xs[i].Labels)
    66  	}
    67  	return xs, nil
    68  }
    69  
    70  func (m *MultiTenantIndex) LabelNames(ctx context.Context, userID string, from, through model.Time, matchers ...*labels.Matcher) ([]string, error) {
    71  	res, err := m.idx.LabelNames(ctx, userID, from, through, withTenantLabelMatcher(userID, matchers)...)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	// Strip out the tenant label in response.
    77  	i := sort.SearchStrings(res, TenantLabel)
    78  	if i == len(res) || res[i] != TenantLabel {
    79  		return res, nil
    80  	}
    81  
    82  	return append(res[:i], res[i+1:]...), nil
    83  }
    84  
    85  func (m *MultiTenantIndex) LabelValues(ctx context.Context, userID string, from, through model.Time, name string, matchers ...*labels.Matcher) ([]string, error) {
    86  	// Prevent queries for the internal tenant label
    87  	if name == TenantLabel {
    88  		return nil, nil
    89  	}
    90  	return m.idx.LabelValues(ctx, userID, from, through, name, withTenantLabelMatcher(userID, matchers)...)
    91  }
    92  
    93  func (m *MultiTenantIndex) Stats(ctx context.Context, userID string, from, through model.Time, blooms *stats.Blooms, shard *index.ShardAnnotation, matchers ...*labels.Matcher) (*stats.Blooms, error) {
    94  	return m.idx.Stats(ctx, userID, from, through, blooms, shard, withTenantLabelMatcher(userID, matchers)...)
    95  }