|
|
|
|
@ -22,6 +22,7 @@ import ( |
|
|
|
|
"path/filepath" |
|
|
|
|
"sort" |
|
|
|
|
"strconv" |
|
|
|
|
"sync" |
|
|
|
|
"testing" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
@ -2194,6 +2195,71 @@ func TestPostingsForMatchers(t *testing.T) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TestQuerierIndexQueriesRace tests the index queries with racing appends.
|
|
|
|
|
func TestQuerierIndexQueriesRace(t *testing.T) { |
|
|
|
|
const testRepeats = 1000 |
|
|
|
|
|
|
|
|
|
testCases := []struct { |
|
|
|
|
matchers []*labels.Matcher |
|
|
|
|
}{ |
|
|
|
|
{ |
|
|
|
|
matchers: []*labels.Matcher{ |
|
|
|
|
// This matcher should involve the AllPostings posting list in calculating the posting lists.
|
|
|
|
|
labels.MustNewMatcher(labels.MatchNotEqual, labels.MetricName, "metric"), |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
matchers: []*labels.Matcher{ |
|
|
|
|
// The first matcher should be effectively the same as AllPostings, because all series have always_0=0
|
|
|
|
|
// If it is evaluated first, then __name__=metric will contain more series than always_0=0.
|
|
|
|
|
labels.MustNewMatcher(labels.MatchNotEqual, "always_0", "0"), |
|
|
|
|
labels.MustNewMatcher(labels.MatchEqual, labels.MetricName, "metric"), |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for _, c := range testCases { |
|
|
|
|
c := c |
|
|
|
|
t.Run(fmt.Sprintf("%v", c.matchers), func(t *testing.T) { |
|
|
|
|
db := openTestDB(t, DefaultOptions(), nil) |
|
|
|
|
h := db.Head() |
|
|
|
|
t.Cleanup(func() { |
|
|
|
|
require.NoError(t, db.Close()) |
|
|
|
|
}) |
|
|
|
|
ctx, cancel := context.WithCancel(context.Background()) |
|
|
|
|
wg := &sync.WaitGroup{} |
|
|
|
|
wg.Add(1) |
|
|
|
|
go appendSeries(t, ctx, wg, h) |
|
|
|
|
t.Cleanup(wg.Wait) |
|
|
|
|
t.Cleanup(cancel) |
|
|
|
|
|
|
|
|
|
for i := 0; i < testRepeats; i++ { |
|
|
|
|
q, err := db.Querier(ctx, math.MinInt64, math.MaxInt64) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
values, _, err := q.LabelValues("seq", c.matchers...) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
require.Emptyf(t, values, `label values for label "seq" should be empty`) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func appendSeries(t *testing.T, ctx context.Context, wg *sync.WaitGroup, h *Head) { |
|
|
|
|
defer wg.Done() |
|
|
|
|
|
|
|
|
|
for i := 0; ctx.Err() != nil; i++ { |
|
|
|
|
app := h.Appender(context.Background()) |
|
|
|
|
_, err := app.Append(0, labels.FromStrings(labels.MetricName, "metric", "seq", strconv.Itoa(i), "always_0", "0"), 0, 0) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
err = app.Commit() |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
// Throttle down the appends to keep the test somewhat nimble.
|
|
|
|
|
time.Sleep(time.Millisecond) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TestClose ensures that calling Close more than once doesn't block and doesn't panic.
|
|
|
|
|
func TestClose(t *testing.T) { |
|
|
|
|
dir := t.TempDir() |
|
|
|
|
|