Repository: VictoriaMetrics/VictoriaMetrics
Pull request #5581 (2024-01-08 17:05:44)

Handling negative index in Graphite groupByNode/aliasByNode
Graphite supports negative index to access by tail when group nodes. This should to the trick to implement this feature. Tested on vmselect in the cluster mode

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/5581?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Comparison is base [(`91ccea2`)](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics/commit/91ccea236f62e07ead2ea71affc661c350cb5f65?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics) 60.16% compared to head [(`71cc750`)](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/5581?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics) 60.19%.


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #5581      +/-   ##
==========================================
+ Coverage   60.16%   60.19%   +0.03%     
==========================================
  Files         401      401              
  Lines       75498    75507       +9     
==========================================
+ Hits        45422    45452      +30     
+ Misses      27545    27527      -18     
+ Partials     2531     2528       -3     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/5581?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VictoriaMetrics).

f41gh7: @rbizos  may I ask you to squash commits and sign it as described at https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification

 It'll be great, if you mention changes at changelog file https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/docs/CHANGELOG.md#tip
rbizos: after a little hiccup, that should be good. Let me know if there is anything else I can do :) 

Patch:
diff --git a/app/vmselect/graphite/transform.go b/app/vmselect/graphite/transform.go
index 5cfeca59a..7047edf85 100644
--- a/app/vmselect/graphite/transform.go
+++ b/app/vmselect/graphite/transform.go
@@ -3599,6 +3599,17 @@ func groupSeriesByNodes(ss []*series, nodes []graphiteql.Expr) map[string][]*ser
 	return m
 }
 
+func getAbsoluteNodeIndex(index, size int) int {
+	// handling the negative index case
+	if index < 0 && index+size > 0 {
+		index = index + size
+	}
+	if index >= size || index < 0 {
+		return -1
+	}
+	return index
+}
+
 func getNameFromNodes(name string, tags map[string]string, nodes []graphiteql.Expr) string {
 	if len(nodes) == 0 {
 		return ""
@@ -3609,7 +3620,7 @@ func getNameFromNodes(name string, tags map[string]string, nodes []graphiteql.Ex
 	for _, node := range nodes {
 		switch t := node.(type) {
 		case *graphiteql.NumberExpr:
-			if n := int(t.N); n >= 0 && n < len(parts) {
+			if n := getAbsoluteNodeIndex(int(t.N), len(parts)); n >= 0 {
 				dstParts = append(dstParts, parts[n])
 			}
 		case *graphiteql.StringExpr:
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index aaa01c9d2..2710228bd 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -28,6 +28,7 @@ The sandbox cluster installation is running under the constant load generated by
 
 ## tip
 
+* FEATURE: [vmselect](https://docs.victoriametrics.com/vmselect.html): adding support for negative index in Graphite groupByNode/aliasByNode. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5581).
 * FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): add support for [DataDog v2 data ingestion protocol](https://docs.datadoghq.com/api/latest/metrics/#submit-metrics). See [these docs](https://docs.victoriametrics.com/#how-to-send-data-from-datadog-agent) and [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4451).
 * FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): expose ability to set OAuth2 endpoint parameters per each `-remoteWrite.url` via the command-line flag `-remoteWrite.oauth2.endpointParams`. See [these docs](https://docs.victoriametrics.com/vmagent.html#advanced-usage). Thanks to @mhill-holoplot for the [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5427).
 * FEATURE: [vmalert](https://docs.victoriametrics.com/vmagent.html): expose ability to set OAuth2 endpoint parameters via the following command-line flags:


Test patch:
diff --git a/app/vmselect/graphite/transform_test.go b/app/vmselect/graphite/transform_test.go
index 388d84b78..22b918010 100644
--- a/app/vmselect/graphite/transform_test.go
+++ b/app/vmselect/graphite/transform_test.go
@@ -79,3 +79,17 @@ func TestGraphiteToGolangRegexpReplace(t *testing.T) {
 	f(`a\d+`, `a\d+`)
 	f(`\1f\\oo\2`, `$1f\\oo$2`)
 }
+
+func TestGetAbsoluteNodeIndex(t *testing.T) {
+	f := func(index, size, expectedIndex int) {
+		t.Helper()
+		absoluteIndex := getAbsoluteNodeIndex(index, size)
+		if absoluteIndex != expectedIndex {
+			t.Fatalf("unexpected result for getAbsoluteNodeIndex(%d, %d); got %d; want %d", index, size, expectedIndex, absoluteIndex)
+		}
+	}
+	f(1, 1, -1)
+	f(0, 1, 0)
+	f(-1, 3, 2)
+	f(-3, 1, -1)
+}