shithub: furgit

Download patch

ref: 4668c6c07b32a3c185fdd7bfc585fb978f535a4a
parent: b90b167cfbce785088c5236960515bc460e062d8
author: Runxi Yu <me@runxiyu.org>
date: Wed Mar 4 07:53:05 EST 2026

objectstore/packed: Split

--- /dev/null
+++ b/objectstore/packed/idx_candidates_mru.go
@@ -1,0 +1,73 @@
+package packed
+
+// packCandidateNode is one node in the candidate MRU order list.
+type packCandidateNode struct {
+	candidate packCandidate
+	prev      *packCandidateNode
+	next      *packCandidateNode
+}
+
+// touchCandidate moves one candidate to the front of the lookup order.
+// This is done on a best-effort basis.
+func (store *Store) touchCandidate(packName string) {
+	if !store.candidatesMu.TryLock() {
+		return
+	}
+	defer store.candidatesMu.Unlock()
+
+	node := store.candidateNodeByPack[packName]
+	if node == nil || node == store.candidateHead {
+		return
+	}
+
+	if node.prev != nil {
+		node.prev.next = node.next
+	}
+
+	if node.next != nil {
+		node.next.prev = node.prev
+	}
+
+	if store.candidateTail == node {
+		store.candidateTail = node.prev
+	}
+
+	node.prev = nil
+
+	node.next = store.candidateHead
+	if store.candidateHead != nil {
+		store.candidateHead.prev = node
+	}
+
+	store.candidateHead = node
+	if store.candidateTail == nil {
+		store.candidateTail = node
+	}
+}
+
+// firstCandidatePackName returns the current head pack name, or "" when none
+// are available.
+func (store *Store) firstCandidatePackName() string {
+	store.candidatesMu.RLock()
+	defer store.candidatesMu.RUnlock()
+
+	if store.candidateHead == nil {
+		return ""
+	}
+
+	return store.candidateHead.candidate.packName
+}
+
+// nextCandidatePackName returns the pack name after currentPack in current MRU
+// order, or "" at end / when currentPack is not present.
+func (store *Store) nextCandidatePackName(currentPack string) string {
+	store.candidatesMu.RLock()
+	defer store.candidatesMu.RUnlock()
+
+	node := store.candidateNodeByPack[currentPack]
+	if node == nil || node.next == nil {
+		return ""
+	}
+
+	return node.next.candidate.packName
+}
--- /dev/null
+++ b/objectstore/packed/idx_lookup.go
@@ -1,0 +1,91 @@
+package packed
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+
+	"codeberg.org/lindenii/furgit/objectid"
+)
+
+// lookup resolves one object ID to its pack offset within this index.
+func (index *idxFile) lookup(id objectid.ObjectID) (uint64, bool, error) {
+	if id.Algorithm() != index.algo {
+		return 0, false, fmt.Errorf("objectstore/packed: object id algorithm mismatch")
+	}
+
+	idBytes := (&id).RawBytes()
+
+	hashSize := len(idBytes)
+	if hashSize != index.algo.Size() {
+		return 0, false, fmt.Errorf("objectstore/packed: unexpected object id length")
+	}
+
+	first := int(idBytes[0])
+
+	lo := 0
+	if first > 0 {
+		lo = int(index.fanout[first-1])
+	}
+
+	hi := int(index.fanout[first])
+	if lo < 0 || hi < 0 || lo > hi || hi > index.numObjects {
+		return 0, false, fmt.Errorf("objectstore/packed: idx %q has invalid fanout bounds", index.idxName)
+	}
+
+	for lo < hi {
+		mid := lo + (hi-lo)/2
+
+		nameOffset := index.namesOffset + mid*hashSize
+		if nameOffset < 0 || nameOffset+hashSize > len(index.data) {
+			return 0, false, fmt.Errorf("objectstore/packed: idx %q truncated name table", index.idxName)
+		}
+
+		cmp := bytes.Compare(index.data[nameOffset:nameOffset+hashSize], idBytes)
+		if cmp == 0 {
+			offset, err := index.offsetAt(mid)
+			if err != nil {
+				return 0, false, err
+			}
+
+			return offset, true, nil
+		}
+
+		if cmp < 0 {
+			lo = mid + 1
+		} else {
+			hi = mid
+		}
+	}
+
+	return 0, false, nil
+}
+
+// offsetAt resolves the pack offset for one object index entry.
+func (index *idxFile) offsetAt(objectIndex int) (uint64, error) {
+	if objectIndex < 0 || objectIndex >= index.numObjects {
+		return 0, fmt.Errorf("objectstore/packed: idx %q offset index out of bounds", index.idxName)
+	}
+
+	wordOffset := index.offset32Offset + objectIndex*4
+	if wordOffset < 0 || wordOffset+4 > len(index.data) {
+		return 0, fmt.Errorf("objectstore/packed: idx %q truncated 32-bit offset table", index.idxName)
+	}
+
+	word := binary.BigEndian.Uint32(index.data[wordOffset : wordOffset+4])
+	if word&0x80000000 == 0 {
+		return uint64(word), nil
+	}
+
+	pos := int(word & 0x7fffffff)
+	if pos < 0 || pos >= index.offset64Count {
+		return 0, fmt.Errorf("objectstore/packed: idx %q invalid 64-bit offset position", index.idxName)
+	}
+
+	offOffset := index.offset64Offset + pos*8
+	if offOffset < 0 || offOffset+8 > len(index.data)-2*index.algo.Size() {
+		return 0, fmt.Errorf("objectstore/packed: idx %q truncated 64-bit offset table", index.idxName)
+	}
+
+	return binary.BigEndian.Uint64(index.data[offOffset : offOffset+8]), nil
+}
--- a/objectstore/packed/idx_lookup_candidates.go
+++ b/objectstore/packed/idx_lookup_candidates.go
@@ -23,13 +23,6 @@
 	mtime int64
 }
 
-// packCandidateNode is one node in the candidate MRU order list.
-type packCandidateNode struct {
-	candidate packCandidate
-	prev      *packCandidateNode
-	next      *packCandidateNode
-}
-
 // ensureCandidates discovers pack/index pairs once.
 func (store *Store) ensureCandidates() error {
 	store.discoverOnce.Do(func() {
@@ -133,69 +126,4 @@
 	})
 
 	return candidates, nil
-}
-
-// touchCandidate moves one candidate to the front of the lookup order.
-// This is done on a best-effort basis.
-func (store *Store) touchCandidate(packName string) {
-	if !store.candidatesMu.TryLock() {
-		return
-	}
-	defer store.candidatesMu.Unlock()
-
-	node := store.candidateNodeByPack[packName]
-	if node == nil || node == store.candidateHead {
-		return
-	}
-
-	if node.prev != nil {
-		node.prev.next = node.next
-	}
-
-	if node.next != nil {
-		node.next.prev = node.prev
-	}
-
-	if store.candidateTail == node {
-		store.candidateTail = node.prev
-	}
-
-	node.prev = nil
-
-	node.next = store.candidateHead
-	if store.candidateHead != nil {
-		store.candidateHead.prev = node
-	}
-
-	store.candidateHead = node
-	if store.candidateTail == nil {
-		store.candidateTail = node
-	}
-}
-
-// firstCandidatePackName returns the current head pack name, or "" when none
-// are available.
-func (store *Store) firstCandidatePackName() string {
-	store.candidatesMu.RLock()
-	defer store.candidatesMu.RUnlock()
-
-	if store.candidateHead == nil {
-		return ""
-	}
-
-	return store.candidateHead.candidate.packName
-}
-
-// nextCandidatePackName returns the pack name after currentPack in current MRU
-// order, or "" at end / when currentPack is not present.
-func (store *Store) nextCandidatePackName(currentPack string) string {
-	store.candidatesMu.RLock()
-	defer store.candidatesMu.RUnlock()
-
-	node := store.candidateNodeByPack[currentPack]
-	if node == nil || node.next == nil {
-		return ""
-	}
-
-	return node.next.candidate.packName
 }
--- a/objectstore/packed/idx_parse.go
+++ b/objectstore/packed/idx_parse.go
@@ -1,11 +1,8 @@
 package packed
 
 import (
-	"bytes"
 	"encoding/binary"
 	"fmt"
-
-	"codeberg.org/lindenii/furgit/objectid"
 )
 
 const (
@@ -78,86 +75,4 @@
 	}
 
 	return nil
-}
-
-// lookup resolves one object ID to its pack offset within this index.
-func (index *idxFile) lookup(id objectid.ObjectID) (uint64, bool, error) {
-	if id.Algorithm() != index.algo {
-		return 0, false, fmt.Errorf("objectstore/packed: object id algorithm mismatch")
-	}
-
-	idBytes := (&id).RawBytes()
-
-	hashSize := len(idBytes)
-	if hashSize != index.algo.Size() {
-		return 0, false, fmt.Errorf("objectstore/packed: unexpected object id length")
-	}
-
-	first := int(idBytes[0])
-
-	lo := 0
-	if first > 0 {
-		lo = int(index.fanout[first-1])
-	}
-
-	hi := int(index.fanout[first])
-	if lo < 0 || hi < 0 || lo > hi || hi > index.numObjects {
-		return 0, false, fmt.Errorf("objectstore/packed: idx %q has invalid fanout bounds", index.idxName)
-	}
-
-	for lo < hi {
-		mid := lo + (hi-lo)/2
-
-		nameOffset := index.namesOffset + mid*hashSize
-		if nameOffset < 0 || nameOffset+hashSize > len(index.data) {
-			return 0, false, fmt.Errorf("objectstore/packed: idx %q truncated name table", index.idxName)
-		}
-
-		cmp := bytes.Compare(index.data[nameOffset:nameOffset+hashSize], idBytes)
-		if cmp == 0 {
-			offset, err := index.offsetAt(mid)
-			if err != nil {
-				return 0, false, err
-			}
-
-			return offset, true, nil
-		}
-
-		if cmp < 0 {
-			lo = mid + 1
-		} else {
-			hi = mid
-		}
-	}
-
-	return 0, false, nil
-}
-
-// offsetAt resolves the pack offset for one object index entry.
-func (index *idxFile) offsetAt(objectIndex int) (uint64, error) {
-	if objectIndex < 0 || objectIndex >= index.numObjects {
-		return 0, fmt.Errorf("objectstore/packed: idx %q offset index out of bounds", index.idxName)
-	}
-
-	wordOffset := index.offset32Offset + objectIndex*4
-	if wordOffset < 0 || wordOffset+4 > len(index.data) {
-		return 0, fmt.Errorf("objectstore/packed: idx %q truncated 32-bit offset table", index.idxName)
-	}
-
-	word := binary.BigEndian.Uint32(index.data[wordOffset : wordOffset+4])
-	if word&0x80000000 == 0 {
-		return uint64(word), nil
-	}
-
-	pos := int(word & 0x7fffffff)
-	if pos < 0 || pos >= index.offset64Count {
-		return 0, fmt.Errorf("objectstore/packed: idx %q invalid 64-bit offset position", index.idxName)
-	}
-
-	offOffset := index.offset64Offset + pos*8
-	if offOffset < 0 || offOffset+8 > len(index.data)-2*index.algo.Size() {
-		return 0, fmt.Errorf("objectstore/packed: idx %q truncated 64-bit offset table", index.idxName)
-	}
-
-	return binary.BigEndian.Uint64(index.data[offOffset : offOffset+8]), nil
 }
--