This ReadUvarint() method is time-sensitive, because it's running inside a mutex. It's called very often.
I'd like to offer a more performant version, that will improve latencies:
func ReadUvarint(r io.ByteReader) (uint64, error) {
// Modified from the go standard library. Copyright the Go Authors and
// released under the BSD License.
var x uint64
var s uint
for i := 0; ; i++ {
b, err := r.ReadByte()
if err != nil {
if err == io.EOF && i != 0 {
// "eof" will look like a success.
// If we've read part of a value, this is not a
// success.
err = io.ErrUnexpectedEOF
}
return 0, err
}
if (i == 8 && b >= 0x80) || i >= MaxLenUvarint63 {
// this is the 9th and last byte we're willing to read, but it
// signals there's more (1 in MSB).
// or this is the >= 10th byte, and for some reason we're still here.
return 0, ErrOverflow
}
if b < 0x80 {
if b == 0 && s > 0 {
return 0, ErrNotMinimal
}
return x | uint64(b)<<s, nil
}
x |= uint64(b&0x7f) << s
s += 7
}
}
func ReadUvarint(r io.ByteReader) (uint64, error) {
// Modified from the go standard library. Copyright the Go Authors and
// released under the BSD License.
var x uint64
var s uint
for s = 0; ; s+=7 {
b, err := r.ReadByte()
if err != nil {
if err == io.EOF && i != 0 {
// "eof" will look like a success.
// If we've read part of a value, this is not a
// success.
err = io.ErrUnexpectedEOF
}
return 0, err
}
if (s == 56 && b >= 0x80) || s >= (7 * MaxLenUvarint63) {
// this is the 9th and last byte we're willing to read, but it
// signals there's more (1 in MSB).
// or this is the >= 10th byte, and for some reason we're still here.
return 0, ErrOverflow
}
if b < 0x80 {
if b == 0 && s > 0 {
return 0, ErrNotMinimal
}
return x | uint64(b)<<s, nil
}
x |= uint64(b&0x7f) << s
s += 7
}
}
The 'i == 8' is replaced with 's == 56'. MaxLenUvarint63 is '9', currently, so that's not an overflow problem.
This change removes the unnecessary addition operation for 'i'.