github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/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/Sirupsen/logrus" 10 "github.com/docker/docker/api/types" 11 "github.com/docker/docker/api/types/filters" 12 "github.com/docker/docker/layer" 13 "github.com/docker/docker/pkg/directory" 14 "github.com/docker/docker/volume" 15 "github.com/opencontainers/go-digest" 16 ) 17 18 func (daemon *Daemon) getLayerRefs() map[layer.ChainID]int { 19 tmpImages := daemon.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.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 allImages, err := daemon.Images(filters.NewArgs(), false, true) 57 if err != nil { 58 return nil, fmt.Errorf("failed to retrieve image list: %v", err) 59 } 60 61 // Get all local volumes 62 allVolumes := []*types.Volume{} 63 getLocalVols := func(v volume.Volume) error { 64 select { 65 case <-ctx.Done(): 66 return ctx.Err() 67 default: 68 name := v.Name() 69 refs := daemon.volumes.Refs(v) 70 71 tv := volumeToAPIType(v) 72 sz, err := directory.Size(v.Path()) 73 if err != nil { 74 logrus.Warnf("failed to determine size of volume %v", name) 75 sz = -1 76 } 77 tv.UsageData = &types.VolumeUsageData{Size: sz, RefCount: int64(len(refs))} 78 allVolumes = append(allVolumes, tv) 79 } 80 81 return nil 82 } 83 84 err = daemon.traverseLocalVolumes(getLocalVols) 85 if err != nil { 86 return nil, err 87 } 88 89 // Get total layers size on disk 90 layerRefs := daemon.getLayerRefs() 91 allLayers := daemon.layerStore.Map() 92 var allLayersSize int64 93 for _, l := range allLayers { 94 select { 95 case <-ctx.Done(): 96 return nil, ctx.Err() 97 default: 98 size, err := l.DiffSize() 99 if err == nil { 100 if _, ok := layerRefs[l.ChainID()]; ok { 101 allLayersSize += size 102 } else { 103 logrus.Warnf("found leaked image layer %v", l.ChainID()) 104 } 105 } else { 106 logrus.Warnf("failed to get diff size for layer %v", l.ChainID()) 107 } 108 } 109 } 110 111 return &types.DiskUsage{ 112 LayersSize: allLayersSize, 113 Containers: allContainers, 114 Volumes: allVolumes, 115 Images: allImages, 116 }, nil 117 }