Skip to content

Commit

Permalink
Record: add helper constructors; allocation avoiders w/ unsafe
Browse files Browse the repository at this point in the history
See embedded comments. I often find myself producing strings and never
touching the record fields itself once the record struct is created, so
having a few small helpers to avoid allocating through the use of unsafe
seems like a small quality of life improvement. There is plenty of
warning on the functions themselves to not touch the return fields.
  • Loading branch information
twmb committed May 11, 2021
1 parent f4a6baf commit 780d168
Showing 1 changed file with 58 additions and 1 deletion.
59 changes: 58 additions & 1 deletion pkg/kgo/record_and_fetch.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package kgo

import "time"
import (
"reflect"
"time"
"unsafe"
)

// RecordHeader contains extra information that can be sent with Records.
type RecordHeader struct {
Expand Down Expand Up @@ -129,6 +133,59 @@ type Record struct {
Offset int64
}

// StringRecord returns a Record with the Value field set to the input value
// string. For producing, this function is useful in tandem with the
// client-level ProduceTopic option.
//
// This function uses the 'unsafe' package to avoid copying value into a slice.
//
// NOTE: It is NOT SAFE to modify the record's value. This function should only
// be used if you only ever read record fields. This function can safely be used
// for producing; the client never modifies a record's key nor value fields.
func StringRecord(value string) *Record {
var slice []byte
slicehdr := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
slicehdr.Data = ((*reflect.StringHeader)(unsafe.Pointer(&value))).Data
slicehdr.Len = len(value)
slicehdr.Cap = len(value)

return &Record{Value: slice}
}

// KeyStringRecord returns a Record with the Key and Value fields set to the
// input key and value strings. For producing, this function is useful in
// tandem with the client-level ProduceTopic option.
//
// This function uses the 'unsafe' package to avoid copying value into a slice.
//
// NOTE: It is NOT SAFE to modify the record's value. This function should only
// be used if you only ever read record fields. This function can safely be used
// for producing; the client never modifies a record's key nor value fields.
func KeyStringRecord(key, value string) *Record {
r := StringRecord(value)

keyhdr := (*reflect.SliceHeader)(unsafe.Pointer(&r.Key))
keyhdr.Data = ((*reflect.StringHeader)(unsafe.Pointer(&key))).Data
keyhdr.Len = len(key)
keyhdr.Cap = len(key)

return r
}

// SliceRecord returns a Record with the Value field set to the input value
// slice. For producing, this function is useful in tandem with the
// client-level ProduceTopic option.
func SliceRecord(value []byte) *Record {
return &Record{Value: value}
}

// KeySliceRecord returns a Record with the Key and Value fields set to the
// input key and value slices. For producing, this function is useful in
// tandem with the client-level ProduceTopic option.
func KeySliceRecord(key, value []byte) *Record {
return &Record{Key: key, Value: value}
}

// FetchPartition is a response for a partition in a fetched topic from a
// broker.
type FetchPartition struct {
Expand Down

0 comments on commit 780d168

Please sign in to comment.