aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--objectstore/packed/delta_apply.go19
-rw-r--r--objectstore/packed/delta_plan.go16
-rw-r--r--objectstore/packed/entry_parse.go6
-rw-r--r--objectstore/packed/read_header.go6
-rw-r--r--objectstore/packed/read_header_resolve.go61
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)
+ }
+ }
+}