From 1861bf38f588b288bc66196aba1c2516f97aa90c Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Mon, 29 Jun 2020 18:00:22 +0200 Subject: [PATCH] tombstones: Fixed Add method in order to support trimming time series; Simplified the algo. (#7471) * tombstones: Fixed Add method in order to support edge trimming; Simplified the algo. Signed-off-by: Bartlomiej Plotka * Removed duplicated test case. Signed-off-by: Bartlomiej Plotka * Fixed comment, removed "edge" mention. Signed-off-by: Bartlomiej Plotka * Removed trimming word. Signed-off-by: Bartlomiej Plotka --- tsdb/tombstones/tombstones.go | 68 ++++++++++++------------------ tsdb/tombstones/tombstones_test.go | 46 +++++++++++++++----- 2 files changed, 63 insertions(+), 51 deletions(-) diff --git a/tsdb/tombstones/tombstones.go b/tsdb/tombstones/tombstones.go index 615c6d743..a94ccc5e0 100644 --- a/tsdb/tombstones/tombstones.go +++ b/tsdb/tombstones/tombstones.go @@ -22,6 +22,7 @@ import ( "io/ioutil" "os" "path/filepath" + "sort" "sync" "github.com/go-kit/kit/log" @@ -286,47 +287,32 @@ type Intervals []Interval // Add the new time-range to the existing ones. // The existing ones must be sorted. -func (itvs Intervals) Add(n Interval) Intervals { - for i, r := range itvs { - // TODO(gouthamve): Make this codepath easier to digest. - if r.InBounds(n.Mint-1) || r.InBounds(n.Mint) { - if n.Maxt > r.Maxt { - itvs[i].Maxt = n.Maxt - } - - j := 0 - for _, r2 := range itvs[i+1:] { - if n.Maxt < r2.Mint { - break - } - j++ - } - if j != 0 { - if itvs[i+j].Maxt > n.Maxt { - itvs[i].Maxt = itvs[i+j].Maxt - } - itvs = append(itvs[:i+1], itvs[i+j+1:]...) - } - return itvs - } - - if r.InBounds(n.Maxt+1) || r.InBounds(n.Maxt) { - if n.Mint < r.Maxt { - itvs[i].Mint = n.Mint - } - return itvs - } - - if n.Mint < r.Mint { - newRange := make(Intervals, i, len(itvs[:i])+1) - copy(newRange, itvs[:i]) - newRange = append(newRange, n) - newRange = append(newRange, itvs[i:]...) - - return newRange - } +func (in Intervals) Add(n Interval) Intervals { + if len(in) == 0 { + return append(in, n) + } + // Find min and max indexes of intervals that overlap with the new interval. + // Intervals are closed [t1, t2] and t is discreet, so if neighbour intervals are 1 step difference + // to the new one, we can merge those together. + mini := sort.Search(len(in), func(i int) bool { return in[i].Maxt >= n.Mint-1 }) + if mini == len(in) { + return append(in, n) } - itvs = append(itvs, n) - return itvs + maxi := sort.Search(len(in)-mini, func(i int) bool { return in[mini+i].Mint > n.Maxt+1 }) + if maxi == 0 { + if mini == 0 { + return append(Intervals{n}, in...) + } + return append(in[:mini], append(Intervals{n}, in[mini:]...)...) + } + + if n.Mint < in[mini].Mint { + in[mini].Mint = n.Mint + } + in[mini].Maxt = in[maxi+mini-1].Maxt + if n.Maxt > in[mini].Maxt { + in[mini].Maxt = n.Maxt + } + return append(in[:mini+1], in[maxi+mini:]...) } diff --git a/tsdb/tombstones/tombstones_test.go b/tsdb/tombstones/tombstones_test.go index 1f45f3f99..43c2dbd3b 100644 --- a/tsdb/tombstones/tombstones_test.go +++ b/tsdb/tombstones/tombstones_test.go @@ -15,6 +15,7 @@ package tombstones import ( "io/ioutil" + "math" "math/rand" "os" "sync" @@ -25,7 +26,7 @@ import ( "github.com/prometheus/prometheus/util/testutil" ) -func TestWriteAndReadbackTombStones(t *testing.T) { +func TestWriteAndReadbackTombstones(t *testing.T) { tmpdir, _ := ioutil.TempDir("", "test") defer func() { testutil.Ok(t, os.RemoveAll(tmpdir)) @@ -80,19 +81,19 @@ func TestAddingNewIntervals(t *testing.T) { }, { exist: Intervals{{1, 10}, {12, 20}, {25, 30}}, - new: Interval{21, 23}, - exp: Intervals{{1, 10}, {12, 23}, {25, 30}}, + new: Interval{21, 25}, + exp: Intervals{{1, 10}, {12, 30}}, + }, + { + exist: Intervals{{1, 10}, {12, 20}, {25, 30}}, + new: Interval{22, 23}, + exp: Intervals{{1, 10}, {12, 20}, {22, 23}, {25, 30}}, }, { exist: Intervals{{1, 2}, {3, 5}, {7, 7}}, new: Interval{6, 7}, exp: Intervals{{1, 2}, {3, 7}}, }, - { - exist: Intervals{{1, 10}, {12, 20}, {25, 30}}, - new: Interval{21, 25}, - exp: Intervals{{1, 10}, {12, 30}}, - }, { exist: Intervals{{1, 10}, {12, 20}, {25, 30}}, new: Interval{18, 23}, @@ -123,11 +124,36 @@ func TestAddingNewIntervals(t *testing.T) { new: Interval{1, 3}, exp: Intervals{{1, 3}, {5, 10}, {12, 20}, {25, 30}}, }, + { + exist: Intervals{{5, 10}, {12, 20}, {25, 30}}, + new: Interval{35, 40}, + exp: Intervals{{5, 10}, {12, 20}, {25, 30}, {35, 40}}, + }, + { + new: Interval{math.MinInt64, 2}, + exp: Intervals{{math.MinInt64, 2}}, + }, + { + exist: Intervals{{math.MinInt64, 2}}, + new: Interval{9, math.MaxInt64}, + exp: Intervals{{math.MinInt64, 2}, {9, math.MaxInt64}}, + }, + { + exist: Intervals{{9, math.MaxInt64}}, + new: Interval{math.MinInt64, 2}, + exp: Intervals{{math.MinInt64, 2}, {9, math.MaxInt64}}, + }, + { + exist: Intervals{{9, math.MaxInt64}}, + new: Interval{math.MinInt64, 10}, + exp: Intervals{{math.MinInt64, math.MaxInt64}}, + }, } for _, c := range cases { - - testutil.Equals(t, c.exp, c.exist.Add(c.new)) + t.Run("", func(t *testing.T) { + testutil.Equals(t, c.exp, c.exist.Add(c.new)) + }) } }