Repository: moby/moby (language: go)

Issue:
dockerd max-concurrent-uploads/download is not working according to the documentation
### Description

According to the [documentation](https://docs.docker.com/engine/reference/commandline/dockerd/#daemon), max-concurrent-uploads/download is set for ***each*** push/pull command:

>      --max-concurrent-uploads int            Set the max concurrent uploads for each push (default 5)
>      --max-download-attempts int             Set the max download attempts for each pull (default 5)

However, it seems the max-concurrent-uploads/download is a “global” limit across all the transfers running on the dockerd daemon:

* https://github.com/moby/moby/blob/v20.10.20/distribution/xfer/transfer.go#L282-L301
* https://github.com/moby/moby/blob/v20.10.20/distribution/xfer/transfer.go#L321-L393

So, if I'm running multiple docker pushes/pulls in parallel, the max concurrent uploads/downloads will be respected across all the pushes/pulls, instead of being for each push/pull.

It seems like the documentation is wrong, or there is a bug?

### Reproduce

https://user-images.githubusercontent.com/33168/197350928-2649b864-7a6c-4eeb-a2dc-fb23e26df9c6.mov



### Expected behavior

_No response_

### docker version

```bash
Client:
 Cloud integration: v1.0.29
 Version:           20.10.20
 API version:       1.41
 Go version:        go1.18.7
 Git commit:        9fdeb9c
 Built:             Tue Oct 18 18:20:35 2022
 OS/Arch:           darwin/amd64
 Context:           default
 Experimental:      true

Server: Docker Desktop 4.13.0 (89412)
 Engine:
  Version:          20.10.20
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.18.7
  Git commit:       03df974
  Built:            Tue Oct 18 18:18:35 2022
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.8
  GitCommit:        9cd3357b7fd7218e4aec3eae239db1f68a5a6ec6
 runc:
  Version:          1.1.4
  GitCommit:        v1.1.4-0-g5fd4c4d
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
```


### docker info

```bash
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc., v0.9.1)
  compose: Docker Compose (Docker Inc., v2.12.0)
  dev: Docker Dev Environments (Docker Inc., v0.0.3)
  extension: Manages Docker extensions (Docker Inc., v0.2.13)
  sbom: View the packaged-based Software Bill Of Materials (SBOM) for an image (Anchore Inc., 0.6.0)
  scan: Docker Scan (Docker Inc., v0.21.0)

Server:
 Containers: 60
  Running: 5
  Paused: 0
  Stopped: 55
 Images: 257
 Server Version: 20.10.20
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: runc io.containerd.runc.v2 io.containerd.runtime.v1.linux
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 9cd3357b7fd7218e4aec3eae239db1f68a5a6ec6
 runc version: v1.1.4-0-g5fd4c4d
 init version: de40ad0
 Security Options:
  seccomp
   Profile: default
  cgroupns
 Kernel Version: 5.15.49-linuxkit
 Operating System: Docker Desktop
 OSType: linux
 Architecture: x86_64
 CPUs: 8
 Total Memory: 7.772GiB
 Name: docker-desktop
 ID: JUMX:UP7B:ZRFZ:4IGD:DKZE:EVL3:VMCC:KZ4L:RY42:4WWM:735H:2SYH
 Docker Root Dir: /var/lib/docker
 Debug Mode: true
  File Descriptors: 45
  Goroutines: 48
  System Time: 2022-10-22T16:34:36.239358203Z
  EventsListeners: 4
 HTTP Proxy: http.docker.internal:3128
 HTTPS Proxy: http.docker.internal:3128
 No Proxy: hubproxy.docker.internal
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  hubproxy.docker.internal:5000
  127.0.0.0/8
 Live Restore Enabled: false
```


### Additional Info

_No response_


Discussion / hints:
My view is that the documentation is wrong here. The limits were implemented before the documentation was added. Looking at the history, these setting were added in 7368e41c07c21a1e2c6a49abecd1c2fc76404e49 to address issues with downloads not being able to complete in some environments due to too many concurrent transfers happening at the same time.
In this context, those limits only make sense if you apply them to the whole engine.

Fix patch:
diff --git a/cmd/dockerd/config.go b/cmd/dockerd/config.go
index 8b6dfed39e3fc..263efc28aa2fa 100644
--- a/cmd/dockerd/config.go
+++ b/cmd/dockerd/config.go
@@ -45,8 +45,8 @@ func installCommonConfigFlags(conf *config.Config, flags *pflag.FlagSet) error {
 	flags.Var(opts.NewNamedMapOpts("log-opts", conf.LogConfig.Config, nil), "log-opt", "Default log driver options for containers")
 
 	flags.StringVar(&conf.CorsHeaders, "api-cors-header", "", "Set CORS headers in the Engine API")
-	flags.IntVar(&conf.MaxConcurrentDownloads, "max-concurrent-downloads", conf.MaxConcurrentDownloads, "Set the max concurrent downloads for each pull")
-	flags.IntVar(&conf.MaxConcurrentUploads, "max-concurrent-uploads", conf.MaxConcurrentUploads, "Set the max concurrent uploads for each push")
+	flags.IntVar(&conf.MaxConcurrentDownloads, "max-concurrent-downloads", conf.MaxConcurrentDownloads, "Set the max concurrent downloads")
+	flags.IntVar(&conf.MaxConcurrentUploads, "max-concurrent-uploads", conf.MaxConcurrentUploads, "Set the max concurrent uploads")
 	flags.IntVar(&conf.MaxDownloadAttempts, "max-download-attempts", conf.MaxDownloadAttempts, "Set the max download attempts for each pull")
 	flags.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", conf.ShutdownTimeout, "Set the default shutdown timeout")
 
diff --git a/daemon/config/config.go b/daemon/config/config.go
index a47515d161d91..d1f02c330c95d 100644
--- a/daemon/config/config.go
+++ b/daemon/config/config.go
@@ -24,11 +24,11 @@ import (
 const (
 	// DefaultMaxConcurrentDownloads is the default value for
 	// maximum number of downloads that
-	// may take place at a time for each pull.
+	// may take place at a time.
 	DefaultMaxConcurrentDownloads = 3
 	// DefaultMaxConcurrentUploads is the default value for
 	// maximum number of uploads that
-	// may take place at a time for each push.
+	// may take place at a time.
 	DefaultMaxConcurrentUploads = 5
 	// DefaultDownloadAttempts is the default value for
 	// maximum number of attempts that


Test patch: