Artifact 1285b3ddb4adc3a8443ef98f9406b1dd608a387af6938ee7491a9b16ce1aab7e:
- File
internal/sync/sparse.go
— part of check-in
[b5a64230b3]
at
2026-10-21 14:43:59
on branch feat/submanifest-reader
— feat(sparse): adopt sparse-cone at horizon-rfc a5741263ab
The draft now settles zit #257 to #260, so the four rows that waited on it close against code:
- Compaction and local filtering keep every manifest and sub-manifest node, interiors included (5.4, 6.3). RetainProvenance previously let an outside interior whose children were all held leaves go; the draft now requires it held, since it is the range proof that reaches the leaf. - A server answering a cone request acknowledges the reply with pragma cone-served in its leading pragma run (6.3). This server applies a request's whole cone or refuses it, and a refusal resets the reply, so the pragma is never sent for a refused or dense reply. SyncResult and CloneResult report ConeServed beside Elided, now public too. - An empty cone is refused (3.2); a new row and case pin it, locally and over the wire. - The per-round bound covers the tree walk only (6.2). A new row tests that a requester does not act on a dense inventory. It stays partial: an out-of-cone blob announced in the same reply as its check-in cannot be classified yet and is fetched, then filtered; zit #262 asks the draft to account for that cost. (user: [email protected], size: 1762) [annotate] [blame] [check-ins using] [more...]
package sync import ( "fmt" "github.com/danmestas/go-libfossil/internal/cone" "github.com/danmestas/go-libfossil/internal/deck" "github.com/danmestas/go-libfossil/internal/xfer" ) // The draft defines request pragmas, but no capability advertisement spelling. // Unknown pragmas remain ignored by peers that predate sparse transfer. // coneServedPragma acknowledges a reply that applied the request's whole cone // (draft-fossil-sparse-cone-00 ยง6.3). It travels only from server to client. const coneServedPragma = "cone-served" func conePragmas(c *cone.Cone) []xfer.Card { if c == nil { return nil } cards := make([]xfer.Card, 0, len(c.Include())+len(c.Exclude())) for _, m := range c.Include() { cards = append(cards, &xfer.PragmaCard{Name: "cone", Values: []string{deck.FossilEncode(m)}}) } for _, m := range c.Exclude() { cards = append(cards, &xfer.PragmaCard{Name: "cone-not", Values: []string{deck.FossilEncode(m)}}) } return cards } func requestCone(cards []xfer.Card) (*cone.Cone, error) { var include, exclude []string for _, card := range cards { p, ok := card.(*xfer.PragmaCard) if !ok || (p.Name != "cone" && p.Name != "cone-not") { continue } if len(p.Values) != 1 || len(p.Values[0]) > 2*cone.MaxMemberLen { return nil, fmt.Errorf("sparse cone: invalid member") } if len(include)+len(exclude) >= cone.MaxMembers { return nil, fmt.Errorf("sparse cone: too many members") } m := deck.FossilDecode(p.Values[0]) if p.Name == "cone" { include = append(include, m) } else { exclude = append(exclude, m) } } if len(include)+len(exclude) == 0 { return nil, nil } c, err := cone.New(include, exclude) if err != nil { return nil, fmt.Errorf("sparse cone: %w", err) } return c, nil }