Beispiel #1
0
func TestWALWriter_WritePoints_Single(t *testing.T) {
	dir := MustTempDir()
	defer os.RemoveAll(dir)
	f := MustTempFile(dir)
	w := tsm1.NewWALSegmentWriter(f)

	p1 := tsm1.NewValue(time.Unix(1, 0), 1.1)
	p2 := tsm1.NewValue(time.Unix(1, 0), int64(1))
	p3 := tsm1.NewValue(time.Unix(1, 0), true)
	p4 := tsm1.NewValue(time.Unix(1, 0), "string")

	values := map[string][]tsm1.Value{
		"cpu,host=A#!~#float":  []tsm1.Value{p1},
		"cpu,host=A#!~#int":    []tsm1.Value{p2},
		"cpu,host=A#!~#bool":   []tsm1.Value{p3},
		"cpu,host=A#!~#string": []tsm1.Value{p4},
	}

	entry := &tsm1.WriteWALEntry{
		Values: values,
	}

	if err := w.Write(mustMarshalEntry(entry)); err != nil {
		fatal(t, "write points", err)
	}

	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		fatal(t, "seek", err)
	}

	r := tsm1.NewWALSegmentReader(f)

	if !r.Next() {
		t.Fatalf("expected next, got false")
	}

	we, err := r.Read()
	if err != nil {
		fatal(t, "read entry", err)
	}

	e, ok := we.(*tsm1.WriteWALEntry)
	if !ok {
		t.Fatalf("expected WriteWALEntry: got %#v", e)
	}

	for k, v := range e.Values {
		for i, vv := range v {
			if got, exp := vv.String(), values[k][i].String(); got != exp {
				t.Fatalf("points mismatch: got %v, exp %v", got, exp)
			}
		}
	}

	if n := r.Count(); n != MustReadFileSize(f) {
		t.Fatalf("wrong count of bytes read, got %d, exp %d", n, MustReadFileSize(f))
	}
}
Beispiel #2
0
func TestWALWriter_WritePoints_Multiple(t *testing.T) {
	dir := MustTempDir()
	defer os.RemoveAll(dir)
	f := MustTempFile(dir)
	w := tsm1.NewWALSegmentWriter(f)

	p1 := parsePoint("cpu,host=A value=1.1 1000000000")
	p2 := parsePoint("cpu,host=B value=1.1 1000000000")

	exp := [][]models.Point{
		[]models.Point{
			p1,
		},
		[]models.Point{
			p2,
		},
	}

	for _, e := range exp {
		entry := &tsm1.WriteWALEntry{
			Points: e,
		}

		if err := w.Write(entry); err != nil {
			fatal(t, "write points", err)
		}
	}

	// Seek back to the beinning of the file for reading
	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		fatal(t, "seek", err)
	}

	r := tsm1.NewWALSegmentReader(f)

	for _, ep := range exp {
		if !r.Next() {
			t.Fatalf("expected next, got false")
		}

		we, err := r.Read()
		if err != nil {
			fatal(t, "read entry", err)
		}

		e, ok := we.(*tsm1.WriteWALEntry)
		if !ok {
			t.Fatalf("expected WriteWALEntry: got %#v", e)
		}

		points := e.Points
		for i, p := range ep {
			if exp, got := points[i].String(), p.String(); exp != got {
				t.Fatalf("points mismatch: got %v, exp %v", got, exp)
			}
		}
	}
}
Beispiel #3
0
func TestWALWriter_WritePoints_LargeBatch(t *testing.T) {
	dir := MustTempDir()
	defer os.RemoveAll(dir)
	f := MustTempFile(dir)
	w := tsm1.NewWALSegmentWriter(f)

	var points []tsm1.Value
	for i := 0; i < 100000; i++ {
		points = append(points, tsm1.NewValue(time.Unix(int64(i), 0), int64(1)))
	}

	values := map[string][]tsm1.Value{
		"cpu,host=A,server=01,foo=bar,tag=really-long#!~#float": points,
		"mem,host=A,server=01,foo=bar,tag=really-long#!~#float": points,
	}

	entry := &tsm1.WriteWALEntry{
		Values: values,
	}

	if err := w.Write(mustMarshalEntry(entry)); err != nil {
		fatal(t, "write points", err)
	}

	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		fatal(t, "seek", err)
	}

	r := tsm1.NewWALSegmentReader(f)

	if !r.Next() {
		t.Fatalf("expected next, got false")
	}

	we, err := r.Read()
	if err != nil {
		fatal(t, "read entry", err)
	}

	e, ok := we.(*tsm1.WriteWALEntry)
	if !ok {
		t.Fatalf("expected WriteWALEntry: got %#v", e)
	}

	for k, v := range e.Values {
		for i, vv := range v {
			if got, exp := vv.String(), values[k][i].String(); got != exp {
				t.Fatalf("points mismatch: got %v, exp %v", got, exp)
			}
		}
	}

	if n := r.Count(); n != MustReadFileSize(f) {
		t.Fatalf("wrong count of bytes read, got %d, exp %d", n, MustReadFileSize(f))
	}
}
Beispiel #4
0
func TestWALWriter_Corrupt(t *testing.T) {
	dir := MustTempDir()
	defer os.RemoveAll(dir)
	f := MustTempFile(dir)
	w := tsm1.NewWALSegmentWriter(f)
	corruption := []byte{1, 4, 0, 0, 0}

	p1 := tsm1.NewValue(time.Unix(1, 0), 1.1)
	values := map[string][]tsm1.Value{
		"cpu,host=A#!~#float": []tsm1.Value{p1},
	}

	entry := &tsm1.WriteWALEntry{
		Values: values,
	}
	if err := w.Write(mustMarshalEntry(entry)); err != nil {
		fatal(t, "write points", err)
	}

	// Write some random bytes to the file to simulate corruption.
	if _, err := f.Write(corruption); err != nil {
		fatal(t, "corrupt WAL segment", err)
	}

	// Create the WAL segment reader.
	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		fatal(t, "seek", err)
	}
	r := tsm1.NewWALSegmentReader(f)

	// Try to decode two entries.

	if !r.Next() {
		t.Fatalf("expected next, got false")
	}
	if _, err := r.Read(); err != nil {
		fatal(t, "read entry", err)
	}

	if !r.Next() {
		t.Fatalf("expected next, got false")
	}
	if _, err := r.Read(); err == nil {
		fatal(t, "read entry did not return err", nil)
	}

	// Count should only return size of valid data.
	expCount := MustReadFileSize(f) - int64(len(corruption))
	if n := r.Count(); n != expCount {
		t.Fatalf("wrong count of bytes read, got %d, exp %d", n, expCount)
	}
}
Beispiel #5
0
func MustWALSegment(dir string, entries []tsm1.WALEntry) *tsm1.WALSegmentReader {
	f := MustTempFile(dir)
	w := tsm1.NewWALSegmentWriter(f)

	for _, e := range entries {
		if err := w.Write(mustMarshalEntry(e)); err != nil {
			panic(fmt.Sprintf("write WAL entry: %v", err))
		}
	}

	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		panic(fmt.Sprintf("seek WAL: %v", err))
	}

	return tsm1.NewWALSegmentReader(f)
}
Beispiel #6
0
func TestWALWriter_WritePoints_Single(t *testing.T) {
	dir := MustTempDir()
	defer os.RemoveAll(dir)
	f := MustTempFile(dir)
	w := tsm1.NewWALSegmentWriter(f)

	p1 := parsePoint("cpu,host=A value=1.1 1000000000")

	points := []models.Point{
		p1,
	}

	entry := &tsm1.WriteWALEntry{
		Points: points,
	}

	if err := w.Write(entry); err != nil {
		fatal(t, "write points", err)
	}

	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		fatal(t, "seek", err)
	}

	r := tsm1.NewWALSegmentReader(f)

	if !r.Next() {
		t.Fatalf("expected next, got false")
	}

	we, err := r.Read()
	if err != nil {
		fatal(t, "read entry", err)
	}

	e, ok := we.(*tsm1.WriteWALEntry)
	if !ok {
		t.Fatalf("expected WriteWALEntry: got %#v", e)
	}

	for i, p := range e.Points {
		if exp, got := points[i].String(), p.String(); exp != got {
			t.Fatalf("points mismatch: got %v, exp %v", got, exp)
		}
	}
}
Beispiel #7
0
func TestWALWriter_WriteDelete_Single(t *testing.T) {
	dir := MustTempDir()
	defer os.RemoveAll(dir)
	f := MustTempFile(dir)
	w := tsm1.NewWALSegmentWriter(f)

	entry := &tsm1.DeleteWALEntry{
		Keys: []string{"cpu"},
	}

	if err := w.Write(entry); err != nil {
		fatal(t, "write points", err)
	}

	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		fatal(t, "seek", err)
	}

	r := tsm1.NewWALSegmentReader(f)

	if !r.Next() {
		t.Fatalf("expected next, got false")
	}

	we, err := r.Read()
	if err != nil {
		fatal(t, "read entry", err)
	}

	e, ok := we.(*tsm1.DeleteWALEntry)
	if !ok {
		t.Fatalf("expected WriteWALEntry: got %#v", e)
	}

	if got, exp := len(e.Keys), len(entry.Keys); got != exp {
		t.Fatalf("key length mismatch: got %v, exp %v", got, exp)
	}

	if got, exp := e.Keys[0], entry.Keys[0]; got != exp {
		t.Fatalf("key mismatch: got %v, exp %v", got, exp)
	}
}
Beispiel #8
0
func BenchmarkWALSegmentReader(b *testing.B) {
	points := map[string][]tsm1.Value{}
	for i := 0; i < 5000; i++ {
		k := "cpu,host=A#!~#value"
		points[k] = append(points[k], tsm1.NewValue(time.Unix(int64(i), 0), 1.1))
	}

	dir := MustTempDir()
	defer os.RemoveAll(dir)

	f := MustTempFile(dir)
	w := tsm1.NewWALSegmentWriter(f)

	write := &tsm1.WriteWALEntry{
		Values: points,
	}

	for i := 0; i < 100; i++ {
		if err := w.Write(write); err != nil {
			b.Fatalf("unexpected error writing entry: %v", err)
		}
	}

	r := tsm1.NewWALSegmentReader(f)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		f.Seek(0, os.SEEK_SET)
		b.StartTimer()

		for r.Next() {
			_, err := r.Read()
			if err != nil {
				b.Fatalf("unexpected error reading entry: %v", err)
			}
		}
	}
}
Beispiel #9
0
func BenchmarkWALSegmentReader(b *testing.B) {
	points := make([]models.Point, 5000)
	for i := range points {
		points[i] = parsePoint(fmt.Sprintf("cpu,host=host-%d value=1.1 1000000000", i))
	}

	dir := MustTempDir()
	defer os.RemoveAll(dir)

	f := MustTempFile(dir)
	w := tsm1.NewWALSegmentWriter(f)

	write := &tsm1.WriteWALEntry{
		Points: points,
	}

	for i := 0; i < 100; i++ {
		if err := w.Write(write); err != nil {
			b.Fatalf("unexpected error writing entry: %v", err)
		}
	}

	r := tsm1.NewWALSegmentReader(f)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		f.Seek(0, os.SEEK_SET)
		b.StartTimer()

		for r.Next() {
			_, err := r.Read()
			if err != nil {
				b.Fatalf("unexpected error reading entry: %v", err)
			}
		}
	}
}
Beispiel #10
0
func BenchmarkWALSegmentWriter(b *testing.B) {
	points := map[string][]tsm1.Value{}
	for i := 0; i < 5000; i++ {
		k := "cpu,host=A#!~#value"
		points[k] = append(points[k], tsm1.NewValue(time.Unix(int64(i), 0), 1.1))
	}

	dir := MustTempDir()
	defer os.RemoveAll(dir)

	f := MustTempFile(dir)
	w := tsm1.NewWALSegmentWriter(f)

	write := &tsm1.WriteWALEntry{
		Values: points,
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if err := w.Write(mustMarshalEntry(write)); err != nil {
			b.Fatalf("unexpected error writing entry: %v", err)
		}
	}
}
Beispiel #11
0
func TestWALWriter_WritePoints_Multiple(t *testing.T) {
	dir := MustTempDir()
	defer os.RemoveAll(dir)
	f := MustTempFile(dir)
	w := tsm1.NewWALSegmentWriter(f)

	p1 := tsm1.NewValue(time.Unix(1, 0), int64(1))
	p2 := tsm1.NewValue(time.Unix(1, 0), int64(2))

	exp := []struct {
		key    string
		values []tsm1.Value
	}{
		{"cpu,host=A#!~#value", []tsm1.Value{p1}},
		{"cpu,host=B#!~#value", []tsm1.Value{p2}},
	}

	for _, v := range exp {
		entry := &tsm1.WriteWALEntry{
			Values: map[string][]tsm1.Value{v.key: v.values},
		}

		if err := w.Write(entry); err != nil {
			fatal(t, "write points", err)
		}
	}

	// Seek back to the beinning of the file for reading
	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		fatal(t, "seek", err)
	}

	r := tsm1.NewWALSegmentReader(f)

	for _, ep := range exp {
		if !r.Next() {
			t.Fatalf("expected next, got false")
		}

		we, err := r.Read()
		if err != nil {
			fatal(t, "read entry", err)
		}

		e, ok := we.(*tsm1.WriteWALEntry)
		if !ok {
			t.Fatalf("expected WriteWALEntry: got %#v", e)
		}

		for k, v := range e.Values {
			if got, exp := k, ep.key; got != exp {
				t.Fatalf("key mismatch. got %v, exp %v", got, exp)
			}

			if got, exp := len(v), len(ep.values); got != exp {
				t.Fatalf("values length mismatch: got %v, exp %v", got, exp)
			}

			for i, vv := range v {
				if got, exp := vv.String(), ep.values[i].String(); got != exp {
					t.Fatalf("points mismatch: got %v, exp %v", got, exp)
				}
			}
		}
	}
}
Beispiel #12
0
func TestWALWriter_WritePointsDelete_Multiple(t *testing.T) {
	dir := MustTempDir()
	defer os.RemoveAll(dir)
	f := MustTempFile(dir)
	w := tsm1.NewWALSegmentWriter(f)

	p1 := tsm1.NewValue(time.Unix(1, 0), true)
	values := map[string][]tsm1.Value{
		"cpu,host=A#!~#value": []tsm1.Value{p1},
	}

	writeEntry := &tsm1.WriteWALEntry{
		Values: values,
	}

	if err := w.Write(writeEntry); err != nil {
		fatal(t, "write points", err)
	}

	// Write the delete entry
	deleteEntry := &tsm1.DeleteWALEntry{
		Keys: []string{"cpu,host=A#!~value"},
	}

	if err := w.Write(deleteEntry); err != nil {
		fatal(t, "write points", err)
	}

	// Seek back to the beinning of the file for reading
	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		fatal(t, "seek", err)
	}

	r := tsm1.NewWALSegmentReader(f)

	// Read the write points first
	if !r.Next() {
		t.Fatalf("expected next, got false")
	}

	we, err := r.Read()
	if err != nil {
		fatal(t, "read entry", err)
	}

	e, ok := we.(*tsm1.WriteWALEntry)
	if !ok {
		t.Fatalf("expected WriteWALEntry: got %#v", e)
	}

	for k, v := range e.Values {
		if got, exp := len(v), len(values[k]); got != exp {
			t.Fatalf("values length mismatch: got %v, exp %v", got, exp)
		}

		for i, vv := range v {
			if got, exp := vv.String(), values[k][i].String(); got != exp {
				t.Fatalf("points mismatch: got %v, exp %v", got, exp)
			}
		}
	}

	// Read the delete second
	if !r.Next() {
		t.Fatalf("expected next, got false")
	}

	we, err = r.Read()
	if err != nil {
		fatal(t, "read entry", err)
	}

	de, ok := we.(*tsm1.DeleteWALEntry)
	if !ok {
		t.Fatalf("expected DeleteWALEntry: got %#v", e)
	}

	if got, exp := len(de.Keys), len(deleteEntry.Keys); got != exp {
		t.Fatalf("key length mismatch: got %v, exp %v", got, exp)
	}

	if got, exp := de.Keys[0], deleteEntry.Keys[0]; got != exp {
		t.Fatalf("key mismatch: got %v, exp %v", got, exp)
	}
}
Beispiel #13
0
func TestWALWriter_WritePointsDelete_Multiple(t *testing.T) {
	dir := MustTempDir()
	defer os.RemoveAll(dir)
	f := MustTempFile(dir)
	w := tsm1.NewWALSegmentWriter(f)

	p1 := parsePoint("cpu,host=A value=1.1 1000000000")

	write := &tsm1.WriteWALEntry{
		Points: []models.Point{p1},
	}

	if err := w.Write(write); err != nil {
		fatal(t, "write points", err)
	}

	// Write the delete entry
	deleteEntry := &tsm1.DeleteWALEntry{
		Keys: []string{"cpu"},
	}

	if err := w.Write(deleteEntry); err != nil {
		fatal(t, "write points", err)
	}

	// Seek back to the beinning of the file for reading
	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		fatal(t, "seek", err)
	}

	r := tsm1.NewWALSegmentReader(f)

	// Read the write points first
	if !r.Next() {
		t.Fatalf("expected next, got false")
	}

	we, err := r.Read()
	if err != nil {
		fatal(t, "read entry", err)
	}

	e, ok := we.(*tsm1.WriteWALEntry)
	if !ok {
		t.Fatalf("expected WriteWALEntry: got %#v", e)
	}

	points := e.Points
	for i, p := range write.Points {
		if exp, got := points[i].String(), p.String(); exp != got {
			t.Fatalf("points mismatch: got %v, exp %v", got, exp)
		}
	}

	// Read the delete second
	if !r.Next() {
		t.Fatalf("expected next, got false")
	}

	we, err = r.Read()
	if err != nil {
		fatal(t, "read entry", err)
	}

	de, ok := we.(*tsm1.DeleteWALEntry)
	if !ok {
		t.Fatalf("expected DeleteWALEntry: got %#v", e)
	}

	if got, exp := len(de.Keys), len(deleteEntry.Keys); got != exp {
		t.Fatalf("key length mismatch: got %v, exp %v", got, exp)
	}

	if got, exp := de.Keys[0], deleteEntry.Keys[0]; got != exp {
		t.Fatalf("key mismatch: got %v, exp %v", got, exp)
	}
}
Beispiel #14
0
// // Tests compacting a multiple wal segment into one tsm file
func TestCompactor_MultipleWALSegment(t *testing.T) {
	dir := MustTempDir()
	defer os.RemoveAll(dir)

	// First WAL segment
	v1 := tsm1.NewValue(time.Unix(1, 0), float64(1))
	v2 := tsm1.NewValue(time.Unix(1, 0), float64(1))
	v3 := tsm1.NewValue(time.Unix(2, 0), float64(2))

	points1 := map[string][]tsm1.Value{
		"cpu,host=A#!~#value": []tsm1.Value{v1, v3},
		"cpu,host=B#!~#value": []tsm1.Value{v2},
	}

	entries := []tsm1.WALEntry{
		&tsm1.WriteWALEntry{
			Values: points1,
		},
	}

	f1 := MustTempFile(dir)
	defer f1.Close()

	w := tsm1.NewWALSegmentWriter(f1)
	for _, e := range entries {
		if err := w.Write(e); err != nil {
			t.Fatalf("unexpected error writing entry: %v", err)
		}
	}
	if err := w.Close(); err != nil {
		t.Fatalf("unexpected error closing writer: %v", err)
	}

	// Second WAL segment
	v4 := tsm1.NewValue(time.Unix(2, 0), float64(2))
	v5 := tsm1.NewValue(time.Unix(3, 0), float64(1))
	v6 := tsm1.NewValue(time.Unix(4, 0), float64(1))

	points2 := map[string][]tsm1.Value{
		"cpu,host=A#!~#value": []tsm1.Value{v5, v6},
		"cpu,host=B#!~#value": []tsm1.Value{v4},
	}

	entries = []tsm1.WALEntry{
		&tsm1.WriteWALEntry{
			Values: points2,
		},
	}

	f2 := MustTempFile(dir)
	defer f2.Close()

	w = tsm1.NewWALSegmentWriter(f2)
	for _, e := range entries {
		if err := w.Write(e); err != nil {
			t.Fatalf("unexpected error writing entry: %v", err)
		}
	}
	if err := w.Close(); err != nil {
		t.Fatalf("unexpected error closing writer: %v", err)
	}

	compactor := &tsm1.Compactor{
		Dir: dir,
	}

	files, err := compactor.Compact([]string{f1.Name(), f2.Name()})
	if err != nil {
		t.Fatalf("unexpected error compacting: %v", err)
	}

	if got, exp := len(files), 1; got != exp {
		t.Fatalf("files length mismatch: got %v, exp %v", got, exp)
	}

	f, err := os.Open(files[0])
	if err != nil {
		t.Fatalf("unexpected error openting tsm: %v", err)
	}
	defer f.Close()

	r, err := tsm1.NewTSMReader(f)
	if err != nil {
		t.Fatalf("unexpected error creating tsm reader: %v", err)
	}
	defer r.Close()

	keys := r.Keys()
	if got, exp := len(keys), 2; got != exp {
		t.Fatalf("keys length mismatch: got %v, exp %v", got, exp)
	}

	var data = []struct {
		key    string
		points []tsm1.Value
	}{
		{"cpu,host=A#!~#value", []tsm1.Value{v1, v3, v5, v6}},
		{"cpu,host=B#!~#value", []tsm1.Value{v2, v4}},
	}

	for _, p := range data {
		values, err := r.ReadAll(p.key)
		if err != nil {
			t.Fatalf("unexpected error reading: %v", err)
		}

		if got, exp := len(values), len(p.points); got != exp {
			t.Fatalf("values length mismatch: got %v, exp %v", got, exp)
		}

		for i, point := range p.points {
			assertValueEqual(t, values[i], point)
		}
	}
}