Merge pull request #18506 from nalind/so-much-diffsize

libpod/Container.rootFsSize(): use recorded image sizes
This commit is contained in:
OpenShift Merge Robot 2023-05-10 06:08:12 -04:00 committed by GitHub
commit c307aeba37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 37 additions and 63 deletions

View File

@ -55,10 +55,11 @@ const (
preCheckpointDir = "pre-checkpoint" preCheckpointDir = "pre-checkpoint"
) )
// rootFsSize gets the size of the container's root filesystem // rootFsSize gets the size of the container, which can be divided notionally
// A container FS is split into two parts. The first is the top layer, a // into two parts. The first is the part of its size that can be directly
// mutable layer, and the rest is the RootFS: the set of immutable layers // attributed to its base image, if it has one. The second is the set of
// that make up the image on which the container is based. // changes that the container has had made relative to that base image. Both
// parts include some ancillary data, and we count that, too.
func (c *Container) rootFsSize() (int64, error) { func (c *Container) rootFsSize() (int64, error) {
if c.config.Rootfs != "" { if c.config.Rootfs != "" {
return 0, nil return 0, nil
@ -72,58 +73,33 @@ func (c *Container) rootFsSize() (int64, error) {
return 0, err return 0, err
} }
// Ignore the size of the top layer. The top layer is a mutable RW layer
// and is not considered a part of the rootfs
rwLayer, err := c.runtime.store.Layer(container.LayerID)
if err != nil {
return 0, err
}
layer, err := c.runtime.store.Layer(rwLayer.Parent)
if err != nil {
return 0, err
}
size := int64(0) size := int64(0)
for layer.Parent != "" { if container.ImageID != "" {
layerSize, err := c.runtime.store.DiffSize(layer.Parent, layer.ID) size, err = c.runtime.store.ImageSize(container.ImageID)
if err != nil {
return size, fmt.Errorf("getting diffsize of layer %q and its parent %q: %w", layer.ID, layer.Parent, err)
}
size += layerSize
layer, err = c.runtime.store.Layer(layer.Parent)
if err != nil { if err != nil {
return 0, err return 0, err
} }
} }
// Get the size of the last layer. Has to be outside of the loop
// because the parent of the last layer is "", and lstore.Get("") layerSize, err := c.runtime.store.ContainerSize(c.ID())
// will return an error.
layerSize, err := c.runtime.store.DiffSize(layer.Parent, layer.ID)
return size + layerSize, err return size + layerSize, err
} }
// rwSize gets the size of the mutable top layer of the container. // rwSize gets the combined size of the writeable layer and any ancillary data
// for a given container.
func (c *Container) rwSize() (int64, error) { func (c *Container) rwSize() (int64, error) {
if c.config.Rootfs != "" { if c.config.Rootfs != "" {
size, err := util.SizeOfPath(c.config.Rootfs) size, err := util.SizeOfPath(c.config.Rootfs)
return int64(size), err return int64(size), err
} }
container, err := c.runtime.store.Container(c.ID()) layerSize, err := c.runtime.store.ContainerSize(c.ID())
if err != nil { if err != nil {
return 0, err return 0, err
} }
// The top layer of a container is return layerSize, nil
// the only readable/writeable layer, all others are immutable.
rwLayer, err := c.runtime.store.Layer(container.LayerID)
if err != nil {
return 0, err
}
// Get the size of the top layer by calculating the size of the diff
// between the layer and its parent.
return c.runtime.store.DiffSize(rwLayer.Parent, rwLayer.ID)
} }
// bundlePath returns the path to the container's root filesystem - where the OCI spec will be // bundlePath returns the path to the container's root filesystem - where the OCI spec will be

View File

@ -6,7 +6,7 @@ import (
"github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/libpod/lock" "github.com/containers/podman/v4/libpod/lock"
"github.com/containers/podman/v4/libpod/plugin" "github.com/containers/podman/v4/libpod/plugin"
"github.com/containers/podman/v4/pkg/util" "github.com/containers/storage/pkg/directory"
) )
// Volume is a libpod named volume. // Volume is a libpod named volume.
@ -109,7 +109,8 @@ func (v *Volume) Name() string {
// Returns the size on disk of volume // Returns the size on disk of volume
func (v *Volume) Size() (uint64, error) { func (v *Volume) Size() (uint64, error) {
return util.SizeOfPath(v.config.MountPoint) size, err := directory.Size(v.config.MountPoint)
return uint64(size), err
} }
// Driver retrieves the volume's driver. // Driver retrieves the volume's driver.

View File

@ -18,6 +18,7 @@ import (
"github.com/containers/podman/v4/pkg/util" "github.com/containers/podman/v4/pkg/util"
"github.com/containers/podman/v4/utils" "github.com/containers/podman/v4/utils"
"github.com/containers/storage" "github.com/containers/storage"
"github.com/containers/storage/pkg/directory"
"github.com/containers/storage/pkg/unshare" "github.com/containers/storage/pkg/unshare"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/spf13/pflag" "github.com/spf13/pflag"
@ -280,7 +281,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
dfImages = append(dfImages, &report) dfImages = append(dfImages, &report)
} }
// Get Containers and iterate them // Get containers and iterate over them
cons, err := ic.Libpod.GetAllContainers() cons, err := ic.Libpod.GetAllContainers()
if err != nil { if err != nil {
return nil, err return nil, err
@ -322,7 +323,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
dfContainers = append(dfContainers, &report) dfContainers = append(dfContainers, &report)
} }
// Get volumes and iterate them // Get volumes and iterate over them
vols, err := ic.Libpod.GetAllVolumes() vols, err := ic.Libpod.GetAllVolumes()
if err != nil { if err != nil {
return nil, err return nil, err
@ -330,7 +331,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
dfVolumes := make([]*entities.SystemDfVolumeReport, 0, len(vols)) dfVolumes := make([]*entities.SystemDfVolumeReport, 0, len(vols))
for _, v := range vols { for _, v := range vols {
var reclaimableSize uint64 var reclaimableSize int64
mountPoint, err := v.MountPoint() mountPoint, err := v.MountPoint()
if err != nil { if err != nil {
return nil, err return nil, err
@ -341,7 +342,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
// TODO: fix this. // TODO: fix this.
continue continue
} }
volSize, err := util.SizeOfPath(mountPoint) volSize, err := directory.Size(mountPoint)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -355,8 +356,8 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
report := entities.SystemDfVolumeReport{ report := entities.SystemDfVolumeReport{
VolumeName: v.Name(), VolumeName: v.Name(),
Links: len(inUse), Links: len(inUse),
Size: int64(volSize), Size: volSize,
ReclaimableSize: int64(reclaimableSize), ReclaimableSize: reclaimableSize,
} }
dfVolumes = append(dfVolumes, &report) dfVolumes = append(dfVolumes, &report)
} }

View File

@ -3,7 +3,6 @@ package util
import ( import (
"errors" "errors"
"fmt" "fmt"
"io/fs"
"math" "math"
"os" "os"
"os/user" "os/user"
@ -26,6 +25,7 @@ import (
"github.com/containers/podman/v4/pkg/namespaces" "github.com/containers/podman/v4/pkg/namespaces"
"github.com/containers/podman/v4/pkg/rootless" "github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/pkg/signal" "github.com/containers/podman/v4/pkg/signal"
"github.com/containers/storage/pkg/directory"
"github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/idtools"
stypes "github.com/containers/storage/types" stypes "github.com/containers/storage/types"
securejoin "github.com/cyphar/filepath-securejoin" securejoin "github.com/cyphar/filepath-securejoin"
@ -618,19 +618,10 @@ func LookupUser(name string) (*user.User, error) {
// SizeOfPath determines the file usage of a given path. it was called volumeSize in v1 // SizeOfPath determines the file usage of a given path. it was called volumeSize in v1
// and now is made to be generic and take a path instead of a libpod volume // and now is made to be generic and take a path instead of a libpod volume
// Deprecated: use github.com/containers/storage/pkg/directory.Size() instead.
func SizeOfPath(path string) (uint64, error) { func SizeOfPath(path string) (uint64, error) {
var size uint64 size, err := directory.Size(path)
err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error { return uint64(size), err
if err == nil && !d.IsDir() {
info, err := d.Info()
if err != nil {
return err
}
size += uint64(info.Size())
}
return err
})
return size, err
} }
// EncryptConfig translates encryptionKeys into a EncriptionsConfig structure // EncryptConfig translates encryptionKeys into a EncriptionsConfig structure

View File

@ -55,18 +55,23 @@ function teardown() {
Type | Images | Containers | Local Volumes Type | Images | Containers | Local Volumes
Total | 1 | 2 | 0 Total | 1 | 2 | 0
Active | 1 | 1 | 0 Active | 1 | 1 | 0
RawSize | ~12...... | 0 | 0 RawSize | ~12...... | !0 | 0
RawReclaimable | 0 | 0 | 0 RawReclaimable | 0 | !0 | 0
Reclaimable | ~\(0%\) | ~\(50%\) | ~\(0%\)
TotalCount | 1 | 2 | 0 TotalCount | 1 | 2 | 0
Size | ~12.*MB | 0B | 0B Size | ~12.*MB | !0B | 0B
' '
while read -a fields; do while read -a fields; do
for i in 0 1 2;do for i in 0 1 2;do
expect="${fields[$((i+1))]}" expect="${fields[$((i+1))]}"
actual=$(jq -r ".[$i].${fields[0]}" <<<"$results") actual=$(jq -r ".[$i].${fields[0]}" <<<"$results")
# Do exact-match check, unless the expect term starts with ~ # Do exact-match check, unless the expect term starts with ~ or !
op='=' op='='
if [[ "$expect" =~ ^\! ]]; then
op='!='
expect=${expect##\!}
fi
if [[ "$expect" =~ ^~ ]]; then if [[ "$expect" =~ ^~ ]]; then
op='=~' op='=~'
expect=${expect##\~} expect=${expect##\~}