Example #1
0
func prepareInstantQuery(node Node, timestamp clientmodel.Timestamp, storage local.Storage, queryStats *stats.TimerGroup) (local.Preloader, error) {
	analyzeTimer := queryStats.GetTimer(stats.QueryAnalysisTime).Start()
	analyzer := NewQueryAnalyzer(storage)
	Walk(analyzer, node)
	analyzeTimer.Stop()

	// TODO: Preloading should time out after a given duration.
	preloadTimer := queryStats.GetTimer(stats.PreloadTime).Start()
	p := storage.NewPreloader()
	for fp, rangeDuration := range analyzer.FullRanges {
		if err := p.PreloadRange(fp, timestamp.Add(-rangeDuration), timestamp, *stalenessDelta); err != nil {
			p.Close()
			return nil, err
		}
	}
	for fp := range analyzer.IntervalRanges {
		if err := p.PreloadRange(fp, timestamp, timestamp, *stalenessDelta); err != nil {
			p.Close()
			return nil, err
		}
	}
	preloadTimer.Stop()

	ii := &iteratorInitializer{
		storage: storage,
	}
	Walk(ii, node)

	return p, nil
}
Example #2
0
// makeView materializes a View according to a ViewRequestBuilder, subject to a
// timeout.
func (t *TieredStorage) makeView(builder metric.ViewRequestBuilder, deadline time.Duration, queryStats *stats.TimerGroup) (metric.View, error) {
	t.mu.RLock()
	defer t.mu.RUnlock()
	if t.state != tieredStorageServing {
		return nil, fmt.Errorf("storage is not serving")
	}

	// The result channel needs a one-element buffer in case we have timed
	// out in makeView, but the view rendering still completes afterwards
	// and writes to the channel.
	result := make(chan metric.View, 1)
	// The abort channel needs a one-element buffer in case the view
	// rendering has already exited and doesn't consume from the channel
	// anymore.
	abortChan := make(chan bool, 1)
	errChan := make(chan error)
	queryStats.GetTimer(stats.ViewQueueTime).Start()
	t.ViewQueue <- viewJob{
		builder: builder,
		output:  result,
		abort:   abortChan,
		err:     errChan,
		stats:   queryStats,
	}

	select {
	case view := <-result:
		return view, nil
	case err := <-errChan:
		return nil, err
	case <-time.After(deadline):
		abortChan <- true
		return nil, fmt.Errorf("fetching query data timed out after %s", deadline)
	}
}
Example #3
0
// EvalToString evaluates the given node into a string of the given format.
func EvalToString(node Node, timestamp clientmodel.Timestamp, format OutputFormat, storage local.Storage, queryStats *stats.TimerGroup) string {
	prepareTimer := queryStats.GetTimer(stats.TotalQueryPreparationTime).Start()
	closer, err := prepareInstantQuery(node, timestamp, storage, queryStats)
	prepareTimer.Stop()
	if err != nil {
		panic(err)
	}
	defer closer.Close()

	evalTimer := queryStats.GetTimer(stats.InnerEvalTime).Start()
	switch node.Type() {
	case ScalarType:
		scalar := node.(ScalarNode).Eval(timestamp)
		evalTimer.Stop()
		switch format {
		case Text:
			return fmt.Sprintf("scalar: %v @[%v]", scalar, timestamp)
		case JSON:
			return TypedValueToJSON(scalar, "scalar")
		}
	case VectorType:
		vector := node.(VectorNode).Eval(timestamp)
		evalTimer.Stop()
		switch format {
		case Text:
			return vector.String()
		case JSON:
			return TypedValueToJSON(vector, "vector")
		}
	case MatrixType:
		matrix := node.(MatrixNode).Eval(timestamp)
		evalTimer.Stop()
		switch format {
		case Text:
			return matrix.String()
		case JSON:
			return TypedValueToJSON(matrix, "matrix")
		}
	case StringType:
		str := node.(StringNode).Eval(timestamp)
		evalTimer.Stop()
		switch format {
		case Text:
			return str
		case JSON:
			return TypedValueToJSON(str, "string")
		}
	}
	panic("Switch didn't cover all node types")
}
Example #4
0
// EvalToString evaluates the given node into a string of the given format.
func EvalToString(node Node, timestamp clientmodel.Timestamp, format OutputFormat, storage metric.PreloadingPersistence, queryStats *stats.TimerGroup) string {
	viewTimer := queryStats.GetTimer(stats.TotalViewBuildingTime).Start()
	viewAdapter, err := viewAdapterForInstantQuery(node, timestamp, storage, queryStats)
	viewTimer.Stop()
	if err != nil {
		panic(err)
	}

	evalTimer := queryStats.GetTimer(stats.InnerEvalTime).Start()
	switch node.Type() {
	case SCALAR:
		scalar := node.(ScalarNode).Eval(timestamp, viewAdapter)
		evalTimer.Stop()
		switch format {
		case TEXT:
			return fmt.Sprintf("scalar: %v @[%v]", scalar, timestamp)
		case JSON:
			return TypedValueToJSON(scalar, "scalar")
		}
	case VECTOR:
		vector := node.(VectorNode).Eval(timestamp, viewAdapter)
		evalTimer.Stop()
		switch format {
		case TEXT:
			return vector.String()
		case JSON:
			return TypedValueToJSON(vector, "vector")
		}
	case MATRIX:
		matrix := node.(MatrixNode).Eval(timestamp, viewAdapter)
		evalTimer.Stop()
		switch format {
		case TEXT:
			return matrix.String()
		case JSON:
			return TypedValueToJSON(matrix, "matrix")
		}
	case STRING:
		str := node.(StringNode).Eval(timestamp, viewAdapter)
		evalTimer.Stop()
		switch format {
		case TEXT:
			return str
		case JSON:
			return TypedValueToJSON(str, "string")
		}
	}
	panic("Switch didn't cover all node types")
}
Example #5
0
func prepareRangeQuery(node Node, start clientmodel.Timestamp, end clientmodel.Timestamp, interval time.Duration, storage local.Storage, queryStats *stats.TimerGroup) (local.Preloader, error) {
	analyzeTimer := queryStats.GetTimer(stats.QueryAnalysisTime).Start()
	analyzer := NewQueryAnalyzer(storage)
	Walk(analyzer, node)
	analyzeTimer.Stop()

	// TODO: Preloading should time out after a given duration.
	preloadTimer := queryStats.GetTimer(stats.PreloadTime).Start()
	p := storage.NewPreloader()
	for fp, rangeDuration := range analyzer.FullRanges {
		if err := p.PreloadRange(fp, start.Add(-rangeDuration), end, *stalenessDelta); err != nil {
			p.Close()
			return nil, err
		}
		/*
			if interval < rangeDuration {
				if err := p.GetMetricRange(fp, end, end.Sub(start)+rangeDuration); err != nil {
					p.Close()
					return nil, err
				}
			} else {
				if err := p.GetMetricRangeAtInterval(fp, start, end, interval, rangeDuration); err != nil {
					p.Close()
					return nil, err
				}
			}
		*/
	}
	for fp := range analyzer.IntervalRanges {
		if err := p.PreloadRange(fp, start, end, *stalenessDelta); err != nil {
			p.Close()
			return nil, err
		}
	}
	preloadTimer.Stop()

	ii := &iteratorInitializer{
		storage: storage,
	}
	Walk(ii, node)

	return p, nil
}
Example #6
0
func viewAdapterForRangeQuery(node Node, start clientmodel.Timestamp, end clientmodel.Timestamp, interval time.Duration, storage metric.PreloadingPersistence, queryStats *stats.TimerGroup) (*viewAdapter, error) {
	analyzeTimer := queryStats.GetTimer(stats.QueryAnalysisTime).Start()
	analyzer := NewQueryAnalyzer(storage)
	analyzer.AnalyzeQueries(node)
	analyzeTimer.Stop()

	requestBuildTimer := queryStats.GetTimer(stats.ViewRequestBuildTime).Start()
	viewBuilder := storage.NewViewRequestBuilder()
	for fingerprint, rangeDuration := range analyzer.FullRanges {
		if interval < rangeDuration {
			viewBuilder.GetMetricRange(&fingerprint, start.Add(-rangeDuration), end)
		} else {
			viewBuilder.GetMetricRangeAtInterval(&fingerprint, start.Add(-rangeDuration), end, interval, rangeDuration)
		}
	}
	for fingerprint := range analyzer.IntervalRanges {
		viewBuilder.GetMetricAtInterval(&fingerprint, start, end, interval)
	}
	requestBuildTimer.Stop()

	buildTimer := queryStats.GetTimer(stats.InnerViewBuildingTime).Start()
	view, err := viewBuilder.Execute(time.Duration(60)*time.Second, queryStats)
	buildTimer.Stop()
	if err != nil {
		return nil, err
	}
	return NewViewAdapter(view, storage, queryStats), nil
}
Example #7
0
// EvalToVector evaluates the given node into a Vector. Matrices aren't supported.
func EvalToVector(node Node, timestamp clientmodel.Timestamp, storage local.Storage, queryStats *stats.TimerGroup) (Vector, error) {
	prepareTimer := queryStats.GetTimer(stats.TotalQueryPreparationTime).Start()
	closer, err := prepareInstantQuery(node, timestamp, storage, queryStats)
	prepareTimer.Stop()
	if err != nil {
		panic(err)
	}
	defer closer.Close()

	evalTimer := queryStats.GetTimer(stats.InnerEvalTime).Start()
	switch node.Type() {
	case ScalarType:
		scalar := node.(ScalarNode).Eval(timestamp)
		evalTimer.Stop()
		return Vector{&Sample{Value: scalar}}, nil
	case VectorType:
		vector := node.(VectorNode).Eval(timestamp)
		evalTimer.Stop()
		return vector, nil
	case MatrixType:
		return nil, errors.New("matrices not supported by EvalToVector")
	case StringType:
		str := node.(StringNode).Eval(timestamp)
		evalTimer.Stop()
		return Vector{
			&Sample{
				Metric: clientmodel.COWMetric{
					Metric: clientmodel.Metric{
						"__value__": clientmodel.LabelValue(str),
					},
					Copied: true,
				},
			},
		}, nil
	}
	panic("Switch didn't cover all node types")
}
Example #8
0
// EvalVectorRange evaluates a VectorNode with a range query.
func EvalVectorRange(node VectorNode, start clientmodel.Timestamp, end clientmodel.Timestamp, interval time.Duration, storage local.Storage, queryStats *stats.TimerGroup) (Matrix, error) {
	// Explicitly initialize to an empty matrix since a nil Matrix encodes to
	// null in JSON.
	matrix := Matrix{}

	prepareTimer := queryStats.GetTimer(stats.TotalQueryPreparationTime).Start()
	closer, err := prepareRangeQuery(node, start, end, interval, storage, queryStats)
	prepareTimer.Stop()
	if err != nil {
		return nil, err
	}
	defer closer.Close()

	// TODO implement watchdog timer for long-running queries.
	evalTimer := queryStats.GetTimer(stats.InnerEvalTime).Start()
	sampleStreams := map[uint64]*SampleStream{}
	for t := start; !t.After(end); t = t.Add(interval) {
		vector := node.Eval(t)
		for _, sample := range vector {
			samplePair := metric.SamplePair{
				Value:     sample.Value,
				Timestamp: sample.Timestamp,
			}
			groupingKey := labelsToKey(sample.Metric.Metric)
			if sampleStreams[groupingKey] == nil {
				sampleStreams[groupingKey] = &SampleStream{
					Metric: sample.Metric,
					Values: metric.Values{samplePair},
				}
			} else {
				sampleStreams[groupingKey].Values = append(sampleStreams[groupingKey].Values, samplePair)
			}
		}
	}
	evalTimer.Stop()

	appendTimer := queryStats.GetTimer(stats.ResultAppendTime).Start()
	for _, sampleStream := range sampleStreams {
		matrix = append(matrix, *sampleStream)
	}
	appendTimer.Stop()

	return matrix, nil
}
Example #9
0
// EvalVectorRange evaluates a VectorNode with a range query.
func EvalVectorRange(node VectorNode, start clientmodel.Timestamp, end clientmodel.Timestamp, interval time.Duration, storage metric.PreloadingPersistence, queryStats *stats.TimerGroup) (Matrix, error) {
	// Explicitly initialize to an empty matrix since a nil Matrix encodes to
	// null in JSON.
	matrix := Matrix{}

	viewTimer := queryStats.GetTimer(stats.TotalViewBuildingTime).Start()
	viewAdapter, err := viewAdapterForRangeQuery(node, start, end, interval, storage, queryStats)
	viewTimer.Stop()
	if err != nil {
		return nil, err
	}

	// TODO implement watchdog timer for long-running queries.
	evalTimer := queryStats.GetTimer(stats.InnerEvalTime).Start()
	sampleSets := map[uint64]*metric.SampleSet{}
	for t := start; t.Before(end); t = t.Add(interval) {
		vector := node.Eval(t, viewAdapter)
		for _, sample := range vector {
			samplePair := metric.SamplePair{
				Value:     sample.Value,
				Timestamp: sample.Timestamp,
			}
			groupingKey := labelsToKey(sample.Metric)
			if sampleSets[groupingKey] == nil {
				sampleSets[groupingKey] = &metric.SampleSet{
					Metric: sample.Metric,
					Values: metric.Values{samplePair},
				}
			} else {
				sampleSets[groupingKey].Values = append(sampleSets[groupingKey].Values, samplePair)
			}
		}
	}
	evalTimer.Stop()

	appendTimer := queryStats.GetTimer(stats.ResultAppendTime).Start()
	for _, sampleSet := range sampleSets {
		matrix = append(matrix, *sampleSet)
	}
	appendTimer.Stop()

	return matrix, nil
}