2017-05-26 15:56:31 +00:00
|
|
|
// Copyright 2017 The Prometheus Authors
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2017-05-16 07:13:33 +00:00
|
|
|
package tsdb
|
2017-11-21 11:15:02 +00:00
|
|
|
|
|
|
|
import (
|
2018-12-05 16:34:42 +00:00
|
|
|
"context"
|
2017-11-21 11:15:02 +00:00
|
|
|
"io/ioutil"
|
2018-10-23 21:35:52 +00:00
|
|
|
"math/rand"
|
2017-11-21 11:15:02 +00:00
|
|
|
"os"
|
2017-11-30 14:34:49 +00:00
|
|
|
"path/filepath"
|
2017-11-21 11:15:02 +00:00
|
|
|
"testing"
|
2017-12-07 01:06:14 +00:00
|
|
|
|
2018-10-23 21:35:52 +00:00
|
|
|
"github.com/go-kit/kit/log"
|
2017-12-05 16:17:33 +00:00
|
|
|
"github.com/prometheus/tsdb/testutil"
|
2019-01-28 11:24:49 +00:00
|
|
|
"github.com/prometheus/tsdb/tsdbutil"
|
2017-11-21 11:15:02 +00:00
|
|
|
)
|
|
|
|
|
2018-02-12 10:40:12 +00:00
|
|
|
// In Prometheus 2.1.0 we had a bug where the meta.json version was falsely bumped
|
|
|
|
// to 2. We had a migration in place resetting it to 1 but we should move immediately to
|
|
|
|
// version 3 next time to avoid confusion and issues.
|
|
|
|
func TestBlockMetaMustNeverBeVersion2(t *testing.T) {
|
|
|
|
dir, err := ioutil.TempDir("", "metaversion")
|
|
|
|
testutil.Ok(t, err)
|
|
|
|
defer os.RemoveAll(dir)
|
|
|
|
|
|
|
|
testutil.Ok(t, writeMetaFile(dir, &BlockMeta{}))
|
|
|
|
|
|
|
|
meta, err := readMetaFile(dir)
|
|
|
|
testutil.Ok(t, err)
|
|
|
|
testutil.Assert(t, meta.Version != 2, "meta.json version must never be 2")
|
|
|
|
}
|
|
|
|
|
2017-11-21 11:15:02 +00:00
|
|
|
func TestSetCompactionFailed(t *testing.T) {
|
2018-02-23 15:04:50 +00:00
|
|
|
tmpdir, err := ioutil.TempDir("", "test")
|
2017-12-07 01:06:14 +00:00
|
|
|
testutil.Ok(t, err)
|
2018-02-23 15:04:50 +00:00
|
|
|
defer os.RemoveAll(tmpdir)
|
2017-11-21 11:15:02 +00:00
|
|
|
|
2019-01-28 11:24:49 +00:00
|
|
|
blockDir := createBlock(t, tmpdir, genSeries(1, 1, 0, 0))
|
2019-01-16 10:03:52 +00:00
|
|
|
b, err := OpenBlock(nil, blockDir, nil)
|
2018-12-29 11:20:51 +00:00
|
|
|
testutil.Ok(t, err)
|
2017-12-07 01:06:14 +00:00
|
|
|
testutil.Equals(t, false, b.meta.Compaction.Failed)
|
|
|
|
testutil.Ok(t, b.setCompactionFailed())
|
|
|
|
testutil.Equals(t, true, b.meta.Compaction.Failed)
|
|
|
|
testutil.Ok(t, b.Close())
|
2017-11-21 11:15:02 +00:00
|
|
|
|
2019-01-16 10:03:52 +00:00
|
|
|
b, err = OpenBlock(nil, blockDir, nil)
|
2017-12-07 01:06:14 +00:00
|
|
|
testutil.Ok(t, err)
|
|
|
|
testutil.Equals(t, true, b.meta.Compaction.Failed)
|
2018-12-29 11:20:51 +00:00
|
|
|
testutil.Ok(t, b.Close())
|
2017-11-21 11:15:02 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 11:24:49 +00:00
|
|
|
// createBlock creates a block with given set of series and returns its dir.
|
|
|
|
func createBlock(tb testing.TB, dir string, series []Series) string {
|
2018-10-23 21:35:52 +00:00
|
|
|
head, err := NewHead(nil, nil, nil, 2*60*60*1000)
|
|
|
|
testutil.Ok(tb, err)
|
|
|
|
defer head.Close()
|
|
|
|
|
2019-01-28 11:24:49 +00:00
|
|
|
app := head.Appender()
|
|
|
|
for _, s := range series {
|
|
|
|
ref := uint64(0)
|
|
|
|
it := s.Iterator()
|
|
|
|
for it.Next() {
|
|
|
|
t, v := it.At()
|
|
|
|
if ref != 0 {
|
|
|
|
err := app.AddFast(ref, t, v)
|
2019-01-18 16:58:17 +00:00
|
|
|
if err == nil {
|
|
|
|
continue
|
|
|
|
}
|
2018-10-23 21:35:52 +00:00
|
|
|
}
|
2019-01-28 11:24:49 +00:00
|
|
|
ref, err = app.Add(s.Labels(), t, v)
|
2018-10-23 21:35:52 +00:00
|
|
|
testutil.Ok(tb, err)
|
|
|
|
}
|
2019-01-28 11:24:49 +00:00
|
|
|
testutil.Ok(tb, it.Err())
|
2018-10-23 21:35:52 +00:00
|
|
|
}
|
2019-01-28 11:24:49 +00:00
|
|
|
err = app.Commit()
|
|
|
|
testutil.Ok(tb, err)
|
2018-10-23 21:35:52 +00:00
|
|
|
|
2018-12-05 16:34:42 +00:00
|
|
|
compactor, err := NewLeveledCompactor(context.Background(), nil, log.NewNopLogger(), []int64{1000000}, nil)
|
2018-10-23 21:35:52 +00:00
|
|
|
testutil.Ok(tb, err)
|
|
|
|
|
|
|
|
testutil.Ok(tb, os.MkdirAll(dir, 0777))
|
|
|
|
|
|
|
|
ulid, err := compactor.Write(dir, head, head.MinTime(), head.MaxTime(), nil)
|
|
|
|
testutil.Ok(tb, err)
|
2018-12-29 07:23:56 +00:00
|
|
|
return filepath.Join(dir, ulid.String())
|
2018-10-23 21:35:52 +00:00
|
|
|
}
|
2019-01-28 11:24:49 +00:00
|
|
|
|
|
|
|
// genSeries generates series with a given number of labels and values.
|
|
|
|
func genSeries(totalSeries, labelCount int, mint, maxt int64) []Series {
|
|
|
|
if totalSeries == 0 || labelCount == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-02-14 13:29:41 +00:00
|
|
|
series := make([]Series, totalSeries)
|
2019-01-28 11:24:49 +00:00
|
|
|
for i := 0; i < totalSeries; i++ {
|
|
|
|
lbls := make(map[string]string, labelCount)
|
|
|
|
for len(lbls) < labelCount {
|
|
|
|
lbls[randString()] = randString()
|
|
|
|
}
|
|
|
|
samples := make([]tsdbutil.Sample, 0, maxt-mint+1)
|
|
|
|
for t := mint; t <= maxt; t++ {
|
|
|
|
samples = append(samples, sample{t: t, v: rand.Float64()})
|
|
|
|
}
|
|
|
|
series[i] = newSeries(lbls, samples)
|
|
|
|
}
|
2019-02-14 13:29:41 +00:00
|
|
|
return series
|
|
|
|
}
|
|
|
|
|
|
|
|
// populateSeries generates series from given labels, mint and maxt.
|
|
|
|
func populateSeries(lbls []map[string]string, mint, maxt int64) []Series {
|
|
|
|
if len(lbls) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2019-01-28 11:24:49 +00:00
|
|
|
|
2019-02-14 13:29:41 +00:00
|
|
|
series := make([]Series, 0, len(lbls))
|
|
|
|
for _, lbl := range lbls {
|
|
|
|
if len(lbl) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
samples := make([]tsdbutil.Sample, 0, maxt-mint+1)
|
|
|
|
for t := mint; t <= maxt; t++ {
|
|
|
|
samples = append(samples, sample{t: t, v: rand.Float64()})
|
|
|
|
}
|
|
|
|
series = append(series, newSeries(lbl, samples))
|
|
|
|
}
|
2019-01-28 11:24:49 +00:00
|
|
|
return series
|
|
|
|
}
|
|
|
|
|
|
|
|
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
const (
|
|
|
|
letterIdxBits = 6 // 6 bits to represent a letter index
|
|
|
|
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
|
|
|
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
|
|
|
)
|
|
|
|
|
|
|
|
// randString generates random string.
|
|
|
|
func randString() string {
|
|
|
|
maxLength := int32(50)
|
|
|
|
length := rand.Int31n(maxLength)
|
|
|
|
b := make([]byte, length+1)
|
|
|
|
// A rand.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
|
|
|
for i, cache, remain := length, rand.Int63(), letterIdxMax; i >= 0; {
|
|
|
|
if remain == 0 {
|
|
|
|
cache, remain = rand.Int63(), letterIdxMax
|
|
|
|
}
|
|
|
|
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
|
|
|
b[i] = letterBytes[idx]
|
|
|
|
i--
|
|
|
|
}
|
|
|
|
cache >>= letterIdxBits
|
|
|
|
remain--
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(b)
|
|
|
|
}
|