From 0a402db53ce7ca9177cbce691ce6a802f88ea183 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Mon, 9 Mar 2026 21:57:53 -0700 Subject: [PATCH] refactor: add typed sync.Pool wrapper to eliminate any Introduce util/pools.Pool[T] as a generic typed wrapper around sync.Pool. Migrate existing pool usages in contenthash, converter, and overlay packages to use the new wrapper, removing unchecked type assertions at each call site. Signed-off-by: Tonis Tiigi --- cache/contenthash/checksum.go | 13 ++++++------- util/converter/converter.go | 11 +++++------ util/overlay/overlay_linux.go | 16 +++++++--------- util/pools/pools.go | 29 +++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 util/pools/pools.go diff --git a/cache/contenthash/checksum.go b/cache/contenthash/checksum.go index f9641a5a0..0f28ca091 100644 --- a/cache/contenthash/checksum.go +++ b/cache/contenthash/checksum.go @@ -19,6 +19,7 @@ import ( "github.com/moby/buildkit/session" "github.com/moby/buildkit/snapshot" "github.com/moby/buildkit/util/cachedigest" + "github.com/moby/buildkit/util/pools" "github.com/moby/locker" "github.com/moby/patternmatcher" digest "github.com/opencontainers/go-digest" @@ -1261,15 +1262,13 @@ func ensureOriginMetadata(md cache.RefMetadata) cache.RefMetadata { return em } -var pool32K = sync.Pool{ - New: func() any { - buf := make([]byte, 32*1024) // 32K - return &buf - }, -} +var pool32K = pools.New(func() *[]byte { + buf := make([]byte, 32*1024) // 32K + return &buf +}) func poolsCopy(dst io.Writer, src io.Reader) (written int64, err error) { - buf := pool32K.Get().(*[]byte) + buf := pool32K.Get() written, err = io.CopyBuffer(dst, src, *buf) pool32K.Put(buf) return diff --git a/util/converter/converter.go b/util/converter/converter.go index 7452c8c1f..0cb099809 100644 --- a/util/converter/converter.go +++ b/util/converter/converter.go @@ -19,6 +19,7 @@ import ( "github.com/moby/buildkit/util/compression" "github.com/moby/buildkit/util/converter/tarconverter" "github.com/moby/buildkit/util/iohelper" + "github.com/moby/buildkit/util/pools" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" @@ -68,11 +69,9 @@ type conversion struct { immDiffIDs map[digest.Digest]struct{} // diffIDs of immutable layers } -var bufioPool = sync.Pool{ - New: func() any { - return nil - }, -} +var bufioPool = pools.New(func() *bufio.Writer { + return nil +}) func rewriteTimestampInTarHeader(epoch time.Time) tarconverter.HeaderConverter { return func(hdr *tar.Header) { @@ -104,7 +103,7 @@ func (c *conversion) convert(ctx context.Context, cs content.Store, desc ocispec var bufW *bufio.Writer if pooledW := bufioPool.Get(); pooledW != nil { - bufW = pooledW.(*bufio.Writer) + bufW = pooledW bufW.Reset(w) } else { bufW = bufio.NewWriterSize(w, 128*1024) diff --git a/util/overlay/overlay_linux.go b/util/overlay/overlay_linux.go index 076e83479..3f10c72ae 100644 --- a/util/overlay/overlay_linux.go +++ b/util/overlay/overlay_linux.go @@ -10,7 +10,6 @@ import ( "os" "path/filepath" "strings" - "sync" "syscall" "github.com/containerd/containerd/v2/core/mount" @@ -18,6 +17,7 @@ import ( "github.com/containerd/continuity/devices" "github.com/containerd/continuity/fs" "github.com/containerd/continuity/sysx" + "github.com/moby/buildkit/util/pools" "github.com/pkg/errors" "golang.org/x/sys/unix" ) @@ -404,12 +404,10 @@ func compareSymlinkTarget(p1, p2 string) (bool, error) { return t1 == t2, nil } -var bufPool = sync.Pool{ - New: func() any { - b := make([]byte, 32*1024) - return &b - }, -} +var bufPool = pools.New(func() *[]byte { + b := make([]byte, 32*1024) + return &b +}) // Ported from continuity project // https://github.com/containerd/continuity/blob/bce1c3f9669b6f3e7f6656ee715b0b4d75fa64a6/fs/path.go#L151 @@ -437,9 +435,9 @@ func compareFileContent(p1, p2 string) (bool, error) { return false, errors.Errorf("%s is not a regular file", p2) } - b1 := bufPool.Get().(*[]byte) + b1 := bufPool.Get() defer bufPool.Put(b1) - b2 := bufPool.Get().(*[]byte) + b2 := bufPool.Get() defer bufPool.Put(b2) for { n1, err1 := io.ReadFull(f1, *b1) diff --git a/util/pools/pools.go b/util/pools/pools.go new file mode 100644 index 000000000..2f847e81a --- /dev/null +++ b/util/pools/pools.go @@ -0,0 +1,29 @@ +package pools + +import "sync" + +// Pool provides a typed wrapper around sync.Pool. +type Pool[T any] struct { + pool sync.Pool +} + +// New returns a typed pool backed by sync.Pool. +func New[T any](newFn func() T) *Pool[T] { + return &Pool[T]{ + pool: sync.Pool{ + New: func() any { + return newFn() + }, + }, + } +} + +// Get returns a pooled value. +func (p *Pool[T]) Get() T { + return p.pool.Get().(T) +} + +// Put returns a value to the pool. +func (p *Pool[T]) Put(v T) { + p.pool.Put(v) +}