Преглед изворни кода

Don’t hold container lock for size calculation

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Tonis Tiigi пре 8 година
родитељ
комит
bd33a99acf
6 измењених фајлова са 39 додато и 33 уклоњено
  1. 1 1
      daemon/container_operations_windows.go
  2. 8 8
      daemon/getsize_unix.go
  3. 12 14
      daemon/inspect.go
  4. 1 1
      daemon/inspect_unix.go
  5. 15 7
      daemon/list.go
  6. 2 2
      daemon/prune.go

+ 1 - 1
daemon/container_operations_windows.go

@@ -12,7 +12,7 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s
 }
 }
 
 
 // getSize returns real size & virtual size
 // getSize returns real size & virtual size
-func (daemon *Daemon) getSize(container *container.Container) (int64, int64) {
+func (daemon *Daemon) getSize(containerID string) (int64, int64) {
 	// TODO Windows
 	// TODO Windows
 	return 0, 0
 	return 0, 0
 }
 }

+ 8 - 8
daemon/getsize_unix.go

@@ -4,32 +4,32 @@ package daemon
 
 
 import (
 import (
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
-	"github.com/docker/docker/container"
 )
 )
 
 
 // getSize returns the real size & virtual size of the container.
 // getSize returns the real size & virtual size of the container.
-func (daemon *Daemon) getSize(container *container.Container) (int64, int64) {
+func (daemon *Daemon) getSize(containerID string) (int64, int64) {
 	var (
 	var (
 		sizeRw, sizeRootfs int64
 		sizeRw, sizeRootfs int64
 		err                error
 		err                error
 	)
 	)
 
 
-	if err := daemon.Mount(container); err != nil {
-		logrus.Errorf("Failed to compute size of container rootfs %s: %s", container.ID, err)
+	rwlayer, err := daemon.layerStore.GetRWLayer(containerID)
+	if err != nil {
+		logrus.Errorf("Failed to compute size of container rootfs %v: %v", containerID, err)
 		return sizeRw, sizeRootfs
 		return sizeRw, sizeRootfs
 	}
 	}
-	defer daemon.Unmount(container)
+	defer daemon.layerStore.ReleaseRWLayer(rwlayer)
 
 
-	sizeRw, err = container.RWLayer.Size()
+	sizeRw, err = rwlayer.Size()
 	if err != nil {
 	if err != nil {
 		logrus.Errorf("Driver %s couldn't return diff size of container %s: %s",
 		logrus.Errorf("Driver %s couldn't return diff size of container %s: %s",
-			daemon.GraphDriverName(), container.ID, err)
+			daemon.GraphDriverName(), containerID, err)
 		// FIXME: GetSize should return an error. Not changing it now in case
 		// FIXME: GetSize should return an error. Not changing it now in case
 		// there is a side-effect.
 		// there is a side-effect.
 		sizeRw = -1
 		sizeRw = -1
 	}
 	}
 
 
-	if parent := container.RWLayer.Parent(); parent != nil {
+	if parent := rwlayer.Parent(); parent != nil {
 		sizeRootfs, err = parent.Size()
 		sizeRootfs, err = parent.Size()
 		if err != nil {
 		if err != nil {
 			sizeRootfs = -1
 			sizeRootfs = -1

+ 12 - 14
daemon/inspect.go

@@ -36,10 +36,10 @@ func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.Co
 	}
 	}
 
 
 	container.Lock()
 	container.Lock()
-	defer container.Unlock()
 
 
-	base, err := daemon.getInspectData(container, size)
+	base, err := daemon.getInspectData(container)
 	if err != nil {
 	if err != nil {
+		container.Unlock()
 		return nil, err
 		return nil, err
 	}
 	}
 
 
@@ -73,6 +73,14 @@ func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.Co
 	}
 	}
 	networkSettings.NetworkSettingsBase.Ports = ports
 	networkSettings.NetworkSettingsBase.Ports = ports
 
 
+	container.Unlock()
+
+	if size {
+		sizeRw, sizeRootFs := daemon.getSize(base.ID)
+		base.SizeRw = &sizeRw
+		base.SizeRootFs = &sizeRootFs
+	}
+
 	return &types.ContainerJSON{
 	return &types.ContainerJSON{
 		ContainerJSONBase: base,
 		ContainerJSONBase: base,
 		Mounts:            mountPoints,
 		Mounts:            mountPoints,
@@ -91,7 +99,7 @@ func (daemon *Daemon) containerInspect120(name string) (*v1p20.ContainerJSON, er
 	container.Lock()
 	container.Lock()
 	defer container.Unlock()
 	defer container.Unlock()
 
 
-	base, err := daemon.getInspectData(container, false)
+	base, err := daemon.getInspectData(container)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -114,7 +122,7 @@ func (daemon *Daemon) containerInspect120(name string) (*v1p20.ContainerJSON, er
 	}, nil
 	}, nil
 }
 }
 
 
-func (daemon *Daemon) getInspectData(container *container.Container, size bool) (*types.ContainerJSONBase, error) {
+func (daemon *Daemon) getInspectData(container *container.Container) (*types.ContainerJSONBase, error) {
 	// make a copy to play with
 	// make a copy to play with
 	hostConfig := *container.HostConfig
 	hostConfig := *container.HostConfig
 
 
@@ -168,16 +176,6 @@ func (daemon *Daemon) getInspectData(container *container.Container, size bool)
 		HostConfig:   &hostConfig,
 		HostConfig:   &hostConfig,
 	}
 	}
 
 
-	var (
-		sizeRw     int64
-		sizeRootFs int64
-	)
-	if size {
-		sizeRw, sizeRootFs = daemon.getSize(container)
-		contJSONBase.SizeRw = &sizeRw
-		contJSONBase.SizeRootFs = &sizeRootFs
-	}
-
 	// Now set any platform-specific fields
 	// Now set any platform-specific fields
 	contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase)
 	contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase)
 
 

+ 1 - 1
daemon/inspect_unix.go

@@ -30,7 +30,7 @@ func (daemon *Daemon) containerInspectPre120(name string) (*v1p19.ContainerJSON,
 	container.Lock()
 	container.Lock()
 	defer container.Unlock()
 	defer container.Unlock()
 
 
-	base, err := daemon.getInspectData(container, false)
+	base, err := daemon.getInspectData(container)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}

+ 15 - 7
daemon/list.go

@@ -208,19 +208,32 @@ func (daemon *Daemon) reduceContainers(config *types.ContainerListOptions, reduc
 // reducePsContainer is the basic representation for a container as expected by the ps command.
 // reducePsContainer is the basic representation for a container as expected by the ps command.
 func (daemon *Daemon) reducePsContainer(container *container.Container, ctx *listContext, reducer containerReducer) (*types.Container, error) {
 func (daemon *Daemon) reducePsContainer(container *container.Container, ctx *listContext, reducer containerReducer) (*types.Container, error) {
 	container.Lock()
 	container.Lock()
-	defer container.Unlock()
 
 
 	// filter containers to return
 	// filter containers to return
 	action := includeContainerInList(container, ctx)
 	action := includeContainerInList(container, ctx)
 	switch action {
 	switch action {
 	case excludeContainer:
 	case excludeContainer:
+		container.Unlock()
 		return nil, nil
 		return nil, nil
 	case stopIteration:
 	case stopIteration:
+		container.Unlock()
 		return nil, errStopIteration
 		return nil, errStopIteration
 	}
 	}
 
 
 	// transform internal container struct into api structs
 	// transform internal container struct into api structs
-	return reducer(container, ctx)
+	newC, err := reducer(container, ctx)
+	container.Unlock()
+	if err != nil {
+		return nil, err
+	}
+
+	// release lock because size calculation is slow
+	if ctx.Size {
+		sizeRw, sizeRootFs := daemon.getSize(newC.ID)
+		newC.SizeRw = sizeRw
+		newC.SizeRootFs = sizeRootFs
+	}
+	return newC, nil
 }
 }
 
 
 // foldFilter generates the container filter based on the user's filtering options.
 // foldFilter generates the container filter based on the user's filtering options.
@@ -642,11 +655,6 @@ func (daemon *Daemon) transformContainer(container *container.Container, ctx *li
 		}
 		}
 	}
 	}
 
 
-	if ctx.Size {
-		sizeRw, sizeRootFs := daemon.getSize(container)
-		newC.SizeRw = sizeRw
-		newC.SizeRootFs = sizeRootFs
-	}
 	newC.Labels = container.Config.Labels
 	newC.Labels = container.Config.Labels
 	newC.Mounts = addMountPoints(container)
 	newC.Mounts = addMountPoints(container)
 
 

+ 2 - 2
daemon/prune.go

@@ -16,7 +16,7 @@ import (
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/volume"
 	"github.com/docker/docker/volume"
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork"
-	"github.com/opencontainers/go-digest"
+	digest "github.com/opencontainers/go-digest"
 )
 )
 
 
 // ContainersPrune removes unused containers
 // ContainersPrune removes unused containers
@@ -34,7 +34,7 @@ func (daemon *Daemon) ContainersPrune(pruneFilters filters.Args) (*types.Contain
 			if !until.IsZero() && c.Created.After(until) {
 			if !until.IsZero() && c.Created.After(until) {
 				continue
 				continue
 			}
 			}
-			cSize, _ := daemon.getSize(c)
+			cSize, _ := daemon.getSize(c.ID)
 			// TODO: sets RmLink to true?
 			// TODO: sets RmLink to true?
 			err := daemon.ContainerRm(c.ID, &types.ContainerRmConfig{})
 			err := daemon.ContainerRm(c.ID, &types.ContainerRmConfig{})
 			if err != nil {
 			if err != nil {