From a3abed80ff4f2981d5614eaec6e176675b9f1557 Mon Sep 17 00:00:00 2001
From: Aliaksandr Valialkin <valyala@gmail.com>
Date: Mon, 1 Jul 2019 17:14:49 +0300
Subject: [PATCH] app/vmselect: do not return empty time series in
 `/api/v1/query` result

---
 app/vmselect/prometheus/prometheus.go |  4 ++--
 app/vmselect/promql/exec.go           | 12 ++++++++++--
 app/vmselect/promql/exec_test.go      | 11 +++++++++--
 3 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/app/vmselect/prometheus/prometheus.go b/app/vmselect/prometheus/prometheus.go
index 44d2ace759..806fd22617 100644
--- a/app/vmselect/prometheus/prometheus.go
+++ b/app/vmselect/prometheus/prometheus.go
@@ -501,7 +501,7 @@ func QueryHandler(at *auth.Token, w http.ResponseWriter, r *http.Request) error
 
 		DenyPartialResponse: getDenyPartialResponse(r),
 	}
-	result, err := promql.Exec(&ec, query)
+	result, err := promql.Exec(&ec, query, true)
 	if err != nil {
 		return fmt.Errorf("cannot execute %q: %s", query, err)
 	}
@@ -562,7 +562,7 @@ func QueryRangeHandler(at *auth.Token, w http.ResponseWriter, r *http.Request) e
 
 		DenyPartialResponse: getDenyPartialResponse(r),
 	}
-	result, err := promql.Exec(&ec, query)
+	result, err := promql.Exec(&ec, query, false)
 	if err != nil {
 		return fmt.Errorf("cannot execute %q: %s", query, err)
 	}
diff --git a/app/vmselect/promql/exec.go b/app/vmselect/promql/exec.go
index 87e474759f..bec9fc9f62 100644
--- a/app/vmselect/promql/exec.go
+++ b/app/vmselect/promql/exec.go
@@ -27,8 +27,8 @@ func ExpandWithExprs(q string) (string, error) {
 	return string(buf), nil
 }
 
-// Exec executes q for the given ec until the deadline.
-func Exec(ec *EvalConfig, q string) ([]netstorage.Result, error) {
+// Exec executes q for the given ec.
+func Exec(ec *EvalConfig, q string, isFirstPointOnly bool) ([]netstorage.Result, error) {
 	if *logSlowQueryDuration > 0 {
 		startTime := time.Now()
 		defer func() {
@@ -66,6 +66,14 @@ func Exec(ec *EvalConfig, q string) ([]netstorage.Result, error) {
 	}
 	ec.End -= ec.Step
 
+	if isFirstPointOnly {
+		// Remove all the points except the first one from every time series.
+		for _, ts := range rv {
+			ts.Values = ts.Values[:1]
+			ts.Timestamps = ts.Timestamps[:1]
+		}
+	}
+
 	maySort := maySortResults(e, rv)
 	result, err := timeseriesToResult(rv, maySort)
 	if err != nil {
diff --git a/app/vmselect/promql/exec_test.go b/app/vmselect/promql/exec_test.go
index 9612778fe8..8f702c122e 100644
--- a/app/vmselect/promql/exec_test.go
+++ b/app/vmselect/promql/exec_test.go
@@ -72,7 +72,7 @@ func TestExecSuccess(t *testing.T) {
 			Deadline: netstorage.NewDeadline(time.Minute),
 		}
 		for i := 0; i < 5; i++ {
-			result, err := Exec(ec, q)
+			result, err := Exec(ec, q, false)
 			if err != nil {
 				t.Fatalf(`unexpected error when executing %q: %s`, q, err)
 			}
@@ -3679,7 +3679,14 @@ func TestExecError(t *testing.T) {
 			Deadline: netstorage.NewDeadline(time.Minute),
 		}
 		for i := 0; i < 4; i++ {
-			rv, err := Exec(ec, q)
+			rv, err := Exec(ec, q, false)
+			if err == nil {
+				t.Fatalf(`expecting non-nil error on %q`, q)
+			}
+			if rv != nil {
+				t.Fatalf(`expecting nil rv`)
+			}
+			rv, err = Exec(ec, q, true)
 			if err == nil {
 				t.Fatalf(`expecting non-nil error on %q`, q)
 			}