github.com/thanos-io/thanos@v0.32.5/pkg/querysharding/analysis.go (about)

     1  // Copyright (c) The Thanos Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  package querysharding
     5  
     6  var excludedLabels = []string{"le"}
     7  
     8  type QueryAnalysis struct {
     9  	// Labels to shard on
    10  	shardingLabels []string
    11  
    12  	// When set to true, sharding is `by` shardingLabels,
    13  	// otherwise it is `without` shardingLabels.
    14  	shardBy bool
    15  }
    16  
    17  func nonShardableQuery() QueryAnalysis {
    18  	return QueryAnalysis{
    19  		shardingLabels: nil,
    20  	}
    21  }
    22  
    23  func (q *QueryAnalysis) scopeToLabels(labels []string, by bool) QueryAnalysis {
    24  	labels = without(labels, excludedLabels)
    25  
    26  	if q.shardingLabels == nil {
    27  		return QueryAnalysis{
    28  			shardBy:        by,
    29  			shardingLabels: labels,
    30  		}
    31  	}
    32  
    33  	if q.shardBy && by {
    34  		return QueryAnalysis{
    35  			shardBy:        true,
    36  			shardingLabels: intersect(q.shardingLabels, labels),
    37  		}
    38  	}
    39  
    40  	if !q.shardBy && !by {
    41  		return QueryAnalysis{
    42  			shardBy:        false,
    43  			shardingLabels: union(q.shardingLabels, labels),
    44  		}
    45  	}
    46  
    47  	// If we are sharding by and without the same time,
    48  	// keep the sharding by labels that are not in the without labels set.
    49  	labelsBy, labelsWithout := q.shardingLabels, labels
    50  	if !q.shardBy {
    51  		labelsBy, labelsWithout = labelsWithout, labelsBy
    52  	}
    53  	return QueryAnalysis{
    54  		shardBy:        true,
    55  		shardingLabels: without(labelsBy, labelsWithout),
    56  	}
    57  }
    58  
    59  func (q *QueryAnalysis) IsShardable() bool {
    60  	return len(q.shardingLabels) > 0
    61  }
    62  
    63  func (q *QueryAnalysis) ShardingLabels() []string {
    64  	if len(q.shardingLabels) == 0 {
    65  		return nil
    66  	}
    67  
    68  	return q.shardingLabels
    69  }
    70  
    71  func (q *QueryAnalysis) ShardBy() bool {
    72  	return q.shardBy
    73  }
    74  
    75  func intersect(sliceA, sliceB []string) []string {
    76  	if len(sliceA) == 0 || len(sliceB) == 0 {
    77  		return []string{}
    78  	}
    79  
    80  	mapA := make(map[string]struct{}, len(sliceA))
    81  	for _, s := range sliceA {
    82  		mapA[s] = struct{}{}
    83  	}
    84  
    85  	mapB := make(map[string]struct{}, len(sliceB))
    86  	for _, s := range sliceB {
    87  		mapB[s] = struct{}{}
    88  	}
    89  
    90  	result := make([]string, 0)
    91  	for k := range mapA {
    92  		if _, ok := mapB[k]; ok {
    93  			result = append(result, k)
    94  		}
    95  	}
    96  
    97  	return result
    98  }
    99  
   100  func without(sliceA, sliceB []string) []string {
   101  	if sliceA == nil {
   102  		return nil
   103  	}
   104  	if len(sliceA) == 0 {
   105  		return []string{}
   106  	}
   107  	if len(sliceB) == 0 {
   108  		return sliceA
   109  	}
   110  
   111  	keyMap := make(map[string]struct{}, len(sliceA))
   112  	for _, s := range sliceA {
   113  		keyMap[s] = struct{}{}
   114  	}
   115  	for _, s := range sliceB {
   116  		delete(keyMap, s)
   117  	}
   118  
   119  	result := make([]string, 0, len(keyMap))
   120  	for k := range keyMap {
   121  		result = append(result, k)
   122  	}
   123  
   124  	return result
   125  }
   126  
   127  func union(sliceA, sliceB []string) []string {
   128  	if len(sliceA) == 0 && len(sliceB) == 0 {
   129  		return []string{}
   130  	}
   131  	if len(sliceA) == 0 {
   132  		return sliceB
   133  	}
   134  	if len(sliceB) == 0 {
   135  		return sliceA
   136  	}
   137  
   138  	keyMap := make(map[string]struct{}, len(sliceA))
   139  	for _, s := range sliceA {
   140  		keyMap[s] = struct{}{}
   141  	}
   142  	for _, s := range sliceB {
   143  		keyMap[s] = struct{}{}
   144  	}
   145  
   146  	result := make([]string, 0, len(keyMap))
   147  	for k := range keyMap {
   148  		result = append(result, k)
   149  	}
   150  
   151  	return result
   152  }