From a5f9e42d7cee9ba9ddf035a5f92838d310998d35 Mon Sep 17 00:00:00 2001 From: Anthony Nandaa Date: Mon, 22 Apr 2024 15:15:09 +0300 Subject: [PATCH] fix: gc policy for windows to use percentage of disk space Initially we had the GC Policy for Windows use only 2 GB (2e9 bytes) of disk space and this was limiting for some build scenarios that need more than that, especially ServerCore images. This commit makes the policy to use percentages as it is on Linux. Also going for 20%, double that of Linux, since Windows images tend to be larger. fixes #4858 docker/buildx#2411 Also, refactors the diskSize logic to simplify it by bringing the `d.AsByte` function back from platform specific files to `gcpolicy.go`. Signed-off-by: Anthony Nandaa --- cmd/buildkitd/config/gcpolicy.go | 23 +++++++++++++++++++ cmd/buildkitd/config/gcpolicy_unix.go | 18 ++++----------- cmd/buildkitd/config/gcpolicy_windows.go | 29 ++++++++++++++++++++---- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/cmd/buildkitd/config/gcpolicy.go b/cmd/buildkitd/config/gcpolicy.go index 4078cc6d5910..5e9ac6ac5c02 100644 --- a/cmd/buildkitd/config/gcpolicy.go +++ b/cmd/buildkitd/config/gcpolicy.go @@ -7,6 +7,7 @@ import ( "time" "github.com/docker/go-units" + "github.com/moby/buildkit/util/bklog" "github.com/pkg/errors" ) @@ -104,3 +105,25 @@ func stripQuotes(s string) string { } return s } + +func DetectDefaultGCCap() DiskSpace { + return DiskSpace{Percentage: DiskSpacePercentage} +} + +func (d DiskSpace) AsBytes(root string) int64 { + if d.Bytes != 0 { + return d.Bytes + } + if d.Percentage == 0 { + return 0 + } + + diskSize, err := getDiskSize(root) + if err != nil { + bklog.L.Warnf("failed to get disk size: %v", err) + return defaultCap + } + avail := diskSize * d.Percentage / 100 + rounded := (avail/(1<<30) + 1) * 1e9 // round up + return rounded +} diff --git a/cmd/buildkitd/config/gcpolicy_unix.go b/cmd/buildkitd/config/gcpolicy_unix.go index 232a9ac336cf..a66bec6d1d2f 100644 --- a/cmd/buildkitd/config/gcpolicy_unix.go +++ b/cmd/buildkitd/config/gcpolicy_unix.go @@ -7,23 +7,13 @@ import ( "syscall" ) -func DetectDefaultGCCap() DiskSpace { - return DiskSpace{Percentage: 10} -} - -func (d DiskSpace) AsBytes(root string) int64 { - if d.Bytes != 0 { - return d.Bytes - } - if d.Percentage == 0 { - return 0 - } +var DiskSpacePercentage int64 = 10 +func getDiskSize(root string) (int64, error) { var st syscall.Statfs_t if err := syscall.Statfs(root, &st); err != nil { - return defaultCap + return 0, err } diskSize := int64(st.Bsize) * int64(st.Blocks) - avail := diskSize * d.Percentage / 100 - return (avail/(1<<30) + 1) * 1e9 // round up + return diskSize, nil } diff --git a/cmd/buildkitd/config/gcpolicy_windows.go b/cmd/buildkitd/config/gcpolicy_windows.go index 55ce4dd77278..77c7099de5f8 100644 --- a/cmd/buildkitd/config/gcpolicy_windows.go +++ b/cmd/buildkitd/config/gcpolicy_windows.go @@ -3,10 +3,29 @@ package config -func DetectDefaultGCCap() DiskSpace { - return DiskSpace{Bytes: defaultCap} -} +import ( + "golang.org/x/sys/windows" +) + +// set as double that for Linux since +// Windows images are generally larger. +var DiskSpacePercentage int64 = 20 + +func getDiskSize(root string) (int64, error) { + rootUTF16, err := windows.UTF16FromString(root) + if err != nil { + return 0, err + } + var freeAvailableBytes uint64 + var totalBytes uint64 + var totalFreeBytes uint64 -func (d DiskSpace) AsBytes(root string) int64 { - return d.Bytes + if err := windows.GetDiskFreeSpaceEx( + &rootUTF16[0], + &freeAvailableBytes, + &totalBytes, + &totalFreeBytes); err != nil { + return 0, err + } + return int64(totalBytes), nil }