Example #1
0
// Ensure the multi-cursor can correctly iterate across multiple non-overlapping subcursors.
func TestMultiCursor_Multiple_NonOverlapping_Reverse(t *testing.T) {
	mc := tsdb.MultiCursor(
		NewCursor([]CursorItem{
			{Key: 0, Value: 0},
			{Key: 3, Value: 30},
			{Key: 4, Value: 40},
		}, false),
		NewCursor([]CursorItem{
			{Key: 1, Value: 10},
			{Key: 2, Value: 20},
		}, false),
	)

	if k, v := mc.SeekTo(4); k != 4 || v.(int) != 40 {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != 3 || v.(int) != 30 {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != 2 || v.(int) != 20 {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != 1 || v.(int) != 10 {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != 0 || v.(int) != 00 {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != tsdb.EOF {
		t.Fatalf("expected eof, got: %x / %x", k, v)
	}
}
Example #2
0
// Ensure the multi-cursor can correctly iterate across multiple overlapping subcursors.
func TestMultiCursor_Multiple_Overlapping(t *testing.T) {
	mc := tsdb.MultiCursor(
		NewCursor([]CursorItem{
			{Key: []byte{0x00}, Value: []byte{0x00}},
			{Key: []byte{0x03}, Value: []byte{0x03}},
			{Key: []byte{0x04}, Value: []byte{0x04}},
		}),
		NewCursor([]CursorItem{
			{Key: []byte{0x00}, Value: []byte{0xF0}},
			{Key: []byte{0x02}, Value: []byte{0xF2}},
			{Key: []byte{0x04}, Value: []byte{0xF4}},
		}),
	)

	if k, v := mc.Seek([]byte{0x00}); !bytes.Equal(k, []byte{0x00}) || !bytes.Equal(v, []byte{0x00}) {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); !bytes.Equal(k, []byte{0x02}) || !bytes.Equal(v, []byte{0xF2}) {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); !bytes.Equal(k, []byte{0x03}) || !bytes.Equal(v, []byte{0x03}) {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); !bytes.Equal(k, []byte{0x04}) || !bytes.Equal(v, []byte{0x04}) {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != nil {
		t.Fatalf("expected eof, got: %x / %x", k, v)
	}
}
Example #3
0
// Ensure the multi-cursor can correctly iterate across multiple overlapping subcursors.
func TestMultiCursor_Multiple_Overlapping(t *testing.T) {
	mc := tsdb.MultiCursor(
		NewCursor([]CursorItem{
			{Key: 0, Value: 0},
			{Key: 3, Value: 3},
			{Key: 4, Value: 4},
		}, true),
		NewCursor([]CursorItem{
			{Key: 0, Value: 0xF0},
			{Key: 2, Value: 0xF2},
			{Key: 4, Value: 0xF4},
		}, true),
	)

	if k, v := mc.SeekTo(0); k != 0 || v.(int) != 0 {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != 2 || v.(int) != 0xF2 {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != 3 || v.(int) != 3 {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != 4 || v.(int) != 4 {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != tsdb.EOF {
		t.Fatalf("expected eof, got: %x / %x", k, v)
	}
}
Example #4
0
// Cursor returns an iterator for a key.
func (tx *Tx) Cursor(key string) tsdb.Cursor {
	walCursor := tx.wal.Cursor(key)

	// Retrieve points bucket. Ignore if there is no bucket.
	b := tx.Bucket([]byte("points")).Bucket([]byte(key))
	if b == nil {
		return walCursor
	}

	c := &Cursor{
		cursor: b.Cursor(),
	}

	return tsdb.MultiCursor(walCursor, c)
}
Example #5
0
// Ensure the multi-cursor can correctly iterate across a single subcursor in reverse order.
func TestMultiCursor_Single_Reverse(t *testing.T) {
	mc := tsdb.MultiCursor(NewCursor([]CursorItem{
		{Key: 0, Value: 0},
		{Key: 1, Value: 10},
		{Key: 2, Value: 20},
	}, false))

	if k, v := mc.SeekTo(2); k != 2 || v.(int) != 20 {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != 1 || v.(int) != 10 {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != 0 || v.(int) != 0 {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != tsdb.EOF {
		t.Fatalf("expected eof, got: %x / %x", k, v)
	}
}
Example #6
0
// Ensure the multi-cursor can correctly iterate across a single subcursor.
func TestMultiCursor_Single(t *testing.T) {
	mc := tsdb.MultiCursor(
		NewCursor([]CursorItem{
			{Key: []byte{0x00}, Value: []byte{0x00}},
			{Key: []byte{0x01}, Value: []byte{0x10}},
			{Key: []byte{0x02}, Value: []byte{0x20}},
		}),
	)

	if k, v := mc.Seek([]byte{0x00}); !bytes.Equal(k, []byte{0x00}) || !bytes.Equal(v, []byte{0x00}) {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); !bytes.Equal(k, []byte{0x01}) || !bytes.Equal(v, []byte{0x10}) {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); !bytes.Equal(k, []byte{0x02}) || !bytes.Equal(v, []byte{0x20}) {
		t.Fatalf("unexpected key/value: %x / %x", k, v)
	} else if k, v = mc.Next(); k != nil {
		t.Fatalf("expected eof, got: %x / %x", k, v)
	}
}
Example #7
0
// Cursor returns an iterator for a key.
func (tx *Tx) Cursor(key string, direction tsdb.Direction) tsdb.Cursor {
	walCursor := tx.wal.Cursor(key, direction)

	// Retrieve points bucket. Ignore if there is no bucket.
	b := tx.Bucket([]byte("points")).Bucket([]byte(key))
	if b == nil {
		return walCursor
	}

	c := &Cursor{
		cursor:    b.Cursor(),
		direction: direction,
	}

	if direction.Reverse() {
		c.last()
	}

	return tsdb.MultiCursor(direction, walCursor, c)
}
Example #8
0
// Ensure the multi-cursor can handle randomly generated data.
func TestMultiCursor_Quick(t *testing.T) {
	quick.Check(func(seek uint64, cursors []Cursor) bool {
		var got, exp [][]byte
		seek %= 100

		// Merge all cursor data to determine expected output.
		// First seen key overrides all other items with the same key.
		m := make(map[string][]byte)
		for _, c := range cursors {
			for _, item := range c.items {
				if bytes.Compare(item.Key, u64tob(seek)) == -1 {
					continue
				}
				if _, ok := m[string(item.Key)]; ok {
					continue
				}
				m[string(item.Key)] = item.Value
			}
		}

		// Convert map back to single item list.
		for k, v := range m {
			exp = append(exp, append([]byte(k), v...))
		}
		sort.Sort(byteSlices(exp))

		// Create multi-cursor and iterate over all items.
		mc := tsdb.MultiCursor(tsdbCursorSlice(cursors)...)
		for k, v := mc.Seek(u64tob(seek)); k != nil; k, v = mc.Next() {
			got = append(got, append(k, v...))
		}

		// Verify results.
		if !reflect.DeepEqual(got, exp) {
			t.Fatalf("mismatch: seek=%d\n\ngot=%+v\n\nexp=%+v", seek, got, exp)
		}

		return true
	}, nil)
}
Example #9
0
// Ensure the multi-cursor can handle randomly generated data.
func TestMultiCursor_Quick(t *testing.T) {
	quick.Check(func(useek uint64, cursors []Cursor) bool {
		var got, exp []CursorItem
		seek := int64(useek) % 100

		// Merge all cursor data to determine expected output.
		// First seen key overrides all other items with the same key.
		m := make(map[int64]CursorItem)
		for _, c := range cursors {
			for _, item := range c.items {
				if item.Key < seek {
					continue
				}
				if _, ok := m[item.Key]; ok {
					continue
				}
				m[item.Key] = item
			}
		}

		// Convert map back to single item list.
		for _, item := range m {
			exp = append(exp, item)
		}
		sort.Sort(CursorItems(exp))

		// Create multi-cursor and iterate over all items.
		mc := tsdb.MultiCursor(tsdbCursorSlice(cursors)...)
		for k, v := mc.SeekTo(seek); k != tsdb.EOF; k, v = mc.Next() {
			got = append(got, CursorItem{k, v.(int)})
		}

		// Verify results.
		if !reflect.DeepEqual(got, exp) {
			t.Fatalf("mismatch: seek=%d\n\ngot=%+v\n\nexp=%+v", seek, got, exp)
		}

		return true
	}, nil)
}
Example #10
0
// Cursor returns an iterator for a key.
func (tx *Tx) Cursor(series string, fields []string, dec *tsdb.FieldCodec, ascending bool) tsdb.Cursor {
	walCursor := tx.wal.Cursor(series, fields, dec, ascending)

	// Retrieve points bucket. Ignore if there is no bucket.
	b := tx.Bucket([]byte("points")).Bucket([]byte(series))
	if b == nil {
		return walCursor
	}

	c := &Cursor{
		cursor:    b.Cursor(),
		fields:    fields,
		dec:       dec,
		ascending: ascending,
	}

	if !ascending {
		c.last()
	}

	return tsdb.MultiCursor(walCursor, c)
}