Skip to content

Commit

Permalink
config: add freeBytes gc policy entry
Browse files Browse the repository at this point in the history
Signed-off-by: Justin Chadwell <me@jedevc.com>
  • Loading branch information
jedevc committed Jun 24, 2024
1 parent 07e2dce commit 0887e26
Show file tree
Hide file tree
Showing 18 changed files with 358 additions and 238 deletions.
322 changes: 179 additions & 143 deletions api/services/control/control.pb.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions api/services/control/control.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ message PruneRequest {
bool all = 2;
int64 keepDuration = 3 [(gogoproto.nullable) = true];
int64 keepBytes = 4 [(gogoproto.nullable) = true];
int64 freeBytes = 5 [(gogoproto.nullable) = true];
}

message DiskUsageRequest {
Expand Down
90 changes: 63 additions & 27 deletions api/types/worker.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/types/worker.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ message GCPolicy {
int64 keepDuration = 2;
int64 keepBytes = 3;
repeated string filters = 4;
int64 freeBytes = 5;
}

message BuildkitVersion {
Expand Down
58 changes: 41 additions & 17 deletions cache/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/snapshot"
"github.com/moby/buildkit/util/bklog"
"github.com/moby/buildkit/util/disk"
"github.com/moby/buildkit/util/flightcontrol"
"github.com/moby/buildkit/util/progress"
digest "github.com/opencontainers/go-digest"
Expand Down Expand Up @@ -1053,26 +1054,46 @@ func (cm *cacheManager) pruneOnce(ctx context.Context, ch chan client.UsageInfo,
}
}

// TODO: pick a better path here
totalFree, _, err := disk.GetDiskSize(cm.mountPool.tmpdirRoot)
if err != nil {
return err
}

return cm.prune(ctx, ch, pruneOpt{
filter: filter,
all: opt.All,
checkShared: check,
keepDuration: opt.KeepDuration,
keepBytes: opt.KeepBytes,
totalSize: totalSize,
filter: filter,
all: opt.All,
checkShared: check,
keepDuration: opt.KeepDuration,
keepBytes: opt.KeepBytes,
totalKeptBytes: totalSize,
freeBytes: opt.FreeBytes,
totalFreeBytes: totalFree,
})
}

func (cm *cacheManager) prune(ctx context.Context, ch chan client.UsageInfo, opt pruneOpt) (err error) {
var toDelete []*deleteRecord

if opt.keepBytes != 0 && opt.totalSize < opt.keepBytes {
var gcMode, gcNeeded bool
if opt.keepBytes != 0 {
gcMode = true
if opt.totalKeptBytes >= opt.keepBytes {
gcNeeded = true
}
}
if opt.freeBytes != 0 {
gcMode = true
if opt.totalFreeBytes >= opt.freeBytes {
gcNeeded = true
}
}
if gcMode && !gcNeeded {
return nil
}

var toDelete []*deleteRecord

cm.mu.Lock()

gcMode := opt.keepBytes != 0
cutOff := time.Now().Add(-opt.keepDuration)

locked := map[*sync.Mutex]struct{}{}
Expand Down Expand Up @@ -1240,7 +1261,7 @@ func (cm *cacheManager) prune(ctx context.Context, ch chan client.UsageInfo, opt
c.Size = cr.equalImmutable.getSize() // benefit from DiskUsage calc
}

opt.totalSize -= c.Size
opt.totalKeptBytes -= c.Size

if cr.equalImmutable != nil {
if err1 := cr.equalImmutable.remove(ctx, false); err == nil {
Expand Down Expand Up @@ -1606,12 +1627,15 @@ func adaptUsageInfo(info *client.UsageInfo) filters.Adaptor {
}

type pruneOpt struct {
filter filters.Filter
all bool
checkShared ExternalRefChecker
keepDuration time.Duration
keepBytes int64
totalSize int64
filter filters.Filter
all bool
checkShared ExternalRefChecker

keepDuration time.Duration
keepBytes int64
totalKeptBytes int64
freeBytes int64
totalFreeBytes int64
}

type deleteRecord struct {
Expand Down
5 changes: 4 additions & 1 deletion client/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func (c *Client) Prune(ctx context.Context, ch chan UsageInfo, opts ...PruneOpti
Filter: info.Filter,
KeepDuration: int64(info.KeepDuration),
KeepBytes: int64(info.KeepBytes),
FreeBytes: int64(info.FreeBytes),
}
if info.All {
req.All = true
Expand Down Expand Up @@ -63,6 +64,7 @@ type PruneInfo struct {
All bool `json:"all"`
KeepDuration time.Duration `json:"keepDuration"`
KeepBytes int64 `json:"keepBytes"`
FreeBytes int64 `json:"freeBytes"`
}

type pruneOptionFunc func(*PruneInfo)
Expand All @@ -75,9 +77,10 @@ var PruneAll = pruneOptionFunc(func(pi *PruneInfo) {
pi.All = true
})

func WithKeepOpt(duration time.Duration, bytes int64) PruneOption {
func WithKeepOpt(duration time.Duration, bytes int64, freeBytes int64) PruneOption {
return pruneOptionFunc(func(pi *PruneInfo) {
pi.KeepDuration = duration
pi.KeepBytes = bytes
pi.FreeBytes = freeBytes
})
}
1 change: 1 addition & 0 deletions client/workers.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func fromAPIGCPolicy(in []*apitypes.GCPolicy) []PruneInfo {
Filter: p.Filters,
KeepDuration: time.Duration(p.KeepDuration),
KeepBytes: p.KeepBytes,
FreeBytes: p.FreeBytes,
})
}
return out
Expand Down
3 changes: 3 additions & 0 deletions cmd/buildctl/debug/workers.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ func printWorkersVerbose(tw *tabwriter.Writer, winfo []*client.WorkerInfo) {
if rule.KeepBytes > 0 {
fmt.Fprintf(tw, "\tKeep Bytes:\t%g\n", units.Bytes(rule.KeepBytes))
}
if rule.FreeBytes > 0 {
fmt.Fprintf(tw, "\tFree Bytes:\t%g\n", units.Bytes(rule.FreeBytes))
}
}
fmt.Fprintf(tw, "\n")
}
Expand Down
10 changes: 9 additions & 1 deletion cmd/buildctl/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ var pruneCommand = cli.Command{
Name: "keep-storage",
Usage: "Keep data below this limit (in MB)",
},
cli.Float64Flag{
Name: "free-storage",
Usage: "Keep free data below this limit (in MB)",
},
cli.StringSliceFlag{
Name: "filter, f",
Usage: "Filter records",
Expand Down Expand Up @@ -56,7 +60,11 @@ func prune(clicontext *cli.Context) error {

opts := []client.PruneOption{
client.WithFilter(clicontext.StringSlice("filter")),
client.WithKeepOpt(clicontext.Duration("keep-duration"), int64(clicontext.Float64("keep-storage")*1e6)),
client.WithKeepOpt(
clicontext.Duration("keep-duration"),
int64(clicontext.Float64("keep-storage")*1e6),
int64(clicontext.Float64("free-storage")*1e6),
),
}

if clicontext.Bool("all") {
Expand Down
1 change: 1 addition & 0 deletions cmd/buildkitd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ type GCPolicy struct {
All bool `toml:"all"`
KeepBytes DiskSpace `toml:"keepBytes"`
KeepDuration Duration `toml:"keepDuration"`
FreeBytes DiskSpace `toml:"freeBytes"`
Filters []string `toml:"filters"`
}

Expand Down
3 changes: 2 additions & 1 deletion cmd/buildkitd/config/gcpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/docker/go-units"
"github.com/moby/buildkit/util/bklog"
"github.com/moby/buildkit/util/disk"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -118,7 +119,7 @@ func (d DiskSpace) AsBytes(root string) int64 {
return 0
}

diskSize, err := getDiskSize(root)
_, diskSize, err := disk.GetDiskSize(root)
if err != nil {
bklog.L.Warnf("failed to get disk size: %v", err)
return defaultCap
Expand Down
16 changes: 0 additions & 16 deletions cmd/buildkitd/config/gcpolicy_unix.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,3 @@
//go:build !windows && !openbsd
// +build !windows,!openbsd

package config

import (
"syscall"
)

var DiskSpacePercentage int64 = 10

func getDiskSize(root string) (int64, error) {
var st syscall.Statfs_t
if err := syscall.Statfs(root, &st); err != nil {
return 0, err
}
diskSize := int64(st.Bsize) * int64(st.Blocks)
return diskSize, nil
}
26 changes: 0 additions & 26 deletions cmd/buildkitd/config/gcpolicy_windows.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,5 @@
//go:build windows
// +build windows

package config

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

if err := windows.GetDiskFreeSpaceEx(
&rootUTF16[0],
&freeAvailableBytes,
&totalBytes,
&totalFreeBytes); err != nil {
return 0, err
}
return int64(totalBytes), nil
}
1 change: 1 addition & 0 deletions cmd/buildkitd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,7 @@ func getGCPolicy(cfg config.GCConfig, root string) []client.PruneInfo {
All: rule.All,
KeepBytes: rule.KeepBytes.AsBytes(root),
KeepDuration: rule.KeepDuration.Duration,
FreeBytes: rule.FreeBytes.AsBytes(root),
})
}
return out
Expand Down
Loading

0 comments on commit 0887e26

Please sign in to comment.