diff options
| author | 2026-02-21 19:44:12 +0800 | |
|---|---|---|
| committer | 2026-02-21 19:44:12 +0800 | |
| commit | 0a4686c132052d9b01ac5d438c6a46e7b4fe22e5 (patch) | |
| tree | 8d344297d337c09d84923895899d8616f509d23d /objectstore/packed | |
| parent | objectstore/packed: Lazily parse idx metadata (diff) | |
| signature | No signature | |
objectstore/packed: Separate idx candidate lookup vs actually opening it
Diffstat (limited to 'objectstore/packed')
| -rw-r--r-- | objectstore/packed/idx_lookup_candidates.go | 116 | ||||
| -rw-r--r-- | objectstore/packed/idx_open.go (renamed from objectstore/packed/idx_load.go) | 110 |
2 files changed, 116 insertions, 110 deletions
diff --git a/objectstore/packed/idx_lookup_candidates.go b/objectstore/packed/idx_lookup_candidates.go new file mode 100644 index 00000000..95323238 --- /dev/null +++ b/objectstore/packed/idx_lookup_candidates.go @@ -0,0 +1,116 @@ +package packed + +import ( + "fmt" + "os" + "slices" + "strings" +) + +// location identifies one object entry in a specific pack file. +type location struct { + packName string + offset uint64 +} + +// packCandidate describes one discovered pack/index pair. +type packCandidate struct { + // packName is the .pack basename. + packName string + // idxName is the .idx basename. + idxName string + // mtime is the pack file modification time for initial ordering. + mtime int64 +} + +// ensureCandidates discovers pack/index pairs once. +func (store *Store) ensureCandidates() error { + store.discoverOnce.Do(func() { + candidates, err := store.discoverCandidates() + candidateByPack := make(map[string]packCandidate, len(candidates)) + for _, candidate := range candidates { + candidateByPack[candidate.packName] = candidate + } + store.stateMu.Lock() + store.candidates = candidates + store.candidateByPack = candidateByPack + store.discoverErr = err + store.stateMu.Unlock() + }) + + store.stateMu.RLock() + err := store.discoverErr + store.stateMu.RUnlock() + return err +} + +// discoverCandidates scans the objects/pack root and returns sorted pack/index +// pairs. +func (store *Store) discoverCandidates() ([]packCandidate, error) { + dir, err := store.root.Open(".") + if err != nil { + if os.IsNotExist(err) { + return nil, nil + } + return nil, err + } + defer func() { _ = dir.Close() }() + + entries, err := dir.ReadDir(-1) + if err != nil { + return nil, err + } + + candidates := make([]packCandidate, 0, len(entries)) + for _, entry := range entries { + if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".idx") { + continue + } + + idxName := entry.Name() + packName := strings.TrimSuffix(idxName, ".idx") + ".pack" + packInfo, err := store.root.Stat(packName) + if err != nil { + if os.IsNotExist(err) { + return nil, fmt.Errorf("objectstore/packed: missing pack file for index %q", idxName) + } + return nil, err + } + + candidates = append(candidates, packCandidate{ + packName: packName, + idxName: idxName, + mtime: packInfo.ModTime().UnixNano(), + }) + } + + slices.SortFunc(candidates, func(a, b packCandidate) int { + if a.mtime != b.mtime { + if a.mtime > b.mtime { + return -1 + } + return 1 + } + return strings.Compare(a.packName, b.packName) + }) + + return candidates, nil +} + +// touchCandidate moves one candidate to the front of the lookup order. +func (store *Store) touchCandidate(packName string) { + store.stateMu.Lock() + defer store.stateMu.Unlock() + for i := range store.candidates { + if store.candidates[i].packName != packName { + continue + } + if i == 0 { + return + } + candidate := store.candidates[i] + copy(store.candidates[1:i+1], store.candidates[0:i]) + store.candidates[0] = candidate + return + } +} diff --git a/objectstore/packed/idx_load.go b/objectstore/packed/idx_open.go index 35e8b925..45f0f83d 100644 --- a/objectstore/packed/idx_load.go +++ b/objectstore/packed/idx_open.go @@ -3,30 +3,12 @@ package packed import ( "fmt" "os" - "slices" - "strings" "syscall" "codeberg.org/lindenii/furgit/internal/intconv" "codeberg.org/lindenii/furgit/objectid" ) -// location identifies one object entry in a specific pack file. -type location struct { - packName string - offset uint64 -} - -// packCandidate describes one discovered pack/index pair. -type packCandidate struct { - // packName is the .pack basename. - packName string - // idxName is the .idx basename. - idxName string - // mtime is the pack file modification time for initial ordering. - mtime int64 -} - // idxFile stores one mapped and validated idx v2 file. type idxFile struct { // idxName is the basename of this .idx file. @@ -56,80 +38,6 @@ type idxFile struct { offset64Count int } -// ensureCandidates discovers pack/index pairs once. -func (store *Store) ensureCandidates() error { - store.discoverOnce.Do(func() { - candidates, err := store.discoverCandidates() - candidateByPack := make(map[string]packCandidate, len(candidates)) - for _, candidate := range candidates { - candidateByPack[candidate.packName] = candidate - } - store.stateMu.Lock() - store.candidates = candidates - store.candidateByPack = candidateByPack - store.discoverErr = err - store.stateMu.Unlock() - }) - - store.stateMu.RLock() - err := store.discoverErr - store.stateMu.RUnlock() - return err -} - -// discoverCandidates scans the objects/pack root and returns sorted pack/index -// pairs. -func (store *Store) discoverCandidates() ([]packCandidate, error) { - dir, err := store.root.Open(".") - if err != nil { - if os.IsNotExist(err) { - return nil, nil - } - return nil, err - } - defer func() { _ = dir.Close() }() - - entries, err := dir.ReadDir(-1) - if err != nil { - return nil, err - } - - candidates := make([]packCandidate, 0, len(entries)) - for _, entry := range entries { - if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".idx") { - continue - } - - idxName := entry.Name() - packName := strings.TrimSuffix(idxName, ".idx") + ".pack" - packInfo, err := store.root.Stat(packName) - if err != nil { - if os.IsNotExist(err) { - return nil, fmt.Errorf("objectstore/packed: missing pack file for index %q", idxName) - } - return nil, err - } - - candidates = append(candidates, packCandidate{ - packName: packName, - idxName: idxName, - mtime: packInfo.ModTime().UnixNano(), - }) - } - - slices.SortFunc(candidates, func(a, b packCandidate) int { - if a.mtime != b.mtime { - if a.mtime > b.mtime { - return -1 - } - return 1 - } - return strings.Compare(a.packName, b.packName) - }) - - return candidates, nil -} - // candidateForPack returns one discovered candidate for a pack basename. func (store *Store) candidateForPack(packName string) (packCandidate, bool) { store.stateMu.RLock() @@ -163,24 +71,6 @@ func (store *Store) openIndex(candidate packCandidate) (*idxFile, error) { return index, nil } -// touchCandidate moves one candidate to the front of the lookup order. -func (store *Store) touchCandidate(packName string) { - store.stateMu.Lock() - defer store.stateMu.Unlock() - for i := range store.candidates { - if store.candidates[i].packName != packName { - continue - } - if i == 0 { - return - } - candidate := store.candidates[i] - copy(store.candidates[1:i+1], store.candidates[0:i]) - store.candidates[0] = candidate - return - } -} - // openIdxFile maps and validates one idx v2 file. func openIdxFile(root *os.Root, idxName, packName string, algo objectid.Algorithm) (*idxFile, error) { file, err := root.Open(idxName) |
