github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/storage/stores/tsdb/querier.go (about) 1 // Copyright 2017 The Prometheus Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package tsdb 15 16 import ( 17 "sort" 18 "strings" 19 "unicode/utf8" 20 21 "github.com/pkg/errors" 22 "github.com/prometheus/prometheus/model/labels" 23 "github.com/prometheus/prometheus/storage" 24 25 "github.com/grafana/loki/pkg/storage/stores/tsdb/index" 26 ) 27 28 // Bitmap used by func isRegexMetaCharacter to check whether a character needs to be escaped. 29 var regexMetaCharacterBytes [16]byte 30 31 // isRegexMetaCharacter reports whether byte b needs to be escaped. 32 func isRegexMetaCharacter(b byte) bool { 33 return b < utf8.RuneSelf && regexMetaCharacterBytes[b%16]&(1<<(b/16)) != 0 34 } 35 36 func init() { 37 for _, b := range []byte(`.+*?()|[]{}^$`) { 38 regexMetaCharacterBytes[b%16] |= 1 << (b / 16) 39 } 40 } 41 42 // IndexReader provides reading access of serialized index data. 43 type IndexReader interface { 44 // Bounds returns the earliest and latest samples in the index 45 Bounds() (int64, int64) 46 47 Checksum() uint32 48 49 // Symbols return an iterator over sorted string symbols that may occur in 50 // series' labels and indices. It is not safe to use the returned strings 51 // beyond the lifetime of the index reader. 52 Symbols() index.StringIter 53 54 // SortedLabelValues returns sorted possible label values. 55 SortedLabelValues(name string, matchers ...*labels.Matcher) ([]string, error) 56 57 // LabelValues returns possible label values which may not be sorted. 58 LabelValues(name string, matchers ...*labels.Matcher) ([]string, error) 59 60 // Postings returns the postings list iterator for the label pairs. 61 // The Postings here contain the offsets to the series inside the index. 62 // Found IDs are not strictly required to point to a valid Series, e.g. 63 // during background garbage collections. Input values must be sorted. 64 Postings(name string, shard *index.ShardAnnotation, values ...string) (index.Postings, error) 65 66 // Series populates the given labels and chunk metas for the series identified 67 // by the reference. 68 // Returns storage.ErrNotFound if the ref does not resolve to a known series. 69 Series(ref storage.SeriesRef, lset *labels.Labels, chks *[]index.ChunkMeta) (uint64, error) 70 71 // LabelNames returns all the unique label names present in the index in sorted order. 72 LabelNames(matchers ...*labels.Matcher) ([]string, error) 73 74 // LabelValueFor returns label value for the given label name in the series referred to by ID. 75 // If the series couldn't be found or the series doesn't have the requested label a 76 // storage.ErrNotFound is returned as error. 77 LabelValueFor(id storage.SeriesRef, label string) (string, error) 78 79 // LabelNamesFor returns all the label names for the series referred to by IDs. 80 // The names returned are sorted. 81 LabelNamesFor(ids ...storage.SeriesRef) ([]string, error) 82 83 // Close releases the underlying resources of the reader. 84 Close() error 85 } 86 87 // PostingsForMatchers assembles a single postings iterator against the index reader 88 // based on the given matchers. The resulting postings are not ordered by series. 89 func PostingsForMatchers(ix IndexReader, shard *index.ShardAnnotation, ms ...*labels.Matcher) (index.Postings, error) { 90 var its, notIts []index.Postings 91 // See which label must be non-empty. 92 // Optimization for case like {l=~".", l!="1"}. 93 labelMustBeSet := make(map[string]bool, len(ms)) 94 for _, m := range ms { 95 if !m.Matches("") { 96 labelMustBeSet[m.Name] = true 97 } 98 } 99 100 for _, m := range ms { 101 if labelMustBeSet[m.Name] { 102 // If this matcher must be non-empty, we can be smarter. 103 matchesEmpty := m.Matches("") 104 isNot := m.Type == labels.MatchNotEqual || m.Type == labels.MatchNotRegexp 105 if isNot && matchesEmpty { // l!="foo" 106 // If the label can't be empty and is a Not and the inner matcher 107 // doesn't match empty, then subtract it out at the end. 108 inverse, err := m.Inverse() 109 if err != nil { 110 return nil, err 111 } 112 113 it, err := postingsForMatcher(ix, shard, inverse) 114 if err != nil { 115 return nil, err 116 } 117 notIts = append(notIts, it) 118 } else if isNot && !matchesEmpty { // l!="" 119 // If the label can't be empty and is a Not, but the inner matcher can 120 // be empty we need to use inversePostingsForMatcher. 121 inverse, err := m.Inverse() 122 if err != nil { 123 return nil, err 124 } 125 126 it, err := inversePostingsForMatcher(ix, shard, inverse) 127 if err != nil { 128 return nil, err 129 } 130 its = append(its, it) 131 } else { // l="a" 132 // Non-Not matcher, use normal postingsForMatcher. 133 it, err := postingsForMatcher(ix, shard, m) 134 if err != nil { 135 return nil, err 136 } 137 its = append(its, it) 138 } 139 } else { // l="" 140 // If the matchers for a labelname selects an empty value, it selects all 141 // the series which don't have the label name set too. See: 142 // https://github.com/prometheus/prometheus/issues/3575 and 143 // https://github.com/prometheus/prometheus/pull/3578#issuecomment-351653555 144 it, err := inversePostingsForMatcher(ix, shard, m) 145 if err != nil { 146 return nil, err 147 } 148 notIts = append(notIts, it) 149 } 150 } 151 152 // If there's nothing to subtract from, add in everything and remove the notIts later. 153 if len(its) == 0 && len(notIts) != 0 { 154 k, v := index.AllPostingsKey() 155 allPostings, err := ix.Postings(k, shard, v) 156 if err != nil { 157 return nil, err 158 } 159 its = append(its, allPostings) 160 } 161 162 it := index.Intersect(its...) 163 164 for _, n := range notIts { 165 it = index.Without(it, n) 166 } 167 168 return it, nil 169 } 170 171 func postingsForMatcher(ix IndexReader, shard *index.ShardAnnotation, m *labels.Matcher) (index.Postings, error) { 172 // This method will not return postings for missing labels. 173 174 // Fast-path for equal matching. 175 if m.Type == labels.MatchEqual { 176 return ix.Postings(m.Name, shard, m.Value) 177 } 178 179 // Fast-path for set matching. 180 if m.Type == labels.MatchRegexp { 181 setMatches := findSetMatches(m.GetRegexString()) 182 if len(setMatches) > 0 { 183 sort.Strings(setMatches) 184 return ix.Postings(m.Name, shard, setMatches...) 185 } 186 } 187 188 vals, err := ix.LabelValues(m.Name) 189 if err != nil { 190 return nil, err 191 } 192 193 var res []string 194 lastVal, isSorted := "", true 195 for _, val := range vals { 196 if m.Matches(val) { 197 res = append(res, val) 198 if isSorted && val < lastVal { 199 isSorted = false 200 } 201 lastVal = val 202 } 203 } 204 205 if len(res) == 0 { 206 return index.EmptyPostings(), nil 207 } 208 209 if !isSorted { 210 sort.Strings(res) 211 } 212 return ix.Postings(m.Name, shard, res...) 213 } 214 215 // inversePostingsForMatcher returns the postings for the series with the label name set but not matching the matcher. 216 func inversePostingsForMatcher(ix IndexReader, shard *index.ShardAnnotation, m *labels.Matcher) (index.Postings, error) { 217 vals, err := ix.LabelValues(m.Name) 218 if err != nil { 219 return nil, err 220 } 221 222 var res []string 223 lastVal, isSorted := "", true 224 for _, val := range vals { 225 if !m.Matches(val) { 226 res = append(res, val) 227 if isSorted && val < lastVal { 228 isSorted = false 229 } 230 lastVal = val 231 } 232 } 233 234 if !isSorted { 235 sort.Strings(res) 236 } 237 return ix.Postings(m.Name, shard, res...) 238 } 239 240 func findSetMatches(pattern string) []string { 241 // Return empty matches if the wrapper from Prometheus is missing. 242 if len(pattern) < 6 || pattern[:4] != "^(?:" || pattern[len(pattern)-2:] != ")$" { 243 return nil 244 } 245 escaped := false 246 sets := []*strings.Builder{{}} 247 for i := 4; i < len(pattern)-2; i++ { 248 if escaped { 249 switch { 250 case isRegexMetaCharacter(pattern[i]): 251 sets[len(sets)-1].WriteByte(pattern[i]) 252 case pattern[i] == '\\': 253 sets[len(sets)-1].WriteByte('\\') 254 default: 255 return nil 256 } 257 escaped = false 258 } else { 259 switch { 260 case isRegexMetaCharacter(pattern[i]): 261 if pattern[i] == '|' { 262 sets = append(sets, &strings.Builder{}) 263 } else { 264 return nil 265 } 266 case pattern[i] == '\\': 267 escaped = true 268 default: 269 sets[len(sets)-1].WriteByte(pattern[i]) 270 } 271 } 272 } 273 matches := make([]string, 0, len(sets)) 274 for _, s := range sets { 275 if s.Len() > 0 { 276 matches = append(matches, s.String()) 277 } 278 } 279 return matches 280 } 281 282 func labelValuesWithMatchers(r IndexReader, name string, matchers ...*labels.Matcher) ([]string, error) { 283 // We're only interested in metrics which have the label <name>. 284 requireLabel, err := labels.NewMatcher(labels.MatchNotEqual, name, "") 285 if err != nil { 286 return nil, errors.Wrapf(err, "Failed to instantiate label matcher") 287 } 288 289 var p index.Postings 290 p, err = PostingsForMatchers(r, nil, append(matchers, requireLabel)...) 291 if err != nil { 292 return nil, err 293 } 294 295 dedupe := map[string]interface{}{} 296 for p.Next() { 297 v, err := r.LabelValueFor(p.At(), name) 298 if err != nil { 299 if err == storage.ErrNotFound { 300 continue 301 } 302 303 return nil, err 304 } 305 dedupe[v] = nil 306 } 307 308 if err = p.Err(); err != nil { 309 return nil, err 310 } 311 312 values := make([]string, 0, len(dedupe)) 313 for value := range dedupe { 314 values = append(values, value) 315 } 316 317 return values, nil 318 } 319 320 func labelNamesWithMatchers(r IndexReader, matchers ...*labels.Matcher) ([]string, error) { 321 p, err := PostingsForMatchers(r, nil, matchers...) 322 if err != nil { 323 return nil, err 324 } 325 326 var postings []storage.SeriesRef 327 for p.Next() { 328 postings = append(postings, p.At()) 329 } 330 if p.Err() != nil { 331 return nil, errors.Wrapf(p.Err(), "postings for label names with matchers") 332 } 333 334 return r.LabelNamesFor(postings...) 335 }