Artifact b6df596d455cff2147834cb6fab009b4619f389d36cace737d53b7572f43c6c5:
- File
internal/manifest/submanifest_replay.go
— part of check-in
[0f543785e1]
at
2026-10-18 17:19:06
on branch feat/submanifest-reader
— fix(manifest): tree storage, privacy and post-commit work per review
- A public check-in makes every sub-manifest it names public, so a leaf a private check-in stored first is sent with the tree. - Sub-manifests are named by the hash policy alone (StoreUnderPolicy), in sha1, sha3 and auto repositories alike, and only those the commit wrote are queued for sync. - A sub-manifest that fills a phantom links the check-ins waiting on it once the commit is durable (§7.1, §7.3), not at the next sweep. - The automatic re-tune runs after the commit is durable, as zit runs it; its failure is logged and never fails the commit. - Enabling selects outside any write transaction, replaying one check-in at a time, then re-reads the settings in a short write; a pin that appeared meanwhile takes §8.1's precedence. - Checkin's transaction body moves to checkinTx, so neither function exceeds 70 lines. (user: [email protected], size: 5382) [annotate] [blame] [check-ins using] [more...]
package manifest // zit's refinement of the automatic selection of draft-fossil-submanifests-00 // §6.3. The draft's objective is advisory -- the implementation SHOULD pick // the least C(k) -- and zit, on enabling, lets the repository's own history // outrank that snapshot: it replays the recent check-ins through the tree // builder at the snapshot's k and its two neighbours and pins the value whose // steady-state commits materialize the fewest bytes. Two writers sharing a // repository should pin alike, so this follows zit's replay step for step: // the window, the candidates, the byte accounting and the tie-break. import ( "fmt" "github.com/danmestas/go-libfossil/db" "github.com/danmestas/go-libfossil/internal/content" "github.com/danmestas/go-libfossil/internal/deck" libfossil "github.com/danmestas/go-libfossil/internal/fsltype" "github.com/danmestas/go-libfossil/internal/hash" ) // replayWindow is how many of the most recent check-ins the replay reads, // zit's window. const replayWindow = 200 // replayArm is one candidate k's tally over the window. type replayArm struct { k int allFlat bool // steady is the materialization bytes of every replayed commit but the // first: a flat commit's manifest, or a tree's root and each sub-manifest // on its first appearance in the window (later ones are shared). steady int64 seen map[string]bool } // replayCommit is one replayed check-in: its manifest and its file set. type replayCommit struct { data []byte d *deck.Deck files []deck.FileCard } // replayK is zit's replay over the last replayWindow check-ins at snapshot, // snapshot-1 and snapshot+1 within 1..12. It reports false when fewer than // two check-ins replay or every candidate stays flat throughout; the caller // then keeps the snapshot's value. It only reads, one check-in at a time, so // it holds one file set and the arms' tallies, never the window. func replayK(q db.Querier, snapshot int) (int, bool, error) { if !validPartitionK(snapshot) { panic("manifest.replayK: snapshot must be from 1 to 12") } rids, name, err := replayWindowRids(q) if err != nil { return 0, false, err } var arms []*replayArm for k := snapshot - 1; k <= snapshot+1; k++ { if validPartitionK(k) { arms = append(arms, &replayArm{k: k, allFlat: true, seen: map[string]bool{}}) } } replayed := 0 for _, rid := range rids { c, ok := loadReplayCommit(q, rid) if !ok { continue } for _, arm := range arms { bytes, err := arm.replay(c, name) if err != nil { return 0, false, err } if replayed > 0 { arm.steady += bytes } } replayed++ } if replayed < 2 { return 0, false, nil } var best *replayArm for _, arm := range arms { if !arm.allFlat && (best == nil || arm.steady < best.steady) { best = arm } } if best == nil { return 0, false, nil } return best.k, true, nil } // replay charges one commit to the arm and returns its bytes. func (a *replayArm) replay(c replayCommit, name func([]byte) (string, error)) (int64, error) { tree, err := BuildTree(c.files, a.k, name) if err != nil { return 0, err } if len(tree.S) == 0 { return int64(len(c.data)), nil } a.allFlat = false root := *c.d root.F, root.S, root.B = nil, tree.S, "" rootBytes, err := root.Marshal() if err != nil { return 0, fmt.Errorf("replay root: %w", err) } total := int64(len(rootBytes)) for _, sub := range tree.Subs { uuid, err := name(sub) if err != nil { return 0, err } if a.seen[uuid] { continue } a.seen[uuid] = true total += int64(len(sub)) } return total, nil } // replayWindowRids is the window's check-ins, oldest first, and the naming // the newest one's name implies, as zit names by its tip. func replayWindowRids(q db.Querier) ([]libfossil.FslID, func([]byte) (string, error), error) { rows, err := q.Query(`SELECT objid FROM (SELECT objid FROM event WHERE type='ci' ORDER BY objid DESC LIMIT ?) ORDER BY objid`, replayWindow) if err != nil { return nil, nil, fmt.Errorf("replay window: %w", err) } var rids []libfossil.FslID for rows.Next() { var rid int64 if err := rows.Scan(&rid); err != nil { rows.Close() return nil, nil, err } rids = append(rids, libfossil.FslID(rid)) } rows.Close() if err := rows.Err(); err != nil || len(rids) == 0 { return nil, nil, err } var tip string if err := q.QueryRow("SELECT uuid FROM blob WHERE rid=?", rids[len(rids)-1]).Scan(&tip); err != nil { return nil, nil, fmt.Errorf("replay tip: %w", err) } alg := hash.AlgSHA3 if len(tip) == 40 { alg = hash.AlgSHA1 } return rids, func(data []byte) (string, error) { return alg.Hash(data), nil }, nil } // loadReplayCommit reads one check-in for the replay, reporting false when // it cannot be read or enumerated, which zit skips uncounted. func loadReplayCommit(q db.Querier, rid libfossil.FslID) (replayCommit, bool) { data, err := content.Expand(q, rid) if err != nil { return replayCommit{}, false } d, err := deck.Parse(data) if err != nil || d.Type != deck.Checkin { return replayCommit{}, false } files, err := checkinFileCards(q, nil, d) if err != nil { return replayCommit{}, false } for i, f := range files { if f.UUID == "" || (i > 0 && deck.Compare(files[i-1].Name, f.Name) >= 0) { return replayCommit{}, false } } return replayCommit{data: data, d: d, files: files}, true }