WIP runtime-controllable concurrency for replication
Changes done so far:
- signal to route concurrency request up to the stepQueue
- pretty hacky, no status reporting yet
- stepQueue upsizing (confirmed that it works, no intermediary commit)
Stuck at: stepQueue downsizing
- idea was to have the stepQueue signal to the activated step that it
should suspend
- ideally, we'd just kill everything associated with the step and track
it as restartable
- the driver model doesn't allow for that though within an attempt
- would need to start a separate run for the step
- less perfect: tell the downsized steps to stop copying, but leave
all zfs sends + rpc conns open
- - doesn't give back the resoures that a step aquired before
being selected as downsize victim (open zfs processe + TCP conn,
some memory in the pipe)
- - looks weird to user if the ps aux
- + re-waking a step is easy: just tell it to proceed with copying
- (the impl would likely pass a check function down into Step.do
and have it check that functino periodically. the suspend should
be acknowledged, and stepQueue should only remove the step from
the active queue _after_ that step has acknowledged that is
suspended)
This commit is contained in:
+30
-6
@@ -55,9 +55,12 @@ const (
|
||||
type activeSideTasks struct {
|
||||
state ActiveSideState
|
||||
|
||||
concurrency int
|
||||
|
||||
// valid for state ActiveSideReplicating, ActiveSidePruneSender, ActiveSidePruneReceiver, ActiveSideDone
|
||||
replicationReport driver.ReportFunc
|
||||
replicationCancel context.CancelFunc
|
||||
replicationReport driver.ReportFunc
|
||||
replicationCancel context.CancelFunc
|
||||
replicationSetConcurrency driver.SetConcurrencyFunc
|
||||
|
||||
// valid for state ActiveSidePruneSender, ActiveSidePruneReceiver, ActiveSideDone
|
||||
prunerSender, prunerReceiver *pruner.Pruner
|
||||
@@ -278,6 +281,8 @@ func activeSide(g *config.Global, in *config.ActiveJob, configJob interface{}) (
|
||||
return nil, errors.Wrap(err, "invalid job name")
|
||||
}
|
||||
|
||||
j.tasks.concurrency = 1 // FIXME
|
||||
|
||||
switch v := configJob.(type) {
|
||||
case *config.PushJob:
|
||||
j.mode, err = modePushFromConfig(g, v, j.name) // shadow
|
||||
@@ -375,6 +380,22 @@ func (j *ActiveSide) SenderConfig() *endpoint.SenderConfig {
|
||||
return push.senderConfig
|
||||
}
|
||||
|
||||
func (j *ActiveSide) SetConcurrency(concurrency int) (err error) {
|
||||
j.updateTasks(func(tasks *activeSideTasks) {
|
||||
if tasks.replicationSetConcurrency != nil {
|
||||
err = tasks.replicationSetConcurrency(concurrency) // no shadow
|
||||
if err == nil {
|
||||
tasks.concurrency = concurrency
|
||||
}
|
||||
} else {
|
||||
// FIXME this is not great, should always be able to set it
|
||||
err = errors.Errorf("cannot set while not replicating")
|
||||
}
|
||||
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (j *ActiveSide) Run(ctx context.Context) {
|
||||
log := GetLogger(ctx)
|
||||
ctx = logging.WithSubsystemLoggers(ctx, log)
|
||||
@@ -436,11 +457,14 @@ func (j *ActiveSide) do(ctx context.Context) {
|
||||
ctx, repCancel := context.WithCancel(ctx)
|
||||
var repWait driver.WaitFunc
|
||||
j.updateTasks(func(tasks *activeSideTasks) {
|
||||
// reset it
|
||||
*tasks = activeSideTasks{}
|
||||
// reset it (almost)
|
||||
old := *tasks
|
||||
*tasks = activeSideTasks{
|
||||
concurrency: old.concurrency,
|
||||
}
|
||||
tasks.replicationCancel = repCancel
|
||||
tasks.replicationReport, repWait = replication.Do(
|
||||
ctx, logic.NewPlanner(j.promRepStateSecs, j.promBytesReplicated, sender, receiver, j.mode.PlannerPolicy()),
|
||||
tasks.replicationReport, repWait, tasks.replicationSetConcurrency = replication.Do(
|
||||
ctx, tasks.concurrency, logic.NewPlanner(j.promRepStateSecs, j.promBytesReplicated, sender, receiver, j.mode.PlannerPolicy()),
|
||||
)
|
||||
tasks.state = ActiveSideReplicating
|
||||
})
|
||||
|
||||
@@ -40,6 +40,7 @@ type Job interface {
|
||||
// must return the root of that subtree as rfs and ok = true
|
||||
OwnedDatasetSubtreeRoot() (rfs *zfs.DatasetPath, ok bool)
|
||||
SenderConfig() *endpoint.SenderConfig
|
||||
SetConcurrency(concurrency int) error
|
||||
}
|
||||
|
||||
type Type string
|
||||
|
||||
@@ -163,6 +163,8 @@ func (j *PassiveSide) SenderConfig() *endpoint.SenderConfig {
|
||||
|
||||
func (*PassiveSide) RegisterMetrics(registerer prometheus.Registerer) {}
|
||||
|
||||
func (*PassiveSide) SetConcurrency(concurrency int) error { return errors.Errorf("not supported") }
|
||||
|
||||
func (j *PassiveSide) Run(ctx context.Context) {
|
||||
|
||||
log := GetLogger(ctx)
|
||||
|
||||
@@ -117,6 +117,8 @@ outer:
|
||||
}
|
||||
}
|
||||
|
||||
func (*SnapJob) SetConcurrency(concurrency int) error { return errors.Errorf("not supported") }
|
||||
|
||||
// Adaptor that implements pruner.History around a pruner.Target.
|
||||
// The ReplicationCursor method is Get-op only and always returns
|
||||
// the filesystem's most recent version's GUID.
|
||||
|
||||
Reference in New Issue
Block a user