2017-11-27 21:13:02 +00:00
|
|
|
package inmem
|
2017-05-19 01:05:33 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2019-04-01 16:46:02 +00:00
|
|
|
"math/rand"
|
2017-05-19 01:05:33 +00:00
|
|
|
"strings"
|
2019-04-01 16:46:02 +00:00
|
|
|
"sync"
|
2017-05-19 01:05:33 +00:00
|
|
|
"testing"
|
2019-04-01 16:46:02 +00:00
|
|
|
"time"
|
2017-05-19 01:05:33 +00:00
|
|
|
|
|
|
|
"github.com/influxdata/influxdb/models"
|
2017-08-15 19:24:22 +00:00
|
|
|
"github.com/influxdata/influxdb/query"
|
2018-02-28 04:23:59 +00:00
|
|
|
"github.com/influxdata/influxdb/tsdb"
|
2017-10-30 21:40:26 +00:00
|
|
|
"github.com/influxdata/influxql"
|
2017-05-19 01:05:33 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Test comparing SeriesIDs for equality.
|
|
|
|
func TestSeriesIDs_Equals(t *testing.T) {
|
2017-11-27 21:13:02 +00:00
|
|
|
ids1 := seriesIDs([]uint64{1, 2, 3})
|
|
|
|
ids2 := seriesIDs([]uint64{1, 2, 3})
|
|
|
|
ids3 := seriesIDs([]uint64{4, 5, 6})
|
2017-05-19 01:05:33 +00:00
|
|
|
|
|
|
|
if !ids1.Equals(ids2) {
|
|
|
|
t.Fatal("expected ids1 == ids2")
|
|
|
|
} else if ids1.Equals(ids3) {
|
|
|
|
t.Fatal("expected ids1 != ids3")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test intersecting sets of SeriesIDs.
|
|
|
|
func TestSeriesIDs_Intersect(t *testing.T) {
|
2017-11-27 21:13:02 +00:00
|
|
|
// Test swapping l & r, all branches of if-else, and exit loop when 'j < len(r)'
|
|
|
|
ids1 := seriesIDs([]uint64{1, 3, 4, 5, 6})
|
|
|
|
ids2 := seriesIDs([]uint64{1, 2, 3, 7})
|
|
|
|
exp := seriesIDs([]uint64{1, 3})
|
2017-05-19 01:05:33 +00:00
|
|
|
got := ids1.Intersect(ids2)
|
|
|
|
|
|
|
|
if !exp.Equals(got) {
|
|
|
|
t.Fatalf("exp=%v, got=%v", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test exit for loop when 'i < len(l)'
|
2017-11-27 21:13:02 +00:00
|
|
|
ids1 = seriesIDs([]uint64{1})
|
|
|
|
ids2 = seriesIDs([]uint64{1, 2})
|
|
|
|
exp = seriesIDs([]uint64{1})
|
2017-05-19 01:05:33 +00:00
|
|
|
got = ids1.Intersect(ids2)
|
|
|
|
|
|
|
|
if !exp.Equals(got) {
|
|
|
|
t.Fatalf("exp=%v, got=%v", exp, got)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test union sets of SeriesIDs.
|
|
|
|
func TestSeriesIDs_Union(t *testing.T) {
|
|
|
|
// Test all branches of if-else, exit loop because of 'j < len(r)', and append remainder from left.
|
2017-11-27 21:13:02 +00:00
|
|
|
ids1 := seriesIDs([]uint64{1, 2, 3, 7})
|
|
|
|
ids2 := seriesIDs([]uint64{1, 3, 4, 5, 6})
|
|
|
|
exp := seriesIDs([]uint64{1, 2, 3, 4, 5, 6, 7})
|
2017-05-19 01:05:33 +00:00
|
|
|
got := ids1.Union(ids2)
|
|
|
|
|
|
|
|
if !exp.Equals(got) {
|
|
|
|
t.Fatalf("exp=%v, got=%v", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test exit because of 'i < len(l)' and append remainder from right.
|
2017-11-27 21:13:02 +00:00
|
|
|
ids1 = seriesIDs([]uint64{1})
|
|
|
|
ids2 = seriesIDs([]uint64{1, 2})
|
|
|
|
exp = seriesIDs([]uint64{1, 2})
|
2017-05-19 01:05:33 +00:00
|
|
|
got = ids1.Union(ids2)
|
|
|
|
|
|
|
|
if !exp.Equals(got) {
|
|
|
|
t.Fatalf("exp=%v, got=%v", exp, got)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test removing one set of SeriesIDs from another.
|
|
|
|
func TestSeriesIDs_Reject(t *testing.T) {
|
|
|
|
// Test all branches of if-else, exit loop because of 'j < len(r)', and append remainder from left.
|
2017-11-27 21:13:02 +00:00
|
|
|
ids1 := seriesIDs([]uint64{1, 2, 3, 7})
|
|
|
|
ids2 := seriesIDs([]uint64{1, 3, 4, 5, 6})
|
|
|
|
exp := seriesIDs([]uint64{2, 7})
|
2017-05-19 01:05:33 +00:00
|
|
|
got := ids1.Reject(ids2)
|
|
|
|
|
|
|
|
if !exp.Equals(got) {
|
|
|
|
t.Fatalf("exp=%v, got=%v", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test exit because of 'i < len(l)'.
|
2017-11-27 21:13:02 +00:00
|
|
|
ids1 = seriesIDs([]uint64{1})
|
|
|
|
ids2 = seriesIDs([]uint64{1, 2})
|
|
|
|
exp = seriesIDs{}
|
2017-05-19 01:05:33 +00:00
|
|
|
got = ids1.Reject(ids2)
|
|
|
|
|
|
|
|
if !exp.Equals(got) {
|
|
|
|
t.Fatalf("exp=%v, got=%v", exp, got)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-10 18:01:52 +00:00
|
|
|
func TestMeasurement_AddSeries_Nil(t *testing.T) {
|
2017-11-27 21:13:02 +00:00
|
|
|
m := newMeasurement("foo", "cpu")
|
2017-10-10 18:01:52 +00:00
|
|
|
if m.AddSeries(nil) {
|
|
|
|
t.Fatalf("AddSeries mismatch: exp false, got true")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-19 01:05:33 +00:00
|
|
|
func TestMeasurement_AppendSeriesKeysByID_Missing(t *testing.T) {
|
2017-11-27 21:13:02 +00:00
|
|
|
m := newMeasurement("foo", "cpu")
|
2017-05-19 01:05:33 +00:00
|
|
|
var dst []string
|
|
|
|
dst = m.AppendSeriesKeysByID(dst, []uint64{1})
|
|
|
|
if exp, got := 0, len(dst); exp != got {
|
|
|
|
t.Fatalf("series len mismatch: exp %v, got %v", exp, got)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMeasurement_AppendSeriesKeysByID_Exists(t *testing.T) {
|
2017-11-27 21:13:02 +00:00
|
|
|
m := newMeasurement("foo", "cpu")
|
|
|
|
s := newSeries(1, m, "cpu,host=foo", models.Tags{models.NewTag([]byte("host"), []byte("foo"))})
|
2017-05-19 01:05:33 +00:00
|
|
|
m.AddSeries(s)
|
|
|
|
|
|
|
|
var dst []string
|
|
|
|
dst = m.AppendSeriesKeysByID(dst, []uint64{1})
|
|
|
|
if exp, got := 1, len(dst); exp != got {
|
|
|
|
t.Fatalf("series len mismatch: exp %v, got %v", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
if exp, got := "cpu,host=foo", dst[0]; exp != got {
|
|
|
|
t.Fatalf("series mismatch: exp %v, got %v", exp, got)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMeasurement_TagsSet_Deadlock(t *testing.T) {
|
2017-11-27 21:13:02 +00:00
|
|
|
m := newMeasurement("foo", "cpu")
|
|
|
|
s1 := newSeries(1, m, "cpu,host=foo", models.Tags{models.NewTag([]byte("host"), []byte("foo"))})
|
2017-05-19 01:05:33 +00:00
|
|
|
m.AddSeries(s1)
|
|
|
|
|
2017-11-27 21:13:02 +00:00
|
|
|
s2 := newSeries(2, m, "cpu,host=bar", models.Tags{models.NewTag([]byte("host"), []byte("bar"))})
|
2017-05-19 01:05:33 +00:00
|
|
|
m.AddSeries(s2)
|
|
|
|
|
|
|
|
m.DropSeries(s1)
|
|
|
|
|
|
|
|
// This was deadlocking
|
2018-02-28 04:23:59 +00:00
|
|
|
s := tsdb.NewSeriesIDSet()
|
|
|
|
s.Add(1)
|
|
|
|
m.TagSets(s, query.IteratorOptions{})
|
2017-05-19 01:05:33 +00:00
|
|
|
if got, exp := len(m.SeriesIDs()), 1; got != exp {
|
|
|
|
t.Fatalf("series count mismatch: got %v, exp %v", got, exp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-01 16:46:02 +00:00
|
|
|
// Ensures the tagKeyValue API contains no deadlocks or sync issues.
|
|
|
|
func TestTagKeyValue_Concurrent(t *testing.T) {
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
done := make(chan struct{})
|
|
|
|
time.AfterFunc(2*time.Second, func() { close(done) })
|
|
|
|
|
|
|
|
v := newTagKeyValue()
|
|
|
|
for i := 0; i < 4; i++ {
|
|
|
|
wg.Add(1)
|
|
|
|
go func(i int) {
|
|
|
|
defer wg.Done()
|
|
|
|
|
|
|
|
rand := rand.New(rand.NewSource(int64(i)))
|
|
|
|
for {
|
|
|
|
// Continue running until time limit.
|
|
|
|
select {
|
|
|
|
case <-done:
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
|
|
|
// Randomly choose next API.
|
|
|
|
switch rand.Intn(7) {
|
|
|
|
case 0:
|
|
|
|
v.bytes()
|
|
|
|
case 1:
|
|
|
|
v.Cardinality()
|
|
|
|
case 2:
|
2021-01-08 17:46:22 +00:00
|
|
|
v.Contains(string([]rune{rune(rand.Intn(52) + 65)}))
|
2019-04-01 16:46:02 +00:00
|
|
|
case 3:
|
2021-01-08 17:46:22 +00:00
|
|
|
v.InsertSeriesIDByte([]byte(string([]rune{rune(rand.Intn(52) + 65)})), rand.Uint64()%1000)
|
2019-04-01 16:46:02 +00:00
|
|
|
case 4:
|
2021-01-08 17:46:22 +00:00
|
|
|
v.Load(string([]rune{rune(rand.Intn(52) + 65)}))
|
2019-04-01 16:46:02 +00:00
|
|
|
case 5:
|
|
|
|
v.Range(func(tagValue string, a seriesIDs) bool {
|
|
|
|
return rand.Intn(10) == 0
|
|
|
|
})
|
|
|
|
case 6:
|
|
|
|
v.RangeAll(func(k string, a seriesIDs) {})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}(i)
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
}
|
|
|
|
|
2017-05-19 01:05:33 +00:00
|
|
|
func BenchmarkMeasurement_SeriesIDForExp_EQRegex(b *testing.B) {
|
2017-11-27 21:13:02 +00:00
|
|
|
m := newMeasurement("foo", "cpu")
|
2017-05-19 01:05:33 +00:00
|
|
|
for i := 0; i < 100000; i++ {
|
2017-11-27 21:13:02 +00:00
|
|
|
s := newSeries(uint64(i), m, "cpu", models.Tags{models.NewTag(
|
2017-05-19 01:05:33 +00:00
|
|
|
[]byte("host"),
|
|
|
|
[]byte(fmt.Sprintf("host%d", i)))})
|
|
|
|
m.AddSeries(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
if exp, got := 100000, len(m.SeriesKeys()); exp != got {
|
|
|
|
b.Fatalf("series count mismatch: exp %v got %v", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
stmt, err := influxql.NewParser(strings.NewReader(`SELECT * FROM cpu WHERE host =~ /host\d+/`)).ParseStatement()
|
|
|
|
if err != nil {
|
|
|
|
b.Fatalf("invalid statement: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
selectStmt := stmt.(*influxql.SelectStatement)
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
ids := m.IDsForExpr(selectStmt.Condition.(*influxql.BinaryExpr))
|
|
|
|
if exp, got := 100000, len(ids); exp != got {
|
|
|
|
b.Fatalf("series count mismatch: exp %v got %v", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkMeasurement_SeriesIDForExp_NERegex(b *testing.B) {
|
2017-11-27 21:13:02 +00:00
|
|
|
m := newMeasurement("foo", "cpu")
|
2017-05-19 01:05:33 +00:00
|
|
|
for i := 0; i < 100000; i++ {
|
2017-11-27 21:13:02 +00:00
|
|
|
s := newSeries(uint64(i), m, "cpu", models.Tags{models.Tag{
|
2017-05-19 01:05:33 +00:00
|
|
|
Key: []byte("host"),
|
|
|
|
Value: []byte(fmt.Sprintf("host%d", i))}})
|
|
|
|
m.AddSeries(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
if exp, got := 100000, len(m.SeriesKeys()); exp != got {
|
|
|
|
b.Fatalf("series count mismatch: exp %v got %v", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
stmt, err := influxql.NewParser(strings.NewReader(`SELECT * FROM cpu WHERE host !~ /foo\d+/`)).ParseStatement()
|
|
|
|
if err != nil {
|
|
|
|
b.Fatalf("invalid statement: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
selectStmt := stmt.(*influxql.SelectStatement)
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
ids := m.IDsForExpr(selectStmt.Condition.(*influxql.BinaryExpr))
|
|
|
|
if exp, got := 100000, len(ids); exp != got {
|
|
|
|
b.Fatalf("series count mismatch: exp %v got %v", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-08-15 19:24:22 +00:00
|
|
|
func benchmarkTagSets(b *testing.B, n int, opt query.IteratorOptions) {
|
2017-11-27 21:13:02 +00:00
|
|
|
m := newMeasurement("foo", "m")
|
2018-02-28 04:23:59 +00:00
|
|
|
ss := tsdb.NewSeriesIDSet()
|
|
|
|
|
2017-05-25 22:52:27 +00:00
|
|
|
for i := 0; i < n; i++ {
|
2017-05-25 23:00:23 +00:00
|
|
|
tags := map[string]string{"tag1": "value1", "tag2": "value2"}
|
2020-05-18 17:55:05 +00:00
|
|
|
s := newSeries(uint64(i), m, "m,tag1=value1,tag2=value2", models.NewTags(tags))
|
2018-02-28 04:23:59 +00:00
|
|
|
ss.Add(uint64(i))
|
2017-05-25 22:52:27 +00:00
|
|
|
m.AddSeries(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
// warm caches
|
2018-02-28 04:23:59 +00:00
|
|
|
m.TagSets(ss, opt)
|
2017-05-25 22:52:27 +00:00
|
|
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
2018-02-28 04:23:59 +00:00
|
|
|
m.TagSets(ss, opt)
|
2017-05-25 22:52:27 +00:00
|
|
|
}
|
2017-05-19 01:05:33 +00:00
|
|
|
}
|
|
|
|
|
2017-05-25 22:52:27 +00:00
|
|
|
func BenchmarkMeasurement_TagSetsNoDimensions_1000(b *testing.B) {
|
2017-08-15 19:24:22 +00:00
|
|
|
benchmarkTagSets(b, 1000, query.IteratorOptions{})
|
2017-05-19 01:05:33 +00:00
|
|
|
}
|
|
|
|
|
2017-05-25 22:52:27 +00:00
|
|
|
func BenchmarkMeasurement_TagSetsDimensions_1000(b *testing.B) {
|
2017-08-15 19:24:22 +00:00
|
|
|
benchmarkTagSets(b, 1000, query.IteratorOptions{Dimensions: []string{"tag1", "tag2"}})
|
2017-05-19 01:05:33 +00:00
|
|
|
}
|
|
|
|
|
2017-05-25 22:52:27 +00:00
|
|
|
func BenchmarkMeasurement_TagSetsNoDimensions_100000(b *testing.B) {
|
2017-08-15 19:24:22 +00:00
|
|
|
benchmarkTagSets(b, 100000, query.IteratorOptions{})
|
2017-05-25 22:52:27 +00:00
|
|
|
}
|
2017-05-19 01:05:33 +00:00
|
|
|
|
2017-05-25 22:52:27 +00:00
|
|
|
func BenchmarkMeasurement_TagSetsDimensions_100000(b *testing.B) {
|
2017-08-15 19:24:22 +00:00
|
|
|
benchmarkTagSets(b, 100000, query.IteratorOptions{Dimensions: []string{"tag1", "tag2"}})
|
2017-05-19 01:05:33 +00:00
|
|
|
}
|