Skip to content

Commit

Permalink
Improve performance of marshalling small keys (#2895)
Browse files Browse the repository at this point in the history
  • Loading branch information
StephenButtolph authored Apr 2, 2024
1 parent 00d4e0a commit f7def4d
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 4 deletions.
8 changes: 4 additions & 4 deletions x/merkledb/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,10 +362,10 @@ func decodeID(src *bytes.Reader) (ids.ID, error) {
}

func encodeKey(key Key) []byte {
estimatedLen := binary.MaxVarintLen64 + len(key.Bytes())
dst := bytes.NewBuffer(make([]byte, 0, estimatedLen))
encodeKeyToBuffer(dst, key)
return dst.Bytes()
keyLen := uintSize(uint64(key.length)) + len(key.Bytes())
buf := bytes.NewBuffer(make([]byte, 0, keyLen))
encodeKeyToBuffer(buf, key)
return buf.Bytes()
}

func encodeKeyToBuffer(dst *bytes.Buffer, key Key) {
Expand Down
94 changes: 94 additions & 0 deletions x/merkledb/codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,81 @@ var (
},
},
}
encodeKeyTests = []struct {
name string
key Key
expectedBytes []byte
}{
{
name: "empty",
key: ToKey([]byte{}),
expectedBytes: []byte{
0x00, // length
},
},
{
name: "1 byte",
key: ToKey([]byte{0}),
expectedBytes: []byte{
0x08, // length
0x00, // key
},
},
{
name: "2 bytes",
key: ToKey([]byte{0, 1}),
expectedBytes: []byte{
0x10, // length
0x00, 0x01, // key
},
},
{
name: "4 bytes",
key: ToKey([]byte{0, 1, 2, 3}),
expectedBytes: []byte{
0x20, // length
0x00, 0x01, 0x02, 0x03, // key
},
},
{
name: "8 bytes",
key: ToKey([]byte{0, 1, 2, 3, 4, 5, 6, 7}),
expectedBytes: []byte{
0x40, // length
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // key
},
},
{
name: "32 bytes",
key: ToKey(make([]byte, 32)),
expectedBytes: append(
[]byte{
0x80, 0x02, // length
},
make([]byte, 32)..., // key
),
},
{
name: "64 bytes",
key: ToKey(make([]byte, 64)),
expectedBytes: append(
[]byte{
0x80, 0x04, // length
},
make([]byte, 64)..., // key
),
},
{
name: "1024 bytes",
key: ToKey(make([]byte, 1024)),
expectedBytes: append(
[]byte{
0x80, 0x40, // length
},
make([]byte, 1024)..., // key
),
},
}
)

func FuzzCodecBool(f *testing.F) {
Expand Down Expand Up @@ -609,6 +684,15 @@ func TestEncodeDBNode(t *testing.T) {
}
}

func TestEncodeKey(t *testing.T) {
for _, test := range encodeKeyTests {
t.Run(test.name, func(t *testing.T) {
bytes := encodeKey(test.key)
require.Equal(t, test.expectedBytes, bytes)
})
}
}

func TestCodecDecodeKeyLengthOverflowRegression(t *testing.T) {
_, err := decodeKey(binary.AppendUvarint(nil, math.MaxInt))
require.ErrorIs(t, err, io.ErrUnexpectedEOF)
Expand Down Expand Up @@ -654,6 +738,16 @@ func Benchmark_EncodeDBNode(b *testing.B) {
}
}

func Benchmark_EncodeKey(b *testing.B) {
for _, benchmark := range encodeKeyTests {
b.Run(benchmark.name, func(b *testing.B) {
for i := 0; i < b.N; i++ {
encodeKey(benchmark.key)
}
})
}
}

func Benchmark_EncodeUint(b *testing.B) {
var dst bytes.Buffer
dst.Grow(binary.MaxVarintLen64)
Expand Down

0 comments on commit f7def4d

Please sign in to comment.