From f31ad11ed0665bfaed90c67890a5fa951301d3f3 Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Wed, 4 Mar 2026 09:55:44 +0800 Subject: objectstore/packed: Split --- objectstore/packed/store.go | 142 ---------------------------------- objectstore/packed/store_lookup.go | 51 ++++++++++++ objectstore/packed/store_open_pack.go | 100 ++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 142 deletions(-) create mode 100644 objectstore/packed/store_lookup.go create mode 100644 objectstore/packed/store_open_pack.go (limited to 'objectstore') diff --git a/objectstore/packed/store.go b/objectstore/packed/store.go index d28113d1..7c1a2905 100644 --- a/objectstore/packed/store.go +++ b/objectstore/packed/store.go @@ -2,8 +2,6 @@ package packed import ( - "errors" - "fmt" "os" "sync" @@ -116,143 +114,3 @@ func (store *Store) Close() error { return closeErr } - -// lookup resolves one object ID to its pack location. -func (store *Store) lookup(id objectid.ObjectID) (location, error) { - var zero location - if id.Algorithm() != store.algo { - return zero, errors.New("objectstore/packed: object id algorithm mismatch") - } - - err := store.ensureCandidates() - if err != nil { - return zero, err - } - - nextPackName := store.firstCandidatePackName() - for nextPackName != "" { - candidate, ok := store.candidateForPack(nextPackName) - if !ok { - nextPackName = store.firstCandidatePackName() - - continue - } - - nextPackName = store.nextCandidatePackName(candidate.packName) - - index, err := store.openIndex(candidate) - if err != nil { - return zero, err - } - - offset, ok, err := index.lookup(id) - if err != nil { - return zero, err - } - - if ok { - store.touchCandidate(candidate.packName) - - return location{packName: index.packName, offset: offset}, nil - } - } - - return zero, objectstore.ErrObjectNotFound -} - -// openPack returns one opened and validated pack handle. -func (store *Store) openPack(name string) (*packFile, error) { - store.stateMu.RLock() - - pack, ok := store.packs[name] - if ok { - store.stateMu.RUnlock() - - return pack, nil - } - - store.stateMu.RUnlock() - - file, err := store.root.Open(name) - if err != nil { - return nil, err - } - - info, err := file.Stat() - if err != nil { - _ = file.Close() - - return nil, err - } - - pack, err = openPackFile(name, file, info.Size()) - if err != nil { - _ = file.Close() - - return nil, err - } - - err = store.verifyPackMatchesIndexes(pack) - if err != nil { - _ = pack.close() - - return nil, err - } - - store.stateMu.Lock() - - existing, ok := store.packs[name] - if ok { - store.stateMu.Unlock() - - _ = pack.close() - - return existing, nil - } - - store.packs[name] = pack - store.stateMu.Unlock() - - return pack, nil -} - -// verifyPackMatchesIndexes checks that one opened pack's trailer hash matches -// every loaded index that references the same pack name. -func (store *Store) verifyPackMatchesIndexes(pack *packFile) error { - err := store.ensureCandidates() - if err != nil { - return err - } - - candidate, ok := store.candidateForPack(pack.name) - if !ok { - return fmt.Errorf("objectstore/packed: missing index for pack %q", pack.name) - } - - index, err := store.openIndex(candidate) - if err != nil { - return err - } - - err = verifyMappedPackMatchesMappedIdx(pack.data, index.data, store.algo) - if err != nil { - return fmt.Errorf("objectstore/packed: pack %q does not match idx %q: %w", pack.name, index.idxName, err) - } - - return nil -} - -// entryMetaAt parses one pack entry header at location. -func (store *Store) entryMetaAt(loc location) (*packFile, entryMeta, error) { - pack, err := store.openPack(loc.packName) - if err != nil { - return nil, entryMeta{}, err - } - - meta, err := parseEntryMeta(pack, store.algo, loc.offset) - if err != nil { - return nil, entryMeta{}, err - } - - return pack, meta, nil -} diff --git a/objectstore/packed/store_lookup.go b/objectstore/packed/store_lookup.go new file mode 100644 index 00000000..cf5a580d --- /dev/null +++ b/objectstore/packed/store_lookup.go @@ -0,0 +1,51 @@ +package packed + +import ( + "errors" + + "codeberg.org/lindenii/furgit/objectid" + "codeberg.org/lindenii/furgit/objectstore" +) + +// lookup resolves one object ID to its pack location. +func (store *Store) lookup(id objectid.ObjectID) (location, error) { + var zero location + if id.Algorithm() != store.algo { + return zero, errors.New("objectstore/packed: object id algorithm mismatch") + } + + err := store.ensureCandidates() + if err != nil { + return zero, err + } + + nextPackName := store.firstCandidatePackName() + for nextPackName != "" { + candidate, ok := store.candidateForPack(nextPackName) + if !ok { + nextPackName = store.firstCandidatePackName() + + continue + } + + nextPackName = store.nextCandidatePackName(candidate.packName) + + index, err := store.openIndex(candidate) + if err != nil { + return zero, err + } + + offset, ok, err := index.lookup(id) + if err != nil { + return zero, err + } + + if ok { + store.touchCandidate(candidate.packName) + + return location{packName: index.packName, offset: offset}, nil + } + } + + return zero, objectstore.ErrObjectNotFound +} diff --git a/objectstore/packed/store_open_pack.go b/objectstore/packed/store_open_pack.go new file mode 100644 index 00000000..f101b624 --- /dev/null +++ b/objectstore/packed/store_open_pack.go @@ -0,0 +1,100 @@ +package packed + +import "fmt" + +// openPack returns one opened and validated pack handle. +func (store *Store) openPack(name string) (*packFile, error) { + store.stateMu.RLock() + + pack, ok := store.packs[name] + if ok { + store.stateMu.RUnlock() + + return pack, nil + } + + store.stateMu.RUnlock() + + file, err := store.root.Open(name) + if err != nil { + return nil, err + } + + info, err := file.Stat() + if err != nil { + _ = file.Close() + + return nil, err + } + + pack, err = openPackFile(name, file, info.Size()) + if err != nil { + _ = file.Close() + + return nil, err + } + + err = store.verifyPackMatchesIndexes(pack) + if err != nil { + _ = pack.close() + + return nil, err + } + + store.stateMu.Lock() + + existing, ok := store.packs[name] + if ok { + store.stateMu.Unlock() + + _ = pack.close() + + return existing, nil + } + + store.packs[name] = pack + store.stateMu.Unlock() + + return pack, nil +} + +// verifyPackMatchesIndexes checks that one opened pack's trailer hash matches +// every loaded index that references the same pack name. +func (store *Store) verifyPackMatchesIndexes(pack *packFile) error { + err := store.ensureCandidates() + if err != nil { + return err + } + + candidate, ok := store.candidateForPack(pack.name) + if !ok { + return fmt.Errorf("objectstore/packed: missing index for pack %q", pack.name) + } + + index, err := store.openIndex(candidate) + if err != nil { + return err + } + + err = verifyMappedPackMatchesMappedIdx(pack.data, index.data, store.algo) + if err != nil { + return fmt.Errorf("objectstore/packed: pack %q does not match idx %q: %w", pack.name, index.idxName, err) + } + + return nil +} + +// entryMetaAt parses one pack entry header at location. +func (store *Store) entryMetaAt(loc location) (*packFile, entryMeta, error) { + pack, err := store.openPack(loc.packName) + if err != nil { + return nil, entryMeta{}, err + } + + meta, err := parseEntryMeta(pack, store.algo, loc.offset) + if err != nil { + return nil, entryMeta{}, err + } + + return pack, meta, nil +} -- cgit v1.3.1-10-gc9f91