github.com/mforkel/docker-ce-i386@v17.12.1-ce-rc2+incompatible/components/engine/daemon/disk_usage.go (about)

     1  package daemon
     2  
     3  import (
     4  	"fmt"
     5  	"sync/atomic"
     6  
     7  	"golang.org/x/net/context"
     8  
     9  	"github.com/docker/docker/api/types"
    10  	"github.com/docker/docker/api/types/filters"
    11  	"github.com/docker/docker/layer"
    12  	"github.com/docker/docker/pkg/directory"
    13  	"github.com/docker/docker/volume"
    14  	"github.com/opencontainers/go-digest"
    15  	"github.com/sirupsen/logrus"
    16  )
    17  
    18  func (daemon *Daemon) getLayerRefs(platform string) map[layer.ChainID]int {
    19  	tmpImages := daemon.stores[platform].imageStore.Map()
    20  	layerRefs := map[layer.ChainID]int{}
    21  	for id, img := range tmpImages {
    22  		dgst := digest.Digest(id)
    23  		if len(daemon.referenceStore.References(dgst)) == 0 && len(daemon.stores[platform].imageStore.Children(id)) != 0 {
    24  			continue
    25  		}
    26  
    27  		rootFS := *img.RootFS
    28  		rootFS.DiffIDs = nil
    29  		for _, id := range img.RootFS.DiffIDs {
    30  			rootFS.Append(id)
    31  			chid := rootFS.ChainID()
    32  			layerRefs[chid]++
    33  		}
    34  	}
    35  
    36  	return layerRefs
    37  }
    38  
    39  // SystemDiskUsage returns information about the daemon data disk usage
    40  func (daemon *Daemon) SystemDiskUsage(ctx context.Context) (*types.DiskUsage, error) {
    41  	if !atomic.CompareAndSwapInt32(&daemon.diskUsageRunning, 0, 1) {
    42  		return nil, fmt.Errorf("a disk usage operation is already running")
    43  	}
    44  	defer atomic.StoreInt32(&daemon.diskUsageRunning, 0)
    45  
    46  	// Retrieve container list
    47  	allContainers, err := daemon.Containers(&types.ContainerListOptions{
    48  		Size: true,
    49  		All:  true,
    50  	})
    51  	if err != nil {
    52  		return nil, fmt.Errorf("failed to retrieve container list: %v", err)
    53  	}
    54  
    55  	// Get all top images with extra attributes
    56  	// TODO @jhowardmsft LCOW. This may need revisiting
    57  	allImages, err := daemon.Images(filters.NewArgs(), false, true)
    58  	if err != nil {
    59  		return nil, fmt.Errorf("failed to retrieve image list: %v", err)
    60  	}
    61  
    62  	// Get all local volumes
    63  	allVolumes := []*types.Volume{}
    64  	getLocalVols := func(v volume.Volume) error {
    65  		select {
    66  		case <-ctx.Done():
    67  			return ctx.Err()
    68  		default:
    69  			if d, ok := v.(volume.DetailedVolume); ok {
    70  				// skip local volumes with mount options since these could have external
    71  				// mounted filesystems that will be slow to enumerate.
    72  				if len(d.Options()) > 0 {
    73  					return nil
    74  				}
    75  			}
    76  			name := v.Name()
    77  			refs := daemon.volumes.Refs(v)
    78  
    79  			tv := volumeToAPIType(v)
    80  			sz, err := directory.Size(v.Path())
    81  			if err != nil {
    82  				logrus.Warnf("failed to determine size of volume %v", name)
    83  				sz = -1
    84  			}
    85  			tv.UsageData = &types.VolumeUsageData{Size: sz, RefCount: int64(len(refs))}
    86  			allVolumes = append(allVolumes, tv)
    87  		}
    88  
    89  		return nil
    90  	}
    91  
    92  	err = daemon.traverseLocalVolumes(getLocalVols)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	// Get total layers size on disk
    98  	var allLayersSize int64
    99  	for platform := range daemon.stores {
   100  		layerRefs := daemon.getLayerRefs(platform)
   101  		allLayers := daemon.stores[platform].layerStore.Map()
   102  		for _, l := range allLayers {
   103  			select {
   104  			case <-ctx.Done():
   105  				return nil, ctx.Err()
   106  			default:
   107  				size, err := l.DiffSize()
   108  				if err == nil {
   109  					if _, ok := layerRefs[l.ChainID()]; ok {
   110  						allLayersSize += size
   111  					} else {
   112  						logrus.Warnf("found leaked image layer %v platform %s", l.ChainID(), platform)
   113  					}
   114  				} else {
   115  					logrus.Warnf("failed to get diff size for layer %v %s", l.ChainID(), platform)
   116  				}
   117  			}
   118  		}
   119  	}
   120  
   121  	return &types.DiskUsage{
   122  		LayersSize: allLayersSize,
   123  		Containers: allContainers,
   124  		Volumes:    allVolumes,
   125  		Images:     allImages,
   126  	}, nil
   127  }