From 97f9397687f51507af75beb708811d2ac6dc32a5 Mon Sep 17 00:00:00 2001
From: Aliaksandr Valialkin <valyala@gmail.com>
Date: Fri, 12 Jul 2019 02:20:29 +0300
Subject: [PATCH] lib/storage: do not reduce `maxMetrics` on time ranges
 exceeding `maxDaysForDateMetricIDs`

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/95
---
 lib/storage/index_db.go | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/lib/storage/index_db.go b/lib/storage/index_db.go
index f911f28323..55f0bc4753 100644
--- a/lib/storage/index_db.go
+++ b/lib/storage/index_db.go
@@ -1269,7 +1269,6 @@ func (is *indexSearch) updateMetricIDsByMetricNameMatch(metricIDs, srcMetricIDs
 }
 
 func (is *indexSearch) getTagFilterWithMinMetricIDsCountAdaptive(tfs *TagFilters, maxMetrics int) (*tagFilter, map[uint64]struct{}, error) {
-	maxMetrics = is.adjustMaxMetricsAdaptive(maxMetrics)
 	kb := &is.kb
 	kb.B = append(kb.B[:0], uselessMultiTagFiltersKeyPrefix)
 	kb.B = encoding.MarshalUint64(kb.B, uint64(maxMetrics))
@@ -1317,7 +1316,22 @@ func (is *indexSearch) getTagFilterWithMinMetricIDsCountAdaptive(tfs *TagFilters
 
 var errTooManyMetrics = errors.New("all the tag filters match too many metrics")
 
-func (is *indexSearch) adjustMaxMetricsAdaptive(maxMetrics int) int {
+func isTooBigTimeRangeForDateMetricIDs(tr TimeRange) bool {
+	minDate := uint64(tr.MinTimestamp) / msecPerDay
+	maxDate := uint64(tr.MaxTimestamp) / msecPerDay
+	return maxDate-minDate > 40
+}
+
+const maxDaysForDateMetricIDs = 40
+
+func (is *indexSearch) adjustMaxMetricsAdaptive(tr TimeRange, maxMetrics int) int {
+	minDate := uint64(tr.MinTimestamp) / msecPerDay
+	maxDate := uint64(tr.MaxTimestamp) / msecPerDay
+	if maxDate-minDate > maxDaysForDateMetricIDs {
+		// Cannot reduce maxMetrics for the given time range,
+		// since the it is expensive extracting metricIDs for the given tr.
+		return maxMetrics
+	}
 	hmPrev := is.db.prevHourMetricIDs.Load().(*hourMetricIDs)
 	if !hmPrev.isFull {
 		return maxMetrics
@@ -1504,7 +1518,8 @@ func (is *indexSearch) updateMetricIDsForTagFilters(metricIDs map[uint64]struct{
 	// Sort tag filters for faster ts.Seek below.
 	sort.Slice(tfs.tfs, func(i, j int) bool { return bytes.Compare(tfs.tfs[i].prefix, tfs.tfs[j].prefix) < 0 })
 
-	minTf, minMetricIDs, err := is.getTagFilterWithMinMetricIDsCountAdaptive(tfs, maxMetrics)
+	maxMetricsAdjusted := is.adjustMaxMetricsAdaptive(tr, maxMetrics)
+	minTf, minMetricIDs, err := is.getTagFilterWithMinMetricIDsCountAdaptive(tfs, maxMetricsAdjusted)
 	if err != nil {
 		if err != errTooManyMetrics {
 			return err
@@ -1809,7 +1824,7 @@ func (is *indexSearch) getMetricIDsForTimeRange(tr TimeRange, maxMetrics int, ac
 	atomic.AddUint64(&is.db.dateMetricIDsSearchCalls, 1)
 	minDate := uint64(tr.MinTimestamp) / msecPerDay
 	maxDate := uint64(tr.MaxTimestamp) / msecPerDay
-	if maxDate-minDate > 40 {
+	if maxDate-minDate > maxDaysForDateMetricIDs {
 		// Too much dates must be covered. Give up.
 		return nil, errMissingMetricIDsForDate
 	}