diff options
Diffstat (limited to 'objectstore/packed')
| -rw-r--r-- | objectstore/packed/delta_apply.go | 19 | ||||
| -rw-r--r-- | objectstore/packed/delta_plan.go | 16 | ||||
| -rw-r--r-- | objectstore/packed/entry_parse.go | 6 | ||||
| -rw-r--r-- | objectstore/packed/read_header.go | 6 | ||||
| -rw-r--r-- | objectstore/packed/read_header_resolve.go | 61 |
5 files changed, 84 insertions, 24 deletions
diff --git a/objectstore/packed/delta_apply.go b/objectstore/packed/delta_apply.go index 6d5c736d..5245e0ba 100644 --- a/objectstore/packed/delta_apply.go +++ b/objectstore/packed/delta_apply.go @@ -14,11 +14,22 @@ func (store *Store) deltaResolveContent(start location) (objecttype.Type, []byte if err != nil { return objecttype.TypeInvalid, nil, err } - return store.deltaResolveChain(chain) + 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) (objecttype.Type, []byte, error) { +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 @@ -47,11 +58,11 @@ func (store *Store) deltaResolveChain(chain deltaChain) (objecttype.Type, []byte store.cacheMu.Unlock() } - if int64(len(out)) != chain.declaredSize { + if int64(len(out)) != declaredSize { return objecttype.TypeInvalid, nil, fmt.Errorf( "objectstore/packed: resolved content size mismatch: got %d want %d", len(out), - chain.declaredSize, + declaredSize, ) } if ty != chain.baseType { diff --git a/objectstore/packed/delta_plan.go b/objectstore/packed/delta_plan.go index f1a3b9b0..05c4b714 100644 --- a/objectstore/packed/delta_plan.go +++ b/objectstore/packed/delta_plan.go @@ -18,8 +18,6 @@ type deltaNode struct { // deltaChain describes how to reconstruct one requested object. type deltaChain struct { - // declaredSize is the target object's declared content size. - declaredSize int64 // baseLoc points to the innermost base object. baseLoc location // baseType is the canonical object type resolved from baseLoc. @@ -34,7 +32,6 @@ func (store *Store) deltaBuildChain(start location) (deltaChain, error) { current := start var chain deltaChain - chain.declaredSize = -1 for { if _, ok := visited[current]; ok { @@ -42,21 +39,10 @@ func (store *Store) deltaBuildChain(start location) (deltaChain, error) { } visited[current] = struct{}{} - pack, meta, err := store.entryMetaAt(current) + _, meta, err := store.entryMetaAt(current) if err != nil { return deltaChain{}, err } - if chain.declaredSize < 0 { - if packfmt.IsBaseObjectType(meta.ty) { - chain.declaredSize = meta.size - } else { - declaredSize, err := deltaDeclaredSizeAt(pack, meta.dataOffset) - if err != nil { - return deltaChain{}, err - } - chain.declaredSize = declaredSize - } - } if packfmt.IsBaseObjectType(meta.ty) { chain.baseLoc = current diff --git a/objectstore/packed/entry_parse.go b/objectstore/packed/entry_parse.go index 69ef80e6..56287386 100644 --- a/objectstore/packed/entry_parse.go +++ b/objectstore/packed/entry_parse.go @@ -56,6 +56,12 @@ func parseEntryMeta(pack *packFile, algo objectid.Algorithm, offset uint64) (ent return zero, fmt.Errorf("objectstore/packed: pack %q has invalid ofs-delta base", pack.name) } meta.baseOfs = offset - entry.OfsBaseDistance + case objecttype.TypeCommit, objecttype.TypeTree, objecttype.TypeBlob, objecttype.TypeTag: + // Base object types do not have delta base metadata. + case objecttype.TypeInvalid, objecttype.TypeFuture: + return zero, fmt.Errorf("objectstore/packed: pack %q has unsupported entry type %d", pack.name, meta.ty) + default: + return zero, fmt.Errorf("objectstore/packed: pack %q has unsupported entry type %d", pack.name, meta.ty) } return meta, nil } diff --git a/objectstore/packed/read_header.go b/objectstore/packed/read_header.go index 63fc6d66..6822975c 100644 --- a/objectstore/packed/read_header.go +++ b/objectstore/packed/read_header.go @@ -11,9 +11,5 @@ func (store *Store) ReadHeader(id objectid.ObjectID) (objecttype.Type, int64, er if err != nil { return objecttype.TypeInvalid, 0, err } - chain, err := store.deltaBuildChain(loc) - if err != nil { - return objecttype.TypeInvalid, 0, err - } - return chain.baseType, chain.declaredSize, nil + return store.resolveHeaderAt(loc) } diff --git a/objectstore/packed/read_header_resolve.go b/objectstore/packed/read_header_resolve.go new file mode 100644 index 00000000..cf49fe2b --- /dev/null +++ b/objectstore/packed/read_header_resolve.go @@ -0,0 +1,61 @@ +package packed + +import ( + "fmt" + + packfmt "codeberg.org/lindenii/furgit/format/pack" + "codeberg.org/lindenii/furgit/objecttype" +) + +// resolveHeaderAt resolves one object's canonical type and declared content size. +func (store *Store) resolveHeaderAt(start location) (objecttype.Type, int64, error) { + visited := make(map[location]struct{}) + current := start + declaredSize := int64(-1) + + for { + if _, ok := visited[current]; ok { + return objecttype.TypeInvalid, 0, fmt.Errorf("objectstore/packed: delta cycle while resolving object header") + } + visited[current] = struct{}{} + + pack, meta, err := store.entryMetaAt(current) + if err != nil { + return objecttype.TypeInvalid, 0, err + } + if declaredSize < 0 { + if packfmt.IsBaseObjectType(meta.ty) { + declaredSize = meta.size + } else { + size, err := deltaDeclaredSizeAt(pack, meta.dataOffset) + if err != nil { + return objecttype.TypeInvalid, 0, err + } + declaredSize = size + } + } + if packfmt.IsBaseObjectType(meta.ty) { + return meta.ty, declaredSize, nil + } + + switch meta.ty { + case objecttype.TypeRefDelta: + next, err := store.lookup(meta.baseRefID) + if err != nil { + return objecttype.TypeInvalid, 0, err + } + current = next + case objecttype.TypeOfsDelta: + current = location{ + packName: current.packName, + offset: meta.baseOfs, + } + case objecttype.TypeCommit, objecttype.TypeTree, objecttype.TypeBlob, objecttype.TypeTag: + return objecttype.TypeInvalid, 0, fmt.Errorf("objectstore/packed: internal invariant violation for base type %d", meta.ty) + case objecttype.TypeInvalid, objecttype.TypeFuture: + return objecttype.TypeInvalid, 0, fmt.Errorf("objectstore/packed: unsupported pack type %d", meta.ty) + default: + return objecttype.TypeInvalid, 0, fmt.Errorf("objectstore/packed: unsupported pack type %d", meta.ty) + } + } +} |
