From 776d3622fb2707b81cdaa21a20b2ac98718a7a8f Mon Sep 17 00:00:00 2001 From: Tom Pillot Date: Fri, 20 Jan 2023 10:30:39 +0100 Subject: [PATCH 1/2] Remove support of providing metric TTL with label --- api/remotestorage/remotestorage.go | 2 +- cassandra/index/index.go | 40 ------ cassandra/index/index_test.go | 129 ------------------ dummy/index.go | 44 +----- .../squirreldb-cassandra-index-bench/bench.go | 14 +- 5 files changed, 15 insertions(+), 214 deletions(-) diff --git a/api/remotestorage/remotestorage.go b/api/remotestorage/remotestorage.go index 1ab9a19b..5a18fea6 100644 --- a/api/remotestorage/remotestorage.go +++ b/api/remotestorage/remotestorage.go @@ -70,7 +70,7 @@ func (r *RemoteStorage) Appender(ctx context.Context) storage.Appender { timeToLive, err = strconv.ParseInt(ttlRaw, 10, 64) if err != nil { - return errAppender{fmt.Errorf("can't parse time to live '%s', using default: %w", ttlRaw, err)} + return errAppender{fmt.Errorf("can't parse time to live header '%s': %w", ttlRaw, err)} } } diff --git a/cassandra/index/index.go b/cassandra/index/index.go index ad74379f..88f2994f 100644 --- a/cassandra/index/index.go +++ b/cassandra/index/index.go @@ -70,8 +70,6 @@ const ( expireBatchSize = 1000 ) -const timeToLiveLabelName = "__ttl__" - const ( // The expiration of entries in Cassandra starts everyday at 00:00 UTC + expirationStartOffset. expirationStartOffset = 6 * time.Hour @@ -2105,11 +2103,6 @@ func (c *CassandraIndex) lookupIDsFromCache( for i, req := range requests { ttlSeconds := req.TTLSeconds - if ttlSeconds == 0 { - // TODO: Compatibility with TTL label, will be removed later. - ttlSeconds = timeToLiveFromLabels(&req.Labels) - } - if ttlSeconds == 0 { ttlSeconds = int64(c.options.DefaultTimeToLive.Seconds()) } @@ -4423,19 +4416,6 @@ func (c *CassandraIndex) selectIDS2LabelsAndExpiration( ) } -// popLabelsValue get and delete value via its name from a labels.Label list. -func popLabelsValue(labels *labels.Labels, key string) (string, bool) { - for i, label := range *labels { - if label.Name == key { - *labels = append((*labels)[:i], (*labels)[i+1:]...) - - return label.Value, true - } - } - - return "", false -} - // sortLabels returns the labels.Label list sorted by name. func sortLabels(labelList labels.Labels) labels.Labels { sortedLabels := labelList.Copy() @@ -4444,26 +4424,6 @@ func sortLabels(labelList labels.Labels) labels.Labels { return sortedLabels } -// Returns and delete time to live from a labels.Label list. -func timeToLiveFromLabels(labels *labels.Labels) int64 { - value, exists := popLabelsValue(labels, timeToLiveLabelName) - - var timeToLive int64 - - if exists { - var err error - timeToLive, err = strconv.ParseInt(value, 10, 64) - - if err != nil { - log.Warn().Err(err).Msg("Can't get time to live from labels, using default") - - return 0 - } - } - - return timeToLive -} - // InternalUpdateAllShards updates the expiration of all shards. // Shards older than the TTL will be deleted, other shard will have their expiration created or updated. func (c *CassandraIndex) InternalUpdateAllShards(ctx context.Context, ttl time.Duration) error { diff --git a/cassandra/index/index_test.go b/cassandra/index/index_test.go index 7fce0abb..08fe60d8 100644 --- a/cassandra/index/index_test.go +++ b/cassandra/index/index_test.go @@ -1047,135 +1047,6 @@ func Benchmark_labelsToID(b *testing.B) { } } -func Test_timeToLiveFromLabels(t *testing.T) { - tests := []struct { - name string - labels labels.Labels - wantLabels labels.Labels - want int64 - }{ - { - name: "no ttl", - labels: labels.Labels{ - {Name: "__name__", Value: "up"}, - {Name: "job", Value: "scrape"}, - }, - want: 0, - wantLabels: labels.Labels{ - {Name: "__name__", Value: "up"}, - {Name: "job", Value: "scrape"}, - }, - }, - { - name: "with ttl", - labels: labels.Labels{ - {Name: "__name__", Value: "up"}, - {Name: "job", Value: "scrape"}, - {Name: "__ttl__", Value: "3600"}, - }, - want: 3600, - wantLabels: labels.Labels{ - {Name: "__name__", Value: "up"}, - {Name: "job", Value: "scrape"}, - }, - }, - { - name: "with ttl2", - labels: labels.Labels{ - {Name: "__name__", Value: "up"}, - {Name: "__ttl__", Value: "3600"}, - {Name: "job", Value: "scrape"}, - }, - want: 3600, - wantLabels: labels.Labels{ - {Name: "__name__", Value: "up"}, - {Name: "job", Value: "scrape"}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := timeToLiveFromLabels(&tt.labels) - if got != tt.want { - t.Errorf("timeToLiveFromLabels() got = %v, want %v", got, tt.want) - } - if !reflect.DeepEqual(tt.labels, tt.wantLabels) { - t.Errorf("timeToLiveFromLabels() labels = %v, want %v", tt.labels, tt.wantLabels) - } - }) - } -} - -func Benchmark_timeToLiveFromLabels(b *testing.B) { - tests := []struct { - name string - labels labels.Labels - wantLabels labels.Labels - wantTTL int64 - wantErr bool - }{ - { - name: "no ttl", - labels: labels.Labels{ - {Name: "__name__", Value: "up"}, - {Name: "job", Value: "scrape"}, - }, - }, - { - name: "with ttl", - labels: labels.Labels{ - {Name: "__name__", Value: "up"}, - {Name: ttlLabel, Value: "3600"}, - {Name: "job", Value: "scrape"}, - }, - }, - { - name: "12 labels no ttl", - labels: labels.Labels{ - {Name: "job", Value: "scrape"}, - {Name: "__name__", Value: "up"}, - {Name: "labels1", Value: "value1"}, - {Name: "labels2", Value: "value2"}, - {Name: "labels3", Value: "value3"}, - {Name: "labels4", Value: "value4"}, - {Name: "labels5", Value: "value5"}, - {Name: "labels6", Value: "value6"}, - {Name: "labels7", Value: "value7"}, - {Name: "labels8", Value: "value8"}, - {Name: "labels9", Value: "value9"}, - {Name: "labels10", Value: "value10"}, - }, - }, - { - name: "12 labels ttl", - labels: labels.Labels{ - {Name: "job", Value: "scrape"}, - {Name: "__name__", Value: "up"}, - {Name: "labels1", Value: "value1"}, - {Name: "labels2", Value: "value2"}, - {Name: "labels3", Value: "value3"}, - {Name: "labels4", Value: "value4"}, - {Name: "labels5", Value: "value5"}, - {Name: "labels6", Value: "value6"}, - {Name: ttlLabel, Value: "3600"}, - {Name: "labels7", Value: "value7"}, - {Name: "labels8", Value: "value8"}, - {Name: "labels9", Value: "value9"}, - {Name: "labels10", Value: "value10"}, - }, - }, - } - for _, tt := range tests { - b.Run(tt.name, func(b *testing.B) { - for n := 0; n < b.N; n++ { - labelsIn := make(labels.Labels, len(tt.labels)) - copy(labelsIn, tt.labels) - _ = timeToLiveFromLabels(&labelsIn) - } - }) - } -} - func Test_sortLabels(t *testing.T) { type args struct { labels labels.Labels diff --git a/dummy/index.go b/dummy/index.go index 4f1b66cf..0f63b632 100644 --- a/dummy/index.go +++ b/dummy/index.go @@ -3,10 +3,8 @@ package dummy import ( "context" "fmt" - "log" "sort" "squirreldb/types" - "strconv" "strings" "sync" "time" @@ -14,7 +12,10 @@ import ( "github.com/prometheus/prometheus/model/labels" ) -const postinglabelName = "__label|names__" +const ( + postinglabelName = "__label|names__" + defaultTimeToLive = 24 * time.Hour +) type MetricsLabel struct { List []types.MetricLabel @@ -134,9 +135,9 @@ func (idx *Index) LookupIDs(ctx context.Context, requests []types.LookupRequest) } for i, req := range requests { - ttls[i] = timeToLiveFromLabels(&req.Labels) + ttls[i] = req.TTLSeconds if ttls[i] == 0 { - ttls[i] = int64(86400) + ttls[i] = int64(defaultTimeToLive.Seconds()) } ids[i] = types.MetricID(req.Labels.Hash()) @@ -265,36 +266,3 @@ outer: return list } - -// copied from cassandra/index. -func timeToLiveFromLabels(labels *labels.Labels) int64 { - value, exists := popLabelsValue(labels, "__ttl__") - - var timeToLive int64 - - if exists { - var err error - timeToLive, err = strconv.ParseInt(value, 10, 64) - - if err != nil { - log.Printf("Warning: Can't get time to live from labels (%v), using default", err) - - return 0 - } - } - - return timeToLive -} - -// copied from cassandra/index. -func popLabelsValue(labels *labels.Labels, key string) (string, bool) { - for i, label := range *labels { - if label.Name == key { - *labels = append((*labels)[:i], (*labels)[i+1:]...) - - return label.Value, true - } - } - - return "", false -} diff --git a/tests/squirreldb-cassandra-index-bench/bench.go b/tests/squirreldb-cassandra-index-bench/bench.go index 4e809e2b..c7a1bef4 100644 --- a/tests/squirreldb-cassandra-index-bench/bench.go +++ b/tests/squirreldb-cassandra-index-bench/bench.go @@ -494,7 +494,7 @@ func makeInsertRequests(now time.Time, shardID string, rnd *rand.Rand) []types.L // We remove 1 days (and max ttl update delay) so the expiration of the // metrics is yesterday - negativeTTL := strconv.FormatInt(-86400-int64(index.InternalMaxTTLUpdateDelay().Seconds()), 10) + negativeTTL := -int64((24*time.Hour + index.InternalMaxTTLUpdateDelay()).Seconds()) for n := 0; n < *shardSize; n++ { userID := strconv.FormatInt(rnd.Int63n(100000), 10) @@ -518,21 +518,23 @@ func makeInsertRequests(now time.Time, shardID string, rnd *rand.Rand) []types.L labelsMap[fmt.Sprintf("label%02d", i)] = strconv.FormatInt(rnd.Int63n(20), 10) } - if *expiredFaction > 0 && n%*expiredFaction == 0 { - labelsMap["__ttl__"] = negativeTTL - } - promLabel := labels.FromMap(labelsMap) if *sortInsert { sort.Sort(promLabel) } - metrics[n] = types.LookupRequest{ + request := types.LookupRequest{ Start: now, End: now, Labels: promLabel, } + + if *expiredFaction > 0 && n%*expiredFaction == 0 { + request.TTLSeconds = negativeTTL + } + + metrics[n] = request } return metrics From 898473e61f65a4465227e2382c89b11f32acf8eb Mon Sep 17 00:00:00 2001 From: Tom Pillot Date: Fri, 20 Jan 2023 10:39:25 +0100 Subject: [PATCH 2/2] Remove support for X-PromQL HTTP headers The new X-SquirrelDB headers should be used instead. --- api/api.go | 2 +- api/promql/queryable.go | 20 -------------------- types/types.go | 15 +++++---------- 3 files changed, 6 insertions(+), 31 deletions(-) diff --git a/api/api.go b/api/api.go index c0eb6671..eb995ad4 100644 --- a/api/api.go +++ b/api/api.go @@ -35,7 +35,7 @@ import ( const ( httpServerShutdownTimeout = 10 * time.Second - // A read sample limit is already implemented dynamically with the header X-PromQL-Max-Evaluated-Points. + // A read sample limit is already implemented dynamically with the header X-SquirrelDB-Max-Evaluated-Points. remoteReadSampleLimit = 0 // No limit remoteReadMaxBytesInFrame = 1048576 // 1 MiB (Prometheus default) ) diff --git a/api/promql/queryable.go b/api/promql/queryable.go index e0d2ed2b..16bfceff 100644 --- a/api/promql/queryable.go +++ b/api/promql/queryable.go @@ -92,10 +92,6 @@ func (s Store) newQuerierFromHeaders(ctx context.Context, mint, maxt int64) (que } value := r.Header.Get(types.HeaderForcedMatcher) - if value == "" { - value = r.Header.Get(types.HeaderForcedMatcherOld) - } - if value != "" { part := strings.SplitN(value, "=", 2) if len(part) != 2 { @@ -128,10 +124,6 @@ func (s Store) newQuerierFromHeaders(ctx context.Context, mint, maxt int64) (que maxEvaluatedSeries := s.DefaultMaxEvaluatedSeries maxEvaluatedSeriesText := r.Header.Get(types.HeaderMaxEvaluatedSeries) - if maxEvaluatedSeriesText == "" { - maxEvaluatedSeriesText = r.Header.Get(types.HeaderMaxEvaluatedSeriesOld) - } - if maxEvaluatedSeriesText != "" { tmp, err := strconv.ParseUint(maxEvaluatedSeriesText, 10, 32) if err != nil { @@ -149,10 +141,6 @@ func (s Store) newQuerierFromHeaders(ctx context.Context, mint, maxt int64) (que maxEvaluatedPoints := s.DefaultMaxEvaluatedPoints maxEvaluatedPointsText := r.Header.Get(types.HeaderMaxEvaluatedPoints) - if maxEvaluatedPointsText == "" { - maxEvaluatedPointsText = r.Header.Get(types.HeaderMaxEvaluatedPointsOld) - } - if maxEvaluatedPointsText != "" { tmp, err := strconv.ParseUint(maxEvaluatedPointsText, 10, 64) if err != nil { @@ -177,10 +165,6 @@ func (s Store) newQuerierFromHeaders(ctx context.Context, mint, maxt int64) (que } value = r.Header.Get(types.HeaderForcePreAggregated) - if value == "" { - value = r.Header.Get(types.HeaderForcePreAggregatedOld) - } - if value != "" { tmp, err := strconv.ParseBool(value) if err != nil { @@ -191,10 +175,6 @@ func (s Store) newQuerierFromHeaders(ctx context.Context, mint, maxt int64) (que } value = r.Header.Get(types.HeaderForceRaw) - if value == "" { - value = r.Header.Get(types.HeaderForceRawOld) - } - if value != "" { tmp, err := strconv.ParseBool(value) if err != nil { diff --git a/types/types.go b/types/types.go index 3ddb1f36..e7569d3a 100644 --- a/types/types.go +++ b/types/types.go @@ -134,25 +134,20 @@ func WrapContext(ctx context.Context, r *http.Request) context.Context { // HTTP headers available to dynamically change settings on PromQL and remote read. const ( // Add one matcher to limit the evaluated series. - HeaderForcedMatcher = "X-SquirrelDB-Forced-Matcher" - HeaderForcedMatcherOld = "X-PromQL-Forced-Matcher" + HeaderForcedMatcher = "X-SquirrelDB-Forced-Matcher" // Limit the number of series that can be evaluated by a request. // A limit of 0 means unlimited. - HeaderMaxEvaluatedSeries = "X-SquirrelDB-Max-Evaluated-Series" - HeaderMaxEvaluatedSeriesOld = "X-PromQL-Max-Evaluated-Series" + HeaderMaxEvaluatedSeries = "X-SquirrelDB-Max-Evaluated-Series" // Limit the number of points that can be evaluated by a request. // A limit of 0 means unlimited. - HeaderMaxEvaluatedPoints = "X-SquirrelDB-Max-Evaluated-Points" - HeaderMaxEvaluatedPointsOld = "X-PromQL-Max-Evaluated-Points" + HeaderMaxEvaluatedPoints = "X-SquirrelDB-Max-Evaluated-Points" // Force using pre-aggregated data instead of raw points. Default for // query is raw data. Default for query_range depends on step value. - HeaderForcePreAggregated = "X-SquirrelDB-ForcePreAggregated" - HeaderForcePreAggregatedOld = "X-PromQL-ForcePreAggregated" + HeaderForcePreAggregated = "X-SquirrelDB-ForcePreAggregated" // Force using raw data instead of pre-aggregated points. If both ForcePreAggregated // and ForceRaw are true, ForceRaw has priority. Default for query is raw data. // Default for query_range depends on step value. - HeaderForceRaw = "X-SquirrelDB-ForceRaw" - HeaderForceRawOld = "X-PromQL-ForceRaw" + HeaderForceRaw = "X-SquirrelDB-ForceRaw" // Only match metrics from this tenant. Metrics written with this header // are associated to this tenant (a tenant label is added to the metric labels). HeaderTenant = "X-SquirrelDB-Tenant"