167 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
| // 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.
 | |
| 
 | |
| package tsdb
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"io/ioutil"
 | |
| 	"math/rand"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/go-kit/kit/log"
 | |
| 	"github.com/prometheus/tsdb/testutil"
 | |
| 	"github.com/prometheus/tsdb/tsdbutil"
 | |
| )
 | |
| 
 | |
| // 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")
 | |
| }
 | |
| 
 | |
| func TestSetCompactionFailed(t *testing.T) {
 | |
| 	tmpdir, err := ioutil.TempDir("", "test")
 | |
| 	testutil.Ok(t, err)
 | |
| 	defer os.RemoveAll(tmpdir)
 | |
| 
 | |
| 	blockDir := createBlock(t, tmpdir, genSeries(1, 1, 0, 0))
 | |
| 	b, err := OpenBlock(nil, blockDir, nil)
 | |
| 	testutil.Ok(t, err)
 | |
| 	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())
 | |
| 
 | |
| 	b, err = OpenBlock(nil, blockDir, nil)
 | |
| 	testutil.Ok(t, err)
 | |
| 	testutil.Equals(t, true, b.meta.Compaction.Failed)
 | |
| 	testutil.Ok(t, b.Close())
 | |
| }
 | |
| 
 | |
| // createBlock creates a block with given set of series and returns its dir.
 | |
| func createBlock(tb testing.TB, dir string, series []Series) string {
 | |
| 	head, err := NewHead(nil, nil, nil, 2*60*60*1000)
 | |
| 	testutil.Ok(tb, err)
 | |
| 	defer head.Close()
 | |
| 
 | |
| 	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)
 | |
| 				if err == nil {
 | |
| 					continue
 | |
| 				}
 | |
| 			}
 | |
| 			ref, err = app.Add(s.Labels(), t, v)
 | |
| 			testutil.Ok(tb, err)
 | |
| 		}
 | |
| 		testutil.Ok(tb, it.Err())
 | |
| 	}
 | |
| 	err = app.Commit()
 | |
| 	testutil.Ok(tb, err)
 | |
| 
 | |
| 	compactor, err := NewLeveledCompactor(context.Background(), nil, log.NewNopLogger(), []int64{1000000}, nil)
 | |
| 	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)
 | |
| 	return filepath.Join(dir, ulid.String())
 | |
| }
 | |
| 
 | |
| // 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
 | |
| 	}
 | |
| 
 | |
| 	series := make([]Series, totalSeries)
 | |
| 	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)
 | |
| 	}
 | |
| 	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
 | |
| 	}
 | |
| 
 | |
| 	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))
 | |
| 	}
 | |
| 	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)
 | |
| }
 |