aboutsummaryrefslogtreecommitdiff
path: root/object
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-06-12 13:57:04 +0000
committerGravatar Runxi Yu2026-06-12 13:59:00 +0000
commitda64f6e61cbd30c82042b0c23118faceba512751 (patch)
tree16b45db2545d246913e69329280a4540d31915c5 /object
parentobject/store/packed: Basic reading functionality (diff)
object/store/internal/digest: Add docs, errors, record, result
Committing as I re-review
Diffstat (limited to 'object')
-rw-r--r--object/store/packed/internal/ingest/doc.go11
-rw-r--r--object/store/packed/internal/ingest/errors.go36
-rw-r--r--object/store/packed/internal/ingest/record.go55
-rw-r--r--object/store/packed/internal/ingest/result.go26
4 files changed, 128 insertions, 0 deletions
diff --git a/object/store/packed/internal/ingest/doc.go b/object/store/packed/internal/ingest/doc.go
new file mode 100644
index 00000000..67be037b
--- /dev/null
+++ b/object/store/packed/internal/ingest/doc.go
@@ -0,0 +1,11 @@
+// Package ingest writes one incoming pack stream
+// into an objects/pack directory
+// as a finalized pack, index, and reverse index.
+//
+// WritePack streams the pack to a temporary file
+// while scanning its entries,
+// resolves every delta against in-pack bases,
+// optionally completes thin packs from an external base reader,
+// and publishes the artifacts under content-addressed names
+// derived from the pack trailer hash.
+package ingest
diff --git a/object/store/packed/internal/ingest/errors.go b/object/store/packed/internal/ingest/errors.go
new file mode 100644
index 00000000..e268182e
--- /dev/null
+++ b/object/store/packed/internal/ingest/errors.go
@@ -0,0 +1,36 @@
+package ingest
+
+import (
+ "errors"
+ "fmt"
+
+ "lindenii.org/go/furgit/object/id"
+)
+
+// ErrMalformedPack reports that
+// the incoming pack stream is truncated,
+// inconsistent, or otherwise unparseable.
+var ErrMalformedPack = errors.New("object/store/packed/internal/ingest: malformed pack")
+
+// ErrThinPackNotPermitted reports that
+// the incoming pack is thin,
+// referencing bases not contained within it,
+// but no external base reader was supplied to complete it.
+var ErrThinPackNotPermitted = errors.New("object/store/packed/internal/ingest: thin pack not permitted: no thin base supplied")
+
+// ThinBasesMissingError reports that
+// an incoming thin pack references base objects
+// that the supplied thin base reader does not contain,
+// so the pack cannot be completed.
+type ThinBasesMissingError struct {
+ // OIDs holds the missing base object IDs, sorted.
+ OIDs []id.ObjectID
+}
+
+// Error implements error.
+func (e *ThinBasesMissingError) Error() string {
+ return fmt.Sprintf(
+ "object/store/packed/internal/ingest: thin pack references %d missing base objects",
+ len(e.OIDs),
+ )
+}
diff --git a/object/store/packed/internal/ingest/record.go b/object/store/packed/internal/ingest/record.go
new file mode 100644
index 00000000..460365fd
--- /dev/null
+++ b/object/store/packed/internal/ingest/record.go
@@ -0,0 +1,55 @@
+package ingest
+
+import (
+ "lindenii.org/go/furgit/internal/format/packfile"
+ "lindenii.org/go/furgit/object/id"
+)
+
+// record is the scanned metadata for one packed entry,
+// completed in place as deltas are resolved.
+//
+// Records are appended in pack-offset order,
+// so a record's index in the slice is also its pack order.
+type record struct {
+ // offset is the entry's start offset in the pack.
+ offset uint64
+
+ // headerLen is the entry header length in bytes,
+ // so the zlib payload begins at offset+headerLen.
+ headerLen uint64
+
+ // packedLen is the total on-disk entry length in bytes,
+ // covering the header and the compressed payload.
+ packedLen uint64
+
+ // crc32 is the CRC32 of the entry's packed bytes.
+ crc32 uint32
+
+ // packedType is the entry type as encoded in the pack.
+ packedType packfile.EntryType
+
+ // declaredSize is the declared inflated payload size.
+ declaredSize uint64
+
+ // baseOffset is the base entry offset for an ofs-delta.
+ baseOffset uint64
+
+ // baseOID is the base object ID for a ref-delta.
+ baseOID id.ObjectID
+
+ // objectType is the resolved object type,
+ // meaningful once resolved is true.
+ objectType packfile.EntryType
+
+ // oid is the resolved object ID,
+ // meaningful once resolved is true.
+ oid id.ObjectID
+
+ // resolved reports whether oid and objectType are final.
+ resolved bool
+}
+
+// dataOffset returns the entry's compressed payload start offset.
+func (record *record) dataOffset() uint64 {
+ return record.offset + record.headerLen
+}
diff --git a/object/store/packed/internal/ingest/result.go b/object/store/packed/internal/ingest/result.go
new file mode 100644
index 00000000..0ae5593a
--- /dev/null
+++ b/object/store/packed/internal/ingest/result.go
@@ -0,0 +1,26 @@
+package ingest
+
+import "lindenii.org/go/furgit/object/id"
+
+// Result describes one finalized pack write.
+type Result struct {
+ // PackName is the destination-relative name of the written pack.
+ PackName string
+
+ // IdxName is the destination-relative name of the written index.
+ IdxName string
+
+ // RevName is the destination-relative name of the written reverse index.
+ RevName string
+
+ // PackHash is the pack trailer hash
+ // shared by the pack, index, and reverse index.
+ PackHash id.ObjectID
+
+ // ObjectCount is the number of objects in the finalized pack,
+ // including any bases appended during thin completion.
+ ObjectCount uint32
+
+ // ThinFixed reports whether thin completion appended local bases.
+ ThinFixed bool
+}