Skip to content

Commit

Permalink
colblk: implement a common interface across column data accessors
Browse files Browse the repository at this point in the history
Introduce a new generic Array[T] type that allows indexed access to data and
implement it across the various accessors.
  • Loading branch information
jbowens committed Jul 19, 2024
1 parent 6492e86 commit b26e632
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 12 deletions.
7 changes: 5 additions & 2 deletions sstable/colblk/bitmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ type Bitmap struct {
bitCount int
}

// Assert that Bitmap implements Array[bool].
var _ Array[bool] = Bitmap{}

// DecodeBitmap decodes the structure of a Bitmap and returns a Bitmap that
// reads from b supporting bitCount logical bits. No bounds checking is
// performed, so the caller must guarantee the bitmap is appropriately sized and
Expand All @@ -50,8 +53,8 @@ func DecodeBitmap(b []byte, off uint32, bitCount int) (bitmap Bitmap, endOffset
// Assert that DecodeBitmap implements DecodeFunc.
var _ DecodeFunc[Bitmap] = DecodeBitmap

// Get returns true if the bit at position i is set and false otherwise.
func (b Bitmap) Get(i int) bool {
// At returns true if the bit at position i is set and false otherwise.
func (b Bitmap) At(i int) bool {
return (b.data.At(i>>6 /* i/64 */) & (1 << uint(i%64))) != 0
}

Expand Down
12 changes: 6 additions & 6 deletions sstable/colblk/bitmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func dumpBitmap(w io.Writer, b Bitmap) {
if i > 0 && i%64 == 0 {
w.Write([]byte{'\n'})
}
if b.Get(i) {
if b.At(i) {
w.Write([]byte{'1'})
} else {
w.Write([]byte{'0'})
Expand Down Expand Up @@ -104,31 +104,31 @@ func TestBitmapRandom(t *testing.T) {
bitmap, endOffset := DecodeBitmap(data, 0, size)
require.Equal(t, uint32(len(data)), endOffset)
for i := 0; i < size; i++ {
if got := bitmap.Get(i); got != v[i] {
if got := bitmap.At(i); got != v[i] {
t.Fatalf("b.Get(%d) = %t; want %t", i, got, v[i])
}
}
for i := 0; i < size; i++ {
succ := bitmap.Successor(i)
// Ensure that Successor always returns the index of a set bit.
if succ != size && !bitmap.Get(succ) {
if succ != size && !bitmap.At(succ) {
t.Fatalf("b.Successor(%d) = %d; bit at index %d is not set", i, succ, succ)
}
pred := bitmap.Predecessor(i)
// Ensure that Predecessor always returns the index of a set bit.
if pred >= 0 && !bitmap.Get(pred) {
if pred >= 0 && !bitmap.At(pred) {
t.Fatalf("b.Predecessor(%d) = %d; bit at index %d is not set", i, pred, pred)
}

// Ensure there are no set bits between i and succ.
for j := i; j < succ; j++ {
if bitmap.Get(j) {
if bitmap.At(j) {
t.Fatalf("b.Successor(%d) = %d; bit at index %d is set", i, succ, j)
}
}
// Ensure there are no set bits between pred and i.
for j := pred + 1; j < i; j++ {
if bitmap.Get(j) {
if bitmap.At(j) {
t.Fatalf("b.Predecessor(%d) = %d; bit at index %d is set", i, pred, j)
}
}
Expand Down
2 changes: 1 addition & 1 deletion sstable/colblk/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ func testRandomBlock(t *testing.T, rng *rand.Rand, rows int, schema []DataType)
b := r.Bitmap(col)
vals := make([]bool, r.header.Rows)
for i := range vals {
vals[i] = b.Get(i)
vals[i] = b.At(i)
}
got = vals
case DataTypeUint8:
Expand Down
6 changes: 6 additions & 0 deletions sstable/colblk/column.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,9 @@ type Encoder interface {
// The rows argument must be number of logical rows encoded within the data
// structure.
type DecodeFunc[T any] func(buf []byte, offset uint32, rows int) (decoded T, nextOffset uint32)

// An Array provides indexed access to an array of values.
type Array[V any] interface {
// At returns the i'th value in the array.
At(i int) V
}
11 changes: 11 additions & 0 deletions sstable/colblk/prefix_bytes.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"fmt"
"io"
"math/bits"
"slices"
"strings"
"unsafe"

Expand Down Expand Up @@ -171,6 +172,9 @@ type PrefixBytes struct {
rawBytes RawBytes
}

// Assert that PrefixBytes implements Array[[]byte].
var _ Array[[]byte] = PrefixBytes{}

// DecodePrefixBytes decodes the structure of a PrefixBytes, constructing an
// accessor for an array of lexicographically sorted byte slices constructed by
// PrefixBytesBuilder. Count must be the number of logical slices within the
Expand Down Expand Up @@ -205,6 +209,13 @@ func DecodePrefixBytes(
// Assert that DecodePrefixBytes implements DecodeFunc.
var _ DecodeFunc[PrefixBytes] = DecodePrefixBytes

// At returns the i'th []byte slice in the PrefixBytes. At must allocate, so
// callers should prefer accessing a slice's constituent components through
// SharedPrefix, BundlePrefix and RowSuffix.
func (b PrefixBytes) At(i int) []byte {
return slices.Concat(b.SharedPrefix(), b.RowBundlePrefix(i), b.RowSuffix(i))
}

// SharedPrefix return a []byte of the shared prefix that was extracted from
// all of the values in the Bytes vector. The returned slice should not be
// mutated.
Expand Down
3 changes: 3 additions & 0 deletions sstable/colblk/raw_bytes.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ type RawBytes struct {
data unsafe.Pointer
}

// Assert that RawBytes implements Array[[]byte].
var _ Array[[]byte] = RawBytes{}

// DecodeRawBytes decodes the structure of a RawBytes, constructing an accessor
// for an array of byte slices constructed by RawBytesBuilder. Count must be the
// number of byte slices within the array.
Expand Down
6 changes: 3 additions & 3 deletions sstable/colblk/unsafe_slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ type UnsafeIntegerSlice[T constraints.Integer] struct {
deltaWidth uintptr
}

// Assert that UnsafeIntegerSlice implements Array.
var _ Array[uint8] = UnsafeIntegerSlice[uint8]{}

// DecodeUnsafeIntegerSlice decodes the structure of a slice of uints from a
// byte slice.
func DecodeUnsafeIntegerSlice[T constraints.Integer](
Expand Down Expand Up @@ -109,9 +112,6 @@ func makeUnsafeIntegerSlice[T constraints.Integer](
}
}

// TODO(jackson): Remove when more of the read path is hooked up.
var _ = makeUnsafeIntegerSlice[uint64]

// At returns the `i`-th element of the slice.
func (s UnsafeIntegerSlice[T]) At(i int) T {
// TODO(jackson): Experiment with other alternatives that might be faster
Expand Down

0 comments on commit b26e632

Please sign in to comment.