From 2155b46915a4df821405d26f576d9fae9fa5178e Mon Sep 17 00:00:00 2001 From: Zhang Wei Date: Tue, 19 Jul 2016 00:02:41 +0800 Subject: [PATCH 1/2] Enhancement: allow parallel stop Stop multiple containers in parallel to speed up stop process, allow maximum 50 parallel stops. Signed-off-by: Abhinav Dahiya Signed-off-by: Zhang Wei --- cli/command/container/stop.go | 8 ++++++-- cli/command/container/utils.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/cli/command/container/stop.go b/cli/command/container/stop.go index dddb7efa22..2f22fd09a4 100644 --- a/cli/command/container/stop.go +++ b/cli/command/container/stop.go @@ -39,11 +39,15 @@ func NewStopCommand(dockerCli *command.DockerCli) *cobra.Command { func runStop(dockerCli *command.DockerCli, opts *stopOptions) error { ctx := context.Background() + timeout := time.Duration(opts.time) * time.Second var errs []string + + errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, id string) error { + return dockerCli.Client().ContainerStop(ctx, id, &timeout) + }) for _, container := range opts.containers { - timeout := time.Duration(opts.time) * time.Second - if err := dockerCli.Client().ContainerStop(ctx, container, &timeout); err != nil { + if err := <-errChan; err != nil { errs = append(errs, err.Error()) } else { fmt.Fprintf(dockerCli.Out(), "%s\n", container) diff --git a/cli/command/container/utils.go b/cli/command/container/utils.go index 8c993dcce5..7e895834f9 100644 --- a/cli/command/container/utils.go +++ b/cli/command/container/utils.go @@ -90,3 +90,35 @@ func getExitCode(dockerCli *command.DockerCli, ctx context.Context, containerID } return c.State.Running, c.State.ExitCode, nil } + +func parallelOperation(ctx context.Context, cids []string, op func(ctx context.Context, id string) error) chan error { + if len(cids) == 0 { + return nil + } + const defaultParallel int = 50 + sem := make(chan struct{}, defaultParallel) + errChan := make(chan error) + + // make sure result is printed in correct order + output := map[string]chan error{} + for _, c := range cids { + output[c] = make(chan error, 1) + } + go func() { + for _, c := range cids { + err := <-output[c] + errChan <- err + } + }() + + go func() { + for _, c := range cids { + sem <- struct{}{} // Wait for active queue sem to drain. + go func(container string) { + output[container] <- op(ctx, container) + <-sem + }(c) + } + }() + return errChan +} From f1dda4395eb52eaeca8f9a1c76c2e2c3e6532490 Mon Sep 17 00:00:00 2001 From: Zhang Wei Date: Mon, 12 Sep 2016 17:21:08 +0800 Subject: [PATCH 2/2] Add parallel operation support for pause/unpause Support parallel pause/unpause Signed-off-by: Zhang Wei --- cli/command/container/pause.go | 3 ++- cli/command/container/unpause.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cli/command/container/pause.go b/cli/command/container/pause.go index 0cc5b351ba..6817cf60eb 100644 --- a/cli/command/container/pause.go +++ b/cli/command/container/pause.go @@ -34,8 +34,9 @@ func runPause(dockerCli *command.DockerCli, opts *pauseOptions) error { ctx := context.Background() var errs []string + errChan := parallelOperation(ctx, opts.containers, dockerCli.Client().ContainerPause) for _, container := range opts.containers { - if err := dockerCli.Client().ContainerPause(ctx, container); err != nil { + if err := <-errChan; err != nil { errs = append(errs, err.Error()) } else { fmt.Fprintf(dockerCli.Out(), "%s\n", container) diff --git a/cli/command/container/unpause.go b/cli/command/container/unpause.go index c3635db555..c4d8d4841e 100644 --- a/cli/command/container/unpause.go +++ b/cli/command/container/unpause.go @@ -35,8 +35,9 @@ func runUnpause(dockerCli *command.DockerCli, opts *unpauseOptions) error { ctx := context.Background() var errs []string + errChan := parallelOperation(ctx, opts.containers, dockerCli.Client().ContainerUnpause) for _, container := range opts.containers { - if err := dockerCli.Client().ContainerUnpause(ctx, container); err != nil { + if err := <-errChan; err != nil { errs = append(errs, err.Error()) } else { fmt.Fprintf(dockerCli.Out(), "%s\n", container)