Micro-optimization: store strong hash as a uint64 instead of a byte slice

This commit is contained in:
Kovid Goyal
2023-07-05 22:42:07 +05:30
parent 55f9359e1b
commit bbb6a4ae35
2 changed files with 21 additions and 28 deletions

View File

@@ -9,7 +9,6 @@
package rsync
import (
"bytes"
"encoding/binary"
"fmt"
"hash"
@@ -123,25 +122,25 @@ func (self *Operation) Unserialize(data []byte) (n int, err error) {
// Signature hash item generated from target.
type BlockHash struct {
Index uint64
StrongHash []byte
WeakHash uint32
StrongHash uint64
}
func (self BlockHash) Serialize() []byte {
ans := make([]byte, 12+len(self.StrongHash))
ans := make([]byte, 20)
bin.PutUint64(ans, self.Index)
bin.PutUint32(ans[8:], self.WeakHash)
copy(ans[12:], self.StrongHash)
bin.PutUint64(ans[12:], self.StrongHash)
return ans
}
func (self *BlockHash) Unserialize(data []byte, hash_size int) (err error) {
if len(data) < 12+hash_size {
return fmt.Errorf("record too small to be a BlockHash: %d < %d", len(data), 12+hash_size)
func (self *BlockHash) Unserialize(data []byte) (err error) {
if len(data) < 20 {
return fmt.Errorf("record too small to be a BlockHash: %d < %d", len(data), 20)
}
self.Index = bin.Uint64(data)
self.WeakHash = bin.Uint32(data[8:])
self.StrongHash = data[12 : 12+hash_size]
self.StrongHash = bin.Uint64(data[12:])
return
}
@@ -156,12 +155,12 @@ type rsync struct {
BlockSize int
// This must be non-nil before using any functions
hasher hash.Hash
hasher_constructor func() hash.Hash
hasher hash.Hash64
hasher_constructor func() hash.Hash64
buffer []byte
}
func (r *rsync) SetHasher(c func() hash.Hash) {
func (r *rsync) SetHasher(c func() hash.Hash64) {
r.hasher_constructor = c
r.hasher = c()
}
@@ -358,8 +357,7 @@ type diff struct {
// A single β hash may correlate with many unique hashes.
hash_lookup map[uint32][]BlockHash
source io.Reader
hasher hash.Hash
hash_buf []byte
hasher hash.Hash64
window, data struct{ pos, sz int }
block_size int
@@ -379,10 +377,10 @@ func (self *diff) Next() (op *Operation, err error) {
return self.ready_ops.pop_front(), nil
}
func (self *diff) hash(b []byte) []byte {
func (self *diff) hash(b []byte) uint64 {
self.hasher.Reset()
self.hasher.Write(b)
return self.hasher.Sum(self.hash_buf[:0])
return self.hasher.Sum64()
}
// Combine OpBlock into OpBlockRange. To do this store the previous
@@ -531,7 +529,6 @@ func (r *rsync) CreateDiff(source io.Reader, signature []BlockHash) func() (*Ope
block_size: r.BlockSize, buffer: make([]byte, 0, (r.BlockSize * 8)),
hash_lookup: make(map[uint32][]BlockHash, len(signature)),
source: source, hasher: r.hasher_constructor(),
hash_buf: make([]byte, 0, r.hasher.Size()),
}
for _, h := range signature {
key := h.WeakHash
@@ -556,10 +553,10 @@ func (r *rsync) CreateDelta(source io.Reader, signature []BlockHash, ops Operati
}
// Use a more unique way to identify a set of bytes.
func (r *rsync) hash(v []byte) []byte {
func (r *rsync) hash(v []byte) uint64 {
r.hasher.Reset()
r.hasher.Write(v)
return r.hasher.Sum(nil)
return r.hasher.Sum64()
}
func (r *rsync) HashSize() int { return r.hasher.Size() }
@@ -567,12 +564,9 @@ func (r *rsync) HashBlockSize() int { return r.hasher.BlockSize() }
func (r *rsync) HasHasher() bool { return r.hasher != nil }
// Searches for a given strong hash among all strong hashes in this bucket.
func find_hash(hh []BlockHash, hv []byte) (uint64, bool) {
if len(hv) == 0 {
return 0, false
}
func find_hash(hh []BlockHash, hv uint64) (uint64, bool) {
for _, block := range hh {
if bytes.Equal(block.StrongHash, hv) {
if block.StrongHash == hv {
return block.Index, true
}
}

View File

@@ -60,7 +60,7 @@ func (self *Api) read_signature_header(data []byte) (consumed int, err error) {
switch strong_hash := StrongHashType(bin.Uint16(data[4:])); strong_hash {
case XXH3:
self.Strong_hash_type = strong_hash
self.rsync.SetHasher(func() hash.Hash { return xxh3.New() })
self.rsync.SetHasher(func() hash.Hash64 { return xxh3.New() })
default:
return consumed, fmt.Errorf("Invalid strong_hash in signature header: %d", strong_hash)
}
@@ -84,11 +84,10 @@ func (self *Api) read_signature_header(data []byte) (consumed int, err error) {
}
func (self *Api) read_signature_blocks(data []byte) (consumed int) {
hash_size := self.rsync.HashSize()
block_hash_size := hash_size + 12
block_hash_size := self.rsync.HashSize() + 12
for ; len(data) >= block_hash_size; data = data[block_hash_size:] {
bl := BlockHash{}
bl.Unserialize(data[:block_hash_size], hash_size)
bl.Unserialize(data[:block_hash_size])
self.signature = append(self.signature, bl)
consumed += block_hash_size
}
@@ -241,7 +240,7 @@ func NewPatcher(expected_input_size int64) (ans *Patcher) {
}
ans = &Patcher{}
ans.rsync.BlockSize = utils.Min(bs, MaxBlockSize)
ans.rsync.SetHasher(func() hash.Hash { return xxh3.New() })
ans.rsync.SetHasher(func() hash.Hash64 { return xxh3.New() })
if ans.rsync.HashBlockSize() > 0 && ans.rsync.HashBlockSize() < ans.rsync.BlockSize {
ans.rsync.BlockSize = (ans.rsync.BlockSize / ans.rsync.HashBlockSize()) * ans.rsync.HashBlockSize()