mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Merge cdf4b3ec3a
into 61aa82865d
This commit is contained in:
commit
19345549f0
26
cmd/prometheus/labels.go
Normal file
26
cmd/prometheus/labels.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build !stringlabels
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/prometheus/prometheus/tsdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mapCommonLabelSymbols(_ *tsdb.DB, _ *slog.Logger) error {
|
||||||
|
return nil
|
||||||
|
}
|
136
cmd/prometheus/labels_stringlabels.go
Normal file
136
cmd/prometheus/labels_stringlabels.go
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//go:build stringlabels
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmp"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
|
"github.com/prometheus/prometheus/tsdb"
|
||||||
|
"github.com/prometheus/prometheus/tsdb/index"
|
||||||
|
)
|
||||||
|
|
||||||
|
// countBlockSymbols reads given block index and counts how many time each string
|
||||||
|
// occurs on time series labels.
|
||||||
|
func countBlockSymbols(ctx context.Context, block *tsdb.Block) (map[string]int, error) {
|
||||||
|
names := map[string]int{}
|
||||||
|
|
||||||
|
ir, err := block.Index()
|
||||||
|
if err != nil {
|
||||||
|
return names, err
|
||||||
|
}
|
||||||
|
|
||||||
|
labelNames, err := ir.LabelNames(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return names, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range labelNames {
|
||||||
|
name = strings.Clone(name)
|
||||||
|
|
||||||
|
if _, ok := names[name]; !ok {
|
||||||
|
names[name] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
values, err := ir.LabelValues(ctx, name)
|
||||||
|
if err != nil {
|
||||||
|
return names, err
|
||||||
|
}
|
||||||
|
for _, value := range values {
|
||||||
|
value = strings.Clone(value)
|
||||||
|
|
||||||
|
if _, ok := names[value]; !ok {
|
||||||
|
names[value] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := ir.Postings(ctx, name, value)
|
||||||
|
if err != nil {
|
||||||
|
return names, err
|
||||||
|
}
|
||||||
|
|
||||||
|
refs, err := index.ExpandPostings(p)
|
||||||
|
if err != nil {
|
||||||
|
return names, err
|
||||||
|
}
|
||||||
|
|
||||||
|
names[name] += len(refs)
|
||||||
|
names[value] += len(refs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return names, ir.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
type labelCost struct {
|
||||||
|
name string
|
||||||
|
cost int
|
||||||
|
}
|
||||||
|
|
||||||
|
// selectBlockStringsToMap takes a block and returns a list of strings that are most commonly
|
||||||
|
// present on all time series.
|
||||||
|
// List is sorted starting with the most frequent strings.
|
||||||
|
func selectBlockStringsToMap(block *tsdb.Block) ([]string, error) {
|
||||||
|
names, err := countBlockSymbols(context.Background(), block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to build list of common strings in block %s: %w", block.Meta().ULID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
costs := make([]labelCost, 0, len(names))
|
||||||
|
for name, count := range names {
|
||||||
|
costs = append(costs, labelCost{name: name, cost: (len(name) - 1) * count})
|
||||||
|
}
|
||||||
|
slices.SortFunc(costs, func(a, b labelCost) int {
|
||||||
|
return cmp.Compare(b.cost, a.cost)
|
||||||
|
})
|
||||||
|
|
||||||
|
mappedLabels := make([]string, 0, 256)
|
||||||
|
for i, c := range costs {
|
||||||
|
if i >= 256 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
mappedLabels = append(mappedLabels, c.name)
|
||||||
|
}
|
||||||
|
return mappedLabels, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapCommonLabelSymbols(db *tsdb.DB, logger *slog.Logger) error {
|
||||||
|
var block *tsdb.Block
|
||||||
|
for _, b := range db.Blocks() {
|
||||||
|
if block == nil || b.MaxTime() > block.MaxTime() {
|
||||||
|
block = b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if block == nil {
|
||||||
|
logger.Info("No tsdb blocks found, can't map common label strings")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info(
|
||||||
|
"Finding most common label strings in last block",
|
||||||
|
slog.String("block", block.String()),
|
||||||
|
)
|
||||||
|
mappedLabels, err := selectBlockStringsToMap(block)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Info("Mapped common label strings", slog.Int("count", len(mappedLabels)))
|
||||||
|
labels.MapLabels(mappedLabels)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -853,6 +853,12 @@ func main() {
|
||||||
|
|
||||||
cfg.web.Flags = map[string]string{}
|
cfg.web.Flags = map[string]string{}
|
||||||
|
|
||||||
|
cfg.tsdb.PreInitFunc = func(db *tsdb.DB) {
|
||||||
|
if err = mapCommonLabelSymbols(db, logger); err != nil {
|
||||||
|
logger.Warn("Failed to map common strings in labels", slog.Any("err", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Exclude kingpin default flags to expose only Prometheus ones.
|
// Exclude kingpin default flags to expose only Prometheus ones.
|
||||||
boilerplateFlags := kingpin.New("", "").Version("")
|
boilerplateFlags := kingpin.New("", "").Version("")
|
||||||
for _, f := range a.Model().Flags {
|
for _, f := range a.Model().Flags {
|
||||||
|
@ -1797,6 +1803,7 @@ type tsdbOptions struct {
|
||||||
CompactionDelayMaxPercent int
|
CompactionDelayMaxPercent int
|
||||||
EnableOverlappingCompaction bool
|
EnableOverlappingCompaction bool
|
||||||
EnableOOONativeHistograms bool
|
EnableOOONativeHistograms bool
|
||||||
|
PreInitFunc tsdb.PreInitFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (opts tsdbOptions) ToTSDBOptions() tsdb.Options {
|
func (opts tsdbOptions) ToTSDBOptions() tsdb.Options {
|
||||||
|
@ -1821,6 +1828,7 @@ func (opts tsdbOptions) ToTSDBOptions() tsdb.Options {
|
||||||
EnableDelayedCompaction: opts.EnableDelayedCompaction,
|
EnableDelayedCompaction: opts.EnableDelayedCompaction,
|
||||||
CompactionDelayMaxPercent: opts.CompactionDelayMaxPercent,
|
CompactionDelayMaxPercent: opts.CompactionDelayMaxPercent,
|
||||||
EnableOverlappingCompaction: opts.EnableOverlappingCompaction,
|
EnableOverlappingCompaction: opts.EnableOverlappingCompaction,
|
||||||
|
PreInitFunc: opts.PreInitFunc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,124 @@ import (
|
||||||
"github.com/cespare/xxhash/v2"
|
"github.com/cespare/xxhash/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// List of labels that should be mapped to a single byte value.
|
||||||
|
// Obviously can't have more than 256 here.
|
||||||
|
mappedLabels = []string{}
|
||||||
|
mappedLabelIndex = map[string]byte{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// MapLabels takes a list of strings that shuld use a single byte storage
|
||||||
|
// inside labels, making them use as little memory as possible.
|
||||||
|
// Since we use a single byte mapping we can only have 256 such strings.
|
||||||
|
//
|
||||||
|
// We MUST store empty string ("") as one of the values here and if you
|
||||||
|
// don't pass it into MapLabels() then it will be injected.
|
||||||
|
//
|
||||||
|
// If you pass more strings than 256 then extra strings will be ignored.
|
||||||
|
func MapLabels(names []string) {
|
||||||
|
// We must always store empty string. Push it to the front of the slice if not present.
|
||||||
|
if !slices.Contains(names, "") {
|
||||||
|
names = append([]string{""}, names...)
|
||||||
|
}
|
||||||
|
|
||||||
|
mappedLabels = make([]string, 0, 256)
|
||||||
|
mappedLabelIndex = make(map[string]byte, 256)
|
||||||
|
|
||||||
|
for i, name := range names {
|
||||||
|
if i >= 256 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
mappedLabels = append(mappedLabels, name)
|
||||||
|
mappedLabelIndex[name] = byte(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
names := []string{
|
||||||
|
// Empty string, this must be present here.
|
||||||
|
"",
|
||||||
|
// These label names are always present on every time series.
|
||||||
|
MetricName,
|
||||||
|
InstanceName,
|
||||||
|
"job",
|
||||||
|
// Common label names.
|
||||||
|
BucketLabel,
|
||||||
|
"code",
|
||||||
|
"handler",
|
||||||
|
"quantile",
|
||||||
|
// Meta metric names injected by Prometheus itself.
|
||||||
|
"scrape_body_size_bytes",
|
||||||
|
"scrape_duration_seconds",
|
||||||
|
"scrape_sample_limit",
|
||||||
|
"scrape_samples_post_metric_relabeling",
|
||||||
|
"scrape_samples_scraped",
|
||||||
|
"scrape_series_added",
|
||||||
|
"scrape_timeout_seconds",
|
||||||
|
// Common metric names from client libraries.
|
||||||
|
"process_cpu_seconds_total",
|
||||||
|
"process_max_fds",
|
||||||
|
"process_network_receive_bytes_total",
|
||||||
|
"process_network_transmit_bytes_total",
|
||||||
|
"process_open_fds",
|
||||||
|
"process_resident_memory_bytes",
|
||||||
|
"process_start_time_seconds ",
|
||||||
|
"process_virtual_memory_bytes",
|
||||||
|
"process_virtual_memory_max_bytes",
|
||||||
|
// client_go specific metrics
|
||||||
|
"go_gc_heap_frees_by_size_bytes_bucket",
|
||||||
|
"go_gc_heap_allocs_by_size_bytes_bucket",
|
||||||
|
"net_conntrack_dialer_conn_failed_total",
|
||||||
|
"go_sched_pauses_total_other_seconds_bucket",
|
||||||
|
"go_sched_pauses_total_gc_seconds_bucket",
|
||||||
|
"go_sched_pauses_stopping_other_seconds_bucket",
|
||||||
|
"go_sched_pauses_stopping_gc_seconds_bucket",
|
||||||
|
"go_sched_latencies_seconds_bucket",
|
||||||
|
"go_gc_pauses_seconds_bucket",
|
||||||
|
"go_gc_duration_seconds",
|
||||||
|
// node_exporter metrics
|
||||||
|
"node_cpu_seconds_total",
|
||||||
|
"node_scrape_collector_success",
|
||||||
|
"node_scrape_collector_duration_seconds",
|
||||||
|
"node_cpu_scaling_governor",
|
||||||
|
"node_cpu_guest_seconds_total",
|
||||||
|
"node_hwmon_temp_celsius",
|
||||||
|
"node_hwmon_sensor_label",
|
||||||
|
"node_hwmon_temp_max_celsius",
|
||||||
|
"node_cooling_device_max_state",
|
||||||
|
"node_cooling_device_cur_state",
|
||||||
|
"node_softnet_times_squeezed_total",
|
||||||
|
"node_softnet_received_rps_total",
|
||||||
|
"node_softnet_processed_total",
|
||||||
|
"node_softnet_flow_limit_count_total",
|
||||||
|
"node_softnet_dropped_total",
|
||||||
|
"node_softnet_cpu_collision_total",
|
||||||
|
"node_softnet_backlog_len",
|
||||||
|
"node_schedstat_waiting_seconds_total",
|
||||||
|
"node_schedstat_timeslices_total",
|
||||||
|
"node_schedstat_running_seconds_total",
|
||||||
|
"node_cpu_scaling_frequency_min_hertz",
|
||||||
|
"node_cpu_scaling_frequency_max_hertz",
|
||||||
|
"node_cpu_scaling_frequency_hertz",
|
||||||
|
"node_cpu_frequency_min_hertz",
|
||||||
|
"node_cpu_frequency_max_hertz",
|
||||||
|
"node_hwmon_temp_crit_celsius",
|
||||||
|
"node_hwmon_temp_crit_alarm_celsius",
|
||||||
|
"node_cpu_core_throttles_total",
|
||||||
|
"node_thermal_zone_temp",
|
||||||
|
"node_hwmon_temp_min_celsius",
|
||||||
|
"node_hwmon_chip_names",
|
||||||
|
"node_filesystem_readonly",
|
||||||
|
"node_filesystem_device_error",
|
||||||
|
"node_filesystem_size_bytes",
|
||||||
|
"node_filesystem_free_bytes",
|
||||||
|
"node_filesystem_files_free",
|
||||||
|
"node_filesystem_files",
|
||||||
|
"node_filesystem_avail_bytes",
|
||||||
|
}
|
||||||
|
MapLabels(names)
|
||||||
|
}
|
||||||
|
|
||||||
// Labels is implemented by a single flat string holding name/value pairs.
|
// Labels is implemented by a single flat string holding name/value pairs.
|
||||||
// Each name and value is preceded by its length in varint encoding.
|
// Each name and value is preceded by its length in varint encoding.
|
||||||
// Names are in order.
|
// Names are in order.
|
||||||
|
@ -30,12 +148,15 @@ type Labels struct {
|
||||||
data string
|
data string
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeSize(data string, index int) (int, int) {
|
func decodeSize(data string, index int) (int, int, bool) {
|
||||||
// Fast-path for common case of a single byte, value 0..127.
|
// Fast-path for common case of a single byte, value 0..127.
|
||||||
b := data[index]
|
b := data[index]
|
||||||
index++
|
index++
|
||||||
|
if b == 0x0 {
|
||||||
|
return 1, index, true
|
||||||
|
}
|
||||||
if b < 0x80 {
|
if b < 0x80 {
|
||||||
return int(b), index
|
return int(b), index, false
|
||||||
}
|
}
|
||||||
size := int(b & 0x7F)
|
size := int(b & 0x7F)
|
||||||
for shift := uint(7); ; shift += 7 {
|
for shift := uint(7); ; shift += 7 {
|
||||||
|
@ -48,15 +169,27 @@ func decodeSize(data string, index int) (int, int) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return size, index
|
return size, index, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeString(data string, index int) (string, int) {
|
func decodeString(data string, index int) (string, int) {
|
||||||
var size int
|
var size int
|
||||||
size, index = decodeSize(data, index)
|
var mapped bool
|
||||||
|
size, index, mapped = decodeSize(data, index)
|
||||||
|
if mapped {
|
||||||
|
b := data[index]
|
||||||
|
return mappedLabels[int(b)], index + size
|
||||||
|
}
|
||||||
return data[index : index+size], index + size
|
return data[index : index+size], index + size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func encodeShortString(s string) (int, byte) {
|
||||||
|
if i, ok := mappedLabelIndex[s]; ok {
|
||||||
|
return 0, i
|
||||||
|
}
|
||||||
|
return len(s), 0
|
||||||
|
}
|
||||||
|
|
||||||
// Bytes returns ls as a byte slice.
|
// Bytes returns ls as a byte slice.
|
||||||
// It uses non-printing characters and so should not be used for printing.
|
// It uses non-printing characters and so should not be used for printing.
|
||||||
func (ls Labels) Bytes(buf []byte) []byte {
|
func (ls Labels) Bytes(buf []byte) []byte {
|
||||||
|
@ -197,11 +330,24 @@ func (ls Labels) Get(name string) string {
|
||||||
return "" // Prometheus does not store blank label names.
|
return "" // Prometheus does not store blank label names.
|
||||||
}
|
}
|
||||||
for i := 0; i < len(ls.data); {
|
for i := 0; i < len(ls.data); {
|
||||||
var size int
|
var size, next int
|
||||||
size, i = decodeSize(ls.data, i)
|
var mapped bool
|
||||||
|
var lName, lValue string
|
||||||
|
size, next, mapped = decodeSize(ls.data, i) // Read the key index and size.
|
||||||
|
if mapped { // Key is a mapped string, so decode it fully and move i to the value index.
|
||||||
|
lName, i = decodeString(ls.data, i)
|
||||||
|
if lName == name {
|
||||||
|
lValue, _ = decodeString(ls.data, i)
|
||||||
|
return lValue
|
||||||
|
}
|
||||||
|
if lName[0] > name[0] { // Stop looking if we've gone past.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else { // Value is stored raw in the data string.
|
||||||
|
i = next // Move index to the start of the key string.
|
||||||
if ls.data[i] == name[0] {
|
if ls.data[i] == name[0] {
|
||||||
lName := ls.data[i : i+size]
|
lName = ls.data[i : i+size]
|
||||||
i += size
|
i += size // We got the key string, move the index to the start of the value.
|
||||||
if lName == name {
|
if lName == name {
|
||||||
lValue, _ := decodeString(ls.data, i)
|
lValue, _ := decodeString(ls.data, i)
|
||||||
return lValue
|
return lValue
|
||||||
|
@ -212,8 +358,9 @@ func (ls Labels) Get(name string) string {
|
||||||
}
|
}
|
||||||
i += size
|
i += size
|
||||||
}
|
}
|
||||||
size, i = decodeSize(ls.data, i)
|
}
|
||||||
i += size
|
size, i, _ = decodeSize(ls.data, i) // Read the value index and size.
|
||||||
|
i += size // move the index past the value so we can read the next key.
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -224,11 +371,22 @@ func (ls Labels) Has(name string) bool {
|
||||||
return false // Prometheus does not store blank label names.
|
return false // Prometheus does not store blank label names.
|
||||||
}
|
}
|
||||||
for i := 0; i < len(ls.data); {
|
for i := 0; i < len(ls.data); {
|
||||||
var size int
|
var size, next int
|
||||||
size, i = decodeSize(ls.data, i)
|
var mapped bool
|
||||||
|
var lName string
|
||||||
|
size, next, mapped = decodeSize(ls.data, i)
|
||||||
|
if mapped {
|
||||||
|
lName, i = decodeString(ls.data, i)
|
||||||
|
if lName == name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if lName[0] > name[0] { // Stop looking if we've gone past.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i = next
|
||||||
if ls.data[i] == name[0] {
|
if ls.data[i] == name[0] {
|
||||||
lName := ls.data[i : i+size]
|
lName = ls.data[i : i+size]
|
||||||
i += size
|
|
||||||
if lName == name {
|
if lName == name {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -236,9 +394,10 @@ func (ls Labels) Has(name string) bool {
|
||||||
if ls.data[i] > name[0] { // Stop looking if we've gone past.
|
if ls.data[i] > name[0] { // Stop looking if we've gone past.
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
i += size
|
i += size
|
||||||
}
|
}
|
||||||
size, i = decodeSize(ls.data, i)
|
size, i, _ = decodeSize(ls.data, i)
|
||||||
i += size
|
i += size
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -356,10 +515,10 @@ func Compare(a, b Labels) int {
|
||||||
// Now we know that there is some difference before the end of a and b.
|
// Now we know that there is some difference before the end of a and b.
|
||||||
// Go back through the fields and find which field that difference is in.
|
// Go back through the fields and find which field that difference is in.
|
||||||
firstCharDifferent, i := i, 0
|
firstCharDifferent, i := i, 0
|
||||||
size, nextI := decodeSize(a.data, i)
|
size, nextI, _ := decodeSize(a.data, i)
|
||||||
for nextI+size <= firstCharDifferent {
|
for nextI+size <= firstCharDifferent {
|
||||||
i = nextI + size
|
i = nextI + size
|
||||||
size, nextI = decodeSize(a.data, i)
|
size, nextI, _ = decodeSize(a.data, i)
|
||||||
}
|
}
|
||||||
// Difference is inside this entry.
|
// Difference is inside this entry.
|
||||||
aStr, _ := decodeString(a.data, i)
|
aStr, _ := decodeString(a.data, i)
|
||||||
|
@ -385,9 +544,9 @@ func (ls Labels) Len() int {
|
||||||
count := 0
|
count := 0
|
||||||
for i := 0; i < len(ls.data); {
|
for i := 0; i < len(ls.data); {
|
||||||
var size int
|
var size int
|
||||||
size, i = decodeSize(ls.data, i)
|
size, i, _ = decodeSize(ls.data, i)
|
||||||
i += size
|
i += size
|
||||||
size, i = decodeSize(ls.data, i)
|
size, i, _ = decodeSize(ls.data, i)
|
||||||
i += size
|
i += size
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
|
@ -422,7 +581,7 @@ func (ls Labels) Validate(f func(l Label) error) error {
|
||||||
func (ls Labels) DropMetricName() Labels {
|
func (ls Labels) DropMetricName() Labels {
|
||||||
for i := 0; i < len(ls.data); {
|
for i := 0; i < len(ls.data); {
|
||||||
lName, i2 := decodeString(ls.data, i)
|
lName, i2 := decodeString(ls.data, i)
|
||||||
size, i2 := decodeSize(ls.data, i2)
|
size, i2, _ := decodeSize(ls.data, i2)
|
||||||
i2 += size
|
i2 += size
|
||||||
if lName == MetricName {
|
if lName == MetricName {
|
||||||
if i == 0 { // Make common case fast with no allocations.
|
if i == 0 { // Make common case fast with no allocations.
|
||||||
|
@ -518,12 +677,27 @@ func marshalLabelsToSizedBuffer(lbls []Label, data []byte) int {
|
||||||
|
|
||||||
func marshalLabelToSizedBuffer(m *Label, data []byte) int {
|
func marshalLabelToSizedBuffer(m *Label, data []byte) int {
|
||||||
i := len(data)
|
i := len(data)
|
||||||
i -= len(m.Value)
|
|
||||||
|
size, b := encodeShortString(m.Value)
|
||||||
|
if size == 0 {
|
||||||
|
i--
|
||||||
|
data[i] = b
|
||||||
|
} else {
|
||||||
|
i -= size
|
||||||
copy(data[i:], m.Value)
|
copy(data[i:], m.Value)
|
||||||
i = encodeSize(data, i, len(m.Value))
|
}
|
||||||
i -= len(m.Name)
|
i = encodeSize(data, i, size)
|
||||||
|
|
||||||
|
size, b = encodeShortString(m.Name)
|
||||||
|
if size == 0 {
|
||||||
|
i--
|
||||||
|
data[i] = b
|
||||||
|
} else {
|
||||||
|
i -= size
|
||||||
copy(data[i:], m.Name)
|
copy(data[i:], m.Name)
|
||||||
i = encodeSize(data, i, len(m.Name))
|
}
|
||||||
|
i = encodeSize(data, i, size)
|
||||||
|
|
||||||
return len(data) - i
|
return len(data) - i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,9 +755,16 @@ func labelsSize(lbls []Label) (n int) {
|
||||||
|
|
||||||
func labelSize(m *Label) (n int) {
|
func labelSize(m *Label) (n int) {
|
||||||
// strings are encoded as length followed by contents.
|
// strings are encoded as length followed by contents.
|
||||||
l := len(m.Name)
|
l, _ := encodeShortString(m.Name)
|
||||||
|
if l == 0 {
|
||||||
|
l++
|
||||||
|
}
|
||||||
n += l + sizeVarint(uint64(l))
|
n += l + sizeVarint(uint64(l))
|
||||||
l = len(m.Value)
|
|
||||||
|
l, _ = encodeShortString(m.Value)
|
||||||
|
if l == 0 {
|
||||||
|
l++
|
||||||
|
}
|
||||||
n += l + sizeVarint(uint64(l))
|
n += l + sizeVarint(uint64(l))
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,8 +82,8 @@ func labelsWithHashCollision() (labels.Labels, labels.Labels) {
|
||||||
|
|
||||||
if ls1.Hash() != ls2.Hash() {
|
if ls1.Hash() != ls2.Hash() {
|
||||||
// These ones are the same when using -tags stringlabels
|
// These ones are the same when using -tags stringlabels
|
||||||
ls1 = labels.FromStrings("__name__", "metric", "lbl", "HFnEaGl")
|
ls1 = labels.FromStrings("__name__", "metric", "lbl", "D3opXYk")
|
||||||
ls2 = labels.FromStrings("__name__", "metric", "lbl", "RqcXatm")
|
ls2 = labels.FromStrings("__name__", "metric", "lbl", "G1__3.m")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ls1.Hash() != ls2.Hash() {
|
if ls1.Hash() != ls2.Hash() {
|
||||||
|
|
|
@ -224,6 +224,9 @@ type Options struct {
|
||||||
// PostingsDecoderFactory allows users to customize postings decoders based on BlockMeta.
|
// PostingsDecoderFactory allows users to customize postings decoders based on BlockMeta.
|
||||||
// By default, DefaultPostingsDecoderFactory will be used to create raw posting decoder.
|
// By default, DefaultPostingsDecoderFactory will be used to create raw posting decoder.
|
||||||
PostingsDecoderFactory PostingsDecoderFactory
|
PostingsDecoderFactory PostingsDecoderFactory
|
||||||
|
|
||||||
|
// PreInitFunc is a function that will be called before the HEAD is initialized.
|
||||||
|
PreInitFunc PreInitFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
type NewCompactorFunc func(ctx context.Context, r prometheus.Registerer, l *slog.Logger, ranges []int64, pool chunkenc.Pool, opts *Options) (Compactor, error)
|
type NewCompactorFunc func(ctx context.Context, r prometheus.Registerer, l *slog.Logger, ranges []int64, pool chunkenc.Pool, opts *Options) (Compactor, error)
|
||||||
|
@ -234,6 +237,8 @@ type BlockQuerierFunc func(b BlockReader, mint, maxt int64) (storage.Querier, er
|
||||||
|
|
||||||
type BlockChunkQuerierFunc func(b BlockReader, mint, maxt int64) (storage.ChunkQuerier, error)
|
type BlockChunkQuerierFunc func(b BlockReader, mint, maxt int64) (storage.ChunkQuerier, error)
|
||||||
|
|
||||||
|
type PreInitFunc func(*DB)
|
||||||
|
|
||||||
// DB handles reads and writes of time series falling into
|
// DB handles reads and writes of time series falling into
|
||||||
// a hashed partition of a seriedb.
|
// a hashed partition of a seriedb.
|
||||||
type DB struct {
|
type DB struct {
|
||||||
|
@ -1011,6 +1016,10 @@ func open(dir string, l *slog.Logger, r prometheus.Registerer, opts *Options, rn
|
||||||
minValidTime = inOrderMaxTime
|
minValidTime = inOrderMaxTime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if db.opts.PreInitFunc != nil {
|
||||||
|
db.opts.PreInitFunc(db)
|
||||||
|
}
|
||||||
|
|
||||||
if initErr := db.head.Init(minValidTime); initErr != nil {
|
if initErr := db.head.Init(minValidTime); initErr != nil {
|
||||||
db.head.metrics.walCorruptionsTotal.Inc()
|
db.head.metrics.walCorruptionsTotal.Inc()
|
||||||
var e *errLoadWbl
|
var e *errLoadWbl
|
||||||
|
|
|
@ -6247,8 +6247,8 @@ func labelsWithHashCollision() (labels.Labels, labels.Labels) {
|
||||||
|
|
||||||
if ls1.Hash() != ls2.Hash() {
|
if ls1.Hash() != ls2.Hash() {
|
||||||
// These ones are the same when using -tags stringlabels
|
// These ones are the same when using -tags stringlabels
|
||||||
ls1 = labels.FromStrings("__name__", "metric", "lbl", "HFnEaGl")
|
ls1 = labels.FromStrings("__name__", "metric", "lbl", "D3opXYk")
|
||||||
ls2 = labels.FromStrings("__name__", "metric", "lbl", "RqcXatm")
|
ls2 = labels.FromStrings("__name__", "metric", "lbl", "G1__3.m")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ls1.Hash() != ls2.Hash() {
|
if ls1.Hash() != ls2.Hash() {
|
||||||
|
|
Loading…
Reference in a new issue