Skip to content

Commit 2ec2aa6

Browse files
committed
feat(shed): actor state diff stats
1 parent fc70735 commit 2ec2aa6

File tree

1 file changed

+81
-12
lines changed

1 file changed

+81
-12
lines changed

cmd/lotus-shed/state-stats.go

Lines changed: 81 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ var statSnapshotCmd = &cli.Command{
360360
Flags: []cli.Flag{
361361
&cli.StringFlag{
362362
Name: "tipset",
363-
Usage: "specify tipset to call method on (pass comma separated array of cids)",
363+
Usage: "specify tipset to call method on (pass comma separated array of cids or @<height> to specify tipset by height)",
364364
},
365365
&cli.IntFlag{
366366
Name: "workers",
@@ -618,11 +618,19 @@ The top level stats reported for an actor is computed independently of all field
618618
accounting of the true size of the actor in the state datastore.
619619
620620
The calculation of these stats results in the actor state being traversed twice. The dag-cache-size flag can be used
621-
to reduce the number of decode operations performed by caching the decoded object after first access.`,
621+
to reduce the number of decode operations performed by caching the decoded object after first access.
622+
623+
When using the diff-tipset flag, the stats output will only include the mutated state between the two tipsets, not
624+
the total state of the actor in either tipset.
625+
`,
622626
Flags: []cli.Flag{
623627
&cli.StringFlag{
624628
Name: "tipset",
625-
Usage: "specify tipset to call method on (pass comma separated array of cids)",
629+
Usage: "specify tipset to call method on (pass comma separated array of cids or @<height> to specify tipset by height)",
630+
},
631+
&cli.StringFlag{
632+
Name: "diff-tipset",
633+
Usage: "specify tipset to diff against, stat output will include only the mutated state between the two tipsets (pass comma separated array of cids or @<height> to specify tipset by height)",
626634
},
627635
&cli.IntFlag{
628636
Name: "workers",
@@ -688,12 +696,12 @@ to reduce the number of decode operations performed by caching the decoded objec
688696
numWorkers := cctx.Int("workers")
689697
dagCacheSize := cctx.Int("dag-cache-size")
690698

691-
eg, egctx := errgroup.WithContext(ctx)
692-
693699
jobs := make(chan address.Address, numWorkers)
694700
results := make(chan actorStats, numWorkers)
695701

696-
worker := func(ctx context.Context, id int) error {
702+
sc := &statCollector{}
703+
704+
worker := func(ctx context.Context, id int, ts *types.TipSet) error {
697705
completed := 0
698706
defer func() {
699707
log.Infow("worker done", "id", id, "completed", completed)
@@ -720,7 +728,7 @@ to reduce the number of decode operations performed by caching the decoded objec
720728
}
721729
}
722730

723-
actStats, err := collectStats(ctx, addr, actor, dag)
731+
actStats, err := sc.collectStats(ctx, addr, actor, dag)
724732
if err != nil {
725733
return err
726734
}
@@ -738,20 +746,68 @@ to reduce the number of decode operations performed by caching the decoded objec
738746
}
739747
}
740748

749+
eg, egctx := errgroup.WithContext(ctx)
741750
for w := 0; w < numWorkers; w++ {
742751
id := w
743752
eg.Go(func() error {
744-
return worker(egctx, id)
753+
return worker(egctx, id, ts)
745754
})
746755
}
747756

757+
done := make(chan struct{})
748758
go func() {
749-
defer close(jobs)
759+
defer func() {
760+
close(jobs)
761+
close(done)
762+
}()
750763
for _, addr := range addrs {
751764
jobs <- addr
752765
}
753766
}()
754767

768+
// if diff-tipset is set, we need to load the actors from the diff tipset and compare, so we'll
769+
// discard the results for this run, then run the workers again with a new set of jobs and take
770+
// the results from the second run which should just include the diff.
771+
772+
if diffTs := cctx.String("diff-tipset"); diffTs != "" {
773+
// read and discard results
774+
go func() {
775+
for range results { // nolint:revive
776+
}
777+
}()
778+
779+
_ = eg.Wait()
780+
log.Infow("done with first pass, starting diff")
781+
close(results)
782+
783+
<-done
784+
785+
dts, err := lcli.ParseTipSetRef(ctx, tsr, diffTs)
786+
if err != nil {
787+
return err
788+
}
789+
// TODO: if anyone cares for the "all" case, re-load actors here
790+
log.Infow("diff tipset", "parentstate", dts.ParentState())
791+
792+
jobs = make(chan address.Address, numWorkers)
793+
results = make(chan actorStats, numWorkers)
794+
795+
eg, egctx = errgroup.WithContext(ctx)
796+
for w := 0; w < numWorkers; w++ {
797+
id := w
798+
eg.Go(func() error {
799+
return worker(egctx, id, dts)
800+
})
801+
}
802+
803+
go func() {
804+
defer close(jobs)
805+
for _, addr := range addrs {
806+
jobs <- addr
807+
}
808+
}()
809+
}
810+
755811
go func() {
756812
// error is check later
757813
_ = eg.Wait()
@@ -866,7 +922,12 @@ func collectSnapshotJobStats(ctx context.Context, in job, dag format.NodeGetter,
866922
return results, nil
867923
}
868924

869-
func collectStats(ctx context.Context, addr address.Address, actor *types.Actor, dag format.NodeGetter) (actorStats, error) {
925+
type statCollector struct {
926+
rootCidSet *cid.Set
927+
fieldCidSets map[string]*cid.Set
928+
}
929+
930+
func (sc *statCollector) collectStats(ctx context.Context, addr address.Address, actor *types.Actor, dag format.NodeGetter) (actorStats, error) {
870931
log.Infow("actor", "addr", addr, "code", actor.Code, "name", builtin.ActorNameByCode(actor.Code))
871932

872933
nd, err := dag.Get(ctx, actor.Head)
@@ -903,6 +964,14 @@ func collectStats(ctx context.Context, addr address.Address, actor *types.Actor,
903964
}
904965
}
905966

967+
if sc.rootCidSet == nil {
968+
sc.rootCidSet = cid.NewSet()
969+
sc.fieldCidSets = make(map[string]*cid.Set)
970+
for _, field := range fields {
971+
sc.fieldCidSets[field.Name] = cid.NewSet()
972+
}
973+
}
974+
906975
actStats := actorStats{
907976
Address: addr,
908977
Actor: actor,
@@ -913,7 +982,7 @@ func collectStats(ctx context.Context, addr address.Address, actor *types.Actor,
913982
walk: carWalkFunc,
914983
}
915984

916-
if err := merkledag.Walk(ctx, dsc.walkLinks, actor.Head, cid.NewSet().Visit, merkledag.Concurrent()); err != nil {
985+
if err := merkledag.Walk(ctx, dsc.walkLinks, actor.Head, sc.rootCidSet.Visit, merkledag.Concurrent()); err != nil {
917986
return actorStats{}, err
918987
}
919988

@@ -925,7 +994,7 @@ func collectStats(ctx context.Context, addr address.Address, actor *types.Actor,
925994
walk: carWalkFunc,
926995
}
927996

928-
if err := merkledag.Walk(ctx, dsc.walkLinks, field.Cid, cid.NewSet().Visit, merkledag.Concurrent()); err != nil {
997+
if err := merkledag.Walk(ctx, dsc.walkLinks, field.Cid, sc.fieldCidSets[field.Name].Visit, merkledag.Concurrent()); err != nil {
929998
return actorStats{}, err
930999
}
9311000

0 commit comments

Comments
 (0)