Artifact 5550f907eedcb4040cbe4ea6a5d292d9508989a7cb10c7c42515db38b00a2599:
- File
internal/manifest/parsed_memo.go
— part of check-in
[48ff1f5084]
at
2026-10-22 21:17:12
on branch feat/horizon-cones
— perf(manifest): stop re-walking delta chains and re-parsing manifests in a rebuild
Rebuilding a clone of the Fossil SCM repository (67,894 artifacts, 21,008 check-ins) took about 3 minutes of which 104 s was parentTreeGap asking content.AvailableByUUID, an uncached delta-chain walk with one SQL statement per node, for every parent of every check-in. It now uses the sweep's availability cache like the rest of the guard.
The same sweep parsed each check-in three times (as a child, as its child's parent, as a delta baseline) and rebuilt its file maps. The sweep's content cache now keeps the parsed deck, file views and baseline rid of its few most recent check-ins (Cache.Derived), dropped with the cached bytes on Invalidate and Clear. Derived hits count as reuse in the cascade stats, so the shared-cache regression guard keeps measuring it.
The rebuilt event, mlink, plink, tagxref, leaf, filename, cherrypick, orphan, unclustered, unsent, forumpost, attachment, phantom, blob and delta tables are row-for-row identical to the previous code's. (user: [email protected], size: 2996) [annotate] [blame] [check-ins using] [more...]
package manifest import ( "errors" "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" ) // A sweep reads each check-in as a child, again as its child's parent, and // again as a delta baseline, and parsing a large manifest dominates each read. // The parsed deck and file views of the few most recent check-ins are kept in // the sweep's content.Cache beside their bytes, so each is built once. Both are // shared: no caller may modify them. type ( parsedKey libfossil.FslID // -> *deck.Deck filesKey libfossil.FslID // -> *manifestFiles baselineKey string // baseline UUID -> libfossil.FslID ) // errExpandManifest marks a manifest whose bytes could not be expanded, as // against bytes that expanded but do not parse. var errExpandManifest = errors.New("expand manifest") // rememberCheckin keeps d, the parse of the check-in manifest at rid. func rememberCheckin(cache *content.Cache, rid libfossil.FslID, d *deck.Deck) { if d.Type == deck.Checkin { cache.SetDerived(parsedKey(rid), d) } } // parseManifestAt expands and parses the manifest at rid. A check-in is served // from, and kept in, cache's derived memo. func parseManifestAt(q db.Querier, cache *content.Cache, rid libfossil.FslID) (*deck.Deck, error) { if v, ok := cache.Derived(parsedKey(rid)); ok { return v.(*deck.Deck), nil } data, err := expandManifestBytes(q, cache, rid) if err != nil { return nil, fmt.Errorf("%w rid=%d: %w", errExpandManifest, rid, err) } if len(data) == 0 { return nil, fmt.Errorf("manifest rid=%d is empty", rid) } d, err := deck.Parse(data) if err != nil { return nil, fmt.Errorf("parse manifest rid=%d: %w", rid, err) } rememberCheckin(cache, rid, d) return d, nil } // rememberFiles keeps mf, the file views of the check-in manifest at rid. func rememberFiles(cache *content.Cache, rid libfossil.FslID, mf *manifestFiles) { cache.SetDerived(filesKey(rid), mf) } // manifestFilesAt returns the file views of d, the parse of the check-in at rid. func manifestFilesAt(q db.Querier, cache *content.Cache, rid libfossil.FslID, d *deck.Deck) (*manifestFiles, error) { if v, ok := cache.Derived(filesKey(rid)); ok { return v.(*manifestFiles), nil } mf, err := loadManifestFiles(q, cache, d) if err != nil { return nil, err } rememberFiles(cache, rid, mf) return mf, nil } // baselineRid resolves a delta's baseline hash to its available rid. Content // is only ever added, so an available baseline stays available and the chain // walk behind that verdict is kept with the cache. func baselineRid(q db.Querier, cache *content.Cache, uuid string) (libfossil.FslID, bool) { if v, ok := cache.Derived(baselineKey(uuid)); ok { return v.(libfossil.FslID), true } rid, ok := content.AvailableByUUID(q, uuid) if ok { cache.SetDerived(baselineKey(uuid), rid) } return rid, ok }