| 
									
										
										
										
											2017-05-26 23:56:31 +08: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 15:13:33 +08:00
										 |  |  | package tsdb | 
					
						
							| 
									
										
										
										
											2017-11-21 19:15:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2018-12-06 00:34:42 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2017-11-21 19:15:02 +08:00
										 |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2018-10-24 05:35:52 +08:00
										 |  |  | 	"math/rand" | 
					
						
							| 
									
										
										
										
											2017-11-21 19:15:02 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2017-11-30 22:34:49 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2017-11-21 19:15:02 +08:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2017-12-07 09:06:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-24 05:35:52 +08:00
										 |  |  | 	"github.com/go-kit/kit/log" | 
					
						
							| 
									
										
										
										
											2017-12-06 00:17:33 +08:00
										 |  |  | 	"github.com/prometheus/tsdb/testutil" | 
					
						
							| 
									
										
										
										
											2019-01-28 19:24:49 +08:00
										 |  |  | 	"github.com/prometheus/tsdb/tsdbutil" | 
					
						
							| 
									
										
										
										
											2017-11-21 19:15:02 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-12 18:40:12 +08: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 19:15:02 +08:00
										 |  |  | func TestSetCompactionFailed(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-02-23 23:04:50 +08:00
										 |  |  | 	tmpdir, err := ioutil.TempDir("", "test") | 
					
						
							| 
									
										
										
										
											2017-12-07 09:06:14 +08:00
										 |  |  | 	testutil.Ok(t, err) | 
					
						
							| 
									
										
										
										
											2018-02-23 23:04:50 +08:00
										 |  |  | 	defer os.RemoveAll(tmpdir) | 
					
						
							| 
									
										
										
										
											2017-11-21 19:15:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-28 19:24:49 +08:00
										 |  |  | 	blockDir := createBlock(t, tmpdir, genSeries(1, 1, 0, 0)) | 
					
						
							| 
									
										
										
										
											2019-01-16 18:03:52 +08:00
										 |  |  | 	b, err := OpenBlock(nil, blockDir, nil) | 
					
						
							| 
									
										
										
										
											2018-12-29 19:20:51 +08:00
										 |  |  | 	testutil.Ok(t, err) | 
					
						
							| 
									
										
										
										
											2017-12-07 09:06:14 +08: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 19:15:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-16 18:03:52 +08:00
										 |  |  | 	b, err = OpenBlock(nil, blockDir, nil) | 
					
						
							| 
									
										
										
										
											2017-12-07 09:06:14 +08:00
										 |  |  | 	testutil.Ok(t, err) | 
					
						
							|  |  |  | 	testutil.Equals(t, true, b.meta.Compaction.Failed) | 
					
						
							| 
									
										
										
										
											2018-12-29 19:20:51 +08:00
										 |  |  | 	testutil.Ok(t, b.Close()) | 
					
						
							| 
									
										
										
										
											2017-11-21 19:15:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-28 19:24:49 +08: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-24 05:35:52 +08:00
										 |  |  | 	head, err := NewHead(nil, nil, nil, 2*60*60*1000) | 
					
						
							|  |  |  | 	testutil.Ok(tb, err) | 
					
						
							|  |  |  | 	defer head.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-28 19:24:49 +08: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-19 00:58:17 +08:00
										 |  |  | 				if err == nil { | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-10-24 05:35:52 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-01-28 19:24:49 +08:00
										 |  |  | 			ref, err = app.Add(s.Labels(), t, v) | 
					
						
							| 
									
										
										
										
											2018-10-24 05:35:52 +08:00
										 |  |  | 			testutil.Ok(tb, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-01-28 19:24:49 +08:00
										 |  |  | 		testutil.Ok(tb, it.Err()) | 
					
						
							| 
									
										
										
										
											2018-10-24 05:35:52 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-01-28 19:24:49 +08:00
										 |  |  | 	err = app.Commit() | 
					
						
							|  |  |  | 	testutil.Ok(tb, err) | 
					
						
							| 
									
										
										
										
											2018-10-24 05:35:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-06 00:34:42 +08:00
										 |  |  | 	compactor, err := NewLeveledCompactor(context.Background(), nil, log.NewNopLogger(), []int64{1000000}, nil) | 
					
						
							| 
									
										
										
										
											2018-10-24 05:35:52 +08: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 15:23:56 +08:00
										 |  |  | 	return filepath.Join(dir, ulid.String()) | 
					
						
							| 
									
										
										
										
											2018-10-24 05:35:52 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-01-28 19:24:49 +08: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 21:29:41 +08:00
										 |  |  | 	series := make([]Series, totalSeries) | 
					
						
							| 
									
										
										
										
											2019-01-28 19:24:49 +08: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 21:29:41 +08: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 19:24:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-14 21:29:41 +08: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 19:24:49 +08: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) | 
					
						
							|  |  |  | } |