| 
									
										
										
										
											2020-06-10 00:57:31 +08:00
										 |  |  | // Copyright 2017 The Prometheus Authors
 | 
					
						
							|  |  |  | // Licensed under the Apache License, Version 2.0 (the "License");
 | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License.
 | 
					
						
							|  |  |  | // You may obtain a copy of the License at
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS,
 | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and
 | 
					
						
							|  |  |  | // limitations under the License.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package storage | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/prometheus/prometheus/pkg/labels" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // secondaryQuerier is a wrapper that allows a querier to be treated in a best effort manner.
 | 
					
						
							|  |  |  | // This means that an error on any method returned by Querier except Close will be returned as a warning,
 | 
					
						
							|  |  |  | // and the result will be empty.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Additionally, Querier ensures that if ANY SeriesSet returned by this querier's Select failed on an initial Next,
 | 
					
						
							|  |  |  | // All other SeriesSet will be return no response as well. This ensures consistent partial response strategy, where you
 | 
					
						
							|  |  |  | // have either full results or none from each secondary Querier.
 | 
					
						
							|  |  |  | // NOTE: This works well only for implementations that only fail during first Next() (e.g fetch from network). If implementation fails
 | 
					
						
							|  |  |  | // during further iterations, set will panic. If Select is invoked after first Next of any returned SeriesSet, querier will panic.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Not go-routine safe.
 | 
					
						
							|  |  |  | // NOTE: Prometheus treats all remote storages as secondary / best effort.
 | 
					
						
							|  |  |  | type secondaryQuerier struct { | 
					
						
							|  |  |  | 	genericQuerier | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	once      sync.Once | 
					
						
							|  |  |  | 	done      bool | 
					
						
							|  |  |  | 	asyncSets []genericSeriesSet | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newSecondaryQuerierFrom(q Querier) genericQuerier { | 
					
						
							|  |  |  | 	return &secondaryQuerier{genericQuerier: newGenericQuerierFrom(q)} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newSecondaryQuerierFromChunk(cq ChunkQuerier) genericQuerier { | 
					
						
							|  |  |  | 	return &secondaryQuerier{genericQuerier: newGenericQuerierFromChunk(cq)} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-10 01:38:35 +08:00
										 |  |  | func (s *secondaryQuerier) LabelValues(name string, matchers ...*labels.Matcher) ([]string, Warnings, error) { | 
					
						
							|  |  |  | 	vals, w, err := s.genericQuerier.LabelValues(name, matchers...) | 
					
						
							| 
									
										
										
										
											2020-06-10 00:57:31 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, append([]error{err}, w...), nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return vals, w, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-20 20:38:08 +08:00
										 |  |  | func (s *secondaryQuerier) LabelNames(matchers ...*labels.Matcher) ([]string, Warnings, error) { | 
					
						
							|  |  |  | 	names, w, err := s.genericQuerier.LabelNames(matchers...) | 
					
						
							| 
									
										
										
										
											2020-06-10 00:57:31 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, append([]error{err}, w...), nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return names, w, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-31 23:03:02 +08:00
										 |  |  | func (s *secondaryQuerier) Select(sortSeries bool, hints *SelectHints, matchers ...*labels.Matcher) genericSeriesSet { | 
					
						
							|  |  |  | 	if s.done { | 
					
						
							|  |  |  | 		panic("secondaryQuerier: Select invoked after first Next of any returned SeriesSet was done") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.asyncSets = append(s.asyncSets, s.genericQuerier.Select(sortSeries, hints, matchers...)) | 
					
						
							| 
									
										
										
										
											2020-06-10 00:57:31 +08:00
										 |  |  | 	curr := len(s.asyncSets) - 1 | 
					
						
							| 
									
										
										
										
											2020-07-31 23:03:02 +08:00
										 |  |  | 	return &lazyGenericSeriesSet{init: func() (genericSeriesSet, bool) { | 
					
						
							| 
									
										
										
										
											2020-06-10 00:57:31 +08:00
										 |  |  | 		s.once.Do(func() { | 
					
						
							| 
									
										
										
										
											2020-07-31 23:03:02 +08:00
										 |  |  | 			// At first init invocation we iterate over all async sets and ensure its Next() returns some value without
 | 
					
						
							| 
									
										
										
										
											2020-06-10 00:57:31 +08:00
										 |  |  | 			// errors. This is to ensure we support consistent partial failures.
 | 
					
						
							|  |  |  | 			for i, set := range s.asyncSets { | 
					
						
							|  |  |  | 				if set.Next() { | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				ws := set.Warnings() | 
					
						
							|  |  |  | 				if err := set.Err(); err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-31 23:03:02 +08:00
										 |  |  | 					// One of the sets failed, ensure current one returning errors as warnings, and rest of the sets return nothing.
 | 
					
						
							|  |  |  | 					// (All or nothing logic).
 | 
					
						
							|  |  |  | 					s.asyncSets[curr] = warningsOnlySeriesSet(append([]error{err}, ws...)) | 
					
						
							| 
									
										
										
										
											2020-06-10 00:57:31 +08:00
										 |  |  | 					for i := range s.asyncSets { | 
					
						
							| 
									
										
										
										
											2020-07-31 23:03:02 +08:00
										 |  |  | 						if curr == i { | 
					
						
							|  |  |  | 							continue | 
					
						
							| 
									
										
										
										
											2020-06-10 00:57:31 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2020-07-31 23:03:02 +08:00
										 |  |  | 						s.asyncSets[i] = noopGenericSeriesSet{} | 
					
						
							| 
									
										
										
										
											2020-06-10 00:57:31 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// Exhausted set.
 | 
					
						
							|  |  |  | 				s.asyncSets[i] = warningsOnlySeriesSet(ws) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			s.done = true | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch s.asyncSets[curr].(type) { | 
					
						
							|  |  |  | 		case warningsOnlySeriesSet, noopGenericSeriesSet: | 
					
						
							|  |  |  | 			return s.asyncSets[curr], false | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return s.asyncSets[curr], true | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-07-31 23:03:02 +08:00
										 |  |  | 	}} | 
					
						
							| 
									
										
										
										
											2020-06-10 00:57:31 +08:00
										 |  |  | } |