shithub: furgit

Download patch

ref: ac400226b0b622aae21b09cb6c83f07924647d0d
parent: 5ee77b00a0c00d2ef5c796260a34bbd6e8ac39a8
author: Runxi Yu <me@runxiyu.org>
date: Thu Jan 29 16:01:40 EST 2026

delta, packed: Use xxhash instead of murmurhash2

--- a/delta_write_deltify.go
+++ b/delta_write_deltify.go
@@ -3,7 +3,7 @@
 import (
 	"bytes"
 
-	"codeberg.org/lindenii/furgit/internal/murmurhash2"
+	"github.com/cespare/xxhash/v2"
 )
 
 const (
@@ -62,7 +62,7 @@
 type deltaBlock struct {
 	length int
 	offset int
-	hash   uint32
+	hash   uint64
 }
 
 type deltaTable struct {
@@ -82,7 +82,7 @@
 	data   []byte
 }
 
-func deltify(base, target []byte, seed uint32) ([]deltaInstruction, error) {
+func deltify(base, target []byte, seed uint64) ([]deltaInstruction, error) {
 	if base == nil {
 		base = []byte{}
 	}
@@ -96,7 +96,7 @@
 	return deltifyMemMem(target, 0, len(target), seed, dt, base, 0, len(base))
 }
 
-func deltifyMemMem(target []byte, fileoffset, filesize int, seed uint32, dt *deltaTable, base []byte, baseOffset0, baseSize int) ([]deltaInstruction, error) {
+func deltifyMemMem(target []byte, fileoffset, filesize int, seed uint64, dt *deltaTable, base []byte, baseOffset0, baseSize int) ([]deltaInstruction, error) {
 	const allocChunkSize = 64
 	instr := make([]deltaInstruction, 0, allocChunkSize)
 	offset0 := fileoffset
@@ -141,7 +141,7 @@
 	return instr, nil
 }
 
-func deltaTableInitMem(data []byte, fileoffset, filesize int, seed uint32) (*deltaTable, error) {
+func deltaTableInitMem(data []byte, fileoffset, filesize int, seed uint64) (*deltaTable, error) {
 	dt := &deltaTable{
 		nalloc: 128,
 		size:   128,
@@ -164,8 +164,13 @@
 	return dt, nil
 }
 
-func deltaHashBlock(p []byte, seed uint32) uint32 {
-	return murmurhash2.Sum32(p, seed)
+func deltaHashBlock(p []byte, seed uint64) uint64 {
+	if seed == 0 {
+		return xxhash.Sum64(p)
+	}
+	d := xxhash.NewWithSeed(seed)
+	_, _ = d.Write(p)
+	return d.Sum64()
 }
 
 func deltaNextBlockLen(data []byte, fileoffset, filesize int) int {
@@ -188,7 +193,7 @@
 	return p - fileoffset
 }
 
-func (dt *deltaTable) addBlock(data []byte, offset0, length, offset int, h uint32) error {
+func (dt *deltaTable) addBlock(data []byte, offset0, length, offset int, h uint64) error {
 	if length == 0 {
 		return nil
 	}
@@ -200,22 +205,22 @@
 		return nil
 	}
 	dt.offs[idx] = uint32(dt.nblocks + 1)
-	dt.blocks[dt.nblocks] = deltaBlock{
-		length: length,
-		offset: offset,
-		hash:   h,
-	}
+		dt.blocks[dt.nblocks] = deltaBlock{
+			length: length,
+			offset: offset,
+			hash:   h,
+		}
 	dt.nblocks++
 	dt.len++
 	return nil
 }
 
-func (dt *deltaTable) lookupBlock(chunk []byte, length int, seed uint32, base []byte, baseOffset0 int) *deltaBlock {
+func (dt *deltaTable) lookupBlock(chunk []byte, length int, seed uint64, base []byte, baseOffset0 int) *deltaBlock {
 	if dt == nil || dt.size == 0 {
 		return nil
 	}
 	h := deltaHashBlock(chunk, seed)
-	for i := int(h % uint32(dt.size)); dt.offs[i] != 0; i = (i + 1) % dt.size {
+	for i := int(h % uint64(dt.size)); dt.offs[i] != 0; i = (i + 1) % dt.size {
 		block := &dt.blocks[dt.offs[i]-1]
 		if block.hash != h || block.length != length {
 			continue
@@ -231,11 +236,11 @@
 	return nil
 }
 
-func (dt *deltaTable) lookupSlot(data []byte, offset0, offset, length int, h uint32) (int, bool) {
+func (dt *deltaTable) lookupSlot(data []byte, offset0, offset, length int, h uint64) (int, bool) {
 	if dt == nil || dt.size == 0 {
 		return 0, false
 	}
-	for i := int(h % uint32(dt.size)); ; i = (i + 1) % dt.size {
+	for i := int(h % uint64(dt.size)); ; i = (i + 1) % dt.size {
 		if dt.offs[i] == 0 {
 			return i, false
 		}
@@ -273,7 +278,7 @@
 		dt.offs = make([]uint32, dt.size)
 		for i := 0; i < dt.nblocks; i++ {
 			block := &dt.blocks[i]
-			idx := int(block.hash % uint32(dt.size))
+			idx := int(block.hash % uint64(dt.size))
 			for dt.offs[idx] != 0 {
 				idx = (idx + 1) % dt.size
 			}
--- a/delta_write_encode.go
+++ b/delta_write_encode.go
@@ -89,7 +89,7 @@
 	return out, nil
 }
 
-func deltaTry(base, target []byte, seed uint32, minSavings int) ([]byte, bool) {
+func deltaTry(base, target []byte, seed uint64, minSavings int) ([]byte, bool) {
 	if minSavings < 0 {
 		minSavings = 0
 	}
--- a/delta_write_select.go
+++ b/delta_write_select.go
@@ -26,7 +26,7 @@
 	}
 }
 
-func pickDeltaBase(ctx *deltaContext, obj *objectToPack, seed uint32, minSavings, maxDepth int) (*objectToPack, []byte) {
+func pickDeltaBase(ctx *deltaContext, obj *objectToPack, seed uint64, minSavings, maxDepth int) (*objectToPack, []byte) {
 	if ctx == nil || len(ctx.candidates) == 0 {
 		return nil, nil
 	}
--- a/packed_write_pack.go
+++ b/packed_write_pack.go
@@ -319,14 +319,14 @@
 	}
 
 	var dctx deltaContext
-	var deltaSeed uint32
+	var deltaSeed uint64
 	if opts.EnableDeltas {
 		dctx.window = defaultDeltaWindow
-		var seedBytes [4]byte
+		var seedBytes [8]byte
 		if _, err := rand.Read(seedBytes[:]); err != nil {
 			return Hash{}, err
 		}
-		deltaSeed = binary.LittleEndian.Uint32(seedBytes[:])
+		deltaSeed = binary.LittleEndian.Uint64(seedBytes[:])
 	}
 
 	for _, id := range objects {
--