mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Merge remote-tracking branch 'upstream/main' into 56quarters/upstream-update
This commit is contained in:
commit
fc643a4854
12
RELEASE.md
12
RELEASE.md
|
@ -37,7 +37,9 @@ Release cadence of first pre-releases being cut is 6 weeks.
|
|||
| v2.30 | 2021-09-08 | Ganesh Vernekar (GitHub: @codesome) |
|
||||
| v2.31 | 2021-10-20 | Julien Pivotto (GitHub: @roidelapluie) |
|
||||
| v2.32 | 2021-12-01 | Julius Volz (GitHub: @juliusv) |
|
||||
| v2.33 | 2022-01-12 | **searching for volunteer** |
|
||||
| v2.33 | 2022-01-12 | Björn Rabenstein (GitHub: @beorn7) |
|
||||
| v2.34 | 2022-02-23 | Chris Marchbanks (GitHub: @csmarchbanks) |
|
||||
| v2.35 | 2022-04-06 | **searching for volunteer** |
|
||||
|
||||
If you are interested in volunteering please create a pull request against the [prometheus/prometheus](https://github.com/prometheus/prometheus) repository and propose yourself for the release series of your choice.
|
||||
|
||||
|
@ -70,7 +72,7 @@ If a bug fix got accidentally merged into main after non-bug-fix changes in main
|
|||
|
||||
Maintaining the release branches for older minor releases happens on a best effort basis.
|
||||
|
||||
### 0. Updating dependencies
|
||||
### 0. Updating dependencies and promoting/demoting experimental features
|
||||
|
||||
A few days before a major or minor release, consider updating the dependencies.
|
||||
|
||||
|
@ -85,6 +87,10 @@ you can skip the dependency update or only update select dependencies. In such a
|
|||
case, you have to create an issue or pull request in the GitHub project for
|
||||
later follow-up.
|
||||
|
||||
This is also a good time to consider any experimental features and feature
|
||||
flags for promotion to stable or for deprecation or ultimately removal. Do any
|
||||
of these in pull requests, one per feature.
|
||||
|
||||
#### Updating Go dependencies
|
||||
|
||||
```
|
||||
|
@ -155,3 +161,5 @@ For release candidate versions (`v2.16.0-rc.0`), run the benchmark for 3 days us
|
|||
If the release has happened in the latest release branch, merge the changes into main.
|
||||
|
||||
Once the binaries have been uploaded, announce the release on `prometheus-announce@googlegroups.com`. (Please do not use `prometheus-users@googlegroups.com` for announcements anymore.) Check out previous announcement mails for inspiration.
|
||||
|
||||
Finally, in case there is no release shepherd listed for the next release yet, find a volunteer.
|
||||
|
|
|
@ -668,13 +668,16 @@ func TestTargetUpdatesOrder(t *testing.T) {
|
|||
discoveryManager.updatert = 100 * time.Millisecond
|
||||
|
||||
var totalUpdatesCount int
|
||||
provUpdates := make(chan []*targetgroup.Group)
|
||||
for _, up := range tc.updates {
|
||||
go newMockDiscoveryProvider(up...).Run(ctx, provUpdates)
|
||||
if len(up) > 0 {
|
||||
totalUpdatesCount += len(up)
|
||||
}
|
||||
}
|
||||
provUpdates := make(chan []*targetgroup.Group, totalUpdatesCount)
|
||||
|
||||
for _, up := range tc.updates {
|
||||
go newMockDiscoveryProvider(up...).Run(ctx, provUpdates)
|
||||
}
|
||||
|
||||
for x := 0; x < totalUpdatesCount; x++ {
|
||||
select {
|
||||
|
|
|
@ -668,13 +668,16 @@ func TestTargetUpdatesOrder(t *testing.T) {
|
|||
discoveryManager.updatert = 100 * time.Millisecond
|
||||
|
||||
var totalUpdatesCount int
|
||||
provUpdates := make(chan []*targetgroup.Group)
|
||||
for _, up := range tc.updates {
|
||||
go newMockDiscoveryProvider(up...).Run(ctx, provUpdates)
|
||||
if len(up) > 0 {
|
||||
totalUpdatesCount += len(up)
|
||||
}
|
||||
}
|
||||
provUpdates := make(chan []*targetgroup.Group, totalUpdatesCount)
|
||||
|
||||
for _, up := range tc.updates {
|
||||
go newMockDiscoveryProvider(up...).Run(ctx, provUpdates)
|
||||
}
|
||||
|
||||
for x := 0; x < totalUpdatesCount; x++ {
|
||||
select {
|
||||
|
|
14
go.mod
14
go.mod
|
@ -3,13 +3,13 @@ module github.com/prometheus/prometheus
|
|||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go v60.3.0+incompatible
|
||||
github.com/Azure/azure-sdk-for-go v61.1.0+incompatible
|
||||
github.com/Azure/go-autorest/autorest v0.11.23
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.18
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
||||
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a
|
||||
github.com/aws/aws-sdk-go v1.42.25
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137
|
||||
github.com/aws/aws-sdk-go v1.42.28
|
||||
github.com/cespare/xxhash/v2 v2.1.2
|
||||
github.com/containerd/containerd v1.5.7 // indirect
|
||||
github.com/dennwc/varint v1.0.0
|
||||
|
@ -27,7 +27,7 @@ require (
|
|||
github.com/go-zookeeper/zk v1.0.2
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/snappy v0.0.4
|
||||
github.com/google/pprof v0.0.0-20211122183932-1daafda22083
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd
|
||||
github.com/gophercloud/gophercloud v0.24.0
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
||||
github.com/hashicorp/consul/api v1.12.0
|
||||
|
@ -59,14 +59,14 @@ require (
|
|||
github.com/uber/jaeger-lib v2.4.1+incompatible
|
||||
go.uber.org/atomic v1.9.0
|
||||
go.uber.org/goleak v1.1.12
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63
|
||||
golang.org/x/net v0.0.0-20220105145211-5b0dc2dfae98
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11
|
||||
golang.org/x/tools v0.1.8
|
||||
google.golang.org/api v0.63.0
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa
|
||||
google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb
|
||||
google.golang.org/protobuf v1.27.1
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
|
@ -75,7 +75,7 @@ require (
|
|||
k8s.io/apimachinery v0.22.4
|
||||
k8s.io/client-go v0.22.4
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/klog/v2 v2.30.0
|
||||
k8s.io/klog/v2 v2.40.1
|
||||
)
|
||||
|
||||
replace (
|
||||
|
|
24
go.sum
24
go.sum
|
@ -52,8 +52,8 @@ collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
|
|||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-sdk-for-go v41.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-sdk-for-go v60.3.0+incompatible h1:u6EXgnASaUOh38GXCwEpRs+u2bbfJpJpXeB42kU2cjg=
|
||||
github.com/Azure/azure-sdk-for-go v60.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-sdk-for-go v61.1.0+incompatible h1:Qbz3jdfkXIPjZECEuk2E7i3iLhC9Ul74pG5mQRQC+z4=
|
||||
github.com/Azure/azure-sdk-for-go v61.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
|
@ -154,8 +154,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
|||
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-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||
github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a h1:E/8AP5dFtMhl5KPJz66Kt9G0n+7Sn41Fy1wv9/jHOrc=
|
||||
github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||
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/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
|
||||
|
@ -188,8 +188,8 @@ github.com/aws/aws-sdk-go v1.30.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZve
|
|||
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
|
||||
github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.40.11/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
||||
github.com/aws/aws-sdk-go v1.42.25 h1:BbdvHAi+t9LRiaYUyd53noq9jcaAcfzOhSVbKfr6Avs=
|
||||
github.com/aws/aws-sdk-go v1.42.25/go.mod h1:gyRszuZ/icHmHAVE4gc/r+cfCmhA1AD+vqfWbgI+eHs=
|
||||
github.com/aws/aws-sdk-go v1.42.28 h1:YJtgL7IGSN41saY4JLW08jya5nU0vGcuAeAa1OL2M6c=
|
||||
github.com/aws/aws-sdk-go v1.42.28/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/benbjohnson/immutable v0.2.1/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
|
||||
github.com/benbjohnson/tmpl v1.0.0/go.mod h1:igT620JFIi44B6awvU9IsDhR77IXWtFigTLil/RPdps=
|
||||
|
@ -719,8 +719,8 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe
|
|||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20211122183932-1daafda22083 h1:c8EUapQFi+kjzedr4c6WqbwMdmB95+oDBWZ5XFHFYxY=
|
||||
github.com/google/pprof v0.0.0-20211122183932-1daafda22083/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
|
@ -1534,8 +1534,9 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220105145211-5b0dc2dfae98 h1:+6WJMRLHlD7X7frgp7TUZ36RnQzSf9wVVTNakEp+nqY=
|
||||
golang.org/x/net v0.0.0-20220105145211-5b0dc2dfae98/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -1906,8 +1907,9 @@ google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEc
|
|||
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0=
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb h1:ZrsicilzPCS/Xr8qtBZZLpy4P9TYXAfl49ctG1/5tgw=
|
||||
google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
|
|
|
@ -15,6 +15,7 @@ package remote
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
@ -1311,12 +1312,16 @@ func (s *shards) sendSamplesWithBackoff(ctx context.Context, samples []prompb.Ti
|
|||
}
|
||||
|
||||
err = sendWriteRequestWithBackoff(ctx, s.qm.cfg, s.qm.logger, attemptStore, onRetry)
|
||||
if err != nil {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
// When there is resharding, we cancel the context for this queue, which means the data is not sent.
|
||||
// So we exit early to not update the metrics.
|
||||
return err
|
||||
}
|
||||
|
||||
s.qm.metrics.sentBytesTotal.Add(float64(reqSize))
|
||||
s.qm.metrics.highestSentTimestamp.Set(float64(highest / 1000))
|
||||
return nil
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func sendWriteRequestWithBackoff(ctx context.Context, cfg config.QueueConfig, l log.Logger, attempt func(int) error, onRetry func()) error {
|
||||
|
|
|
@ -27,8 +27,12 @@ import (
|
|||
"github.com/prometheus/prometheus/storage"
|
||||
)
|
||||
|
||||
// Indicates that there is no index entry for an exmplar.
|
||||
const noExemplar = -1
|
||||
const (
|
||||
// Indicates that there is no index entry for an exmplar.
|
||||
noExemplar = -1
|
||||
// Estimated number of exemplars per series, for sizing the index.
|
||||
estimatedExemplarsPerSeries = 16
|
||||
)
|
||||
|
||||
type CircularExemplarStorage struct {
|
||||
lock sync.RWMutex
|
||||
|
@ -117,7 +121,7 @@ func NewCircularExemplarStorage(len int64, m *ExemplarMetrics) (ExemplarStorage,
|
|||
}
|
||||
c := &CircularExemplarStorage{
|
||||
exemplars: make([]*circularBufferEntry, len),
|
||||
index: make(map[string]*indexEntry),
|
||||
index: make(map[string]*indexEntry, len/estimatedExemplarsPerSeries),
|
||||
metrics: m,
|
||||
}
|
||||
|
||||
|
@ -202,7 +206,8 @@ Outer:
|
|||
}
|
||||
|
||||
func (ce *CircularExemplarStorage) ValidateExemplar(l labels.Labels, e exemplar.Exemplar) error {
|
||||
seriesLabels := l.String()
|
||||
var buf [1024]byte
|
||||
seriesLabels := l.Bytes(buf[:])
|
||||
|
||||
// TODO(bwplotka): This lock can lock all scrapers, there might high contention on this on scale.
|
||||
// Optimize by moving the lock to be per series (& benchmark it).
|
||||
|
@ -213,7 +218,7 @@ func (ce *CircularExemplarStorage) ValidateExemplar(l labels.Labels, e exemplar.
|
|||
|
||||
// Not thread safe. The append parameters tells us whether this is an external validation, or internal
|
||||
// as a result of an AddExemplar call, in which case we should update any relevant metrics.
|
||||
func (ce *CircularExemplarStorage) validateExemplar(l string, e exemplar.Exemplar, append bool) error {
|
||||
func (ce *CircularExemplarStorage) validateExemplar(key []byte, e exemplar.Exemplar, append bool) error {
|
||||
if len(ce.exemplars) <= 0 {
|
||||
return storage.ErrExemplarsDisabled
|
||||
}
|
||||
|
@ -230,7 +235,7 @@ func (ce *CircularExemplarStorage) validateExemplar(l string, e exemplar.Exempla
|
|||
}
|
||||
}
|
||||
|
||||
idx, ok := ce.index[l]
|
||||
idx, ok := ce.index[string(key)]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
@ -269,7 +274,7 @@ func (ce *CircularExemplarStorage) Resize(l int64) int {
|
|||
oldNextIndex := int64(ce.nextIndex)
|
||||
|
||||
ce.exemplars = make([]*circularBufferEntry, l)
|
||||
ce.index = make(map[string]*indexEntry)
|
||||
ce.index = make(map[string]*indexEntry, l/estimatedExemplarsPerSeries)
|
||||
ce.nextIndex = 0
|
||||
|
||||
// Replay as many entries as needed, starting with oldest first.
|
||||
|
@ -305,13 +310,14 @@ func (ce *CircularExemplarStorage) Resize(l int64) int {
|
|||
// migrate is like AddExemplar but reuses existing structs. Expected to be called in batch and requires
|
||||
// external lock and does not compute metrics.
|
||||
func (ce *CircularExemplarStorage) migrate(entry *circularBufferEntry) {
|
||||
seriesLabels := entry.ref.seriesLabels.String()
|
||||
var buf [1024]byte
|
||||
seriesLabels := entry.ref.seriesLabels.Bytes(buf[:])
|
||||
|
||||
idx, ok := ce.index[seriesLabels]
|
||||
idx, ok := ce.index[string(seriesLabels)]
|
||||
if !ok {
|
||||
idx = entry.ref
|
||||
idx.oldest = ce.nextIndex
|
||||
ce.index[seriesLabels] = idx
|
||||
ce.index[string(seriesLabels)] = idx
|
||||
} else {
|
||||
entry.ref = idx
|
||||
ce.exemplars[idx.newest].next = ce.nextIndex
|
||||
|
@ -329,7 +335,8 @@ func (ce *CircularExemplarStorage) AddExemplar(l labels.Labels, e exemplar.Exemp
|
|||
return storage.ErrExemplarsDisabled
|
||||
}
|
||||
|
||||
seriesLabels := l.String()
|
||||
var buf [1024]byte
|
||||
seriesLabels := l.Bytes(buf[:])
|
||||
|
||||
// TODO(bwplotka): This lock can lock all scrapers, there might high contention on this on scale.
|
||||
// Optimize by moving the lock to be per series (& benchmark it).
|
||||
|
@ -345,11 +352,11 @@ func (ce *CircularExemplarStorage) AddExemplar(l labels.Labels, e exemplar.Exemp
|
|||
return err
|
||||
}
|
||||
|
||||
_, ok := ce.index[seriesLabels]
|
||||
_, ok := ce.index[string(seriesLabels)]
|
||||
if !ok {
|
||||
ce.index[seriesLabels] = &indexEntry{oldest: ce.nextIndex, seriesLabels: l}
|
||||
ce.index[string(seriesLabels)] = &indexEntry{oldest: ce.nextIndex, seriesLabels: l}
|
||||
} else {
|
||||
ce.exemplars[ce.index[seriesLabels].newest].next = ce.nextIndex
|
||||
ce.exemplars[ce.index[string(seriesLabels)].newest].next = ce.nextIndex
|
||||
}
|
||||
|
||||
if prev := ce.exemplars[ce.nextIndex]; prev == nil {
|
||||
|
@ -357,12 +364,13 @@ func (ce *CircularExemplarStorage) AddExemplar(l labels.Labels, e exemplar.Exemp
|
|||
} else {
|
||||
// There exists exemplar already on this ce.nextIndex entry, drop it, to make place
|
||||
// for others.
|
||||
prevLabels := prev.ref.seriesLabels.String()
|
||||
var buf [1024]byte
|
||||
prevLabels := prev.ref.seriesLabels.Bytes(buf[:])
|
||||
if prev.next == noExemplar {
|
||||
// Last item for this series, remove index entry.
|
||||
delete(ce.index, prevLabels)
|
||||
delete(ce.index, string(prevLabels))
|
||||
} else {
|
||||
ce.index[prevLabels].oldest = prev.next
|
||||
ce.index[string(prevLabels)].oldest = prev.next
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,8 +378,8 @@ func (ce *CircularExemplarStorage) AddExemplar(l labels.Labels, e exemplar.Exemp
|
|||
// since this is the first exemplar stored for this series.
|
||||
ce.exemplars[ce.nextIndex].next = noExemplar
|
||||
ce.exemplars[ce.nextIndex].exemplar = e
|
||||
ce.exemplars[ce.nextIndex].ref = ce.index[seriesLabels]
|
||||
ce.index[seriesLabels].newest = ce.nextIndex
|
||||
ce.exemplars[ce.nextIndex].ref = ce.index[string(seriesLabels)]
|
||||
ce.index[string(seriesLabels)].newest = ce.nextIndex
|
||||
|
||||
ce.nextIndex = (ce.nextIndex + 1) % len(ce.exemplars)
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ func TestAddExemplar(t *testing.T) {
|
|||
}
|
||||
|
||||
require.NoError(t, es.AddExemplar(l, e))
|
||||
require.Equal(t, es.index[l.String()].newest, 0, "exemplar was not stored correctly")
|
||||
require.Equal(t, es.index[string(l.Bytes(nil))].newest, 0, "exemplar was not stored correctly")
|
||||
|
||||
e2 := exemplar.Exemplar{
|
||||
Labels: labels.Labels{
|
||||
|
@ -126,8 +126,8 @@ func TestAddExemplar(t *testing.T) {
|
|||
}
|
||||
|
||||
require.NoError(t, es.AddExemplar(l, e2))
|
||||
require.Equal(t, es.index[l.String()].newest, 1, "exemplar was not stored correctly, location of newest exemplar for series in index did not update")
|
||||
require.True(t, es.exemplars[es.index[l.String()].newest].exemplar.Equals(e2), "exemplar was not stored correctly, expected %+v got: %+v", e2, es.exemplars[es.index[l.String()].newest].exemplar)
|
||||
require.Equal(t, es.index[string(l.Bytes(nil))].newest, 1, "exemplar was not stored correctly, location of newest exemplar for series in index did not update")
|
||||
require.True(t, es.exemplars[es.index[string(l.Bytes(nil))].newest].exemplar.Equals(e2), "exemplar was not stored correctly, expected %+v got: %+v", e2, es.exemplars[es.index[string(l.Bytes(nil))].newest].exemplar)
|
||||
|
||||
require.NoError(t, es.AddExemplar(l, e2), "no error is expected attempting to add duplicate exemplar")
|
||||
|
||||
|
@ -300,7 +300,7 @@ func TestSelectExemplar_TimeRange(t *testing.T) {
|
|||
Ts: int64(101 + i),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, es.index[l.String()].newest, i, "exemplar was not stored correctly")
|
||||
require.Equal(t, es.index[string(l.Bytes(nil))].newest, i, "exemplar was not stored correctly")
|
||||
}
|
||||
|
||||
m, err := labels.NewMatcher(labels.MatchEqual, l[0].Name, l[0].Value)
|
||||
|
@ -376,14 +376,14 @@ func TestIndexOverwrite(t *testing.T) {
|
|||
|
||||
// Ensure index GC'ing is taking place, there should no longer be any
|
||||
// index entry for series l1 since we just wrote two exemplars for series l2.
|
||||
_, ok := es.index[l1.String()]
|
||||
_, ok := es.index[string(l1.Bytes(nil))]
|
||||
require.False(t, ok)
|
||||
require.Equal(t, &indexEntry{1, 0, l2}, es.index[l2.String()])
|
||||
require.Equal(t, &indexEntry{1, 0, l2}, es.index[string(l2.Bytes(nil))])
|
||||
|
||||
err = es.AddExemplar(l1, exemplar.Exemplar{Value: 4, Ts: 4})
|
||||
require.NoError(t, err)
|
||||
|
||||
i := es.index[l2.String()]
|
||||
i := es.index[string(l2.Bytes(nil))]
|
||||
require.Equal(t, &indexEntry{0, 0, l2}, i)
|
||||
}
|
||||
|
||||
|
@ -492,18 +492,23 @@ func BenchmarkAddExemplar(b *testing.B) {
|
|||
|
||||
for _, n := range []int{10000, 100000, 1000000} {
|
||||
b.Run(fmt.Sprintf("%d", n), func(b *testing.B) {
|
||||
exs, err := NewCircularExemplarStorage(int64(n), eMetrics)
|
||||
require.NoError(b, err)
|
||||
es := exs.(*CircularExemplarStorage)
|
||||
|
||||
b.ResetTimer()
|
||||
l := labels.Labels{{Name: "service", Value: strconv.Itoa(0)}}
|
||||
for i := 0; i < n; i++ {
|
||||
if i%100 == 0 {
|
||||
l = labels.Labels{{Name: "service", Value: strconv.Itoa(i)}}
|
||||
}
|
||||
err = es.AddExemplar(l, exemplar.Exemplar{Value: float64(i), Ts: int64(i), Labels: exLabels})
|
||||
for j := 0; j < b.N; j++ {
|
||||
b.StopTimer()
|
||||
exs, err := NewCircularExemplarStorage(int64(n), eMetrics)
|
||||
require.NoError(b, err)
|
||||
es := exs.(*CircularExemplarStorage)
|
||||
l := labels.Labels{{Name: "service", Value: strconv.Itoa(0)}}
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if i%100 == 0 {
|
||||
l = labels.Labels{{Name: "service", Value: strconv.Itoa(i)}}
|
||||
}
|
||||
err = es.AddExemplar(l, exemplar.Exemplar{Value: float64(i), Ts: int64(i), Labels: exLabels})
|
||||
if err != nil {
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -543,24 +548,24 @@ func BenchmarkResizeExemplars(b *testing.B) {
|
|||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
exs, err := NewCircularExemplarStorage(tc.startSize, eMetrics)
|
||||
require.NoError(b, err)
|
||||
es := exs.(*CircularExemplarStorage)
|
||||
b.Run(fmt.Sprintf("%s-%d-to-%d", tc.name, tc.startSize, tc.endSize), func(b *testing.B) {
|
||||
for j := 0; j < b.N; j++ {
|
||||
b.StopTimer()
|
||||
exs, err := NewCircularExemplarStorage(tc.startSize, eMetrics)
|
||||
require.NoError(b, err)
|
||||
es := exs.(*CircularExemplarStorage)
|
||||
|
||||
for i := 0; i < int(float64(tc.startSize)*float64(1.5)); i++ {
|
||||
l := labels.FromStrings("service", strconv.Itoa(i))
|
||||
for i := 0; i < int(float64(tc.startSize)*float64(1.5)); i++ {
|
||||
l := labels.FromStrings("service", strconv.Itoa(i))
|
||||
|
||||
err = es.AddExemplar(l, exemplar.Exemplar{Value: float64(i), Ts: int64(i)})
|
||||
require.NoError(b, err)
|
||||
}
|
||||
saveIndex := es.index
|
||||
saveExemplars := es.exemplars
|
||||
|
||||
b.Run(fmt.Sprintf("%s-%d-to-%d", tc.name, tc.startSize, tc.endSize), func(t *testing.B) {
|
||||
es.index = saveIndex
|
||||
es.exemplars = saveExemplars
|
||||
b.ResetTimer()
|
||||
es.Resize(tc.endSize)
|
||||
err = es.AddExemplar(l, exemplar.Exemplar{Value: float64(i), Ts: int64(i)})
|
||||
if err != nil {
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
b.StartTimer()
|
||||
es.Resize(tc.endSize)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -868,19 +868,18 @@ func FindIntersectingPostings(p Postings, candidates []Postings) (indexes []int,
|
|||
return nil, it.Err()
|
||||
}
|
||||
}
|
||||
if len(h) == 0 {
|
||||
if h.empty() {
|
||||
return nil, nil
|
||||
}
|
||||
h.Init()
|
||||
heap.Init(&h)
|
||||
|
||||
for len(h) > 0 {
|
||||
if !p.Seek(h.At()) {
|
||||
for !h.empty() {
|
||||
if !p.Seek(h.at()) {
|
||||
return indexes, p.Err()
|
||||
}
|
||||
if p.At() == h.At() {
|
||||
found := heap.Pop(&h).(postingsWithIndex)
|
||||
indexes = append(indexes, found.index)
|
||||
} else if err := h.Next(); err != nil {
|
||||
if p.At() == h.at() {
|
||||
indexes = append(indexes, h.popIndex())
|
||||
} else if err := h.next(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@ -888,16 +887,46 @@ func FindIntersectingPostings(p Postings, candidates []Postings) (indexes []int,
|
|||
return indexes, nil
|
||||
}
|
||||
|
||||
// postingsWithIndex is used as postingsWithIndexHeap elements by FindIntersectingPostings,
|
||||
// keeping track of the original index of each postings while they move inside the heap.
|
||||
type postingsWithIndex struct {
|
||||
index int
|
||||
p Postings
|
||||
// popped means that these postings shouldn't be considered anymore.
|
||||
// See popIndex() comment to understand why we need this.
|
||||
popped bool
|
||||
}
|
||||
|
||||
// postingsWithIndexHeap implements heap.Interface,
|
||||
// with root always pointing to the postings with minimum Postings.At() value.
|
||||
// It also implements a special way of removing elements that marks them as popped and moves them to the bottom of the
|
||||
// heap instead of actually removing them, see popIndex() for more details.
|
||||
type postingsWithIndexHeap []postingsWithIndex
|
||||
|
||||
func (h *postingsWithIndexHeap) Init() { heap.Init(h) }
|
||||
func (h postingsWithIndexHeap) At() storage.SeriesRef { return h[0].p.At() }
|
||||
func (h *postingsWithIndexHeap) Next() error {
|
||||
// empty checks whether the heap is empty, which is true if it has no elements, of if the smallest element is popped.
|
||||
func (h *postingsWithIndexHeap) empty() bool {
|
||||
return len(*h) == 0 || (*h)[0].popped
|
||||
}
|
||||
|
||||
// popIndex pops the smallest heap element and returns its index.
|
||||
// In our implementation we don't actually do heap.Pop(), instead we mark the element as `popped` and fix its position, which
|
||||
// should be after all the non-popped elements according to our sorting strategy.
|
||||
// By skipping the `heap.Pop()` call we avoid an extra allocation in this heap's Pop() implementation which returns an interface{}.
|
||||
func (h *postingsWithIndexHeap) popIndex() int {
|
||||
index := (*h)[0].index
|
||||
(*h)[0].popped = true
|
||||
heap.Fix(h, 0)
|
||||
return index
|
||||
}
|
||||
|
||||
// at provides the storage.SeriesRef where root Postings is pointing at this moment.
|
||||
func (h postingsWithIndexHeap) at() storage.SeriesRef { return h[0].p.At() }
|
||||
|
||||
// next performs the Postings.Next() operation on the root of the heap, performing the related operation on the heap
|
||||
// and conveniently returning the result of calling Postings.Err() if the result of calling Next() was false.
|
||||
// If Next() succeeds, heap is fixed to move the root to its new position, according to its Postings.At() value.
|
||||
// If Next() returns fails and there's no error reported by Postings.Err(), then root is marked as removed and heap is fixed.
|
||||
func (h *postingsWithIndexHeap) next() error {
|
||||
pi := (*h)[0]
|
||||
next := pi.p.Next()
|
||||
if next {
|
||||
|
@ -908,21 +937,35 @@ func (h *postingsWithIndexHeap) Next() error {
|
|||
if err := pi.p.Err(); err != nil {
|
||||
return errors.Wrapf(err, "postings %d", pi.index)
|
||||
}
|
||||
|
||||
heap.Pop(h)
|
||||
h.popIndex()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h postingsWithIndexHeap) Len() int { return len(h) }
|
||||
func (h postingsWithIndexHeap) Less(i, j int) bool { return h[i].p.At() < h[j].p.At() }
|
||||
func (h *postingsWithIndexHeap) Swap(i, j int) { (*h)[i], (*h)[j] = (*h)[j], (*h)[i] }
|
||||
// Len implements heap.Interface.
|
||||
// Notice that Len() > 0 does not imply that heap is not empty as elements are not removed from this heap.
|
||||
// Use empty() to check whether heap is empty or not.
|
||||
func (h postingsWithIndexHeap) Len() int { return len(h) }
|
||||
|
||||
// Less implements heap.Interface, it puts all the popped elements at the bottom,
|
||||
// and then sorts by Postings.At() property of each node.
|
||||
func (h postingsWithIndexHeap) Less(i, j int) bool {
|
||||
if h[i].popped != h[j].popped {
|
||||
return h[j].popped
|
||||
}
|
||||
return h[i].p.At() < h[j].p.At()
|
||||
}
|
||||
|
||||
// Swap implements heap.Interface.
|
||||
func (h *postingsWithIndexHeap) Swap(i, j int) { (*h)[i], (*h)[j] = (*h)[j], (*h)[i] }
|
||||
|
||||
// Push implements heap.Interface.
|
||||
func (h *postingsWithIndexHeap) Push(x interface{}) {
|
||||
*h = append(*h, x.(postingsWithIndex))
|
||||
}
|
||||
|
||||
// Pop implements heap.Interface and pops the last element, which is NOT the min element,
|
||||
// so this doesn't return the same heap.Pop()
|
||||
// Although this method is implemented for correctness, we don't expect it to be used, see popIndex() method for details.
|
||||
func (h *postingsWithIndexHeap) Pop() interface{} {
|
||||
old := *h
|
||||
n := len(old)
|
||||
|
|
|
@ -1164,13 +1164,13 @@ func TestPostingsWithIndexHeap(t *testing.T) {
|
|||
for _, node := range h {
|
||||
node.p.Next()
|
||||
}
|
||||
h.Init()
|
||||
heap.Init(&h)
|
||||
|
||||
for _, expected := range []storage.SeriesRef{1, 5, 10, 20, 25, 30, 50} {
|
||||
require.Equal(t, expected, h.At())
|
||||
require.NoError(t, h.Next())
|
||||
require.Equal(t, expected, h.at())
|
||||
require.NoError(t, h.next())
|
||||
}
|
||||
require.Empty(t, h)
|
||||
require.True(t, h.empty())
|
||||
})
|
||||
|
||||
t.Run("pop", func(t *testing.T) {
|
||||
|
@ -1182,13 +1182,13 @@ func TestPostingsWithIndexHeap(t *testing.T) {
|
|||
for _, node := range h {
|
||||
node.p.Next()
|
||||
}
|
||||
h.Init()
|
||||
heap.Init(&h)
|
||||
|
||||
for _, expected := range []storage.SeriesRef{1, 5, 10, 20} {
|
||||
require.Equal(t, expected, h.At())
|
||||
require.NoError(t, h.Next())
|
||||
require.Equal(t, expected, h.at())
|
||||
require.NoError(t, h.next())
|
||||
}
|
||||
require.Equal(t, storage.SeriesRef(25), h.At())
|
||||
require.Equal(t, storage.SeriesRef(25), h.at())
|
||||
node := heap.Pop(&h).(postingsWithIndex)
|
||||
require.Equal(t, 2, node.index)
|
||||
require.Equal(t, storage.SeriesRef(25), node.p.At())
|
||||
|
|
|
@ -63,7 +63,7 @@ const AlertsContent: FC<AlertsProps> = ({ groups = [], statsCount }) => {
|
|||
return (
|
||||
<Checkbox
|
||||
key={state}
|
||||
wrapperStyles={{ marginRight: 10 }}
|
||||
wrapperStyles={{ marginRight: 20 }}
|
||||
checked={filter[state]}
|
||||
id={`${state}-toggler`}
|
||||
onChange={toggleFilter(state)}
|
||||
|
|
|
@ -12,7 +12,7 @@ exports[`AlertsContent matches a snapshot 1`] = `
|
|||
onChange={[Function]}
|
||||
wrapperStyles={
|
||||
Object {
|
||||
"marginRight": 10,
|
||||
"marginRight": 20,
|
||||
}
|
||||
}
|
||||
>
|
||||
|
@ -35,7 +35,7 @@ exports[`AlertsContent matches a snapshot 1`] = `
|
|||
onChange={[Function]}
|
||||
wrapperStyles={
|
||||
Object {
|
||||
"marginRight": 10,
|
||||
"marginRight": 20,
|
||||
}
|
||||
}
|
||||
>
|
||||
|
@ -58,7 +58,7 @@ exports[`AlertsContent matches a snapshot 1`] = `
|
|||
onChange={[Function]}
|
||||
wrapperStyles={
|
||||
Object {
|
||||
"marginRight": 10,
|
||||
"marginRight": 20,
|
||||
}
|
||||
}
|
||||
>
|
||||
|
|
Loading…
Reference in a new issue