journal/wire_proto.go
Laurence Withers c579349c05 Pre-size net.Buffers
This leads to a further reduction in allocations per call. Before:
	goos: linux
	goarch: amd64
	pkg: src.lwithers.me.uk/go/journal
	cpu: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
	BenchmarkEntry-8   	12611158	    1445 ns/op	   221 B/op	     7 allocs/op
	PASS
	ok  	src.lwithers.me.uk/go/journal	19.673s

After:
	goos: linux
	goarch: amd64
	pkg: src.lwithers.me.uk/go/journal
	cpu: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
	BenchmarkEntry-8   	13613377	     1329 ns/op	    149 B/op	      5 allocs/op
	PASS
	ok  	src.lwithers.me.uk/go/journal	19.435s
2024-02-18 14:44:20 +00:00

46 lines
1.3 KiB
Go

package journal
import (
"encoding/binary"
"io"
"net"
"slices"
)
var (
wireProtocolAttributeSeparator = []byte{'='}
wireProtocolAttributeTerminator = []byte{'\n'}
)
// WireWrite is the lowest-level routine. It writes a journal entry using the
// native wire protocol documented at https://systemd.io/JOURNAL_NATIVE_PROTOCOL/ .
// Invalid attributes are silently skipped. It appends to buf as needed.
//
// As long as w supports the net.buffersWriter interface, the write will be
// atomic, and this function is safe to use across goroutines. Otherwise,
// writes may be interleaved.
func WireWrite(buf *net.Buffers, w io.Writer, attrs []Attr) error {
*buf = slices.Grow(*buf, len(*buf)+len(attrs)*4)
for i := range attrs {
key := attrs[i].Key.key
if key == "" {
// silently discard invalid attributes
continue
}
*buf = append(*buf, []byte(key))
if attrs[i].UseTextProto() {
*buf = append(*buf, wireProtocolAttributeSeparator)
*buf = append(*buf, attrs[i].Value)
} else {
var valueSize [9]byte
valueSize[0] = '\n'
binary.LittleEndian.PutUint64(valueSize[1:], uint64(len(attrs[i].Value)))
*buf = append(*buf, valueSize[:])
*buf = append(*buf, attrs[i].Value)
}
*buf = append(*buf, wireProtocolAttributeTerminator)
}
_, err := buf.WriteTo(w)
return err
}