diff options
23 files changed, 416 insertions, 369 deletions
diff --git a/objectstore/packed/close.go b/objectstore/packed/close.go new file mode 100644 index 00000000..2bb98232 --- /dev/null +++ b/objectstore/packed/close.go @@ -0,0 +1,47 @@ +package packed + +// Close releases mapped pack/index resources associated with the store. +func (store *Store) Close() error { + store.stateMu.Lock() + + if store.closed { + store.stateMu.Unlock() + + return nil + } + + store.closed = true + root := store.root + packs := store.packs + store.stateMu.Unlock() + store.idxMu.RLock() + indexes := store.idxByPack + store.idxMu.RUnlock() + + var closeErr error + + for _, pack := range packs { + err := pack.close() + if err != nil && closeErr == nil { + closeErr = err + } + } + + for _, index := range indexes { + err := index.close() + if err != nil && closeErr == nil { + closeErr = err + } + } + + store.cacheMu.Lock() + store.deltaCache.clear() + store.cacheMu.Unlock() + + err := root.Close() + if err != nil && closeErr == nil { + closeErr = err + } + + return closeErr +} diff --git a/objectstore/packed/delta_apply.go b/objectstore/packed/delta_apply.go deleted file mode 100644 index 71f09ead..00000000 --- a/objectstore/packed/delta_apply.go +++ /dev/null @@ -1,136 +0,0 @@ -package packed - -import ( - "fmt" - - deltaapply "codeberg.org/lindenii/furgit/format/delta/apply" - packfmt "codeberg.org/lindenii/furgit/format/pack" - "codeberg.org/lindenii/furgit/objecttype" -) - -// deltaResolveContent resolves one object's content bytes from its pack location. -func (store *Store) deltaResolveContent(start location) (objecttype.Type, []byte, error) { - chain, err := store.deltaBuildChain(start) - if err != nil { - return objecttype.TypeInvalid, nil, err - } - - pack, meta, err := store.entryMetaAt(start) - if err != nil { - return objecttype.TypeInvalid, nil, err - } - - declaredSize := meta.size - if !packfmt.IsBaseObjectType(meta.ty) { - declaredSize, err = deltaDeclaredSizeAt(pack, meta.dataOffset) - if err != nil { - return objecttype.TypeInvalid, nil, err - } - } - - return store.deltaResolveChain(chain, declaredSize) -} - -// deltaResolveChain resolves one object chain into content bytes. -func (store *Store) deltaResolveChain(chain deltaChain, declaredSize int64) (objecttype.Type, []byte, error) { - ty, out, nextDelta, err := store.deltaResolveChainStart(chain) - if err != nil { - return objecttype.TypeInvalid, nil, err - } - - for i := nextDelta; i >= 0; i-- { - node := chain.deltas[i] - - pack, err := store.openPack(node.loc.packName) - if err != nil { - return objecttype.TypeInvalid, nil, err - } - - delta, err := inflateAt(pack, node.dataOffset, -1) - if err != nil { - return objecttype.TypeInvalid, nil, err - } - - out, err = deltaapply.Apply(out, delta) - if err != nil { - return objecttype.TypeInvalid, nil, err - } - - store.cacheMu.Lock() - store.deltaCache.add( - deltaBaseKey{packName: node.loc.packName, offset: node.loc.offset}, - ty, - out, - ) - store.cacheMu.Unlock() - } - - if int64(len(out)) != declaredSize { - return objecttype.TypeInvalid, nil, fmt.Errorf( - "objectstore/packed: resolved content size mismatch: got %d want %d", - len(out), - declaredSize, - ) - } - - if ty != chain.baseType { - return objecttype.TypeInvalid, nil, fmt.Errorf( - "objectstore/packed: resolved content type mismatch: got %d want %d", - ty, - chain.baseType, - ) - } - - return ty, out, nil -} - -// deltaResolveChainStart finds the nearest cached chain node or inflates the -// innermost base object. It returns the starting bytes and the next delta index -// to apply in reverse order. -func (store *Store) deltaResolveChainStart(chain deltaChain) (objecttype.Type, []byte, int, error) { - for i, node := range chain.deltas { - store.cacheMu.RLock() - ty, out, ok := store.deltaCache.get( - deltaBaseKey{packName: node.loc.packName, offset: node.loc.offset}, - ) - store.cacheMu.RUnlock() - - if ok { - return ty, out, i - 1, nil - } - } - - store.cacheMu.RLock() - ty, out, ok := store.deltaCache.get( - deltaBaseKey{packName: chain.baseLoc.packName, offset: chain.baseLoc.offset}, - ) - store.cacheMu.RUnlock() - - if ok { - return ty, out, len(chain.deltas) - 1, nil - } - - pack, meta, err := store.entryMetaAt(chain.baseLoc) - if err != nil { - return objecttype.TypeInvalid, nil, 0, err - } - - if !packfmt.IsBaseObjectType(meta.ty) { - return objecttype.TypeInvalid, nil, 0, fmt.Errorf("objectstore/packed: delta chain base is not a base object") - } - - base, err := inflateAt(pack, meta.dataOffset, meta.size) - if err != nil { - return objecttype.TypeInvalid, nil, 0, err - } - - store.cacheMu.Lock() - store.deltaCache.add( - deltaBaseKey{packName: chain.baseLoc.packName, offset: chain.baseLoc.offset}, - meta.ty, - base, - ) - store.cacheMu.Unlock() - - return meta.ty, base, len(chain.deltas) - 1, nil -} diff --git a/objectstore/packed/delta_plan.go b/objectstore/packed/delta_build_chain.go index b0b0324c..7a5f3c16 100644 --- a/objectstore/packed/delta_plan.go +++ b/objectstore/packed/delta_build_chain.go @@ -1,32 +1,12 @@ package packed import ( - "bufio" "fmt" - deltaapply "codeberg.org/lindenii/furgit/format/delta/apply" packfmt "codeberg.org/lindenii/furgit/format/pack" "codeberg.org/lindenii/furgit/objecttype" ) -// deltaNode describes one delta object in a reconstruction chain. -type deltaNode struct { - // loc identifies the delta object's pack location. - loc location - // dataOffset points to the start of the delta zlib payload in pack. - dataOffset int -} - -// deltaChain describes how to reconstruct one requested object. -type deltaChain struct { - // baseLoc points to the innermost base object. - baseLoc location - // baseType is the canonical object type resolved from baseLoc. - baseType objecttype.Type - // deltas contains delta objects from target down toward base. - deltas []deltaNode -} - // deltaBuildChain walks one object's chain and builds a reconstruction chain. func (store *Store) deltaBuildChain(start location) (deltaChain, error) { visited := make(map[location]struct{}) @@ -84,23 +64,3 @@ func (store *Store) deltaBuildChain(start location) (deltaChain, error) { } } } - -// deltaDeclaredSizeAt returns the resolved object size declared by one delta -// stream header at dataOffset. -func deltaDeclaredSizeAt(pack *packFile, dataOffset int) (int64, error) { - reader, err := zlibReaderAt(pack, dataOffset) - if err != nil { - return 0, err - } - - defer func() { _ = reader.Close() }() - - br := bufio.NewReaderSize(reader, 32) - - _, size, err := deltaapply.ReadHeaderSizes(br) - if err != nil { - return 0, err - } - - return int64(size), nil -} diff --git a/objectstore/packed/delta_cache.go b/objectstore/packed/delta_cache.go index a911b254..08040620 100644 --- a/objectstore/packed/delta_cache.go +++ b/objectstore/packed/delta_cache.go @@ -5,6 +5,8 @@ import ( "codeberg.org/lindenii/furgit/objecttype" ) +const defaultDeltaCacheMaxBytes = 32 << 20 + // deltaBaseKey identifies one base object by pack location. type deltaBaseKey struct { packName string diff --git a/objectstore/packed/delta_chain.go b/objectstore/packed/delta_chain.go new file mode 100644 index 00000000..d473a25c --- /dev/null +++ b/objectstore/packed/delta_chain.go @@ -0,0 +1,13 @@ +package packed + +import "codeberg.org/lindenii/furgit/objecttype" + +// deltaChain describes how to reconstruct one requested object. +type deltaChain struct { + // baseLoc points to the innermost base object. + baseLoc location + // baseType is the canonical object type resolved from baseLoc. + baseType objecttype.Type + // deltas contains delta objects from target down toward base. + deltas []deltaNode +} diff --git a/objectstore/packed/delta_node.go b/objectstore/packed/delta_node.go new file mode 100644 index 00000000..24ede1e0 --- /dev/null +++ b/objectstore/packed/delta_node.go @@ -0,0 +1,9 @@ +package packed + +// deltaNode describes one delta object in a reconstruction chain. +type deltaNode struct { + // loc identifies the delta object's pack location. + loc location + // dataOffset points to the start of the delta zlib payload in pack. + dataOffset int +} diff --git a/objectstore/packed/delta_resolve_chain.go b/objectstore/packed/delta_resolve_chain.go new file mode 100644 index 00000000..e12bda88 --- /dev/null +++ b/objectstore/packed/delta_resolve_chain.go @@ -0,0 +1,61 @@ +package packed + +import ( + "fmt" + + deltaapply "codeberg.org/lindenii/furgit/format/delta/apply" + "codeberg.org/lindenii/furgit/objecttype" +) + +// deltaResolveChain resolves one object chain into content bytes. +func (store *Store) deltaResolveChain(chain deltaChain, declaredSize int64) (objecttype.Type, []byte, error) { + ty, out, nextDelta, err := store.deltaResolveChainStart(chain) + if err != nil { + return objecttype.TypeInvalid, nil, err + } + + for i := nextDelta; i >= 0; i-- { + node := chain.deltas[i] + + pack, err := store.openPack(node.loc.packName) + if err != nil { + return objecttype.TypeInvalid, nil, err + } + + delta, err := inflateAt(pack, node.dataOffset, -1) + if err != nil { + return objecttype.TypeInvalid, nil, err + } + + out, err = deltaapply.Apply(out, delta) + if err != nil { + return objecttype.TypeInvalid, nil, err + } + + store.cacheMu.Lock() + store.deltaCache.add( + deltaBaseKey{packName: node.loc.packName, offset: node.loc.offset}, + ty, + out, + ) + store.cacheMu.Unlock() + } + + if int64(len(out)) != declaredSize { + return objecttype.TypeInvalid, nil, fmt.Errorf( + "objectstore/packed: resolved content size mismatch: got %d want %d", + len(out), + declaredSize, + ) + } + + if ty != chain.baseType { + return objecttype.TypeInvalid, nil, fmt.Errorf( + "objectstore/packed: resolved content type mismatch: got %d want %d", + ty, + chain.baseType, + ) + } + + return ty, out, nil +} diff --git a/objectstore/packed/delta_resolve_chain_start.go b/objectstore/packed/delta_resolve_chain_start.go new file mode 100644 index 00000000..70266565 --- /dev/null +++ b/objectstore/packed/delta_resolve_chain_start.go @@ -0,0 +1,59 @@ +package packed + +import ( + "fmt" + + packfmt "codeberg.org/lindenii/furgit/format/pack" + "codeberg.org/lindenii/furgit/objecttype" +) + +// deltaResolveChainStart finds the nearest cached chain node or inflates the +// innermost base object. It returns the starting bytes and the next delta index +// to apply in reverse order. +func (store *Store) deltaResolveChainStart(chain deltaChain) (objecttype.Type, []byte, int, error) { + for i, node := range chain.deltas { + store.cacheMu.RLock() + ty, out, ok := store.deltaCache.get( + deltaBaseKey{packName: node.loc.packName, offset: node.loc.offset}, + ) + store.cacheMu.RUnlock() + + if ok { + return ty, out, i - 1, nil + } + } + + store.cacheMu.RLock() + ty, out, ok := store.deltaCache.get( + deltaBaseKey{packName: chain.baseLoc.packName, offset: chain.baseLoc.offset}, + ) + store.cacheMu.RUnlock() + + if ok { + return ty, out, len(chain.deltas) - 1, nil + } + + pack, meta, err := store.entryMetaAt(chain.baseLoc) + if err != nil { + return objecttype.TypeInvalid, nil, 0, err + } + + if !packfmt.IsBaseObjectType(meta.ty) { + return objecttype.TypeInvalid, nil, 0, fmt.Errorf("objectstore/packed: delta chain base is not a base object") + } + + base, err := inflateAt(pack, meta.dataOffset, meta.size) + if err != nil { + return objecttype.TypeInvalid, nil, 0, err + } + + store.cacheMu.Lock() + store.deltaCache.add( + deltaBaseKey{packName: chain.baseLoc.packName, offset: chain.baseLoc.offset}, + meta.ty, + base, + ) + store.cacheMu.Unlock() + + return meta.ty, base, len(chain.deltas) - 1, nil +} diff --git a/objectstore/packed/delta_resolve_content.go b/objectstore/packed/delta_resolve_content.go new file mode 100644 index 00000000..a8de9cbc --- /dev/null +++ b/objectstore/packed/delta_resolve_content.go @@ -0,0 +1,29 @@ +package packed + +import ( + packfmt "codeberg.org/lindenii/furgit/format/pack" + "codeberg.org/lindenii/furgit/objecttype" +) + +// deltaResolveContent resolves one object's content bytes from its pack location. +func (store *Store) deltaResolveContent(start location) (objecttype.Type, []byte, error) { + chain, err := store.deltaBuildChain(start) + if err != nil { + return objecttype.TypeInvalid, nil, err + } + + pack, meta, err := store.entryMetaAt(start) + if err != nil { + return objecttype.TypeInvalid, nil, err + } + + declaredSize := meta.size + if !packfmt.IsBaseObjectType(meta.ty) { + declaredSize, err = deltaDeclaredSizeAt(pack, meta.dataOffset) + if err != nil { + return objecttype.TypeInvalid, nil, err + } + } + + return store.deltaResolveChain(chain, declaredSize) +} diff --git a/objectstore/packed/delta_size.go b/objectstore/packed/delta_size.go new file mode 100644 index 00000000..ca0ccb25 --- /dev/null +++ b/objectstore/packed/delta_size.go @@ -0,0 +1,27 @@ +package packed + +import ( + "bufio" + + deltaapply "codeberg.org/lindenii/furgit/format/delta/apply" +) + +// deltaDeclaredSizeAt returns the resolved object size declared by one delta +// stream header at dataOffset. +func deltaDeclaredSizeAt(pack *packFile, dataOffset int) (int64, error) { + reader, err := zlibReaderAt(pack, dataOffset) + if err != nil { + return 0, err + } + + defer func() { _ = reader.Close() }() + + br := bufio.NewReaderSize(reader, 32) + + _, size, err := deltaapply.ReadHeaderSizes(br) + if err != nil { + return 0, err + } + + return int64(size), nil +} diff --git a/objectstore/packed/entry_meta.go b/objectstore/packed/entry_meta.go new file mode 100644 index 00000000..0bbe8bef --- /dev/null +++ b/objectstore/packed/entry_meta.go @@ -0,0 +1,16 @@ +package packed + +// 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/idx.go b/objectstore/packed/idx.go new file mode 100644 index 00000000..db6a0136 --- /dev/null +++ b/objectstore/packed/idx.go @@ -0,0 +1,36 @@ +package packed + +import ( + "os" + + "codeberg.org/lindenii/furgit/objectid" +) + +// idxFile stores one mapped and validated idx v2 file. +type idxFile struct { + // idxName is the basename of this .idx file. + idxName string + // packName is the matching .pack basename. + packName string + // algo is the hash algorithm encoded by the index. + algo objectid.Algorithm + + // file is the opened index file descriptor. + file *os.File + // data is the mapped index bytes. + data []byte + + // fanout stores fanout table values. + fanout [256]uint32 + // numObjects equals fanout[255]. + numObjects int + + // namesOffset starts the sorted object-id table. + namesOffset int + // offset32Offset starts the 32-bit offset table. + offset32Offset int + // offset64Offset starts the 64-bit offset table. + offset64Offset int + // offset64Count is the number of 64-bit offset entries. + offset64Count int +} diff --git a/objectstore/packed/idx_candidate.go b/objectstore/packed/idx_candidate.go new file mode 100644 index 00000000..2f2ad7a9 --- /dev/null +++ b/objectstore/packed/idx_candidate.go @@ -0,0 +1,10 @@ +package packed + +// candidateForPack returns one discovered candidate for a pack basename. +func (store *Store) candidateForPack(packName string) (packCandidate, bool) { + store.candidatesMu.RLock() + candidate, ok := store.candidateByPack[packName] + store.candidatesMu.RUnlock() + + return candidate, ok +} diff --git a/objectstore/packed/idx_close.go b/objectstore/packed/idx_close.go new file mode 100644 index 00000000..814ec987 --- /dev/null +++ b/objectstore/packed/idx_close.go @@ -0,0 +1,28 @@ +package packed + +import "syscall" + +// close unmaps and closes one idx handle. +func (index *idxFile) close() error { + var closeErr error + + if index.data != nil { + err := syscall.Munmap(index.data) + if err != nil && closeErr == nil { + closeErr = err + } + + index.data = nil + } + + if index.file != nil { + err := index.file.Close() + if err != nil && closeErr == nil { + closeErr = err + } + + index.file = nil + } + + return closeErr +} diff --git a/objectstore/packed/idx_lookup_candidates.go b/objectstore/packed/idx_lookup_candidates.go index 508da2ef..9534476a 100644 --- a/objectstore/packed/idx_lookup_candidates.go +++ b/objectstore/packed/idx_lookup_candidates.go @@ -7,12 +7,6 @@ import ( "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. diff --git a/objectstore/packed/idx_open.go b/objectstore/packed/idx_open.go index c3c97e4d..9eb92682 100644 --- a/objectstore/packed/idx_open.go +++ b/objectstore/packed/idx_open.go @@ -9,44 +9,6 @@ import ( "codeberg.org/lindenii/furgit/objectid" ) -// idxFile stores one mapped and validated idx v2 file. -type idxFile struct { - // idxName is the basename of this .idx file. - idxName string - // packName is the matching .pack basename. - packName string - // algo is the hash algorithm encoded by the index. - algo objectid.Algorithm - - // file is the opened index file descriptor. - file *os.File - // data is the mapped index bytes. - data []byte - - // fanout stores fanout table values. - fanout [256]uint32 - // numObjects equals fanout[255]. - numObjects int - - // namesOffset starts the sorted object-id table. - namesOffset int - // offset32Offset starts the 32-bit offset table. - offset32Offset int - // offset64Offset starts the 64-bit offset table. - offset64Offset int - // offset64Count is the number of 64-bit offset entries. - offset64Count int -} - -// candidateForPack returns one discovered candidate for a pack basename. -func (store *Store) candidateForPack(packName string) (packCandidate, bool) { - store.candidatesMu.RLock() - candidate, ok := store.candidateByPack[packName] - store.candidatesMu.RUnlock() - - return candidate, ok -} - // openIndex returns one opened and parsed index, caching it by pack basename. func (store *Store) openIndex(candidate packCandidate) (*idxFile, error) { store.idxMu.RLock() @@ -134,28 +96,3 @@ func openIdxFile(root *os.Root, idxName, packName string, algo objectid.Algorith return index, nil } - -// close unmaps and closes one idx handle. -func (index *idxFile) close() error { - var closeErr error - - if index.data != nil { - err := syscall.Munmap(index.data) - if err != nil && closeErr == nil { - closeErr = err - } - - index.data = nil - } - - if index.file != nil { - err := index.file.Close() - if err != nil && closeErr == nil { - closeErr = err - } - - index.file = nil - } - - return closeErr -} diff --git a/objectstore/packed/location.go b/objectstore/packed/location.go new file mode 100644 index 00000000..82d17c17 --- /dev/null +++ b/objectstore/packed/location.go @@ -0,0 +1,7 @@ +package packed + +// location identifies one object entry in a specific pack file. +type location struct { + packName string + offset uint64 +} diff --git a/objectstore/packed/new.go b/objectstore/packed/new.go new file mode 100644 index 00000000..407bc1d0 --- /dev/null +++ b/objectstore/packed/new.go @@ -0,0 +1,24 @@ +package packed + +import ( + "os" + + "codeberg.org/lindenii/furgit/objectid" +) + +// New creates a packed-object store rooted at an objects/pack directory. +func New(root *os.Root, algo objectid.Algorithm) (*Store, error) { + if algo.Size() == 0 { + return nil, objectid.ErrInvalidAlgorithm + } + + return &Store{ + root: root, + algo: algo, + candidateByPack: make(map[string]packCandidate), + candidateNodeByPack: make(map[string]*packCandidateNode), + idxByPack: make(map[string]*idxFile), + packs: make(map[string]*packFile), + deltaCache: newDeltaCache(defaultDeltaCacheMaxBytes), + }, nil +} diff --git a/objectstore/packed/read_closer.go b/objectstore/packed/read_closer.go new file mode 100644 index 00000000..c317d002 --- /dev/null +++ b/objectstore/packed/read_closer.go @@ -0,0 +1,19 @@ +package packed + +import "io" + +// readCloser proxies reads and closes one underlying closer. +type readCloser struct { + reader io.Reader + closer io.Closer +} + +// Read proxies reads to the underlying reader. +func (reader *readCloser) Read(dst []byte) (int, error) { + return reader.reader.Read(dst) +} + +// Close closes the underlying closer. +func (reader *readCloser) Close() error { + return reader.closer.Close() +} diff --git a/objectstore/packed/read_reader.go b/objectstore/packed/read_reader.go index d8dfdca9..d5a94482 100644 --- a/objectstore/packed/read_reader.go +++ b/objectstore/packed/read_reader.go @@ -12,22 +12,6 @@ import ( "codeberg.org/lindenii/furgit/objecttype" ) -// readCloser proxies reads and closes one underlying closer. -type readCloser struct { - reader io.Reader - closer io.Closer -} - -// Read proxies reads to the underlying reader. -func (reader *readCloser) Read(dst []byte) (int, error) { - return reader.reader.Read(dst) -} - -// Close closes the underlying closer. -func (reader *readCloser) Close() error { - return reader.closer.Close() -} - // ReadReaderContent reads an object's type, declared content size, and content stream. // // The caller must close the returned reader. diff --git a/objectstore/packed/store.go b/objectstore/packed/store.go index 2da48dff..000e04f2 100644 --- a/objectstore/packed/store.go +++ b/objectstore/packed/store.go @@ -49,69 +49,4 @@ type Store struct { closed bool } -const defaultDeltaCacheMaxBytes = 32 << 20 - var _ objectstore.Store = (*Store)(nil) - -// New creates a packed-object store rooted at an objects/pack directory. -func New(root *os.Root, algo objectid.Algorithm) (*Store, error) { - if algo.Size() == 0 { - return nil, objectid.ErrInvalidAlgorithm - } - - return &Store{ - root: root, - algo: algo, - candidateByPack: make(map[string]packCandidate), - candidateNodeByPack: make(map[string]*packCandidateNode), - idxByPack: make(map[string]*idxFile), - packs: make(map[string]*packFile), - deltaCache: newDeltaCache(defaultDeltaCacheMaxBytes), - }, nil -} - -// Close releases mapped pack/index resources associated with the store. -func (store *Store) Close() error { - store.stateMu.Lock() - - if store.closed { - store.stateMu.Unlock() - - return nil - } - - store.closed = true - root := store.root - packs := store.packs - store.stateMu.Unlock() - store.idxMu.RLock() - indexes := store.idxByPack - store.idxMu.RUnlock() - - var closeErr error - - for _, pack := range packs { - err := pack.close() - if err != nil && closeErr == nil { - closeErr = err - } - } - - for _, index := range indexes { - err := index.close() - if err != nil && closeErr == nil { - closeErr = err - } - } - - store.cacheMu.Lock() - store.deltaCache.clear() - store.cacheMu.Unlock() - - err := root.Close() - if err != nil && closeErr == nil { - closeErr = err - } - - return closeErr -} diff --git a/objectstore/packed/store_open_pack.go b/objectstore/packed/store_open_pack.go index f101b624..c621e08c 100644 --- a/objectstore/packed/store_open_pack.go +++ b/objectstore/packed/store_open_pack.go @@ -1,7 +1,5 @@ package packed -import "fmt" - // openPack returns one opened and validated pack handle. func (store *Store) openPack(name string) (*packFile, error) { store.stateMu.RLock() @@ -57,44 +55,3 @@ func (store *Store) openPack(name string) (*packFile, error) { 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/trailer_match.go b/objectstore/packed/trailer_match.go new file mode 100644 index 00000000..25337cd7 --- /dev/null +++ b/objectstore/packed/trailer_match.go @@ -0,0 +1,29 @@ +package packed + +import "fmt" + +// 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 +} |
