Skip to content

Commit

Permalink
Make binary serialization of value keys appendable
Browse files Browse the repository at this point in the history
The previous binary serialisation format for value-keys, which is a 2D
slice of bytes, started the number rows. This meant that given a set of
bytes the function could determine how many rows to expect. But the
tradeoff is that in order to append a new row to an existing serialized
value-keys one had to change the uvarint representing the number of
rows at the beginning of the value. Because the size is a uvarint, this
could mean shifting bytes, etc.

Instead, do not bother with storing the number of rows at all. Instead,
simply keep reading a uvarint-sized bytes and expect that reading the
last row should result in no leftover bytes.

This allows further optimisations inside the store implementations,
where rather than reading the entire value of value-keys from the store
adding a value and re-serializing it, one could simply append a new
value to the end of the already serialized value-keys.
  • Loading branch information
masih committed Aug 18, 2022
1 parent a81fbb4 commit 2b7e6eb
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 24 deletions.
23 changes: 1 addition & 22 deletions value.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/json"
"errors"
"fmt"
"math"

"github.com/libp2p/go-libp2p-core/peer"
"github.com/multiformats/go-varint"
Expand Down Expand Up @@ -165,7 +164,6 @@ func (BinaryValueSerde) UnmarshalValue(b []byte) (Value, error) {

func (BinaryValueSerde) MarshalValueKeys(vk [][]byte) ([]byte, error) {
var buf bytes.Buffer
buf.Write(varint.ToUvarint(uint64(len(vk))))
for _, v := range vk {
vl := len(v)
uvl := uint64(vl)
Expand All @@ -184,24 +182,8 @@ func (BinaryValueSerde) MarshalValueKeys(vk [][]byte) ([]byte, error) {
func (BinaryValueSerde) UnmarshalValueKeys(b []byte) ([][]byte, error) {
var vk [][]byte
buf := bytes.NewBuffer(b)

// Decode vk length.
ulen, err := varint.ReadUvarint(buf)
if err != nil {
return vk, err
}
if ulen > math.MaxUint32 {
return vk, ErrSerdeOverflow
}
l := int(ulen)
// There should at least be l number of bytes since length of each inner byte slice length
// should have been written, even if it was zero, and minimum size of a uvarint is a byte.
if l < 0 || l > buf.Len() {
return vk, ErrSerdeOverflow
}

// Decode each value key.
for i := 0; i < l; i++ {
for buf.Len() != 0 {
usize, err := varint.ReadUvarint(buf)
if err != nil {
return vk, err
Expand All @@ -212,8 +194,5 @@ func (BinaryValueSerde) UnmarshalValueKeys(b []byte) ([][]byte, error) {
}
vk = append(vk, buf.Next(size))
}
if buf.Len() != 0 {
return vk, fmt.Errorf("too many bytes; %d remain unread", buf.Len())
}
return vk, nil
}
4 changes: 2 additions & 2 deletions value_serde_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func TestBinaryValueSerde_MarshalUnmarshalEmptyValues(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(svk, []byte{0}) {
if len(svk) != 0 {
t.Fatal()
}

Expand All @@ -154,7 +154,7 @@ func TestBinaryValueSerde_MarshalUnmarshalEmptyValues(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(svk, []byte{1, 0}) {
if !reflect.DeepEqual(svk, []byte{0}) {
t.Fatal()
}
}
Expand Down

0 comments on commit 2b7e6eb

Please sign in to comment.