Repository: VictoriaMetrics/VictoriaMetrics
Pull request #1130 (2021-03-15 17:27:49)

adds fake response for telegraph queries
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1124

codecov[bot]: # [Codecov](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130?src=pr&el=h1) Report
> Merging [#1130](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130?src=pr&el=desc) (42db9bb) into [master](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/commit/7f6f350ee19e45002cac83bbfda22d2bf6309ae4?el=desc) (7f6f350) will **decrease** coverage by `0.00%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130/graphs/tree.svg?width=650&height=150&src=pr&token=YND8dYVcXn)](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #1130      +/-   ##
==========================================
- Coverage   60.16%   60.15%   -0.01%     
==========================================
  Files         213      213              
  Lines       25147    25147              
==========================================
- Hits        15130    15128       -2     
- Misses       8619     8623       +4     
+ Partials     1398     1396       -2     
```


| [Impacted Files](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [lib/mergeset/table.go](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130/diff?src=pr&el=tree#diff-bGliL21lcmdlc2V0L3RhYmxlLmdv) | `66.05% <0.00%> (-0.77%)` | :arrow_down: |
| [lib/storage/partition.go](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130/diff?src=pr&el=tree#diff-bGliL3N0b3JhZ2UvcGFydGl0aW9uLmdv) | `65.43% <0.00%> (-0.24%)` | :arrow_down: |
| [app/vmselect/promql/aggr\_incremental.go](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130/diff?src=pr&el=tree#diff-YXBwL3Ztc2VsZWN0L3Byb21xbC9hZ2dyX2luY3JlbWVudGFsLmdv) | `87.98% <0.00%> (ø)` | |
| [lib/storage/index\_db.go](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130/diff?src=pr&el=tree#diff-bGliL3N0b3JhZ2UvaW5kZXhfZGIuZ28=) | `65.49% <0.00%> (+0.05%)` | :arrow_up: |
| [lib/encoding/int.go](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130/diff?src=pr&el=tree#diff-bGliL2VuY29kaW5nL2ludC5nbw==) | `77.41% <0.00%> (+1.61%)` | :arrow_up: |
| [app/vmalert/remotewrite/remotewrite.go](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130/diff?src=pr&el=tree#diff-YXBwL3ZtYWxlcnQvcmVtb3Rld3JpdGUvcmVtb3Rld3JpdGUuZ28=) | `60.74% <0.00%> (+1.86%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130?src=pr&el=footer). Last update [7f6f350...42db9bb](https://codecov.io/gh/VictoriaMetrics/VictoriaMetrics/pull/1130?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/app/vmagent/README.md b/app/vmagent/README.md
index 2606690c5..cf6a739b8 100644
--- a/app/vmagent/README.md
+++ b/app/vmagent/README.md
@@ -515,6 +515,7 @@ See the docs at https://victoriametrics.github.io/vmagent.html .
   -import.maxLineLen max_rows_per_line
     	The maximum length in bytes of a single line accepted by /api/v1/import; the line length can be limited with max_rows_per_line query arg passed to /api/v1/export
     	Supports the following optional suffixes for values: KB, MB, GB, KiB, MiB, GiB (default 104857600)
+  -influx.databasesNames comma separated names of influx database, that will be returned for /query and /influx/query request.
   -influx.maxLineSize value
     	The maximum size in bytes for a single Influx line during parsing
     	Supports the following optional suffixes for values: KB, MB, GB, KiB, MiB, GiB (default 262144)
diff --git a/app/vmagent/main.go b/app/vmagent/main.go
index 865f03459..02b65641c 100644
--- a/app/vmagent/main.go
+++ b/app/vmagent/main.go
@@ -49,6 +49,7 @@ var (
 	dryRun                 = flag.Bool("dryRun", false, "Whether to check only config files without running vmagent. The following files are checked: "+
 		"-promscrape.config, -remoteWrite.relabelConfig, -remoteWrite.urlRelabelConfig . "+
 		"Unknown config entries are allowed in -promscrape.config by default. This can be changed with -promscrape.config.strictParse")
+	influxDatabasesNames = flag.String("influx.databasesNames", "_internal", "Comma separated names of databases, that will be returned for /query and /influx/query api.")
 )
 
 var (
@@ -205,9 +206,17 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool {
 		return true
 	case "/query":
 		// Emulate fake response for influx query.
-		// This is required for TSBS benchmark.
+		// This is required for TSBS benchmark and some telegraph plugins.
 		influxQueryRequests.Inc()
-		fmt.Fprintf(w, `{"results":[{"series":[{"values":[]}]}]}`)
+		var dbs string
+		influxDbs := strings.Split(*influxDatabasesNames, ",")
+		for i := range influxDbs {
+			dbs += fmt.Sprintf(`"[%s]"`, influxDbs[i])
+			if i != len(influxDbs)-1 {
+				dbs += ","
+			}
+		}
+		fmt.Fprintf(w, `{"results":[{"name":"databases","columns":["name"],"series":[{"values":[%s]}]}]}`, dbs)
 		return true
 	case "/targets":
 		promscrapeTargetsRequests.Inc()
diff --git a/app/vminsert/main.go b/app/vminsert/main.go
index 5e69efeb9..55696ec68 100644
--- a/app/vminsert/main.go
+++ b/app/vminsert/main.go
@@ -40,6 +40,7 @@ var (
 		"Usually :4242 must be set. Doesn't work if empty")
 	opentsdbHTTPListenAddr = flag.String("opentsdbHTTPListenAddr", "", "TCP address to listen for OpentTSDB HTTP put requests. Usually :4242 must be set. Doesn't work if empty")
 	maxLabelsPerTimeseries = flag.Int("maxLabelsPerTimeseries", 30, "The maximum number of labels accepted per time series. Superfluous labels are dropped")
+	influxDatabasesNames   = flag.String("influx.databasesNames", "_internal", "Comma separated names of databases, that will be returned for /query and /influx/query api.")
 )
 
 var (
@@ -148,9 +149,17 @@ func RequestHandler(w http.ResponseWriter, r *http.Request) bool {
 		return true
 	case "/influx/query", "/query":
 		// Emulate fake response for influx query.
-		// This is required for TSBS benchmark.
+		// This is required for TSBS benchmark and some telegraph plugins.
 		influxQueryRequests.Inc()
-		fmt.Fprintf(w, `{"results":[{"series":[{"values":[]}]}]}`)
+		var dbs string
+		influxDbs := strings.Split(*influxDatabasesNames, ",")
+		for i := range influxDbs {
+			dbs += fmt.Sprintf(`"[%s]"`, influxDbs[i])
+			if i != len(influxDbs)-1 {
+				dbs += ","
+			}
+		}
+		fmt.Fprintf(w, `{"results":[{"name":"databases","columns":["name"],"series":[{"values":[%s]}]}]}`, dbs)
 		return true
 	case "/prometheus/targets", "/targets":
 		promscrapeTargetsRequests.Inc()
diff --git a/app/vmselect/promql/rollup.go b/app/vmselect/promql/rollup.go
index c7f973a82..282b305aa 100644
--- a/app/vmselect/promql/rollup.go
+++ b/app/vmselect/promql/rollup.go
@@ -538,6 +538,7 @@ func (rc *rollupConfig) doInternal(dstValues []float64, tsm *timeseriesMap, valu
 	// Do not drop trailing data points for queries, which return 2 or 1 point (aka instant queries).
 	// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/845
 	canDropLastSample := rc.CanDropLastSample && len(rc.Timestamps) > 2
+	f := rc.Func
 	for _, tEnd := range rc.Timestamps {
 		tStart := tEnd - window
 		ni = seekFirstTimestampIdxAfter(timestamps[i:], tStart, ni)
@@ -577,7 +578,7 @@ func (rc *rollupConfig) doInternal(dstValues []float64, tsm *timeseriesMap, valu
 			rfa.realNextValue = nan
 		}
 		rfa.currTimestamp = tEnd
-		value := rc.Func(rfa)
+		value := f(rfa)
 		rfa.idx++
 		dstValues = append(dstValues, value)
 	}
@@ -643,12 +644,12 @@ func getScrapeInterval(timestamps []int64) int64 {
 		return int64(maxSilenceInterval)
 	}
 
-	// Estimate scrape interval as 0.6 quantile for the first 100 intervals.
+	// Estimate scrape interval as 0.6 quantile for the first 20 intervals.
 	h := histogram.GetFast()
 	tsPrev := timestamps[0]
 	timestamps = timestamps[1:]
-	if len(timestamps) > 100 {
-		timestamps = timestamps[:100]
+	if len(timestamps) > 20 {
+		timestamps = timestamps[:20]
 	}
 	for _, ts := range timestamps {
 		h.Update(float64(ts - tsPrev))
diff --git a/docs/vmagent.md b/docs/vmagent.md
index 2606690c5..cf6a739b8 100644
--- a/docs/vmagent.md
+++ b/docs/vmagent.md
@@ -515,6 +515,7 @@ See the docs at https://victoriametrics.github.io/vmagent.html .
   -import.maxLineLen max_rows_per_line
     	The maximum length in bytes of a single line accepted by /api/v1/import; the line length can be limited with max_rows_per_line query arg passed to /api/v1/export
     	Supports the following optional suffixes for values: KB, MB, GB, KiB, MiB, GiB (default 104857600)
+  -influx.databasesNames comma separated names of influx database, that will be returned for /query and /influx/query request.
   -influx.maxLineSize value
     	The maximum size in bytes for a single Influx line during parsing
     	Supports the following optional suffixes for values: KB, MB, GB, KiB, MiB, GiB (default 262144)
diff --git a/lib/storage/index_db.go b/lib/storage/index_db.go
index 296494e0a..4e8ee3411 100644
--- a/lib/storage/index_db.go
+++ b/lib/storage/index_db.go
@@ -2356,7 +2356,13 @@ func (is *indexSearch) getMetricIDsForTagFilter(tf *tagFilter, filter *uint64set
 	metricIDs := &uint64set.Set{}
 	if len(tf.orSuffixes) > 0 {
 		// Fast path for orSuffixes - seek for rows for each value from orSuffixes.
-		loopsCount, err := is.updateMetricIDsForOrSuffixesNoFilter(tf, maxMetrics, metricIDs)
+		var loopsCount uint64
+		var err error
+		if filter != nil {
+			loopsCount, err = is.updateMetricIDsForOrSuffixesWithFilter(tf, metricIDs, filter)
+		} else {
+			loopsCount, err = is.updateMetricIDsForOrSuffixesNoFilter(tf, maxMetrics, metricIDs)
+		}
 		if err != nil {
 			return nil, loopsCount, fmt.Errorf("error when searching for metricIDs for tagFilter in fast path: %w; tagFilter=%s", err, tf)
 		}
@@ -2493,19 +2499,22 @@ func (is *indexSearch) updateMetricIDsForOrSuffixesNoFilter(tf *tagFilter, maxMe
 	return loopsCount, nil
 }
 
-func (is *indexSearch) updateMetricIDsForOrSuffixesWithFilter(tf *tagFilter, metricIDs, filter *uint64set.Set) error {
+func (is *indexSearch) updateMetricIDsForOrSuffixesWithFilter(tf *tagFilter, metricIDs, filter *uint64set.Set) (uint64, error) {
 	sortedFilter := filter.AppendTo(nil)
 	kb := kbPool.Get()
 	defer kbPool.Put(kb)
+	var loopsCount uint64
 	for _, orSuffix := range tf.orSuffixes {
 		kb.B = append(kb.B[:0], tf.prefix...)
 		kb.B = append(kb.B, orSuffix...)
 		kb.B = append(kb.B, tagSeparatorChar)
-		if err := is.updateMetricIDsForOrSuffixWithFilter(kb.B, metricIDs, sortedFilter, tf.isNegative); err != nil {
-			return err
+		lc, err := is.updateMetricIDsForOrSuffixWithFilter(kb.B, metricIDs, sortedFilter, tf.isNegative)
+		if err != nil {
+			return loopsCount, err
 		}
+		loopsCount += lc
 	}
-	return nil
+	return loopsCount, nil
 }
 
 func (is *indexSearch) updateMetricIDsForOrSuffixNoFilter(prefix []byte, maxMetrics int, metricIDs *uint64set.Set) (uint64, error) {
@@ -2539,15 +2548,16 @@ func (is *indexSearch) updateMetricIDsForOrSuffixNoFilter(prefix []byte, maxMetr
 	return loopsCount, nil
 }
 
-func (is *indexSearch) updateMetricIDsForOrSuffixWithFilter(prefix []byte, metricIDs *uint64set.Set, sortedFilter []uint64, isNegative bool) error {
+func (is *indexSearch) updateMetricIDsForOrSuffixWithFilter(prefix []byte, metricIDs *uint64set.Set, sortedFilter []uint64, isNegative bool) (uint64, error) {
 	if len(sortedFilter) == 0 {
-		return nil
+		return 0, nil
 	}
 	firstFilterMetricID := sortedFilter[0]
 	lastFilterMetricID := sortedFilter[len(sortedFilter)-1]
 	ts := &is.ts
 	mp := &is.mp
 	mp.Reset()
+	var loopsCount uint64
 	loopsPaceLimiter := 0
 	ts.Seek(prefix)
 	var sf []uint64
@@ -2555,17 +2565,18 @@ func (is *indexSearch) updateMetricIDsForOrSuffixWithFilter(prefix []byte, metri
 	for ts.NextItem() {
 		if loopsPaceLimiter&paceLimiterMediumIterationsMask == 0 {
 			if err := checkSearchDeadlineAndPace(is.deadline); err != nil {
-				return err
+				return loopsCount, err
 			}
 		}
 		loopsPaceLimiter++
 		item := ts.Item
 		if !bytes.HasPrefix(item, prefix) {
-			return nil
+			return loopsCount, nil
 		}
 		if err := mp.InitOnlyTail(item, item[len(prefix):]); err != nil {
-			return err
+			return loopsCount, err
 		}
+		loopsCount += uint64(mp.MetricIDsLen())
 		firstMetricID, lastMetricID := mp.FirstAndLastMetricIDs()
 		if lastMetricID < firstFilterMetricID {
 			// Skip the item, since it contains metricIDs lower
@@ -2575,10 +2586,11 @@ func (is *indexSearch) updateMetricIDsForOrSuffixWithFilter(prefix []byte, metri
 		if firstMetricID > lastFilterMetricID {
 			// Stop searching, since the current item and all the subsequent items
 			// contain metricIDs higher than metricIDs in sortedFilter.
-			return nil
+			return loopsCount, nil
 		}
 		sf = sortedFilter
 		mp.ParseMetricIDs()
+		matchingMetricIDs := mp.MetricIDs[:0]
 		for _, metricID = range mp.MetricIDs {
 			if len(sf) == 0 {
 				break
@@ -2593,18 +2605,23 @@ func (is *indexSearch) updateMetricIDsForOrSuffixWithFilter(prefix []byte, metri
 			if metricID < sf[0] {
 				continue
 			}
+			matchingMetricIDs = append(matchingMetricIDs, metricID)
+			sf = sf[1:]
+		}
+		if len(matchingMetricIDs) > 0 {
 			if isNegative {
-				metricIDs.Del(metricID)
+				for _, metricID := range matchingMetricIDs {
+					metricIDs.Del(metricID)
+				}
 			} else {
-				metricIDs.Add(metricID)
+				metricIDs.AddMulti(matchingMetricIDs)
 			}
-			sf = sf[1:]
 		}
 	}
 	if err := ts.Error(); err != nil {
-		return fmt.Errorf("error when searching for tag filter prefix %q: %w", prefix, err)
+		return loopsCount, fmt.Errorf("error when searching for tag filter prefix %q: %w", prefix, err)
 	}
-	return nil
+	return loopsCount, nil
 }
 
 func binarySearchUint64(a []uint64, v uint64) uint {
@@ -2792,10 +2809,9 @@ func (is *indexSearch) getMetricIDsForDateAndFilters(date uint64, tfs *TagFilter
 	})
 
 	// Populate metricIDs for the first non-negative filter.
-	var tfsPostponed []*tagFilter
 	var metricIDs *uint64set.Set
 	tfwsRemaining := tfws[:0]
-	maxDateMetrics := maxMetrics * 100
+	maxDateMetrics := maxMetrics * 50
 	for i := range tfws {
 		tfw := tfws[i]
 		tf := tfw.tf
@@ -2804,13 +2820,16 @@ func (is *indexSearch) getMetricIDsForDateAndFilters(date uint64, tfs *TagFilter
 			continue
 		}
 		m, loopsCount, err := is.getMetricIDsForDateTagFilter(tf, date, nil, tfs.commonPrefix, maxDateMetrics)
-		is.storeLoopsCountForDateFilter(date, tf, loopsCount)
+		if loopsCount > tfw.loopsCount {
+			is.storeLoopsCountForDateFilter(date, tf, loopsCount)
+		}
 		if err != nil {
 			return nil, err
 		}
 		if m.Len() >= maxDateMetrics {
-			// Too many time series found by a single tag filter. Postpone applying this filter via metricName match.
-			tfsPostponed = append(tfsPostponed, tf)
+			// Too many time series found by a single tag filter. Postpone applying this filter.
+			tfwsRemaining = append(tfwsRemaining, tfw)
+			tfw.loopsCount = loopsCount
 			continue
 		}
 		metricIDs = m
@@ -2846,6 +2865,7 @@ func (is *indexSearch) getMetricIDsForDateAndFilters(date uint64, tfs *TagFilter
 	// when the intial tag filters significantly reduce the number of found metricIDs,
 	// so the remaining filters could be performed via much faster metricName matching instead
 	// of slow selecting of matching metricIDs.
+	var tfsPostponed []*tagFilter
 	for i := range tfwsRemaining {
 		tfw := tfwsRemaining[i]
 		tf := tfw.tf
@@ -2854,24 +2874,26 @@ func (is *indexSearch) getMetricIDsForDateAndFilters(date uint64, tfs *TagFilter
 			// Short circuit - there is no need in applying the remaining filters to an empty set.
 			break
 		}
-		if uint64(metricIDsLen)*maxIndexScanLoopsPerMetric < tfw.loopsCount {
+		if tfw.loopsCount > uint64(metricIDsLen)*loopsCountPerMetricNameMatch {
 			// It should be faster performing metricName match on the remaining filters
 			// instead of scanning big number of entries in the inverted index for these filters.
-			tfsPostponed = append(tfsPostponed, tf)
-			// Store stats for non-executed tf, since it could be updated during protection from thundered herd.
-			is.storeLoopsCountForDateFilter(date, tf, tfw.loopsCount)
-			continue
+			for i < len(tfwsRemaining) {
+				tfw := tfwsRemaining[i]
+				tf := tfw.tf
+				tfsPostponed = append(tfsPostponed, tf)
+				// Store stats for non-executed tf, since it could be updated during protection from thundered herd.
+				is.storeLoopsCountForDateFilter(date, tf, tfw.loopsCount)
+				i++
+			}
+			break
+		}
+		m, loopsCount, err := is.getMetricIDsForDateTagFilter(tf, date, metricIDs, tfs.commonPrefix, 0)
+		if loopsCount > tfw.loopsCount {
+			is.storeLoopsCountForDateFilter(date, tf, loopsCount)
 		}
-		m, loopsCount, err := is.getMetricIDsForDateTagFilter(tf, date, metricIDs, tfs.commonPrefix, maxDateMetrics)
-		is.storeLoopsCountForDateFilter(date, tf, loopsCount)
 		if err != nil {
 			return nil, err
 		}
-		if m.Len() >= maxDateMetrics {
-			// Too many time series found by a single tag filter. Postpone applying this filter via metricName match.
-			tfsPostponed = append(tfsPostponed, tf)
-			continue
-		}
 		if tf.isNegative {
 			metricIDs.Subtract(m)
 		} else {
@@ -3057,7 +3079,7 @@ func (is *indexSearch) getMetricIDsForDateTagFilter(tf *tagFilter, date uint64,
 		// Set high loopsCount for failing filter, so it is moved to the end of filter list.
 		loopsCount = 20e9
 	}
-	if metricIDs.Len() >= maxMetrics {
+	if filter == nil && metricIDs.Len() >= maxMetrics {
 		// Increase loopsCount for tag filter matching too many metrics,
 		// So next time it is moved to the end of filter list.
 		loopsCount *= 2
@@ -3154,10 +3176,8 @@ func (is *indexSearch) updateMetricIDsForPrefix(prefix []byte, metricIDs *uint64
 	return nil
 }
 
-// The maximum number of index scan loops.
-// Bigger number of loops is slower than updateMetricIDsByMetricNameMatch
-// over the found metrics.
-const maxIndexScanLoopsPerMetric = 100
+// The estimated number of index scan loops a single loop in updateMetricIDsByMetricNameMatch takes.
+const loopsCountPerMetricNameMatch = 500
 
 func (is *indexSearch) intersectMetricIDsWithTagFilter(tf *tagFilter, filter *uint64set.Set) (*uint64set.Set, error) {
 	if filter.Len() == 0 {
@@ -3169,7 +3189,8 @@ func (is *indexSearch) intersectMetricIDsWithTagFilter(tf *tagFilter, filter *ui
 	}
 	if len(tf.orSuffixes) > 0 {
 		// Fast path for orSuffixes - seek for rows for each value from orSuffixes.
-		if err := is.updateMetricIDsForOrSuffixesWithFilter(tf, metricIDs, filter); err != nil {
+		_, err := is.updateMetricIDsForOrSuffixesWithFilter(tf, metricIDs, filter)
+		if err != nil {
 			return nil, fmt.Errorf("error when intersecting metricIDs for tagFilter in fast path: %w; tagFilter=%s", err, tf)
 		}
 		return metricIDs, nil


Test patch:
diff --git a/app/vmselect/promql/exec_test.go b/app/vmselect/promql/exec_test.go
index 62f46632f..2d1022d46 100644
--- a/app/vmselect/promql/exec_test.go
+++ b/app/vmselect/promql/exec_test.go
@@ -57,10 +57,11 @@ func TestExecSuccess(t *testing.T) {
 	f := func(q string, resultExpected []netstorage.Result) {
 		t.Helper()
 		ec := &EvalConfig{
-			Start:    start,
-			End:      end,
-			Step:     step,
-			Deadline: searchutils.NewDeadline(time.Now(), time.Minute, ""),
+			Start:       start,
+			End:         end,
+			Step:        step,
+			Deadline:    searchutils.NewDeadline(time.Now(), time.Minute, ""),
+			RoundDigits: 100,
 		}
 		for i := 0; i < 5; i++ {
 			result, err := Exec(ec, q, false)
@@ -6575,10 +6576,11 @@ func TestExecError(t *testing.T) {
 	f := func(q string) {
 		t.Helper()
 		ec := &EvalConfig{
-			Start:    1000,
-			End:      2000,
-			Step:     100,
-			Deadline: searchutils.NewDeadline(time.Now(), time.Minute, ""),
+			Start:       1000,
+			End:         2000,
+			Step:        100,
+			Deadline:    searchutils.NewDeadline(time.Now(), time.Minute, ""),
+			RoundDigits: 100,
 		}
 		for i := 0; i < 4; i++ {
 			rv, err := Exec(ec, q, false)