202 lines
5.5 KiB
Go
202 lines
5.5 KiB
Go
package tsdb
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestShardWriteAndIndex(t *testing.T) {
|
|
tmpDir, _ := ioutil.TempDir("", "shard_test")
|
|
defer os.RemoveAll(tmpDir)
|
|
tmpShard := path.Join(tmpDir, "shard")
|
|
|
|
index := NewDatabaseIndex()
|
|
sh := NewShard(index, tmpShard)
|
|
if err := sh.Open(); err != nil {
|
|
t.Fatalf("error openeing shard: %s", err.Error())
|
|
}
|
|
|
|
pt := NewPoint(
|
|
"cpu",
|
|
map[string]string{"host": "server"},
|
|
map[string]interface{}{"value": 1.0},
|
|
time.Unix(1, 2),
|
|
)
|
|
|
|
err := sh.WritePoints([]Point{pt})
|
|
if err != nil {
|
|
t.Fatalf(err.Error())
|
|
}
|
|
|
|
pt.SetTime(time.Unix(2, 3))
|
|
err = sh.WritePoints([]Point{pt})
|
|
if err != nil {
|
|
t.Fatalf(err.Error())
|
|
}
|
|
|
|
validateIndex := func() {
|
|
if !reflect.DeepEqual(index.names, []string{"cpu"}) {
|
|
t.Fatalf("measurement names in shard didn't match")
|
|
}
|
|
if len(index.series) != 1 {
|
|
t.Fatalf("series wasn't in index")
|
|
}
|
|
seriesTags := index.series[string(pt.Key())].Tags
|
|
if len(seriesTags) != len(pt.Tags()) || pt.Tags()["host"] != seriesTags["host"] {
|
|
t.Fatalf("tags weren't properly saved to series index: %v, %v", pt.Tags(), index.series[string(pt.Key())].Tags)
|
|
}
|
|
if !reflect.DeepEqual(index.measurements["cpu"].TagKeys(), []string{"host"}) {
|
|
t.Fatalf("tag key wasn't saved to measurement index")
|
|
}
|
|
}
|
|
|
|
validateIndex()
|
|
|
|
// ensure the index gets loaded after closing and opening the shard
|
|
sh.Close()
|
|
|
|
index = NewDatabaseIndex()
|
|
sh = NewShard(index, tmpShard)
|
|
if err := sh.Open(); err != nil {
|
|
t.Fatalf("error openeing shard: %s", err.Error())
|
|
}
|
|
|
|
validateIndex()
|
|
|
|
// and ensure that we can still write data
|
|
pt.SetTime(time.Unix(2, 6))
|
|
err = sh.WritePoints([]Point{pt})
|
|
if err != nil {
|
|
t.Fatalf(err.Error())
|
|
}
|
|
}
|
|
|
|
func BenchmarkWritePoints_NewSeries_1K(b *testing.B) { benchmarkWritePoints(b, 38, 3, 3, 1) }
|
|
func BenchmarkWritePoints_NewSeries_100K(b *testing.B) { benchmarkWritePoints(b, 32, 5, 5, 1) }
|
|
func BenchmarkWritePoints_NewSeries_250K(b *testing.B) { benchmarkWritePoints(b, 80, 5, 5, 1) }
|
|
func BenchmarkWritePoints_NewSeries_500K(b *testing.B) { benchmarkWritePoints(b, 160, 5, 5, 1) }
|
|
func BenchmarkWritePoints_NewSeries_1M(b *testing.B) { benchmarkWritePoints(b, 320, 5, 5, 1) }
|
|
|
|
func BenchmarkWritePoints_ExistingSeries_1K(b *testing.B) {
|
|
benchmarkWritePointsExistingSeries(b, 38, 3, 3, 1)
|
|
}
|
|
func BenchmarkWritePoints_ExistingSeries_100K(b *testing.B) {
|
|
benchmarkWritePointsExistingSeries(b, 32, 5, 5, 1)
|
|
}
|
|
func BenchmarkWritePoints_ExistingSeries_250K(b *testing.B) {
|
|
benchmarkWritePointsExistingSeries(b, 80, 5, 5, 1)
|
|
}
|
|
func BenchmarkWritePoints_ExistingSeries_500K(b *testing.B) {
|
|
benchmarkWritePointsExistingSeries(b, 160, 5, 5, 1)
|
|
}
|
|
func BenchmarkWritePoints_ExistingSeries_1M(b *testing.B) {
|
|
benchmarkWritePointsExistingSeries(b, 320, 5, 5, 1)
|
|
}
|
|
|
|
// benchmarkWritePoints benchmarks writing new series to a shard.
|
|
// mCnt - measurmeent count
|
|
// tkCnt - tag key count
|
|
// tvCnt - tag value count (values per tag)
|
|
// pntCnt - points per series. # of series = mCnt * (tvCnt ^ tkCnt)
|
|
func benchmarkWritePoints(b *testing.B, mCnt, tkCnt, tvCnt, pntCnt int) {
|
|
// Generate test series (measurements + unique tag sets).
|
|
series := genTestSeries(mCnt, tkCnt, tvCnt)
|
|
// Create index for the shard to use.
|
|
index := NewDatabaseIndex()
|
|
// Generate point data to write to the shard.
|
|
points := []Point{}
|
|
for _, s := range series {
|
|
for val := 0.0; val < float64(pntCnt); val++ {
|
|
p := NewPoint(s.Measurement, s.Series.Tags, map[string]interface{}{"value": val}, time.Now())
|
|
points = append(points, p)
|
|
}
|
|
}
|
|
|
|
// Stop & reset timers and mem-stats before the main benchmark loop.
|
|
b.StopTimer()
|
|
b.ResetTimer()
|
|
|
|
// Run the benchmark loop.
|
|
for n := 0; n < b.N; n++ {
|
|
tmpDir, _ := ioutil.TempDir("", "shard_test")
|
|
tmpShard := path.Join(tmpDir, "shard")
|
|
shard := NewShard(index, tmpShard)
|
|
shard.Open()
|
|
|
|
b.StartTimer()
|
|
// Call the function being benchmarked.
|
|
chunkedWrite(shard, points)
|
|
|
|
b.StopTimer()
|
|
shard.Close()
|
|
os.RemoveAll(tmpDir)
|
|
}
|
|
}
|
|
|
|
// benchmarkWritePointsExistingSeries benchmarks writing to existing series in a shard.
|
|
// mCnt - measurmeent count
|
|
// tkCnt - tag key count
|
|
// tvCnt - tag value count (values per tag)
|
|
// pntCnt - points per series. # of series = mCnt * (tvCnt ^ tkCnt)
|
|
func benchmarkWritePointsExistingSeries(b *testing.B, mCnt, tkCnt, tvCnt, pntCnt int) {
|
|
// Generate test series (measurements + unique tag sets).
|
|
series := genTestSeries(mCnt, tkCnt, tvCnt)
|
|
// Create index for the shard to use.
|
|
index := NewDatabaseIndex()
|
|
// Generate point data to write to the shard.
|
|
points := []Point{}
|
|
for _, s := range series {
|
|
for val := 0.0; val < float64(pntCnt); val++ {
|
|
p := NewPoint(s.Measurement, s.Series.Tags, map[string]interface{}{"value": val}, time.Now())
|
|
points = append(points, p)
|
|
}
|
|
}
|
|
|
|
tmpDir, _ := ioutil.TempDir("", "")
|
|
defer os.RemoveAll(tmpDir)
|
|
tmpShard := path.Join(tmpDir, "shard")
|
|
shard := NewShard(index, tmpShard)
|
|
shard.Open()
|
|
defer shard.Close()
|
|
chunkedWrite(shard, points)
|
|
|
|
// Reset timers and mem-stats before the main benchmark loop.
|
|
b.ResetTimer()
|
|
|
|
// Run the benchmark loop.
|
|
for n := 0; n < b.N; n++ {
|
|
b.StopTimer()
|
|
for _, p := range points {
|
|
p.SetTime(p.Time().Add(time.Second))
|
|
}
|
|
|
|
b.StartTimer()
|
|
// Call the function being benchmarked.
|
|
chunkedWrite(shard, points)
|
|
}
|
|
}
|
|
|
|
func chunkedWrite(shard *Shard, points []Point) {
|
|
nPts := len(points)
|
|
chunkSz := 10000
|
|
start := 0
|
|
end := chunkSz
|
|
|
|
for {
|
|
if end > nPts {
|
|
end = nPts
|
|
}
|
|
if end-start == 0 {
|
|
break
|
|
}
|
|
|
|
shard.WritePoints(points[start:end])
|
|
start = end
|
|
end += chunkSz
|
|
}
|
|
}
|