mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-14 17:44:06 -08:00
Merge remote-tracking branch 'upstream/main' into codesome/syncprom
This commit is contained in:
commit
0af335cfe8
|
@ -55,7 +55,7 @@ Prometheus will now be reachable at http://localhost:9090/.
|
||||||
|
|
||||||
### Building from source
|
### Building from source
|
||||||
|
|
||||||
To build Prometheus from source code, first ensure that have a working
|
To build Prometheus from source code, first ensure that you have a working
|
||||||
Go environment with [version 1.14 or greater installed](https://golang.org/doc/install).
|
Go environment with [version 1.14 or greater installed](https://golang.org/doc/install).
|
||||||
You also need [Node.js](https://nodejs.org/) and [npm](https://www.npmjs.com/)
|
You also need [Node.js](https://nodejs.org/) and [npm](https://www.npmjs.com/)
|
||||||
installed in order to build the frontend assets.
|
installed in order to build the frontend assets.
|
||||||
|
|
|
@ -25,7 +25,7 @@ Here is a table comparing our two generic Service Discovery implementations.
|
||||||
|
|
||||||
## Requirements of HTTP SD endpoints
|
## Requirements of HTTP SD endpoints
|
||||||
|
|
||||||
If you implement an HTTP SD endpoint, here is a few requirements you should be
|
If you implement an HTTP SD endpoint, here are a few requirements you should be
|
||||||
aware of.
|
aware of.
|
||||||
|
|
||||||
The response is consumed as is, unmodified. On each refresh interval (default: 1
|
The response is consumed as is, unmodified. On each refresh interval (default: 1
|
||||||
|
@ -47,7 +47,7 @@ for incremental updates. A Prometheus instance does not send its hostname and it
|
||||||
is not possible for a SD endpoint to know if the SD requests is the first one
|
is not possible for a SD endpoint to know if the SD requests is the first one
|
||||||
after a restart or not.
|
after a restart or not.
|
||||||
|
|
||||||
The URL to the HTTP SD is not considered secret. The authentication, and any API
|
The URL to the HTTP SD is not considered secret. The authentication and any API
|
||||||
keys should be passed with the appropriate authentication mechanisms. Prometheus
|
keys should be passed with the appropriate authentication mechanisms. Prometheus
|
||||||
supports TLS authentication, basic authentication, OAuth2, and authorization
|
supports TLS authentication, basic authentication, OAuth2, and authorization
|
||||||
headers.
|
headers.
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -8,7 +8,7 @@ require (
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.9.15
|
github.com/Azure/go-autorest/autorest/adal v0.9.15
|
||||||
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
||||||
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||||
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15
|
github.com/alecthomas/units v0.0.0-20210912230133-d1bdfacee922
|
||||||
github.com/aws/aws-sdk-go v1.40.37
|
github.com/aws/aws-sdk-go v1.40.37
|
||||||
github.com/cespare/xxhash/v2 v2.1.2
|
github.com/cespare/xxhash/v2 v2.1.2
|
||||||
github.com/containerd/containerd v1.5.4 // indirect
|
github.com/containerd/containerd v1.5.4 // indirect
|
||||||
|
|
3
go.sum
3
go.sum
|
@ -151,8 +151,9 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 h1:AUNCr9CiJuwrRYS3XieqF+Z9B9gNxo/eANAJCF2eiN4=
|
|
||||||
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||||
|
github.com/alecthomas/units v0.0.0-20210912230133-d1bdfacee922 h1:8ypNbf5sd3Sm3cKJ9waOGoQv6dKAFiFty9L6NP1AqJ4=
|
||||||
|
github.com/alecthomas/units v0.0.0-20210912230133-d1bdfacee922/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||||
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
|
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
|
||||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||||
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
|
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
|
||||||
|
|
|
@ -71,7 +71,7 @@ func BenchmarkRangeQuery(b *testing.B) {
|
||||||
a := storage.Appender(context.Background())
|
a := storage.Appender(context.Background())
|
||||||
ts := int64(s * 10000) // 10s interval.
|
ts := int64(s * 10000) // 10s interval.
|
||||||
for i, metric := range metrics {
|
for i, metric := range metrics {
|
||||||
ref, _ := a.Append(refs[i], metric, ts, float64(s))
|
ref, _ := a.Append(refs[i], metric, ts, float64(s)+float64(i)/float64(len(metrics)))
|
||||||
refs[i] = ref
|
refs[i] = ref
|
||||||
}
|
}
|
||||||
if err := a.Commit(); err != nil {
|
if err := a.Commit(); err != nil {
|
||||||
|
@ -130,6 +130,9 @@ func BenchmarkRangeQuery(b *testing.B) {
|
||||||
{
|
{
|
||||||
expr: "a_X unless b_X{l=~'.*[0-4]$'}",
|
expr: "a_X unless b_X{l=~'.*[0-4]$'}",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
expr: "a_X and b_X{l='notfound'}",
|
||||||
|
},
|
||||||
// Simple functions.
|
// Simple functions.
|
||||||
{
|
{
|
||||||
expr: "abs(a_X)",
|
expr: "abs(a_X)",
|
||||||
|
@ -159,6 +162,9 @@ func BenchmarkRangeQuery(b *testing.B) {
|
||||||
{
|
{
|
||||||
expr: "count_values('value', h_X)",
|
expr: "count_values('value', h_X)",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
expr: "topk(1, a_X)",
|
||||||
|
},
|
||||||
// Combinations.
|
// Combinations.
|
||||||
{
|
{
|
||||||
expr: "rate(a_X[1m]) + rate(b_X[1m])",
|
expr: "rate(a_X[1m]) + rate(b_X[1m])",
|
||||||
|
@ -172,6 +178,10 @@ func BenchmarkRangeQuery(b *testing.B) {
|
||||||
{
|
{
|
||||||
expr: "histogram_quantile(0.9, rate(h_X[5m]))",
|
expr: "histogram_quantile(0.9, rate(h_X[5m]))",
|
||||||
},
|
},
|
||||||
|
// Many-to-one join.
|
||||||
|
{
|
||||||
|
expr: "a_X + on(l) group_right a_one",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// X in an expr will be replaced by different metric sizes.
|
// X in an expr will be replaced by different metric sizes.
|
||||||
|
|
144
promql/engine.go
144
promql/engine.go
|
@ -913,6 +913,8 @@ func (ev *evaluator) Eval(expr parser.Expr) (v parser.Value, ws storage.Warnings
|
||||||
type EvalSeriesHelper struct {
|
type EvalSeriesHelper struct {
|
||||||
// The grouping key used by aggregation.
|
// The grouping key used by aggregation.
|
||||||
groupingKey uint64
|
groupingKey uint64
|
||||||
|
// Used to map left-hand to right-hand in binary operations.
|
||||||
|
signature string
|
||||||
}
|
}
|
||||||
|
|
||||||
// EvalNodeHelper stores extra information and caches for evaluating a single node across steps.
|
// EvalNodeHelper stores extra information and caches for evaluating a single node across steps.
|
||||||
|
@ -925,8 +927,6 @@ type EvalNodeHelper struct {
|
||||||
// Caches.
|
// Caches.
|
||||||
// DropMetricName and label_*.
|
// DropMetricName and label_*.
|
||||||
Dmn map[uint64]labels.Labels
|
Dmn map[uint64]labels.Labels
|
||||||
// signatureFunc.
|
|
||||||
sigf map[string]string
|
|
||||||
// funcHistogramQuantile.
|
// funcHistogramQuantile.
|
||||||
signatureToMetricWithBuckets map[string]*metricWithBuckets
|
signatureToMetricWithBuckets map[string]*metricWithBuckets
|
||||||
// label_replace.
|
// label_replace.
|
||||||
|
@ -957,23 +957,6 @@ func (enh *EvalNodeHelper) DropMetricName(l labels.Labels) labels.Labels {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (enh *EvalNodeHelper) signatureFunc(on bool, names ...string) func(labels.Labels) string {
|
|
||||||
if enh.sigf == nil {
|
|
||||||
enh.sigf = make(map[string]string, len(enh.Out))
|
|
||||||
}
|
|
||||||
f := signatureFunc(on, enh.lblBuf, names...)
|
|
||||||
return func(l labels.Labels) string {
|
|
||||||
enh.lblBuf = l.Bytes(enh.lblBuf)
|
|
||||||
ret, ok := enh.sigf[string(enh.lblBuf)]
|
|
||||||
if ok {
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
ret = f(l)
|
|
||||||
enh.sigf[string(enh.lblBuf)] = ret
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rangeEval evaluates the given expressions, and then for each step calls
|
// rangeEval evaluates the given expressions, and then for each step calls
|
||||||
// the given funcCall with the values computed for each expression at that
|
// the given funcCall with the values computed for each expression at that
|
||||||
// step. The return value is the combination into time series of all the
|
// step. The return value is the combination into time series of all the
|
||||||
|
@ -1432,22 +1415,28 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
|
||||||
return append(enh.Out, Sample{Point: Point{V: val}}), nil
|
return append(enh.Out, Sample{Point: Point{V: val}}), nil
|
||||||
}, e.LHS, e.RHS)
|
}, e.LHS, e.RHS)
|
||||||
case lt == parser.ValueTypeVector && rt == parser.ValueTypeVector:
|
case lt == parser.ValueTypeVector && rt == parser.ValueTypeVector:
|
||||||
|
// Function to compute the join signature for each series.
|
||||||
|
buf := make([]byte, 0, 1024)
|
||||||
|
sigf := signatureFunc(e.VectorMatching.On, buf, e.VectorMatching.MatchingLabels...)
|
||||||
|
initSignatures := func(series labels.Labels, h *EvalSeriesHelper) {
|
||||||
|
h.signature = sigf(series)
|
||||||
|
}
|
||||||
switch e.Op {
|
switch e.Op {
|
||||||
case parser.LAND:
|
case parser.LAND:
|
||||||
return ev.rangeEval(nil, func(v []parser.Value, _ [][]EvalSeriesHelper, enh *EvalNodeHelper) (Vector, storage.Warnings) {
|
return ev.rangeEval(initSignatures, func(v []parser.Value, sh [][]EvalSeriesHelper, enh *EvalNodeHelper) (Vector, storage.Warnings) {
|
||||||
return ev.VectorAnd(v[0].(Vector), v[1].(Vector), e.VectorMatching, enh), nil
|
return ev.VectorAnd(v[0].(Vector), v[1].(Vector), e.VectorMatching, sh[0], sh[1], enh), nil
|
||||||
}, e.LHS, e.RHS)
|
}, e.LHS, e.RHS)
|
||||||
case parser.LOR:
|
case parser.LOR:
|
||||||
return ev.rangeEval(nil, func(v []parser.Value, _ [][]EvalSeriesHelper, enh *EvalNodeHelper) (Vector, storage.Warnings) {
|
return ev.rangeEval(initSignatures, func(v []parser.Value, sh [][]EvalSeriesHelper, enh *EvalNodeHelper) (Vector, storage.Warnings) {
|
||||||
return ev.VectorOr(v[0].(Vector), v[1].(Vector), e.VectorMatching, enh), nil
|
return ev.VectorOr(v[0].(Vector), v[1].(Vector), e.VectorMatching, sh[0], sh[1], enh), nil
|
||||||
}, e.LHS, e.RHS)
|
}, e.LHS, e.RHS)
|
||||||
case parser.LUNLESS:
|
case parser.LUNLESS:
|
||||||
return ev.rangeEval(nil, func(v []parser.Value, _ [][]EvalSeriesHelper, enh *EvalNodeHelper) (Vector, storage.Warnings) {
|
return ev.rangeEval(initSignatures, func(v []parser.Value, sh [][]EvalSeriesHelper, enh *EvalNodeHelper) (Vector, storage.Warnings) {
|
||||||
return ev.VectorUnless(v[0].(Vector), v[1].(Vector), e.VectorMatching, enh), nil
|
return ev.VectorUnless(v[0].(Vector), v[1].(Vector), e.VectorMatching, sh[0], sh[1], enh), nil
|
||||||
}, e.LHS, e.RHS)
|
}, e.LHS, e.RHS)
|
||||||
default:
|
default:
|
||||||
return ev.rangeEval(nil, func(v []parser.Value, _ [][]EvalSeriesHelper, enh *EvalNodeHelper) (Vector, storage.Warnings) {
|
return ev.rangeEval(initSignatures, func(v []parser.Value, sh [][]EvalSeriesHelper, enh *EvalNodeHelper) (Vector, storage.Warnings) {
|
||||||
return ev.VectorBinop(e.Op, v[0].(Vector), v[1].(Vector), e.VectorMatching, e.ReturnBool, enh), nil
|
return ev.VectorBinop(e.Op, v[0].(Vector), v[1].(Vector), e.VectorMatching, e.ReturnBool, sh[0], sh[1], enh), nil
|
||||||
}, e.LHS, e.RHS)
|
}, e.LHS, e.RHS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1774,62 +1763,72 @@ func (ev *evaluator) matrixIterSlice(it *storage.BufferedSeriesIterator, mint, m
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ev *evaluator) VectorAnd(lhs, rhs Vector, matching *parser.VectorMatching, enh *EvalNodeHelper) Vector {
|
func (ev *evaluator) VectorAnd(lhs, rhs Vector, matching *parser.VectorMatching, lhsh, rhsh []EvalSeriesHelper, enh *EvalNodeHelper) Vector {
|
||||||
if matching.Card != parser.CardManyToMany {
|
if matching.Card != parser.CardManyToMany {
|
||||||
panic("set operations must only use many-to-many matching")
|
panic("set operations must only use many-to-many matching")
|
||||||
}
|
}
|
||||||
sigf := enh.signatureFunc(matching.On, matching.MatchingLabels...)
|
if len(lhs) == 0 || len(rhs) == 0 {
|
||||||
|
return nil // Short-circuit: AND with nothing is nothing.
|
||||||
|
}
|
||||||
|
|
||||||
// The set of signatures for the right-hand side Vector.
|
// The set of signatures for the right-hand side Vector.
|
||||||
rightSigs := map[string]struct{}{}
|
rightSigs := map[string]struct{}{}
|
||||||
// Add all rhs samples to a map so we can easily find matches later.
|
// Add all rhs samples to a map so we can easily find matches later.
|
||||||
for _, rs := range rhs {
|
for _, sh := range rhsh {
|
||||||
rightSigs[sigf(rs.Metric)] = struct{}{}
|
rightSigs[sh.signature] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ls := range lhs {
|
for i, ls := range lhs {
|
||||||
// If there's a matching entry in the right-hand side Vector, add the sample.
|
// If there's a matching entry in the right-hand side Vector, add the sample.
|
||||||
if _, ok := rightSigs[sigf(ls.Metric)]; ok {
|
if _, ok := rightSigs[lhsh[i].signature]; ok {
|
||||||
enh.Out = append(enh.Out, ls)
|
enh.Out = append(enh.Out, ls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return enh.Out
|
return enh.Out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ev *evaluator) VectorOr(lhs, rhs Vector, matching *parser.VectorMatching, enh *EvalNodeHelper) Vector {
|
func (ev *evaluator) VectorOr(lhs, rhs Vector, matching *parser.VectorMatching, lhsh, rhsh []EvalSeriesHelper, enh *EvalNodeHelper) Vector {
|
||||||
if matching.Card != parser.CardManyToMany {
|
if matching.Card != parser.CardManyToMany {
|
||||||
panic("set operations must only use many-to-many matching")
|
panic("set operations must only use many-to-many matching")
|
||||||
}
|
}
|
||||||
sigf := enh.signatureFunc(matching.On, matching.MatchingLabels...)
|
if len(lhs) == 0 { // Short-circuit.
|
||||||
|
return rhs
|
||||||
|
} else if len(rhs) == 0 {
|
||||||
|
return lhs
|
||||||
|
}
|
||||||
|
|
||||||
leftSigs := map[string]struct{}{}
|
leftSigs := map[string]struct{}{}
|
||||||
// Add everything from the left-hand-side Vector.
|
// Add everything from the left-hand-side Vector.
|
||||||
for _, ls := range lhs {
|
for i, ls := range lhs {
|
||||||
leftSigs[sigf(ls.Metric)] = struct{}{}
|
leftSigs[lhsh[i].signature] = struct{}{}
|
||||||
enh.Out = append(enh.Out, ls)
|
enh.Out = append(enh.Out, ls)
|
||||||
}
|
}
|
||||||
// Add all right-hand side elements which have not been added from the left-hand side.
|
// Add all right-hand side elements which have not been added from the left-hand side.
|
||||||
for _, rs := range rhs {
|
for j, rs := range rhs {
|
||||||
if _, ok := leftSigs[sigf(rs.Metric)]; !ok {
|
if _, ok := leftSigs[rhsh[j].signature]; !ok {
|
||||||
enh.Out = append(enh.Out, rs)
|
enh.Out = append(enh.Out, rs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return enh.Out
|
return enh.Out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ev *evaluator) VectorUnless(lhs, rhs Vector, matching *parser.VectorMatching, enh *EvalNodeHelper) Vector {
|
func (ev *evaluator) VectorUnless(lhs, rhs Vector, matching *parser.VectorMatching, lhsh, rhsh []EvalSeriesHelper, enh *EvalNodeHelper) Vector {
|
||||||
if matching.Card != parser.CardManyToMany {
|
if matching.Card != parser.CardManyToMany {
|
||||||
panic("set operations must only use many-to-many matching")
|
panic("set operations must only use many-to-many matching")
|
||||||
}
|
}
|
||||||
sigf := enh.signatureFunc(matching.On, matching.MatchingLabels...)
|
// Short-circuit: empty rhs means we will return everything in lhs;
|
||||||
|
// empty lhs means we will return empty - don't need to build a map.
|
||||||
rightSigs := map[string]struct{}{}
|
if len(lhs) == 0 || len(rhs) == 0 {
|
||||||
for _, rs := range rhs {
|
return lhs
|
||||||
rightSigs[sigf(rs.Metric)] = struct{}{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ls := range lhs {
|
rightSigs := map[string]struct{}{}
|
||||||
if _, ok := rightSigs[sigf(ls.Metric)]; !ok {
|
for _, sh := range rhsh {
|
||||||
|
rightSigs[sh.signature] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, ls := range lhs {
|
||||||
|
if _, ok := rightSigs[lhsh[i].signature]; !ok {
|
||||||
enh.Out = append(enh.Out, ls)
|
enh.Out = append(enh.Out, ls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1837,17 +1836,20 @@ func (ev *evaluator) VectorUnless(lhs, rhs Vector, matching *parser.VectorMatchi
|
||||||
}
|
}
|
||||||
|
|
||||||
// VectorBinop evaluates a binary operation between two Vectors, excluding set operators.
|
// VectorBinop evaluates a binary operation between two Vectors, excluding set operators.
|
||||||
func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *parser.VectorMatching, returnBool bool, enh *EvalNodeHelper) Vector {
|
func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *parser.VectorMatching, returnBool bool, lhsh, rhsh []EvalSeriesHelper, enh *EvalNodeHelper) Vector {
|
||||||
if matching.Card == parser.CardManyToMany {
|
if matching.Card == parser.CardManyToMany {
|
||||||
panic("many-to-many only allowed for set operators")
|
panic("many-to-many only allowed for set operators")
|
||||||
}
|
}
|
||||||
sigf := enh.signatureFunc(matching.On, matching.MatchingLabels...)
|
if len(lhs) == 0 || len(rhs) == 0 {
|
||||||
|
return nil // Short-circuit: nothing is going to match.
|
||||||
|
}
|
||||||
|
|
||||||
// The control flow below handles one-to-one or many-to-one matching.
|
// The control flow below handles one-to-one or many-to-one matching.
|
||||||
// For one-to-many, swap sidedness and account for the swap when calculating
|
// For one-to-many, swap sidedness and account for the swap when calculating
|
||||||
// values.
|
// values.
|
||||||
if matching.Card == parser.CardOneToMany {
|
if matching.Card == parser.CardOneToMany {
|
||||||
lhs, rhs = rhs, lhs
|
lhs, rhs = rhs, lhs
|
||||||
|
lhsh, rhsh = rhsh, lhsh
|
||||||
}
|
}
|
||||||
|
|
||||||
// All samples from the rhs hashed by the matching label/values.
|
// All samples from the rhs hashed by the matching label/values.
|
||||||
|
@ -1861,8 +1863,8 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *
|
||||||
rightSigs := enh.rightSigs
|
rightSigs := enh.rightSigs
|
||||||
|
|
||||||
// Add all rhs samples to a map so we can easily find matches later.
|
// Add all rhs samples to a map so we can easily find matches later.
|
||||||
for _, rs := range rhs {
|
for i, rs := range rhs {
|
||||||
sig := sigf(rs.Metric)
|
sig := rhsh[i].signature
|
||||||
// The rhs is guaranteed to be the 'one' side. Having multiple samples
|
// The rhs is guaranteed to be the 'one' side. Having multiple samples
|
||||||
// with the same signature means that the matching is many-to-many.
|
// with the same signature means that the matching is many-to-many.
|
||||||
if duplSample, found := rightSigs[sig]; found {
|
if duplSample, found := rightSigs[sig]; found {
|
||||||
|
@ -1892,8 +1894,8 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *
|
||||||
|
|
||||||
// For all lhs samples find a respective rhs sample and perform
|
// For all lhs samples find a respective rhs sample and perform
|
||||||
// the binary operation.
|
// the binary operation.
|
||||||
for _, ls := range lhs {
|
for i, ls := range lhs {
|
||||||
sig := sigf(ls.Metric)
|
sig := lhsh[i].signature
|
||||||
|
|
||||||
rs, found := rightSigs[sig] // Look for a match in the rhs Vector.
|
rs, found := rightSigs[sig] // Look for a match in the rhs Vector.
|
||||||
if !found {
|
if !found {
|
||||||
|
@ -2210,22 +2212,24 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
|
||||||
resultSize := k
|
resultSize := k
|
||||||
if k > inputVecLen {
|
if k > inputVecLen {
|
||||||
resultSize = inputVecLen
|
resultSize = inputVecLen
|
||||||
|
} else if k == 0 {
|
||||||
|
resultSize = 1
|
||||||
}
|
}
|
||||||
switch op {
|
switch op {
|
||||||
case parser.STDVAR, parser.STDDEV:
|
case parser.STDVAR, parser.STDDEV:
|
||||||
result[groupingKey].value = 0
|
result[groupingKey].value = 0
|
||||||
case parser.TOPK, parser.QUANTILE:
|
case parser.TOPK, parser.QUANTILE:
|
||||||
result[groupingKey].heap = make(vectorByValueHeap, 0, resultSize)
|
result[groupingKey].heap = make(vectorByValueHeap, 1, resultSize)
|
||||||
heap.Push(&result[groupingKey].heap, &Sample{
|
result[groupingKey].heap[0] = Sample{
|
||||||
Point: Point{V: s.V},
|
Point: Point{V: s.V},
|
||||||
Metric: s.Metric,
|
Metric: s.Metric,
|
||||||
})
|
}
|
||||||
case parser.BOTTOMK:
|
case parser.BOTTOMK:
|
||||||
result[groupingKey].reverseHeap = make(vectorByReverseValueHeap, 0, resultSize)
|
result[groupingKey].reverseHeap = make(vectorByReverseValueHeap, 1, resultSize)
|
||||||
heap.Push(&result[groupingKey].reverseHeap, &Sample{
|
result[groupingKey].reverseHeap[0] = Sample{
|
||||||
Point: Point{V: s.V},
|
Point: Point{V: s.V},
|
||||||
Metric: s.Metric,
|
Metric: s.Metric,
|
||||||
})
|
}
|
||||||
case parser.GROUP:
|
case parser.GROUP:
|
||||||
result[groupingKey].value = 1
|
result[groupingKey].value = 1
|
||||||
}
|
}
|
||||||
|
@ -2283,6 +2287,13 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
|
||||||
case parser.TOPK:
|
case parser.TOPK:
|
||||||
if int64(len(group.heap)) < k || group.heap[0].V < s.V || math.IsNaN(group.heap[0].V) {
|
if int64(len(group.heap)) < k || group.heap[0].V < s.V || math.IsNaN(group.heap[0].V) {
|
||||||
if int64(len(group.heap)) == k {
|
if int64(len(group.heap)) == k {
|
||||||
|
if k == 1 { // For k==1 we can replace in-situ.
|
||||||
|
group.heap[0] = Sample{
|
||||||
|
Point: Point{V: s.V},
|
||||||
|
Metric: s.Metric,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
heap.Pop(&group.heap)
|
heap.Pop(&group.heap)
|
||||||
}
|
}
|
||||||
heap.Push(&group.heap, &Sample{
|
heap.Push(&group.heap, &Sample{
|
||||||
|
@ -2294,6 +2305,13 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
|
||||||
case parser.BOTTOMK:
|
case parser.BOTTOMK:
|
||||||
if int64(len(group.reverseHeap)) < k || group.reverseHeap[0].V > s.V || math.IsNaN(group.reverseHeap[0].V) {
|
if int64(len(group.reverseHeap)) < k || group.reverseHeap[0].V > s.V || math.IsNaN(group.reverseHeap[0].V) {
|
||||||
if int64(len(group.reverseHeap)) == k {
|
if int64(len(group.reverseHeap)) == k {
|
||||||
|
if k == 1 { // For k==1 we can replace in-situ.
|
||||||
|
group.reverseHeap[0] = Sample{
|
||||||
|
Point: Point{V: s.V},
|
||||||
|
Metric: s.Metric,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
heap.Pop(&group.reverseHeap)
|
heap.Pop(&group.reverseHeap)
|
||||||
}
|
}
|
||||||
heap.Push(&group.reverseHeap, &Sample{
|
heap.Push(&group.reverseHeap, &Sample{
|
||||||
|
@ -2327,7 +2345,9 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
|
||||||
|
|
||||||
case parser.TOPK:
|
case parser.TOPK:
|
||||||
// The heap keeps the lowest value on top, so reverse it.
|
// The heap keeps the lowest value on top, so reverse it.
|
||||||
sort.Sort(sort.Reverse(aggr.heap))
|
if len(aggr.heap) > 1 {
|
||||||
|
sort.Sort(sort.Reverse(aggr.heap))
|
||||||
|
}
|
||||||
for _, v := range aggr.heap {
|
for _, v := range aggr.heap {
|
||||||
enh.Out = append(enh.Out, Sample{
|
enh.Out = append(enh.Out, Sample{
|
||||||
Metric: v.Metric,
|
Metric: v.Metric,
|
||||||
|
@ -2338,7 +2358,9 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
|
||||||
|
|
||||||
case parser.BOTTOMK:
|
case parser.BOTTOMK:
|
||||||
// The heap keeps the highest value on top, so reverse it.
|
// The heap keeps the highest value on top, so reverse it.
|
||||||
sort.Sort(sort.Reverse(aggr.reverseHeap))
|
if len(aggr.reverseHeap) > 1 {
|
||||||
|
sort.Sort(sort.Reverse(aggr.reverseHeap))
|
||||||
|
}
|
||||||
for _, v := range aggr.reverseHeap {
|
for _, v := range aggr.reverseHeap {
|
||||||
enh.Out = append(enh.Out, Sample{
|
enh.Out = append(enh.Out, Sample{
|
||||||
Metric: v.Metric,
|
Metric: v.Metric,
|
||||||
|
|
5
web/ui/package-lock.json
generated
5
web/ui/package-lock.json
generated
|
@ -8,7 +8,10 @@
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"react-app",
|
"react-app",
|
||||||
"module/*"
|
"module/*"
|
||||||
]
|
],
|
||||||
|
"engines": {
|
||||||
|
"npm": ">=7.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"module/codemirror-promql": {
|
"module/codemirror-promql": {
|
||||||
"version": "0.18.0",
|
"version": "0.18.0",
|
||||||
|
|
|
@ -12,5 +12,8 @@
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"react-app",
|
"react-app",
|
||||||
"module/*"
|
"module/*"
|
||||||
]
|
],
|
||||||
|
"engines": {
|
||||||
|
"npm": ">=7.0.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue