// Tests that a single TSM file can be read and iterated over func TestTSMKeyIterator_Chunked(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) v0 := tsm1.NewValue(1, 1.1) writes := map[string][]tsm1.Value{ "cpu,host=A#!~#value": []tsm1.Value{v0}, } r1 := MustTSMReader(dir, 1, writes) v1 := tsm1.NewValue(2, 2.1) writes1 := map[string][]tsm1.Value{ "cpu,host=A#!~#value": []tsm1.Value{v1}, } r2 := MustTSMReader(dir, 2, writes1) iter, err := tsm1.NewTSMKeyIterator(2, false, r1, r2) if err != nil { t.Fatalf("unexpected error creating WALKeyIterator: %v", err) } var readValues bool var chunk int for iter.Next() { key, _, _, block, err := iter.Read() if err != nil { t.Fatalf("unexpected error read: %v", err) } values, err := tsm1.DecodeBlock(block, nil) if err != nil { t.Fatalf("unexpected error decode: %v", err) } if got, exp := key, "cpu,host=A#!~#value"; got != exp { t.Fatalf("key mismatch: got %v, exp %v", got, exp) } if got, exp := len(values), 2; got != exp { t.Fatalf("values length mismatch: got %v, exp %v", got, exp) } readValues = len(values) > 0 assertValueEqual(t, values[0], v0) assertValueEqual(t, values[1], v1) chunk++ } if got, exp := chunk, 1; got != exp { t.Fatalf("chunk count mismatch: got %v, exp %v", got, exp) } if !readValues { t.Fatalf("failed to read any values") } }
// Tests that duplicate point values are merged. There is only one case // where this could happen and that is when a compaction completed and we replace // the old TSM file with a new one and we crash just before deleting the old file. // No data is lost but the same point time/value would exist in two files until // compaction corrects it. func TestTSMKeyIterator_Duplicate(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) v1 := tsm1.NewValue(1, int64(1)) v2 := tsm1.NewValue(1, int64(2)) writes1 := map[string][]tsm1.Value{ "cpu,host=A#!~#value": []tsm1.Value{v1}, } r1 := MustTSMReader(dir, 1, writes1) writes2 := map[string][]tsm1.Value{ "cpu,host=A#!~#value": []tsm1.Value{v2}, } r2 := MustTSMReader(dir, 2, writes2) iter, err := tsm1.NewTSMKeyIterator(1, false, r1, r2) if err != nil { t.Fatalf("unexpected error creating WALKeyIterator: %v", err) } var readValues bool for iter.Next() { key, _, _, block, err := iter.Read() if err != nil { t.Fatalf("unexpected error read: %v", err) } values, err := tsm1.DecodeBlock(block, nil) if err != nil { t.Fatalf("unexpected error decode: %v", err) } if got, exp := key, "cpu,host=A#!~#value"; got != exp { t.Fatalf("key mismatch: got %v, exp %v", got, exp) } if got, exp := len(values), 1; got != exp { t.Fatalf("values length mismatch: got %v, exp %v", got, exp) } readValues = true assertValueEqual(t, values[0], v2) } if !readValues { t.Fatalf("failed to read any values") } }
// Tests that a single TSM file can be read and iterated over func TestTSMKeyIterator_Chunked(t *testing.T) { t.Skip("fixme") dir := MustTempDir() defer os.RemoveAll(dir) v0 := tsm1.NewValue(1, 1.1) v1 := tsm1.NewValue(2, 2.1) writes := map[string][]tsm1.Value{ "cpu,host=A#!~#value": []tsm1.Value{v0, v1}, } r := MustTSMReader(dir, 1, writes) iter, err := tsm1.NewTSMKeyIterator(1, false, r) if err != nil { t.Fatalf("unexpected error creating WALKeyIterator: %v", err) } var readValues bool var chunk int for iter.Next() { key, _, _, block, err := iter.Read() if err != nil { t.Fatalf("unexpected error read: %v", err) } values, err := tsm1.DecodeBlock(block, nil) if err != nil { t.Fatalf("unexpected error decode: %v", err) } if got, exp := key, "cpu,host=A#!~#value"; got != exp { t.Fatalf("key mismatch: got %v, exp %v", got, exp) } if got, exp := len(values), len(writes); got != exp { t.Fatalf("values length mismatch: got %v, exp %v", got, exp) } for _, v := range values { readValues = true assertValueEqual(t, v, writes["cpu,host=A#!~#value"][chunk]) } chunk++ } if !readValues { t.Fatalf("failed to read any values") } }
// Tests that deleted keys are not seen during iteration with // TSM files. func TestTSMKeyIterator_MultipleKeysDeleted(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) v1 := tsm1.NewValue(2, int64(1)) points1 := map[string][]tsm1.Value{ "cpu,host=A#!~#value": []tsm1.Value{v1}, } r1 := MustTSMReader(dir, 1, points1) if e := r1.Delete([]string{"cpu,host=A#!~#value"}); nil != e { t.Fatal(e) } v2 := tsm1.NewValue(1, float64(1)) v3 := tsm1.NewValue(1, float64(1)) points2 := map[string][]tsm1.Value{ "cpu,host=A#!~#count": []tsm1.Value{v2}, "cpu,host=B#!~#value": []tsm1.Value{v3}, } r2 := MustTSMReader(dir, 2, points2) r2.Delete([]string{"cpu,host=A#!~#count"}) iter, err := tsm1.NewTSMKeyIterator(1, false, r1, r2) if err != nil { t.Fatalf("unexpected error creating WALKeyIterator: %v", err) } var readValues bool var data = []struct { key string value tsm1.Value }{ {"cpu,host=B#!~#value", v3}, } for iter.Next() { key, _, _, block, err := iter.Read() if err != nil { t.Fatalf("unexpected error read: %v", err) } values, err := tsm1.DecodeBlock(block, nil) if err != nil { t.Fatalf("unexpected error decode: %v", err) } if got, exp := key, data[0].key; got != exp { t.Fatalf("key mismatch: got %v, exp %v", got, exp) } if got, exp := len(values), 1; got != exp { t.Fatalf("values length mismatch: got %v, exp %v", got, exp) } readValues = true assertValueEqual(t, values[0], data[0].value) data = data[1:] } if !readValues { t.Fatalf("failed to read any values") } }