diff --git a/tsdb/cursor.go b/tsdb/cursor.go index f63461c5f9..6d68ad5f57 100644 --- a/tsdb/cursor.go +++ b/tsdb/cursor.go @@ -7,11 +7,12 @@ import "github.com/influxdata/influxdb/tsdb/cursors" // talk about consuming data. type ( - IntegerArray = cursors.IntegerArray - FloatArray = cursors.FloatArray - UnsignedArray = cursors.UnsignedArray - StringArray = cursors.StringArray - BooleanArray = cursors.BooleanArray + IntegerArray = cursors.IntegerArray + FloatArray = cursors.FloatArray + UnsignedArray = cursors.UnsignedArray + StringArray = cursors.StringArray + BooleanArray = cursors.BooleanArray + TimestampArray = cursors.TimestampArray IntegerArrayCursor = cursors.IntegerArrayCursor FloatArrayCursor = cursors.FloatArrayCursor diff --git a/tsdb/cursors/arrayvalues.gen.go b/tsdb/cursors/arrayvalues.gen.go index bad5904b70..1a213c666e 100644 --- a/tsdb/cursors/arrayvalues.gen.go +++ b/tsdb/cursors/arrayvalues.gen.go @@ -34,6 +34,50 @@ func (a *FloatArray) Len() int { return len(a.Timestamps) } +// search performs a binary search for UnixNano() v in a +// and returns the position, i, where v would be inserted. +// An additional check of a.Timestamps[i] == v is necessary +// to determine if the value v exists. +func (a *FloatArray) search(v int64) int { + // Define: f(x) → a.Timestamps[x] < v + // Define: f(-1) == true, f(n) == false + // Invariant: f(lo-1) == true, f(hi) == false + lo := 0 + hi := a.Len() + for lo < hi { + mid := int(uint(lo+hi) >> 1) + if a.Timestamps[mid] < v { + lo = mid + 1 // preserves f(lo-1) == true + } else { + hi = mid // preserves f(hi) == false + } + } + + // lo == hi + return lo +} + +// FindRange returns the positions where min and max would be +// inserted into the array. If a[0].UnixNano() > max or +// a[len-1].UnixNano() < min then FindRange returns (-1, -1) +// indicating the array is outside the [min, max]. The values must +// be deduplicated and sorted before calling Exclude or the results +// are undefined. +func (a *FloatArray) FindRange(min, max int64) (int, int) { + if a.Len() == 0 || min > max { + return -1, -1 + } + + minVal := a.MinTime() + maxVal := a.MaxTime() + + if maxVal < min || minVal > max { + return -1, -1 + } + + return a.search(min), a.search(max) +} + // Exclude removes the subset of values in [min, max]. The values must // be deduplicated and sorted before calling Exclude or the results are undefined. func (a *FloatArray) Exclude(min, max int64) { @@ -96,50 +140,6 @@ func (a *FloatArray) Include(min, max int64) { } } -// search performs a binary search for UnixNano() v in a -// and returns the position, i, where v would be inserted. -// An additional check of a.Timestamps[i] == v is necessary -// to determine if the value v exists. -func (a *FloatArray) search(v int64) int { - // Define: f(x) → a.Timestamps[x] < v - // Define: f(-1) == true, f(n) == false - // Invariant: f(lo-1) == true, f(hi) == false - lo := 0 - hi := a.Len() - for lo < hi { - mid := int(uint(lo+hi) >> 1) - if a.Timestamps[mid] < v { - lo = mid + 1 // preserves f(lo-1) == true - } else { - hi = mid // preserves f(hi) == false - } - } - - // lo == hi - return lo -} - -// FindRange returns the positions where min and max would be -// inserted into the array. If a[0].UnixNano() > max or -// a[len-1].UnixNano() < min then FindRange returns (-1, -1) -// indicating the array is outside the [min, max]. The values must -// be deduplicated and sorted before calling Exclude or the results -// are undefined. -func (a *FloatArray) FindRange(min, max int64) (int, int) { - if a.Len() == 0 || min > max { - return -1, -1 - } - - minVal := a.MinTime() - maxVal := a.MaxTime() - - if maxVal < min || minVal > max { - return -1, -1 - } - - return a.search(min), a.search(max) -} - // Merge overlays b to top of a. If two values conflict with // the same timestamp, b is used. Both a and b must be sorted // in ascending order. @@ -235,6 +235,50 @@ func (a *IntegerArray) Len() int { return len(a.Timestamps) } +// search performs a binary search for UnixNano() v in a +// and returns the position, i, where v would be inserted. +// An additional check of a.Timestamps[i] == v is necessary +// to determine if the value v exists. +func (a *IntegerArray) search(v int64) int { + // Define: f(x) → a.Timestamps[x] < v + // Define: f(-1) == true, f(n) == false + // Invariant: f(lo-1) == true, f(hi) == false + lo := 0 + hi := a.Len() + for lo < hi { + mid := int(uint(lo+hi) >> 1) + if a.Timestamps[mid] < v { + lo = mid + 1 // preserves f(lo-1) == true + } else { + hi = mid // preserves f(hi) == false + } + } + + // lo == hi + return lo +} + +// FindRange returns the positions where min and max would be +// inserted into the array. If a[0].UnixNano() > max or +// a[len-1].UnixNano() < min then FindRange returns (-1, -1) +// indicating the array is outside the [min, max]. The values must +// be deduplicated and sorted before calling Exclude or the results +// are undefined. +func (a *IntegerArray) FindRange(min, max int64) (int, int) { + if a.Len() == 0 || min > max { + return -1, -1 + } + + minVal := a.MinTime() + maxVal := a.MaxTime() + + if maxVal < min || minVal > max { + return -1, -1 + } + + return a.search(min), a.search(max) +} + // Exclude removes the subset of values in [min, max]. The values must // be deduplicated and sorted before calling Exclude or the results are undefined. func (a *IntegerArray) Exclude(min, max int64) { @@ -297,50 +341,6 @@ func (a *IntegerArray) Include(min, max int64) { } } -// search performs a binary search for UnixNano() v in a -// and returns the position, i, where v would be inserted. -// An additional check of a.Timestamps[i] == v is necessary -// to determine if the value v exists. -func (a *IntegerArray) search(v int64) int { - // Define: f(x) → a.Timestamps[x] < v - // Define: f(-1) == true, f(n) == false - // Invariant: f(lo-1) == true, f(hi) == false - lo := 0 - hi := a.Len() - for lo < hi { - mid := int(uint(lo+hi) >> 1) - if a.Timestamps[mid] < v { - lo = mid + 1 // preserves f(lo-1) == true - } else { - hi = mid // preserves f(hi) == false - } - } - - // lo == hi - return lo -} - -// FindRange returns the positions where min and max would be -// inserted into the array. If a[0].UnixNano() > max or -// a[len-1].UnixNano() < min then FindRange returns (-1, -1) -// indicating the array is outside the [min, max]. The values must -// be deduplicated and sorted before calling Exclude or the results -// are undefined. -func (a *IntegerArray) FindRange(min, max int64) (int, int) { - if a.Len() == 0 || min > max { - return -1, -1 - } - - minVal := a.MinTime() - maxVal := a.MaxTime() - - if maxVal < min || minVal > max { - return -1, -1 - } - - return a.search(min), a.search(max) -} - // Merge overlays b to top of a. If two values conflict with // the same timestamp, b is used. Both a and b must be sorted // in ascending order. @@ -436,6 +436,50 @@ func (a *UnsignedArray) Len() int { return len(a.Timestamps) } +// search performs a binary search for UnixNano() v in a +// and returns the position, i, where v would be inserted. +// An additional check of a.Timestamps[i] == v is necessary +// to determine if the value v exists. +func (a *UnsignedArray) search(v int64) int { + // Define: f(x) → a.Timestamps[x] < v + // Define: f(-1) == true, f(n) == false + // Invariant: f(lo-1) == true, f(hi) == false + lo := 0 + hi := a.Len() + for lo < hi { + mid := int(uint(lo+hi) >> 1) + if a.Timestamps[mid] < v { + lo = mid + 1 // preserves f(lo-1) == true + } else { + hi = mid // preserves f(hi) == false + } + } + + // lo == hi + return lo +} + +// FindRange returns the positions where min and max would be +// inserted into the array. If a[0].UnixNano() > max or +// a[len-1].UnixNano() < min then FindRange returns (-1, -1) +// indicating the array is outside the [min, max]. The values must +// be deduplicated and sorted before calling Exclude or the results +// are undefined. +func (a *UnsignedArray) FindRange(min, max int64) (int, int) { + if a.Len() == 0 || min > max { + return -1, -1 + } + + minVal := a.MinTime() + maxVal := a.MaxTime() + + if maxVal < min || minVal > max { + return -1, -1 + } + + return a.search(min), a.search(max) +} + // Exclude removes the subset of values in [min, max]. The values must // be deduplicated and sorted before calling Exclude or the results are undefined. func (a *UnsignedArray) Exclude(min, max int64) { @@ -498,50 +542,6 @@ func (a *UnsignedArray) Include(min, max int64) { } } -// search performs a binary search for UnixNano() v in a -// and returns the position, i, where v would be inserted. -// An additional check of a.Timestamps[i] == v is necessary -// to determine if the value v exists. -func (a *UnsignedArray) search(v int64) int { - // Define: f(x) → a.Timestamps[x] < v - // Define: f(-1) == true, f(n) == false - // Invariant: f(lo-1) == true, f(hi) == false - lo := 0 - hi := a.Len() - for lo < hi { - mid := int(uint(lo+hi) >> 1) - if a.Timestamps[mid] < v { - lo = mid + 1 // preserves f(lo-1) == true - } else { - hi = mid // preserves f(hi) == false - } - } - - // lo == hi - return lo -} - -// FindRange returns the positions where min and max would be -// inserted into the array. If a[0].UnixNano() > max or -// a[len-1].UnixNano() < min then FindRange returns (-1, -1) -// indicating the array is outside the [min, max]. The values must -// be deduplicated and sorted before calling Exclude or the results -// are undefined. -func (a *UnsignedArray) FindRange(min, max int64) (int, int) { - if a.Len() == 0 || min > max { - return -1, -1 - } - - minVal := a.MinTime() - maxVal := a.MaxTime() - - if maxVal < min || minVal > max { - return -1, -1 - } - - return a.search(min), a.search(max) -} - // Merge overlays b to top of a. If two values conflict with // the same timestamp, b is used. Both a and b must be sorted // in ascending order. @@ -637,6 +637,50 @@ func (a *StringArray) Len() int { return len(a.Timestamps) } +// search performs a binary search for UnixNano() v in a +// and returns the position, i, where v would be inserted. +// An additional check of a.Timestamps[i] == v is necessary +// to determine if the value v exists. +func (a *StringArray) search(v int64) int { + // Define: f(x) → a.Timestamps[x] < v + // Define: f(-1) == true, f(n) == false + // Invariant: f(lo-1) == true, f(hi) == false + lo := 0 + hi := a.Len() + for lo < hi { + mid := int(uint(lo+hi) >> 1) + if a.Timestamps[mid] < v { + lo = mid + 1 // preserves f(lo-1) == true + } else { + hi = mid // preserves f(hi) == false + } + } + + // lo == hi + return lo +} + +// FindRange returns the positions where min and max would be +// inserted into the array. If a[0].UnixNano() > max or +// a[len-1].UnixNano() < min then FindRange returns (-1, -1) +// indicating the array is outside the [min, max]. The values must +// be deduplicated and sorted before calling Exclude or the results +// are undefined. +func (a *StringArray) FindRange(min, max int64) (int, int) { + if a.Len() == 0 || min > max { + return -1, -1 + } + + minVal := a.MinTime() + maxVal := a.MaxTime() + + if maxVal < min || minVal > max { + return -1, -1 + } + + return a.search(min), a.search(max) +} + // Exclude removes the subset of values in [min, max]. The values must // be deduplicated and sorted before calling Exclude or the results are undefined. func (a *StringArray) Exclude(min, max int64) { @@ -699,50 +743,6 @@ func (a *StringArray) Include(min, max int64) { } } -// search performs a binary search for UnixNano() v in a -// and returns the position, i, where v would be inserted. -// An additional check of a.Timestamps[i] == v is necessary -// to determine if the value v exists. -func (a *StringArray) search(v int64) int { - // Define: f(x) → a.Timestamps[x] < v - // Define: f(-1) == true, f(n) == false - // Invariant: f(lo-1) == true, f(hi) == false - lo := 0 - hi := a.Len() - for lo < hi { - mid := int(uint(lo+hi) >> 1) - if a.Timestamps[mid] < v { - lo = mid + 1 // preserves f(lo-1) == true - } else { - hi = mid // preserves f(hi) == false - } - } - - // lo == hi - return lo -} - -// FindRange returns the positions where min and max would be -// inserted into the array. If a[0].UnixNano() > max or -// a[len-1].UnixNano() < min then FindRange returns (-1, -1) -// indicating the array is outside the [min, max]. The values must -// be deduplicated and sorted before calling Exclude or the results -// are undefined. -func (a *StringArray) FindRange(min, max int64) (int, int) { - if a.Len() == 0 || min > max { - return -1, -1 - } - - minVal := a.MinTime() - maxVal := a.MaxTime() - - if maxVal < min || minVal > max { - return -1, -1 - } - - return a.search(min), a.search(max) -} - // Merge overlays b to top of a. If two values conflict with // the same timestamp, b is used. Both a and b must be sorted // in ascending order. @@ -838,6 +838,50 @@ func (a *BooleanArray) Len() int { return len(a.Timestamps) } +// search performs a binary search for UnixNano() v in a +// and returns the position, i, where v would be inserted. +// An additional check of a.Timestamps[i] == v is necessary +// to determine if the value v exists. +func (a *BooleanArray) search(v int64) int { + // Define: f(x) → a.Timestamps[x] < v + // Define: f(-1) == true, f(n) == false + // Invariant: f(lo-1) == true, f(hi) == false + lo := 0 + hi := a.Len() + for lo < hi { + mid := int(uint(lo+hi) >> 1) + if a.Timestamps[mid] < v { + lo = mid + 1 // preserves f(lo-1) == true + } else { + hi = mid // preserves f(hi) == false + } + } + + // lo == hi + return lo +} + +// FindRange returns the positions where min and max would be +// inserted into the array. If a[0].UnixNano() > max or +// a[len-1].UnixNano() < min then FindRange returns (-1, -1) +// indicating the array is outside the [min, max]. The values must +// be deduplicated and sorted before calling Exclude or the results +// are undefined. +func (a *BooleanArray) FindRange(min, max int64) (int, int) { + if a.Len() == 0 || min > max { + return -1, -1 + } + + minVal := a.MinTime() + maxVal := a.MaxTime() + + if maxVal < min || minVal > max { + return -1, -1 + } + + return a.search(min), a.search(max) +} + // Exclude removes the subset of values in [min, max]. The values must // be deduplicated and sorted before calling Exclude or the results are undefined. func (a *BooleanArray) Exclude(min, max int64) { @@ -900,50 +944,6 @@ func (a *BooleanArray) Include(min, max int64) { } } -// search performs a binary search for UnixNano() v in a -// and returns the position, i, where v would be inserted. -// An additional check of a.Timestamps[i] == v is necessary -// to determine if the value v exists. -func (a *BooleanArray) search(v int64) int { - // Define: f(x) → a.Timestamps[x] < v - // Define: f(-1) == true, f(n) == false - // Invariant: f(lo-1) == true, f(hi) == false - lo := 0 - hi := a.Len() - for lo < hi { - mid := int(uint(lo+hi) >> 1) - if a.Timestamps[mid] < v { - lo = mid + 1 // preserves f(lo-1) == true - } else { - hi = mid // preserves f(hi) == false - } - } - - // lo == hi - return lo -} - -// FindRange returns the positions where min and max would be -// inserted into the array. If a[0].UnixNano() > max or -// a[len-1].UnixNano() < min then FindRange returns (-1, -1) -// indicating the array is outside the [min, max]. The values must -// be deduplicated and sorted before calling Exclude or the results -// are undefined. -func (a *BooleanArray) FindRange(min, max int64) (int, int) { - if a.Len() == 0 || min > max { - return -1, -1 - } - - minVal := a.MinTime() - maxVal := a.MaxTime() - - if maxVal < min || minVal > max { - return -1, -1 - } - - return a.search(min), a.search(max) -} - // Merge overlays b to top of a. If two values conflict with // the same timestamp, b is used. Both a and b must be sorted // in ascending order. @@ -1010,3 +1010,123 @@ func (a *BooleanArray) Merge(b *BooleanArray) { a.Timestamps = out.Timestamps[:k] a.Values = out.Values[:k] } + +type TimestampArray struct { + Timestamps []int64 +} + +func NewTimestampArrayLen(sz int) *TimestampArray { + return &TimestampArray{ + Timestamps: make([]int64, sz), + } +} + +func (a *TimestampArray) MinTime() int64 { + return a.Timestamps[0] +} + +func (a *TimestampArray) MaxTime() int64 { + return a.Timestamps[len(a.Timestamps)-1] +} + +func (a *TimestampArray) Size() int { + panic("not implemented") +} + +func (a *TimestampArray) Len() int { + return len(a.Timestamps) +} + +// search performs a binary search for UnixNano() v in a +// and returns the position, i, where v would be inserted. +// An additional check of a.Timestamps[i] == v is necessary +// to determine if the value v exists. +func (a *TimestampArray) search(v int64) int { + // Define: f(x) → a.Timestamps[x] < v + // Define: f(-1) == true, f(n) == false + // Invariant: f(lo-1) == true, f(hi) == false + lo := 0 + hi := a.Len() + for lo < hi { + mid := int(uint(lo+hi) >> 1) + if a.Timestamps[mid] < v { + lo = mid + 1 // preserves f(lo-1) == true + } else { + hi = mid // preserves f(hi) == false + } + } + + // lo == hi + return lo +} + +// FindRange returns the positions where min and max would be +// inserted into the array. If a[0].UnixNano() > max or +// a[len-1].UnixNano() < min then FindRange returns (-1, -1) +// indicating the array is outside the [min, max]. The values must +// be deduplicated and sorted before calling Exclude or the results +// are undefined. +func (a *TimestampArray) FindRange(min, max int64) (int, int) { + if a.Len() == 0 || min > max { + return -1, -1 + } + + minVal := a.MinTime() + maxVal := a.MaxTime() + + if maxVal < min || minVal > max { + return -1, -1 + } + + return a.search(min), a.search(max) +} + +// Exclude removes the subset of timestamps in [min, max]. The timestamps must +// be deduplicated and sorted before calling Exclude or the results are undefined. +func (a *TimestampArray) Exclude(min, max int64) { + rmin, rmax := a.FindRange(min, max) + if rmin == -1 && rmax == -1 { + return + } + + // a.Timestamps[rmin] ≥ min + // a.Timestamps[rmax] ≥ max + + if rmax < a.Len() { + if a.Timestamps[rmax] == max { + rmax++ + } + rest := a.Len() - rmax + if rest > 0 { + ts := a.Timestamps[:rmin+rest] + copy(ts[rmin:], a.Timestamps[rmax:]) + a.Timestamps = ts + return + } + } + + a.Timestamps = a.Timestamps[:rmin] +} + +// Contains returns true if values exist between min and max inclusive. The +// values must be deduplicated and sorted before calling Contains or the +// results are undefined. +func (a *TimestampArray) Contains(min, max int64) bool { + rmin, rmax := a.FindRange(min, max) + if rmin == -1 && rmax == -1 { + return false + } + + // a.Timestamps[rmin] ≥ min + // a.Timestamps[rmax] ≥ max + + if a.Timestamps[rmin] == min { + return true + } + + if rmax < a.Len() && a.Timestamps[rmax] == max { + return true + } + + return rmax-rmin > 0 +} diff --git a/tsdb/cursors/arrayvalues.gen.go.tmpl b/tsdb/cursors/arrayvalues.gen.go.tmpl index 92406f368e..e8591b8162 100644 --- a/tsdb/cursors/arrayvalues.gen.go.tmpl +++ b/tsdb/cursors/arrayvalues.gen.go.tmpl @@ -1,18 +1,22 @@ package cursors {{range .}} - -{{ $typename := print .Name "Array" }} +{{- $typename := print .Name "Array" }} +{{- $hasType := or (and .Type true) false }} type {{ $typename }} struct { Timestamps []int64 +{{- if $hasType }} Values []{{.Type}} +{{- end }} } func New{{$typename}}Len(sz int) *{{$typename}} { return &{{$typename}}{ Timestamps: make([]int64, sz), +{{- if $hasType }} Values: make([]{{.Type}}, sz), +{{- end }} } } @@ -32,6 +36,51 @@ func (a *{{ $typename}}) Len() int { return len(a.Timestamps) } +// search performs a binary search for UnixNano() v in a +// and returns the position, i, where v would be inserted. +// An additional check of a.Timestamps[i] == v is necessary +// to determine if the value v exists. +func (a *{{ $typename }}) search(v int64) int { + // Define: f(x) → a.Timestamps[x] < v + // Define: f(-1) == true, f(n) == false + // Invariant: f(lo-1) == true, f(hi) == false + lo := 0 + hi := a.Len() + for lo < hi { + mid := int(uint(lo+hi) >> 1) + if a.Timestamps[mid] < v { + lo = mid + 1 // preserves f(lo-1) == true + } else { + hi = mid // preserves f(hi) == false + } + } + + // lo == hi + return lo +} + +// FindRange returns the positions where min and max would be +// inserted into the array. If a[0].UnixNano() > max or +// a[len-1].UnixNano() < min then FindRange returns (-1, -1) +// indicating the array is outside the [min, max]. The values must +// be deduplicated and sorted before calling Exclude or the results +// are undefined. +func (a *{{ $typename }}) FindRange(min, max int64) (int, int) { + if a.Len() == 0 || min > max { + return -1, -1 + } + + minVal := a.MinTime() + maxVal := a.MaxTime() + + if maxVal < min || minVal > max { + return -1, -1 + } + + return a.search(min), a.search(max) +} + +{{- if $hasType }} // Exclude removes the subset of values in [min, max]. The values must // be deduplicated and sorted before calling Exclude or the results are undefined. func (a *{{ $typename }}) Exclude(min, max int64) { @@ -94,50 +143,6 @@ func (a *{{ $typename }}) Include(min, max int64) { } } -// search performs a binary search for UnixNano() v in a -// and returns the position, i, where v would be inserted. -// An additional check of a.Timestamps[i] == v is necessary -// to determine if the value v exists. -func (a *{{ $typename }}) search(v int64) int { - // Define: f(x) → a.Timestamps[x] < v - // Define: f(-1) == true, f(n) == false - // Invariant: f(lo-1) == true, f(hi) == false - lo := 0 - hi := a.Len() - for lo < hi { - mid := int(uint(lo+hi) >> 1) - if a.Timestamps[mid] < v { - lo = mid + 1 // preserves f(lo-1) == true - } else { - hi = mid // preserves f(hi) == false - } - } - - // lo == hi - return lo -} - -// FindRange returns the positions where min and max would be -// inserted into the array. If a[0].UnixNano() > max or -// a[len-1].UnixNano() < min then FindRange returns (-1, -1) -// indicating the array is outside the [min, max]. The values must -// be deduplicated and sorted before calling Exclude or the results -// are undefined. -func (a *{{ $typename }}) FindRange(min, max int64) (int, int) { - if a.Len() == 0 || min > max { - return -1, -1 - } - - minVal := a.MinTime() - maxVal := a.MaxTime() - - if maxVal < min || minVal > max { - return -1, -1 - } - - return a.search(min), a.search(max) -} - // Merge overlays b to top of a. If two values conflict with // the same timestamp, b is used. Both a and b must be sorted // in ascending order. @@ -204,5 +209,56 @@ func (a *{{ $typename }}) Merge(b *{{ $typename }}) { a.Timestamps = out.Timestamps[:k] a.Values = out.Values[:k] } +{{ else }} +// Exclude removes the subset of timestamps in [min, max]. The timestamps must +// be deduplicated and sorted before calling Exclude or the results are undefined. +func (a *{{ $typename }}) Exclude(min, max int64) { + rmin, rmax := a.FindRange(min, max) + if rmin == -1 && rmax == -1 { + return + } + + // a.Timestamps[rmin] ≥ min + // a.Timestamps[rmax] ≥ max + + if rmax < a.Len() { + if a.Timestamps[rmax] == max { + rmax++ + } + rest := a.Len()-rmax + if rest > 0 { + ts := a.Timestamps[:rmin+rest] + copy(ts[rmin:], a.Timestamps[rmax:]) + a.Timestamps = ts + return + } + } + + a.Timestamps = a.Timestamps[:rmin] +} + +// Contains returns true if values exist between min and max inclusive. The +// values must be deduplicated and sorted before calling Contains or the +// results are undefined. +func (a *{{ $typename }}) Contains(min, max int64) bool { + rmin, rmax := a.FindRange(min, max) + if rmin == -1 && rmax == -1 { + return false + } + + // a.Timestamps[rmin] ≥ min + // a.Timestamps[rmax] ≥ max + + if a.Timestamps[rmin] == min { + return true + } + + if rmax < a.Len() && a.Timestamps[rmax] == max { + return true + } + + return rmax-rmin > 0 +} +{{ end }} {{ end }} diff --git a/tsdb/cursors/arrayvalues.gen.go.tmpldata b/tsdb/cursors/arrayvalues.gen.go.tmpldata index 33a49d2604..7ebe5b94c1 100644 --- a/tsdb/cursors/arrayvalues.gen.go.tmpldata +++ b/tsdb/cursors/arrayvalues.gen.go.tmpldata @@ -18,5 +18,9 @@ { "Name":"Boolean", "Type":"bool" + }, + { + "Name":"Timestamp", + "Type": null } ] diff --git a/tsdb/cursors/arrayvalues.gen_test.go b/tsdb/cursors/arrayvalues.gen_test.go index b57f2602e7..f9bf6483be 100644 --- a/tsdb/cursors/arrayvalues.gen_test.go +++ b/tsdb/cursors/arrayvalues.gen_test.go @@ -122,6 +122,50 @@ func TestIntegerArray_Include(t *testing.T) { } } +func makeTimestampArray(count int, min, max int64) *TimestampArray { + vals := NewTimestampArrayLen(count) + + ts := min + inc := (max - min) / int64(count) + + for i := 0; i < count; i++ { + vals.Timestamps[i] = ts + ts += inc + } + + return vals +} + +func TestTimestampArray_Contains(t *testing.T) { + cases := []struct { + n string + min, max int64 + exp bool + }{ + {"no/lo", 0, 9, false}, + {"no/hi", 19, 30, false}, + {"no/middle", 13, 13, false}, + + {"yes/first", 0, 10, true}, + {"yes/first-eq", 10, 10, true}, + {"yes/last", 18, 20, true}, + {"yes/last-eq", 18, 18, true}, + {"yes/all but first and last", 12, 16, true}, + {"yes/middle-eq", 14, 14, true}, + {"yes/middle-overlap", 13, 15, true}, + {"yes/covers", 8, 22, true}, + } + + for _, tc := range cases { + t.Run(fmt.Sprintf("%s[%d,%d]", tc.n, tc.min, tc.max), func(t *testing.T) { + vals := makeTimestampArray(5, 10, 20) + if got := vals.Contains(tc.min, tc.max); got != tc.exp { + t.Errorf("Contains -got/+exp\n%s", cmp.Diff(got, tc.exp)) + } + }) + } +} + func benchExclude(b *testing.B, vals *IntegerArray, min, max int64) { b.ResetTimer() diff --git a/tsdb/tsm1/array_encoding.go b/tsdb/tsm1/array_encoding.go index 864581efad..702e515ff1 100644 --- a/tsdb/tsm1/array_encoding.go +++ b/tsdb/tsm1/array_encoding.go @@ -110,3 +110,15 @@ func DecodeStringArrayBlock(block []byte, a *tsdb.StringArray) error { a.Values, err = StringArrayDecodeAll(vb, a.Values) return err } + +// DecodeTimestampArrayBlock decodes the timestamps from the specified +// block, ignoring the block type and the values. +func DecodeTimestampArrayBlock(block []byte, a *tsdb.TimestampArray) error { + tb, _, err := unpackBlock(block[1:]) + if err != nil { + return err + } + + a.Timestamps, err = TimeArrayDecodeAll(tb, a.Timestamps) + return err +}