github.com/grafana/pyroscope@v1.18.0/pkg/validation/limits.go (about)

     1  package validation
     2  
     3  import (
     4  	"encoding/json"
     5  	"flag"
     6  	"fmt"
     7  	"iter"
     8  	"time"
     9  
    10  	"gopkg.in/yaml.v3"
    11  
    12  	"github.com/pkg/errors"
    13  	"github.com/prometheus/common/model"
    14  
    15  	"github.com/grafana/pyroscope/pkg/distributor/ingestlimits"
    16  	"github.com/grafana/pyroscope/pkg/distributor/sampling"
    17  	"github.com/grafana/pyroscope/pkg/distributor/writepath"
    18  	"github.com/grafana/pyroscope/pkg/frontend/readpath"
    19  	"github.com/grafana/pyroscope/pkg/metastore/index/cleaner/retention"
    20  	phlaremodel "github.com/grafana/pyroscope/pkg/model"
    21  	"github.com/grafana/pyroscope/pkg/phlaredb/block"
    22  	placement "github.com/grafana/pyroscope/pkg/segmentwriter/client/distributor/placement/adaptiveplacement"
    23  )
    24  
    25  const (
    26  	bytesInMB = 1048576
    27  
    28  	// MinCompactorPartialBlockDeletionDelay is the minimum partial blocks deletion delay that can be configured in Mimir.
    29  	// Partial blocks are blocks that are not having meta file uploaded yet.
    30  	MinCompactorPartialBlockDeletionDelay = 4 * time.Hour
    31  )
    32  
    33  // Limits describe all the limits for tenants; can be used to describe global default
    34  // limits via flags, or per-tenant limits via yaml config.
    35  // NOTE: we use custom `model.Duration` instead of standard `time.Duration` because,
    36  // to support tenant-friendly duration format (e.g: "1h30m45s") in JSON value.
    37  type Limits struct {
    38  	// Distributor enforced limits.
    39  	IngestionRateMB        float64              `yaml:"ingestion_rate_mb" json:"ingestion_rate_mb"`
    40  	IngestionBurstSizeMB   float64              `yaml:"ingestion_burst_size_mb" json:"ingestion_burst_size_mb"`
    41  	IngestionLimit         *ingestlimits.Config `yaml:"ingestion_limit" json:"ingestion_limit" category:"advanced" doc:"hidden"`
    42  	IngestionBodyLimitMB   float64              `yaml:"ingestion_body_limit_mb" json:"ingestion_body_limit_mb" category:"advanced" doc:"hidden"`
    43  	DistributorSampling    *sampling.Config     `yaml:"distributor_sampling" json:"distributor_sampling" category:"advanced" doc:"hidden"`
    44  	MaxLabelNameLength     int                  `yaml:"max_label_name_length" json:"max_label_name_length"`
    45  	MaxLabelValueLength    int                  `yaml:"max_label_value_length" json:"max_label_value_length"`
    46  	MaxLabelNamesPerSeries int                  `yaml:"max_label_names_per_series" json:"max_label_names_per_series"`
    47  	MaxSessionsPerSeries   int                  `yaml:"max_sessions_per_series" json:"max_sessions_per_series"`
    48  	EnforceLabelsOrder     bool                 `yaml:"enforce_labels_order" json:"enforce_labels_order"`
    49  
    50  	MaxProfileSizeBytes              int `yaml:"max_profile_size_bytes" json:"max_profile_size_bytes"`
    51  	MaxProfileStacktraceSamples      int `yaml:"max_profile_stacktrace_samples" json:"max_profile_stacktrace_samples"`
    52  	MaxProfileStacktraceSampleLabels int `yaml:"max_profile_stacktrace_sample_labels" json:"max_profile_stacktrace_sample_labels"`
    53  	MaxProfileStacktraceDepth        int `yaml:"max_profile_stacktrace_depth" json:"max_profile_stacktrace_depth"`
    54  	MaxProfileSymbolValueLength      int `yaml:"max_profile_symbol_value_length" json:"max_profile_symbol_value_length"`
    55  
    56  	// Distributor per-app usage breakdown.
    57  	DistributorUsageGroups *UsageGroupConfig `yaml:"distributor_usage_groups" json:"distributor_usage_groups"`
    58  
    59  	// Distributor aggregation.
    60  	DistributorAggregationWindow model.Duration `yaml:"distributor_aggregation_window" json:"distributor_aggregation_window"`
    61  	DistributorAggregationPeriod model.Duration `yaml:"distributor_aggregation_period" json:"distributor_aggregation_period"`
    62  
    63  	// IngestionRelabelingRules allow to specify additional relabeling rules that get applied before a profile gets ingested. There are some default relabeling rules, which ensure consistency of profiling series. The position of the default rules can be contolled by IngestionRelabelingDefaultRulesPosition
    64  	IngestionRelabelingRules                IngestionRelabelRules `yaml:"ingestion_relabeling_rules" json:"ingestion_relabeling_rules" category:"advanced"`
    65  	IngestionRelabelingDefaultRulesPosition RelabelRulesPosition  `yaml:"ingestion_relabeling_default_rules_position" json:"ingestion_relabeling_default_rules_position" category:"advanced"`
    66  
    67  	SampleTypeRelabelingRules SampleTypeRelabelRules `yaml:"sample_type_relabeling_rules" json:"sample_type_relabeling_rules" category:"advanced"`
    68  
    69  	// The tenant shard size determines the how many ingesters a particular
    70  	// tenant will be sharded to. Needs to be specified on distributors for
    71  	// correct distribution and on ingesters so that the local ingestion limit
    72  	// can be calculated correctly.
    73  	IngestionTenantShardSize int `yaml:"ingestion_tenant_shard_size" json:"ingestion_tenant_shard_size"`
    74  
    75  	// IngestionArtificialDelay is the artificial ingestion latency. It make sure the ingestion requests are delayed at the end of the request, to achieve a more uniform latency.
    76  	IngestionArtificialDelay model.Duration `yaml:"ingestion_artificial_delay" json:"ingestion_artificial_delay" category:"experimental" doc:"hidden"`
    77  
    78  	// Ingester enforced limits.
    79  	MaxLocalSeriesPerTenant  int `yaml:"max_local_series_per_tenant" json:"max_local_series_per_tenant"`
    80  	MaxGlobalSeriesPerTenant int `yaml:"max_global_series_per_tenant" json:"max_global_series_per_tenant"`
    81  
    82  	// Querier enforced limits.
    83  	MaxQueryLookback           model.Duration `yaml:"max_query_lookback" json:"max_query_lookback"`
    84  	MaxQueryLength             model.Duration `yaml:"max_query_length" json:"max_query_length"`
    85  	MaxQueryParallelism        int            `yaml:"max_query_parallelism" json:"max_query_parallelism"`
    86  	QueryAnalysisEnabled       bool           `yaml:"query_analysis_enabled" json:"query_analysis_enabled"`
    87  	QueryAnalysisSeriesEnabled bool           `yaml:"query_analysis_series_enabled" json:"query_analysis_series_enabled"`
    88  
    89  	// Flame graph enforced limits.
    90  	MaxFlameGraphNodesDefault              int  `yaml:"max_flamegraph_nodes_default" json:"max_flamegraph_nodes_default"`
    91  	MaxFlameGraphNodesMax                  int  `yaml:"max_flamegraph_nodes_max" json:"max_flamegraph_nodes_max"`
    92  	MaxFlameGraphNodesOnSelectMergeProfile bool `yaml:"max_flamegraph_nodes_on_select_merge_profile" json:"max_flamegraph_nodes_on_select_merge_profile" category:"advanced" doc:"hidden"`
    93  	// Store-gateway.
    94  	StoreGatewayTenantShardSize int `yaml:"store_gateway_tenant_shard_size" json:"store_gateway_tenant_shard_size"`
    95  
    96  	// Query frontend.
    97  	QuerySplitDuration   model.Duration `yaml:"split_queries_by_interval" json:"split_queries_by_interval"`
    98  	QuerySanitizeOnMerge bool           `yaml:"query_sanitize_on_merge" json:"query_sanitize_on_merge"`
    99  
   100  	// Compactor.
   101  	CompactorBlocksRetentionPeriod     model.Duration `yaml:"compactor_blocks_retention_period" json:"compactor_blocks_retention_period"`
   102  	CompactorSplitAndMergeShards       int            `yaml:"compactor_split_and_merge_shards" json:"compactor_split_and_merge_shards"`
   103  	CompactorSplitAndMergeStageSize    int            `yaml:"compactor_split_and_merge_stage_size" json:"compactor_split_and_merge_stage_size"`
   104  	CompactorSplitGroups               int            `yaml:"compactor_split_groups" json:"compactor_split_groups"`
   105  	CompactorTenantShardSize           int            `yaml:"compactor_tenant_shard_size" json:"compactor_tenant_shard_size"`
   106  	CompactorPartialBlockDeletionDelay model.Duration `yaml:"compactor_partial_block_deletion_delay" json:"compactor_partial_block_deletion_delay"`
   107  	CompactorDownsamplerEnabled        bool           `yaml:"compactor_downsampler_enabled" json:"compactor_downsampler_enabled"`
   108  
   109  	// This config doesn't have a CLI flag registered here because they're registered in
   110  	// their own original config struct.
   111  	S3SSEType                 string `yaml:"s3_sse_type" json:"s3_sse_type" doc:"nocli|description=S3 server-side encryption type. Required to enable server-side encryption overrides for a specific tenant. If not set, the default S3 client settings are used."`
   112  	S3SSEKMSKeyID             string `yaml:"s3_sse_kms_key_id" json:"s3_sse_kms_key_id" doc:"nocli|description=S3 server-side encryption KMS Key ID. Ignored if the SSE type override is not set."`
   113  	S3SSEKMSEncryptionContext string `yaml:"s3_sse_kms_encryption_context" json:"s3_sse_kms_encryption_context" doc:"nocli|description=S3 server-side encryption KMS encryption context. If unset and the key ID override is set, the encryption context will not be provided to S3. Ignored if the SSE type override is not set."`
   114  
   115  	// Ensure profiles are dated within the IngestionWindow of the distributor.
   116  	RejectOlderThan model.Duration `yaml:"reject_older_than" json:"reject_older_than"`
   117  	RejectNewerThan model.Duration `yaml:"reject_newer_than" json:"reject_newer_than"`
   118  
   119  	// Write path overrides used in distributor.
   120  	WritePathOverrides writepath.Config `yaml:",inline" json:",inline"`
   121  
   122  	// Write path overrides used in query-frontend.
   123  	ReadPathOverrides readpath.Config `yaml:",inline" json:",inline"`
   124  
   125  	// Data retention configuration.
   126  	Retention retention.Config `yaml:",inline" json:",inline"`
   127  
   128  	// Adaptive placement limits used in distributors and in the metastore.
   129  	// Distributors use these limits to determine how many shards to allocate
   130  	// to a tenant dataset by default, if no placement rules defined.
   131  	AdaptivePlacementLimits placement.PlacementLimits `yaml:",inline" json:",inline"`
   132  
   133  	// RecordingRules allow to specify static recording rules. This is not compatible with recording rules
   134  	// coming from a RecordingRulesClient, that will replace any static rules defined.
   135  	RecordingRules RecordingRules `yaml:"recording_rules" json:"recording_rules" category:"experimental" doc:"hidden"`
   136  
   137  	// Symbolizer.
   138  	Symbolizer Symbolizer `yaml:"symbolizer" json:"symbolizer" category:"experimental" doc:"hidden"`
   139  }
   140  
   141  // LimitError are errors that do not comply with the limits specified.
   142  type LimitError string
   143  
   144  func (e LimitError) Error() string {
   145  	return string(e)
   146  }
   147  
   148  // RegisterFlags adds the flags required to config this to the given FlagSet
   149  func (l *Limits) RegisterFlags(f *flag.FlagSet) {
   150  	f.Float64Var(&l.IngestionRateMB, "distributor.ingestion-rate-limit-mb", 4, "Per-tenant ingestion rate limit in sample size per second. Units in MB.")
   151  	f.Float64Var(&l.IngestionBurstSizeMB, "distributor.ingestion-burst-size-mb", 2, "Per-tenant allowed ingestion burst size (in sample size). Units in MB. The burst size refers to the per-distributor local rate limiter, and should be set at least to the maximum profile size expected in a single push request.")
   152  	f.Float64Var(&l.IngestionBodyLimitMB, "distributor.ingestion-body-limit-mb", 256, "Per-tenant ingestion body size limit in MB, before decompressing. 0 to disable.")
   153  	f.IntVar(&l.IngestionTenantShardSize, "distributor.ingestion-tenant-shard-size", 0, "The tenant's shard size used by shuffle-sharding. Must be set both on ingesters and distributors. 0 disables shuffle sharding.")
   154  
   155  	f.IntVar(&l.MaxLabelNameLength, "validation.max-length-label-name", 1024, "Maximum length accepted for label names.")
   156  	f.IntVar(&l.MaxLabelValueLength, "validation.max-length-label-value", 2048, "Maximum length accepted for label value. This setting also applies to the metric name.")
   157  	f.IntVar(&l.MaxLabelNamesPerSeries, "validation.max-label-names-per-series", 30, "Maximum number of label names per series.")
   158  	f.IntVar(&l.MaxSessionsPerSeries, "validation.max-sessions-per-series", 0, "Maximum number of sessions per series. 0 to disable.")
   159  	f.BoolVar(&l.EnforceLabelsOrder, "validation.enforce-labels-order", false, "Enforce labels order optimization.")
   160  
   161  	f.IntVar(&l.MaxLocalSeriesPerTenant, "ingester.max-local-series-per-tenant", 0, "Maximum number of active series of profiles per tenant, per ingester. 0 to disable.")
   162  	f.IntVar(&l.MaxGlobalSeriesPerTenant, "ingester.max-global-series-per-tenant", 5000, "Maximum number of active series of profiles per tenant, across the cluster. 0 to disable. When the global limit is enabled, each ingester is configured with a dynamic local limit based on the replication factor and the current number of healthy ingesters, and is kept updated whenever the number of ingesters change.")
   163  
   164  	_ = l.MaxQueryLength.Set("24h")
   165  	f.Var(&l.MaxQueryLength, "querier.max-query-length", "The limit to length of queries. 0 to disable.")
   166  
   167  	_ = l.MaxQueryLookback.Set("7d")
   168  	f.Var(&l.MaxQueryLookback, "querier.max-query-lookback", "Limit how far back in profiling data can be queried, up until lookback duration ago. This limit is enforced in the query frontend. If the requested time range is outside the allowed range, the request will not fail, but will be modified to only query data within the allowed time range. 0 to disable, default to 7d.")
   169  
   170  	f.IntVar(&l.StoreGatewayTenantShardSize, "store-gateway.tenant-shard-size", 0, "The tenant's shard size, used when store-gateway sharding is enabled. Value of 0 disables shuffle sharding for the tenant, that is all tenant blocks are sharded across all store-gateway replicas.")
   171  
   172  	_ = l.QuerySplitDuration.Set("0s")
   173  	f.Var(&l.QuerySplitDuration, "querier.split-queries-by-interval", "Split queries by a time interval and execute in parallel. The value 0 disables splitting by time")
   174  	f.BoolVar(&l.QuerySanitizeOnMerge, "querier.sanitize-on-merge", true, "Whether profiles should be sanitized when merging.")
   175  
   176  	f.IntVar(&l.MaxQueryParallelism, "querier.max-query-parallelism", 0, "Maximum number of queries that will be scheduled in parallel by the frontend.")
   177  
   178  	f.BoolVar(&l.QueryAnalysisEnabled, "querier.query-analysis-enabled", true, "Whether query analysis is enabled in the query frontend. If disabled, the /AnalyzeQuery endpoint will return an empty response.")
   179  	f.BoolVar(&l.QueryAnalysisSeriesEnabled, "querier.query-analysis-series-enabled", false, "Whether the series portion of query analysis is enabled. If disabled, no series data (e.g., series count) will be calculated by the /AnalyzeQuery endpoint.")
   180  
   181  	f.IntVar(&l.MaxProfileSizeBytes, "validation.max-profile-size-bytes", 4*1024*1024, "Maximum size of a profile in bytes. This is based off the uncompressed size. 0 to disable.")
   182  	f.IntVar(&l.MaxProfileStacktraceSamples, "validation.max-profile-stacktrace-samples", 16000, "Maximum number of samples in a profile. 0 to disable.")
   183  	f.IntVar(&l.MaxProfileStacktraceSampleLabels, "validation.max-profile-stacktrace-sample-labels", 100, "Maximum number of labels in a profile sample. 0 to disable.")
   184  	f.IntVar(&l.MaxProfileStacktraceDepth, "validation.max-profile-stacktrace-depth", 1000, "Maximum depth of a profile stacktrace. Profiles are not rejected instead stacktraces are truncated. 0 to disable.")
   185  	f.IntVar(&l.MaxProfileSymbolValueLength, "validation.max-profile-symbol-value-length", 65535, "Maximum length of a profile symbol value (labels, function names and filenames, etc...). Profiles are not rejected instead symbol values are truncated. 0 to disable.")
   186  
   187  	f.IntVar(&l.MaxFlameGraphNodesDefault, "querier.max-flamegraph-nodes-default", 8<<10, "Maximum number of flame graph nodes by default. 0 to disable.")
   188  	f.IntVar(&l.MaxFlameGraphNodesMax, "querier.max-flamegraph-nodes-max", 1<<20, "Maximum number of flame graph nodes allowed. 0 to disable.")
   189  	f.BoolVar(&l.MaxFlameGraphNodesOnSelectMergeProfile, "querier.max-flamegraph-nodes-on-select-merge-profile", false, "Enforce the max nodes limits and defaults on SelectMergeProfile API. Historically this limit was not enforced to enable to gather full pprof profiles without truncation.")
   190  
   191  	f.Var(&l.DistributorAggregationWindow, "distributor.aggregation-window", "Duration of the distributor aggregation window. Requires aggregation period to be specified. 0 to disable.")
   192  	f.Var(&l.DistributorAggregationPeriod, "distributor.aggregation-period", "Duration of the distributor aggregation period. Requires aggregation window to be specified. 0 to disable.")
   193  
   194  	f.Var(&l.CompactorBlocksRetentionPeriod, "compactor.blocks-retention-period", "Delete blocks containing samples older than the specified retention period. 0 to disable.")
   195  	f.IntVar(&l.CompactorSplitAndMergeShards, "compactor.split-and-merge-shards", 0, "The number of shards to use when splitting blocks. 0 to disable splitting.")
   196  	f.IntVar(&l.CompactorSplitAndMergeStageSize, "compactor.split-and-merge-stage-size", 0, "Number of stages split shards will be written to. Number of output split shards is controlled by -compactor.split-and-merge-shards.")
   197  	f.IntVar(&l.CompactorSplitGroups, "compactor.split-groups", 1, "Number of groups that blocks for splitting should be grouped into. Each group of blocks is then split separately. Number of output split shards is controlled by -compactor.split-and-merge-shards.")
   198  	f.IntVar(&l.CompactorTenantShardSize, "compactor.compactor-tenant-shard-size", 0, "Max number of compactors that can compact blocks for single tenant. 0 to disable the limit and use all compactors.")
   199  	_ = l.CompactorPartialBlockDeletionDelay.Set("1d")
   200  	f.Var(&l.CompactorPartialBlockDeletionDelay, "compactor.partial-block-deletion-delay", fmt.Sprintf("If a partial block (unfinished block without %s file) hasn't been modified for this time, it will be marked for deletion. The minimum accepted value is %s: a lower value will be ignored and the feature disabled. 0 to disable.", block.MetaFilename, MinCompactorPartialBlockDeletionDelay.String()))
   201  	f.BoolVar(&l.CompactorDownsamplerEnabled, "compactor.compactor-downsampler-enabled", true, "If enabled, the compactor will downsample profiles in blocks at compaction level 3 and above. The original profiles are also kept. Note: This set the default for the teanant overrides, in order to be effective it also requires compactor.downsampler-enabled to be set to true.")
   202  
   203  	_ = l.RejectNewerThan.Set("10m")
   204  	f.Var(&l.RejectNewerThan, "validation.reject-newer-than", "This limits how far into the future profiling data can be ingested. This limit is enforced in the distributor. 0 to disable, defaults to 10m.")
   205  
   206  	_ = l.RejectOlderThan.Set("1h")
   207  	f.Var(&l.RejectOlderThan, "validation.reject-older-than", "This limits how far into the past profiling data can be ingested. This limit is enforced in the distributor. 0 to disable, defaults to 1h.")
   208  
   209  	_ = l.IngestionRelabelingDefaultRulesPosition.Set("first")
   210  	f.Var(&l.IngestionRelabelingDefaultRulesPosition, "distributor.ingestion-relabeling-default-rules-position", "Position of the default ingestion relabeling rules in relation to relabel rules from overrides. Valid values are 'first', 'last' or 'disabled'.")
   211  	_ = l.IngestionRelabelingRules.Set("[]")
   212  	f.Var(&l.IngestionRelabelingRules, "distributor.ingestion-relabeling-rules", "List of ingestion relabel configurations. The relabeling rules work the same way, as those of [Prometheus](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config). All rules are applied in the order they are specified. Note: In most situations, it is more effective to use relabeling directly in Grafana Alloy.")
   213  
   214  	_ = l.SampleTypeRelabelingRules.Set("[]")
   215  	f.Var(&l.SampleTypeRelabelingRules, "distributor.sample-type-relabeling-rules", "List of sample type relabel configurations. Rules are applied to sample types with __type__ and __unit__ labels, along with all series labels.")
   216  
   217  	f.Var(&l.IngestionArtificialDelay, "distributor.ingestion-artificial-delay", "Target ingestion delay to apply to all tenants. If set to a non-zero value, the distributor will artificially delay ingestion time-frame by the specified duration by computing the difference between actual ingestion and the target. There is no delay on actual ingestion of samples, it is only the response back to the client.")
   218  
   219  }
   220  
   221  // UnmarshalYAML implements the yaml.Unmarshaler interface.
   222  func (l *Limits) UnmarshalYAML(unmarshal func(interface{}) error) error {
   223  	// We want to set c to the defaults and then overwrite it with the input.
   224  	// To make unmarshal fill the plain data struct rather than calling UnmarshalYAML
   225  	// again, we have to hide it using a type indirection.  See prometheus/config.
   226  	type plain Limits
   227  
   228  	// During startup we wont have a default value so we don't want to overwrite them
   229  	if defaultLimits != nil {
   230  		b, err := yaml.Marshal(defaultLimits)
   231  		if err != nil {
   232  			return errors.Wrap(err, "cloning limits (marshaling)")
   233  		}
   234  		if err := yaml.Unmarshal(b, (*plain)(l)); err != nil {
   235  			return errors.Wrap(err, "cloning limits (unmarshaling)")
   236  		}
   237  	}
   238  	return unmarshal((*plain)(l))
   239  }
   240  
   241  // Validate validates that this limits config is valid.
   242  func (l *Limits) Validate() error {
   243  	if l.IngestionRelabelingDefaultRulesPosition != "" {
   244  		if err := l.IngestionRelabelingDefaultRulesPosition.Set(string(l.IngestionRelabelingDefaultRulesPosition)); err != nil {
   245  			return err
   246  		}
   247  	}
   248  
   249  	for idx, rule := range l.RecordingRules {
   250  		_, err := phlaremodel.NewRecordingRule(rule)
   251  		if err != nil {
   252  			return fmt.Errorf("rule at pos %d is not valid: %v", idx, err)
   253  		}
   254  	}
   255  
   256  	return nil
   257  }
   258  
   259  // When we load YAML from disk, we want the various per-customer limits
   260  // to default to any values specified on the command line, not default
   261  // command line values.  This global contains those values.  I (Tom) cannot
   262  // find a nicer way I'm afraid.
   263  var defaultLimits *Limits
   264  
   265  // SetDefaultLimitsForYAMLUnmarshalling sets global default limits, used when loading
   266  // Limits from YAML files. This is used to ensure per-tenant limits are defaulted to
   267  // those values.
   268  func SetDefaultLimitsForYAMLUnmarshalling(defaults Limits) {
   269  	defaultLimits = &defaults
   270  }
   271  
   272  type TenantLimits interface {
   273  	// TenantLimits is a function that returns limits for given tenant, or
   274  	// nil, if there are no tenant-specific limits.
   275  	TenantLimits(tenantID string) *Limits
   276  	// AllByTenantID gets a mapping of all tenant IDs and limits for that tenant
   277  	AllByTenantID() map[string]*Limits
   278  	// RuntimeConfig returns the runtime config values, if available, and nil otherwise.
   279  	RuntimeConfig() *RuntimeConfigValues
   280  }
   281  
   282  // Overrides periodically fetch a set of per-tenant overrides, and provides convenience
   283  // functions for fetching the correct value.
   284  type Overrides struct {
   285  	defaultLimits *Limits
   286  	tenantLimits  TenantLimits
   287  }
   288  
   289  // NewOverrides makes a new Overrides.
   290  func NewOverrides(defaults Limits, tenantLimits TenantLimits) (*Overrides, error) {
   291  	return &Overrides{
   292  		tenantLimits:  tenantLimits,
   293  		defaultLimits: &defaults,
   294  	}, nil
   295  }
   296  
   297  func (o *Overrides) AllByTenantID() map[string]*Limits {
   298  	if o.tenantLimits != nil {
   299  		return o.tenantLimits.AllByTenantID()
   300  	}
   301  	return nil
   302  }
   303  
   304  // IngestionRateBytes returns the limit on ingester rate (MBs per second).
   305  func (o *Overrides) IngestionRateBytes(tenantID string) float64 {
   306  	return o.getOverridesForTenant(tenantID).IngestionRateMB * bytesInMB
   307  }
   308  
   309  // IngestionBurstSizeBytes returns the burst size for ingestion rate.
   310  func (o *Overrides) IngestionBurstSizeBytes(tenantID string) int {
   311  	return int(o.getOverridesForTenant(tenantID).IngestionBurstSizeMB * bytesInMB)
   312  }
   313  
   314  func (o *Overrides) IngestionBodyLimitBytes(tenantID string) int64 {
   315  	return int64(o.getOverridesForTenant(tenantID).IngestionBodyLimitMB * bytesInMB)
   316  }
   317  
   318  func (o *Overrides) IngestionLimit(tenantID string) *ingestlimits.Config {
   319  	return o.getOverridesForTenant(tenantID).IngestionLimit
   320  }
   321  
   322  func (o *Overrides) DistributorSampling(tenantID string) *sampling.Config {
   323  	return o.getOverridesForTenant(tenantID).DistributorSampling
   324  }
   325  
   326  // IngestionArtificialDelay returns the artificial ingestion latency for a given user.
   327  func (o *Overrides) IngestionArtificialDelay(tenantID string) time.Duration {
   328  	return time.Duration(o.getOverridesForTenant(tenantID).IngestionArtificialDelay)
   329  }
   330  
   331  // IngestionTenantShardSize returns the ingesters shard size for a given user.
   332  func (o *Overrides) IngestionTenantShardSize(tenantID string) int {
   333  	return o.getOverridesForTenant(tenantID).IngestionTenantShardSize
   334  }
   335  
   336  // MaxLabelNameLength returns maximum length a label name can be.
   337  func (o *Overrides) MaxLabelNameLength(tenantID string) int {
   338  	return o.getOverridesForTenant(tenantID).MaxLabelNameLength
   339  }
   340  
   341  // MaxLabelValueLength returns maximum length a label value can be. This also is
   342  // the maximum length of a metric name.
   343  func (o *Overrides) MaxLabelValueLength(tenantID string) int {
   344  	return o.getOverridesForTenant(tenantID).MaxLabelValueLength
   345  }
   346  
   347  // MaxLabelNamesPerSeries returns maximum number of label/value pairs timeseries.
   348  func (o *Overrides) MaxLabelNamesPerSeries(tenantID string) int {
   349  	return o.getOverridesForTenant(tenantID).MaxLabelNamesPerSeries
   350  }
   351  
   352  // MaxProfileSizeBytes returns the maximum size of a profile in bytes.
   353  func (o *Overrides) MaxProfileSizeBytes(tenantID string) int {
   354  	return o.getOverridesForTenant(tenantID).MaxProfileSizeBytes
   355  }
   356  
   357  // MaxProfileStacktraceSamples returns the maximum number of samples in a profile.
   358  func (o *Overrides) MaxProfileStacktraceSamples(tenantID string) int {
   359  	return o.getOverridesForTenant(tenantID).MaxProfileStacktraceSamples
   360  }
   361  
   362  // MaxProfileStacktraceSampleLabels returns the maximum number of labels in a profile sample.
   363  func (o *Overrides) MaxProfileStacktraceSampleLabels(tenantID string) int {
   364  	return o.getOverridesForTenant(tenantID).MaxProfileStacktraceSampleLabels
   365  }
   366  
   367  // MaxProfileStacktraceDepth returns the maximum depth of a profile stacktrace.
   368  func (o *Overrides) MaxProfileStacktraceDepth(tenantID string) int {
   369  	return o.getOverridesForTenant(tenantID).MaxProfileStacktraceDepth
   370  }
   371  
   372  // MaxProfileSymbolValueLength returns the maximum length of a profile symbol value (labels, function name and filename, etc...).
   373  func (o *Overrides) MaxProfileSymbolValueLength(tenantID string) int {
   374  	return o.getOverridesForTenant(tenantID).MaxProfileSymbolValueLength
   375  }
   376  
   377  // MaxSessionsPerSeries returns the maximum number of sessions per single series.
   378  func (o *Overrides) MaxSessionsPerSeries(tenantID string) int {
   379  	return o.getOverridesForTenant(tenantID).MaxSessionsPerSeries
   380  }
   381  
   382  func (o *Overrides) EnforceLabelsOrder(tenantID string) bool {
   383  	return o.getOverridesForTenant(tenantID).EnforceLabelsOrder
   384  }
   385  
   386  func (o *Overrides) DistributorAggregationWindow(tenantID string) model.Duration {
   387  	return o.getOverridesForTenant(tenantID).DistributorAggregationWindow
   388  }
   389  
   390  func (o *Overrides) DistributorAggregationPeriod(tenantID string) model.Duration {
   391  	return o.getOverridesForTenant(tenantID).DistributorAggregationPeriod
   392  }
   393  
   394  // MaxLocalSeriesPerTenant returns the maximum number of series a tenant is allowed to store
   395  // in a single ingester.
   396  func (o *Overrides) MaxLocalSeriesPerTenant(tenantID string) int {
   397  	return o.getOverridesForTenant(tenantID).MaxLocalSeriesPerTenant
   398  }
   399  
   400  // MaxGlobalSeriesPerTenant returns the maximum number of series a tenant is allowed to store
   401  // across the cluster.
   402  func (o *Overrides) MaxGlobalSeriesPerTenant(tenantID string) int {
   403  	return o.getOverridesForTenant(tenantID).MaxGlobalSeriesPerTenant
   404  }
   405  
   406  // MaxQueryLength returns the limit of the length (in time) of a query.
   407  func (o *Overrides) MaxQueryLength(tenantID string) time.Duration {
   408  	return time.Duration(o.getOverridesForTenant(tenantID).MaxQueryLength)
   409  }
   410  
   411  // MaxQueryParallelism returns the limit to the number of sub-queries the
   412  // frontend will process in parallel.
   413  func (o *Overrides) MaxQueryParallelism(tenantID string) int {
   414  	return o.getOverridesForTenant(tenantID).MaxQueryParallelism
   415  }
   416  
   417  // MaxQueryLookback returns the max lookback period of queries.
   418  func (o *Overrides) MaxQueryLookback(tenantID string) time.Duration {
   419  	return time.Duration(o.getOverridesForTenant(tenantID).MaxQueryLookback)
   420  }
   421  
   422  // MaxFlameGraphNodesDefault returns the max flame graph nodes used by default.
   423  func (o *Overrides) MaxFlameGraphNodesDefault(tenantID string) int {
   424  	return o.getOverridesForTenant(tenantID).MaxFlameGraphNodesDefault
   425  }
   426  
   427  // MaxFlameGraphNodesMax returns the max flame graph nodes allowed.
   428  func (o *Overrides) MaxFlameGraphNodesMax(tenantID string) int {
   429  	return o.getOverridesForTenant(tenantID).MaxFlameGraphNodesMax
   430  }
   431  
   432  // MaxFlameGraphNodesOnSelectMergeProfiles returns if the max flame graph nodes should be enforced for the SelectMergeProfile API.
   433  func (o *Overrides) MaxFlameGraphNodesOnSelectMergeProfile(tenantID string) bool {
   434  	return o.getOverridesForTenant(tenantID).MaxFlameGraphNodesOnSelectMergeProfile
   435  }
   436  
   437  // StoreGatewayTenantShardSize returns the store-gateway shard size for a given user.
   438  func (o *Overrides) StoreGatewayTenantShardSize(userID string) int {
   439  	return o.getOverridesForTenant(userID).StoreGatewayTenantShardSize
   440  }
   441  
   442  // QuerySplitDuration returns the tenant specific split by interval applied in the query frontend.
   443  func (o *Overrides) QuerySplitDuration(tenantID string) time.Duration {
   444  	return time.Duration(o.getOverridesForTenant(tenantID).QuerySplitDuration)
   445  }
   446  
   447  // QuerySanitizeOnMerge returns whether profiles should be sanitized in the read path.
   448  func (o *Overrides) QuerySanitizeOnMerge(tenantID string) bool {
   449  	return o.getOverridesForTenant(tenantID).QuerySanitizeOnMerge
   450  }
   451  
   452  // CompactorTenantShardSize returns number of compactors that this user can use. 0 = all compactors.
   453  func (o *Overrides) CompactorTenantShardSize(userID string) int {
   454  	return o.getOverridesForTenant(userID).CompactorTenantShardSize
   455  }
   456  
   457  // CompactorBlocksRetentionPeriod returns the retention period for a given user.
   458  func (o *Overrides) CompactorBlocksRetentionPeriod(userID string) time.Duration {
   459  	return time.Duration(o.getOverridesForTenant(userID).CompactorBlocksRetentionPeriod)
   460  }
   461  
   462  // CompactorSplitAndMergeShards returns the number of shards to use when splitting blocks.
   463  func (o *Overrides) CompactorSplitAndMergeShards(userID string) int {
   464  	return o.getOverridesForTenant(userID).CompactorSplitAndMergeShards
   465  }
   466  
   467  // CompactorSplitAndMergeStageSize returns the number of stages split shards will be written to.
   468  func (o *Overrides) CompactorSplitAndMergeStageSize(userID string) int {
   469  	return o.getOverridesForTenant(userID).CompactorSplitAndMergeStageSize
   470  }
   471  
   472  // CompactorSplitGroups returns the number of groups that blocks for splitting should be grouped into.
   473  func (o *Overrides) CompactorSplitGroups(userID string) int {
   474  	return o.getOverridesForTenant(userID).CompactorSplitGroups
   475  }
   476  
   477  // CompactorPartialBlockDeletionDelay returns the partial block deletion delay time period for a given user,
   478  // and whether the configured value was valid. If the value wasn't valid, the returned delay is the default one
   479  // and the caller is responsible to warn the Mimir operator about it.
   480  func (o *Overrides) CompactorPartialBlockDeletionDelay(userID string) (delay time.Duration, valid bool) {
   481  	delay = time.Duration(o.getOverridesForTenant(userID).CompactorPartialBlockDeletionDelay)
   482  
   483  	// Forcefully disable partial blocks deletion if the configured delay is too low.
   484  	if delay > 0 && delay < MinCompactorPartialBlockDeletionDelay {
   485  		return 0, false
   486  	}
   487  
   488  	return delay, true
   489  }
   490  
   491  // CompactorDownsamplerEnabled returns true if the downsampler is enabled for a given user.
   492  func (o *Overrides) CompactorDownsamplerEnabled(userId string) bool {
   493  	return o.getOverridesForTenant(userId).CompactorDownsamplerEnabled
   494  }
   495  
   496  // S3SSEType returns the per-tenant S3 SSE type.
   497  func (o *Overrides) S3SSEType(user string) string {
   498  	return o.getOverridesForTenant(user).S3SSEType
   499  }
   500  
   501  // S3SSEKMSKeyID returns the per-tenant S3 KMS-SSE key id.
   502  func (o *Overrides) S3SSEKMSKeyID(user string) string {
   503  	return o.getOverridesForTenant(user).S3SSEKMSKeyID
   504  }
   505  
   506  // S3SSEKMSEncryptionContext returns the per-tenant S3 KMS-SSE encryption context.
   507  func (o *Overrides) S3SSEKMSEncryptionContext(user string) string {
   508  	return o.getOverridesForTenant(user).S3SSEKMSEncryptionContext
   509  }
   510  
   511  // MaxQueriersPerTenant returns the limit to the number of queriers that can be used
   512  // Shuffle sharding will be used to distribute queries across queriers.
   513  // 0 means no limit. Currently disabled.
   514  func (o *Overrides) MaxQueriersPerTenant(tenant string) int { return 0 }
   515  
   516  // RejectNewerThan will ensure that profiles are further than the return value into the future are reject.
   517  func (o *Overrides) RejectNewerThan(tenantID string) time.Duration {
   518  	return time.Duration(o.getOverridesForTenant(tenantID).RejectNewerThan)
   519  }
   520  
   521  // RejectOlderThan will ensure that profiles that are older than the return value are rejected.
   522  func (o *Overrides) RejectOlderThan(tenantID string) time.Duration {
   523  	return time.Duration(o.getOverridesForTenant(tenantID).RejectOlderThan)
   524  }
   525  
   526  // QueryAnalysisEnabled can be used to disable the query analysis endpoint in the query frontend.
   527  func (o *Overrides) QueryAnalysisEnabled(tenantID string) bool {
   528  	return o.getOverridesForTenant(tenantID).QueryAnalysisEnabled
   529  }
   530  
   531  func (o *Overrides) Retention() (defaults retention.Config, overrides iter.Seq2[string, retention.Config]) {
   532  	return GetOverride(o, func(tenantID string, limits *Limits) retention.Config {
   533  		return limits.Retention
   534  	})
   535  }
   536  
   537  // GetOverride is a convenience function to get an override value for all tenants.
   538  // The order is not deterministic.
   539  func GetOverride[T any](o *Overrides, fn func(string, *Limits) T) (defaults T, overrides iter.Seq2[string, T]) {
   540  	defaults = fn("", o.defaultLimits)
   541  	if o.tenantLimits == nil {
   542  		return defaults, func(yield func(string, T) bool) {}
   543  	}
   544  	c := o.tenantLimits.RuntimeConfig()
   545  	if c == nil {
   546  		return defaults, func(yield func(string, T) bool) {}
   547  	}
   548  	return defaults, func(yield func(string, T) bool) {
   549  		for tenantID, limits := range c.TenantLimits {
   550  			if !yield(tenantID, fn(tenantID, limits)) {
   551  				return
   552  			}
   553  		}
   554  	}
   555  }
   556  
   557  // QueryAnalysisSeriesEnabled can be used to disable the series portion of the query analysis endpoint in the query frontend.
   558  // To be used for tenants where calculating series can be expensive.
   559  func (o *Overrides) QueryAnalysisSeriesEnabled(tenantID string) bool {
   560  	return o.getOverridesForTenant(tenantID).QueryAnalysisSeriesEnabled
   561  }
   562  
   563  func (o *Overrides) WritePathOverrides(tenantID string) writepath.Config {
   564  	return o.getOverridesForTenant(tenantID).WritePathOverrides
   565  }
   566  
   567  func (o *Overrides) ReadPathOverrides(tenantID string) readpath.Config {
   568  	return o.getOverridesForTenant(tenantID).ReadPathOverrides
   569  }
   570  
   571  func (o *Overrides) PlacementLimits(tenantID string) placement.PlacementLimits {
   572  	// Both limits aimed at the same thing: limit the number of shards tenant's
   573  	// data is distributed to. The IngestionTenantShardSize specifies the number
   574  	// of ingester instances (taking into account the replication factor), while
   575  	// the PlacementLimits.TenantShards specifies the number of shards and it's
   576  	// not set by default. Each segment writer own very small number of shards
   577  	// (4, by default) so we can use the same value for both.
   578  	t := o.getOverridesForTenant(tenantID)
   579  	l := t.AdaptivePlacementLimits
   580  	if t.IngestionTenantShardSize > 0 && uint64(t.IngestionTenantShardSize) > l.TenantShards {
   581  		l.TenantShards = uint64(t.IngestionTenantShardSize)
   582  	}
   583  	return l
   584  }
   585  
   586  func (o *Overrides) DefaultLimits() *Limits {
   587  	return o.defaultLimits
   588  }
   589  
   590  func (o *Overrides) getOverridesForTenant(tenantID string) *Limits {
   591  	if o.tenantLimits != nil {
   592  		l := o.tenantLimits.TenantLimits(tenantID)
   593  		if l != nil {
   594  			return l
   595  		}
   596  	}
   597  	return o.defaultLimits
   598  }
   599  
   600  // OverwriteMarshalingStringMap will overwrite the src map when unmarshaling
   601  // as opposed to merging.
   602  type OverwriteMarshalingStringMap struct {
   603  	m map[string]string
   604  }
   605  
   606  func NewOverwriteMarshalingStringMap(m map[string]string) OverwriteMarshalingStringMap {
   607  	return OverwriteMarshalingStringMap{m: m}
   608  }
   609  
   610  func (sm *OverwriteMarshalingStringMap) Map() map[string]string {
   611  	return sm.m
   612  }
   613  
   614  // MarshalJSON explicitly uses the type receiver and not pointer receiver
   615  // or it won't be called
   616  func (sm OverwriteMarshalingStringMap) MarshalJSON() ([]byte, error) {
   617  	return json.Marshal(sm.m)
   618  }
   619  
   620  func (sm *OverwriteMarshalingStringMap) UnmarshalJSON(val []byte) error {
   621  	var def map[string]string
   622  	if err := json.Unmarshal(val, &def); err != nil {
   623  		return err
   624  	}
   625  	sm.m = def
   626  
   627  	return nil
   628  }
   629  
   630  // MarshalYAML explicitly uses the type receiver and not pointer receiver
   631  // or it won't be called
   632  func (sm OverwriteMarshalingStringMap) MarshalYAML() (interface{}, error) {
   633  	return sm.m, nil
   634  }
   635  
   636  func (sm *OverwriteMarshalingStringMap) UnmarshalYAML(unmarshal func(interface{}) error) error {
   637  	var def map[string]string
   638  
   639  	err := unmarshal(&def)
   640  	if err != nil {
   641  		return err
   642  	}
   643  	sm.m = def
   644  
   645  	return nil
   646  }