Artifact 658e6fa2d21a5b30f1cb241cf07f2bbdb0e26be18e44fad1cb6ca0f8472290c5:
- File
internal/content/cone_references.go
— part of check-in
[dc33bca3a6]
at
2026-10-22 16:12:54
on branch feat/horizon-cones
— feat(sync): serve and take the structural horizon
The origin now answers pragma horizon-structural (draft-fossil-horizon-00 §6.1, §6.2): it keeps only the manifests and nodes the held set reaches, labels every boundary hash at the head of each reply (§6.2.2), mints the seed for C and sends it, pragma ahead of its file card, when the client offers another name (§6.2.3), and advertises the structural level only then; a request it cannot place or seed is served as content. It refuses a seed offered to it and withholds a gimme'd manifest below the horizon.
A structural store's requests carry horizon-structural and the seed it holds. It routes the announced card to seed.Hold after checking its name and shape, never storing or announcing it, records the labels, and applies the seed after each reply and after the closing link. A first reply that does not serve structural with a seed, or a seed failing provenance, makes it a content-horizon store for good, reported in the result, and the manifests below the horizon are fetched (§5.1, §5.2.4, §6.3). (user: [email protected], size: 6184) [annotate] [blame] [check-ins using] [more...]
package content import ( "context" "fmt" "github.com/danmestas/go-libfossil/db" "github.com/danmestas/go-libfossil/internal/cone" "github.com/danmestas/go-libfossil/internal/deck" libfossil "github.com/danmestas/go-libfossil/internal/fsltype" ) const coneReferenceDepth = 16 const coneReferenceNodes = 1 << 20 // ConeReferences is inferred from raw artifacts wherever crosslink tables cannot // stand in for them: a sparse tree can be healthy before its elided children // permit whole-tree crosslinking, so trees are always read raw, while a check-in // linked completely is answered by its mlink, plink, cherrypick and tagxref rows // (ConeReferenceFacts). Unknown artifacts stay wanted. A covered alias or // structural reference wins over every outside reference. type ConeReferences struct { names map[libfossil.FslID]string outside, inside, required map[string]bool tree map[string]bool held map[string]libfossil.FslID nodes map[libfossil.FslID]*deck.Deck } // Outside reports only proven elision candidates. Delta dependency closure is // a separate operation: a sender can instead expand a retained delta in full. func (p *ConeReferences) Outside(rid libfossil.FslID) bool { if p == nil { return false } uuid := p.names[rid] return p.outside[uuid] && !p.inside[uuid] && !p.required[uuid] } // Required reports a covered alias or a structural reference, including ones // which have not been crosslinked yet. func (p *ConeReferences) Required(rid libfossil.FslID) bool { if p == nil { return false } uuid := p.names[rid] return p.inside[uuid] || p.required[uuid] } // structure reports a structural reference or a sub-manifest node: an // artifact a content horizon holds at every age. func (p *ConeReferences) structure(rid libfossil.FslID) bool { uuid := p.names[rid] return p.required[uuid] || p.tree[uuid] } // file reports a name some held F card gives: a blob, which a horizon may // place below it. A phantom no F card names is not proven to be one. func (p *ConeReferences) file(rid libfossil.FslID) bool { uuid := p.names[rid] return p.inside[uuid] || p.outside[uuid] } // Nodes returns the held sub-manifest nodes by rid, with their names. func (p *ConeReferences) Nodes() map[libfossil.FslID]string { out := make(map[libfossil.FslID]string, len(p.nodes)) for rid := range p.nodes { out[rid] = p.names[rid] } return out } // Artifacts counts the artifact names the classification read. func (p *ConeReferences) Artifacts() int { if p == nil { return 0 } return len(p.names) } // LoadConeReferences classifies both held and phantom artifact names. Traversal // shares the single-name lookup depth and node limits across all roots. func LoadConeReferences(ctx context.Context, q db.Querier, c *cone.Cone) (*ConeReferences, error) { if ctx == nil || q == nil { panic("content.LoadConeReferences: nil context or querier") } p := &ConeReferences{names: map[libfossil.FslID]string{}, outside: map[string]bool{}, inside: map[string]bool{}, required: map[string]bool{}, tree: map[string]bool{}, held: map[string]libfossil.FslID{}, nodes: map[libfossil.FslID]*deck.Deck{}} if err := ctx.Err(); err != nil { return nil, err } if c == nil { return p, nil } facts, err := LoadConeReferenceFacts(ctx, q) if err != nil { return nil, err } return facts.Classify(ctx, c) } // RetainProvenance removes every held sub-manifest node from a proposed drop // set. Sparse-cone Sections 5.4 and 6.3 keep manifests and sub-manifest nodes, // in cone or not: a leaf's F cards are what classify the blobs it names as // elided rather than transit phantoms, and an interior is the range proof that // reaches the leaf. Only blobs are ever dropped. Check-ins never enter a drop // set, since no S card names them. func (p *ConeReferences) RetainProvenance(ctx context.Context, drop map[libfossil.FslID]bool) error { for rid := range p.nodes { if err := ctx.Err(); err != nil { return err } delete(drop, rid) } return ctx.Err() } func (p *ConeReferences) structural(d *deck.Deck) { for _, uuid := range []string{d.B, d.G, d.I} { if uuid != "" { p.required[uuid] = true } } for _, uuid := range d.P { p.required[uuid] = true } for _, q := range d.Q { p.required[q.Target] = true if q.Baseline != "" { p.required[q.Baseline] = true } } for _, t := range d.T { if t.UUID != "" && t.UUID != "*" { p.required[t.UUID] = true } } if d.A != nil && d.A.Source != "" { p.required[d.A.Source] = true } // Cluster inventories are not dependencies; otherwise every clustered file // would be immune to sparse transfer and explicit compaction. } type coneReferenceWalk struct { ctx context.Context cone *cone.Cone refs *ConeReferences nodes map[string]*deck.Deck path map[string]bool visited int } func (w *coneReferenceWalk) walk(cards []deck.SubmanifestCard, upper string, depth int, parentWanted bool) error { for i, card := range cards { if err := w.ctx.Err(); err != nil { return err } if depth > coneReferenceDepth || w.visited >= coneReferenceNodes { return fmt.Errorf("sparse cone: tree traversal bound exceeded") } w.visited++ w.refs.tree[card.UUID] = true limit := upper if i+1 < len(cards) { limit = cards[i+1].Name } wanted := parentWanted && w.cone.MayCover(card.Name, limit) if wanted { w.refs.required[card.UUID] = true } else { w.refs.outside[card.UUID] = true } d := w.nodes[card.UUID] if d == nil { continue } if w.path[card.UUID] { return fmt.Errorf("sparse cone: cyclic sub-manifest %s", card.UUID) } if len(d.F) > 0 { if d.F[0].Name != card.Name || limit != "" && d.F[len(d.F)-1].Name >= limit { return fmt.Errorf("sparse cone: invalid sub-manifest range") } continue } if len(d.S) == 0 || d.S[0].Name != card.Name || limit != "" && d.S[len(d.S)-1].Name >= limit { return fmt.Errorf("sparse cone: invalid sub-manifest range") } w.path[card.UUID] = true err := w.walk(d.S, limit, depth+1, wanted) delete(w.path, card.UUID) if err != nil { return err } } return nil }