pre-migration: refactor timing specification

There are now three times:

1. StartWithin: start within X epochs of the upgrade.
2. DontStartWithin: don't start within X epochs of the upgrade.
3. StopWithin: stop within X epochs of the upgrade.
This commit is contained in:
Steven Allen 2021-01-27 15:58:51 -08:00
parent bceb246080
commit 39d4f6780d
2 changed files with 55 additions and 27 deletions

View File

@ -79,15 +79,19 @@ type PreMigration struct {
// run asynchronously and must abort promptly when canceled. // run asynchronously and must abort promptly when canceled.
PreMigration PreMigrationFunc PreMigration PreMigrationFunc
// When specifies that this pre-migration should be started at most When epochs before the upgrade. // StartWithin specifies that this pre-migration should be started at most StartWithin
When abi.ChainEpoch // epochs before the upgrade.
StartWithin abi.ChainEpoch
// NotAfter specifies that this pre-migration should not be started NotAfter epochs before // DontStartWithin specifies that this pre-migration should not be started DontStartWithin
// the final upgrade epoch. // epochs before the final upgrade epoch.
// //
// This should be set such that the pre-migration is likely to complete at least 5 epochs // This should be set such that the pre-migration is likely to complete before StopWithin.
// before the next pre-migration and/or upgrade epoch hits. DontStartWithin abi.ChainEpoch
NotAfter abi.ChainEpoch
// StopWithin specifies that this pre-migration should be stopped StopWithin epochs of the
// final upgrade epoch.
StopWithin abi.ChainEpoch
} }
type Upgrade struct { type Upgrade struct {
@ -172,13 +176,15 @@ func DefaultUpgradeSchedule() UpgradeSchedule {
Network: network.Version10, Network: network.Version10,
Migration: UpgradeActorsV3, Migration: UpgradeActorsV3,
PreMigrations: []PreMigration{{ PreMigrations: []PreMigration{{
PreMigration: PreUpgradeActorsV3, PreMigration: PreUpgradeActorsV3,
When: 120, StartWithin: 120,
NotAfter: 60, DontStartWithin: 60,
StopWithin: 35,
}, { }, {
PreMigration: PreUpgradeActorsV3, PreMigration: PreUpgradeActorsV3,
When: 30, StartWithin: 30,
NotAfter: 10, DontStartWithin: 15,
StopWithin: 5,
}}, }},
Expensive: true, Expensive: true,
}} }}
@ -201,15 +207,30 @@ func (us UpgradeSchedule) Validate() error {
} }
for _, m := range u.PreMigrations { for _, m := range u.PreMigrations {
if m.When < 0 || m.NotAfter < 0 { if m.StartWithin <= 0 {
return xerrors.Errorf("pre-migration must specify a positive start-within epoch")
}
if m.DontStartWithin < 0 || m.StopWithin < 0 {
return xerrors.Errorf("pre-migration must specify non-negative epochs") return xerrors.Errorf("pre-migration must specify non-negative epochs")
} }
if m.When <= m.NotAfter {
return xerrors.Errorf("pre-migration cannot end before it starts: %d <= %d", m.When, m.NotAfter) if m.StartWithin <= m.StopWithin {
return xerrors.Errorf("pre-migration start-within must come before stop-within")
}
// If we have a dont-start-within.
if m.DontStartWithin != 0 {
if m.DontStartWithin < m.StopWithin {
return xerrors.Errorf("pre-migration dont-start-within must come before stop-within")
}
if m.StartWithin <= m.DontStartWithin {
return xerrors.Errorf("pre-migration start-within must come after dont-start-within")
}
} }
} }
if !sort.SliceIsSorted(u.PreMigrations, func(i, j int) bool { if !sort.SliceIsSorted(u.PreMigrations, func(i, j int) bool {
return u.PreMigrations[i].When > u.PreMigrations[j].When //nolint:scopelint,gosec return u.PreMigrations[i].StartWithin > u.PreMigrations[j].StartWithin //nolint:scopelint,gosec
}) { }) {
return xerrors.Errorf("pre-migrations must be sorted by start epoch") return xerrors.Errorf("pre-migrations must be sorted by start epoch")
} }
@ -312,8 +333,13 @@ func (sm *StateManager) preMigrationWorker(ctx context.Context) {
preCtx, preCancel := context.WithCancel(ctx) preCtx, preCancel := context.WithCancel(ctx)
migrationFunc := prem.PreMigration migrationFunc := prem.PreMigration
afterEpoch := upgradeEpoch - prem.When afterEpoch := upgradeEpoch - prem.StartWithin
notAfterEpoch := upgradeEpoch - prem.NotAfter notAfterEpoch := upgradeEpoch - prem.DontStartWithin
stopEpoch := upgradeEpoch - prem.StopWithin
// We can't start after we stop.
if notAfterEpoch > stopEpoch {
notAfterEpoch = stopEpoch - 1
}
// Add an op to start a pre-migration. // Add an op to start a pre-migration.
schedule = append(schedule, op{ schedule = append(schedule, op{
@ -332,7 +358,7 @@ func (sm *StateManager) preMigrationWorker(ctx context.Context) {
// Add an op to cancel the pre-migration if it's still running. // Add an op to cancel the pre-migration if it's still running.
schedule = append(schedule, op{ schedule = append(schedule, op{
after: notAfterEpoch, after: stopEpoch,
notAfter: -1, notAfter: -1,
run: func(ts *types.TipSet) { preCancel() }, run: func(ts *types.TipSet) { preCancel() },
}) })
@ -345,6 +371,8 @@ func (sm *StateManager) preMigrationWorker(ctx context.Context) {
}) })
// Finally, when the head changes, see if there's anything we need to do. // Finally, when the head changes, see if there's anything we need to do.
//
// We're intentionally ignoring reorgs as they don't matter for our purposes.
for change := range sm.cs.SubHeadChanges(ctx) { for change := range sm.cs.SubHeadChanges(ctx) {
for _, head := range change { for _, head := range change {
for len(schedule) > 0 { for len(schedule) > 0 {
@ -354,7 +382,7 @@ func (sm *StateManager) preMigrationWorker(ctx context.Context) {
} }
// If we haven't passed the pre-migration height... // If we haven't passed the pre-migration height...
if op.notAfter < 0 || head.Val.Height() <= op.notAfter { if op.notAfter < 0 || head.Val.Height() < op.notAfter {
op.run(head.Val) op.run(head.Val)
} }
schedule = schedule[1:] schedule = schedule[1:]

View File

@ -377,7 +377,7 @@ func TestForkPreMigration(t *testing.T) {
return root, nil return root, nil
}, },
PreMigrations: []PreMigration{{ PreMigrations: []PreMigration{{
When: 20, StartWithin: 20,
PreMigration: func(ctx context.Context, _ *StateManager, cache MigrationCache, PreMigration: func(ctx context.Context, _ *StateManager, cache MigrationCache,
_ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error { _ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error {
wait20.Done() wait20.Done()
@ -389,7 +389,7 @@ func TestForkPreMigration(t *testing.T) {
return nil return nil
}, },
}, { }, {
When: 20, StartWithin: 20,
PreMigration: func(ctx context.Context, _ *StateManager, cache MigrationCache, PreMigration: func(ctx context.Context, _ *StateManager, cache MigrationCache,
_ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error { _ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error {
wait20.Done() wait20.Done()
@ -401,7 +401,7 @@ func TestForkPreMigration(t *testing.T) {
return nil return nil
}, },
}, { }, {
When: 20, StartWithin: 20,
PreMigration: func(ctx context.Context, _ *StateManager, cache MigrationCache, PreMigration: func(ctx context.Context, _ *StateManager, cache MigrationCache,
_ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error { _ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error {
wait20.Done() wait20.Done()
@ -414,8 +414,8 @@ func TestForkPreMigration(t *testing.T) {
return fmt.Errorf("failed") return fmt.Errorf("failed")
}, },
}, { }, {
When: 15, StartWithin: 15,
NotAfter: 5, StopWithin: 5,
PreMigration: func(ctx context.Context, _ *StateManager, cache MigrationCache, PreMigration: func(ctx context.Context, _ *StateManager, cache MigrationCache,
_ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error { _ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error {
@ -425,7 +425,7 @@ func TestForkPreMigration(t *testing.T) {
return nil return nil
}, },
}, { }, {
When: 10, StartWithin: 10,
PreMigration: func(ctx context.Context, _ *StateManager, cache MigrationCache, PreMigration: func(ctx context.Context, _ *StateManager, cache MigrationCache,
_ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error { _ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error {