diff --git a/hack/gen-resources/generators/cluster_generator.go b/hack/gen-resources/generators/cluster_generator.go index a002f827a8978..e89b804cc7689 100644 --- a/hack/gen-resources/generators/cluster_generator.go +++ b/hack/gen-resources/generators/cluster_generator.go @@ -8,7 +8,6 @@ import ( "log" "strings" "time" - "github.com/remeh/sizedwaitgroup" v12 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -178,11 +177,11 @@ func (cg *ClusterGenerator) retrieveClusterUri(namespace, releaseSuffix string) func (cg *ClusterGenerator) Generate(opts *util.GenerateOpts) error { log.Printf("Excute in parallel with %v", opts.ClusterOpts.Concurrency) - - wg := sizedwaitgroup.New(int(opts.ClusterOpts.Concurrency)) + + wg := util.New(opts.ClusterOpts.Concurrency) for l := 1; l <= opts.ClusterOpts.Samples; l++ { wg.Add() - go func(i int) error { + generateLoop := func(i int) error { defer wg.Done() log.Printf("Generate cluster #%v of #%v", i, opts.ClusterOpts.Samples) @@ -207,13 +206,12 @@ func (cg *ClusterGenerator) Generate(opts *util.GenerateOpts) error { break } log.Printf("Failed to get cluster credentials %s, retrying...", releaseSuffix) - time.Sleep(10 * time.Second) + time.Sleep(10 * time.Second) caData, cert, key, err = cg.getClusterCredentials(namespace, releaseSuffix) } if err != nil { return err } - log.Print("Get cluster server uri") @@ -246,7 +244,8 @@ func (cg *ClusterGenerator) Generate(opts *util.GenerateOpts) error { return err } return nil - }(l) + } + go generateLoop(l) } wg.Wait() return nil diff --git a/hack/gen-resources/util/sizedwaitgroup.go b/hack/gen-resources/util/sizedwaitgroup.go new file mode 100644 index 0000000000000..b8d7d01593dc7 --- /dev/null +++ b/hack/gen-resources/util/sizedwaitgroup.go @@ -0,0 +1,107 @@ +// The MIT License (MIT) + +// Copyright (c) 2018 Rémy Mathieu + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// https://github.com/remeh/sizedwaitgroup + +// Based upon sync.WaitGroup, SizedWaitGroup allows to start multiple +// routines and to wait for their end using the simple API. + +// SizedWaitGroup adds the feature of limiting the maximum number of +// concurrently started routines. It could for example be used to start +// multiples routines querying a database but without sending too much +// queries in order to not overload the given database. +// +// Rémy Mathieu © 2016 +package util + +import ( + "context" + "math" + "sync" +) + +// SizedWaitGroup has the same role and close to the +// same API as the Golang sync.WaitGroup but adds a limit of +// the amount of goroutines started concurrently. +type SizedWaitGroup struct { + Size int + + current chan struct{} + wg sync.WaitGroup +} + +// New creates a SizedWaitGroup. +// The limit parameter is the maximum amount of +// goroutines which can be started concurrently. +func New(limit int) SizedWaitGroup { + size := math.MaxInt32 // 2^31 - 1 + if limit > 0 { + size = limit + } + return SizedWaitGroup{ + Size: size, + + current: make(chan struct{}, size), + wg: sync.WaitGroup{}, + } +} + +// Add increments the internal WaitGroup counter. +// It can be blocking if the limit of spawned goroutines +// has been reached. It will stop blocking when Done is +// been called. +// +// See sync.WaitGroup documentation for more information. +func (s *SizedWaitGroup) Add() { + s.AddWithContext(context.Background()) +} + +// AddWithContext increments the internal WaitGroup counter. +// It can be blocking if the limit of spawned goroutines +// has been reached. It will stop blocking when Done is +// been called, or when the context is canceled. Returns nil on +// success or an error if the context is canceled before the lock +// is acquired. +// +// See sync.WaitGroup documentation for more information. +func (s *SizedWaitGroup) AddWithContext(ctx context.Context) error { + select { + case <-ctx.Done(): + return ctx.Err() + case s.current <- struct{}{}: + break + } + s.wg.Add(1) + return nil +} + +// Done decrements the SizedWaitGroup counter. +// See sync.WaitGroup documentation for more information. +func (s *SizedWaitGroup) Done() { + <-s.current + s.wg.Done() +} + +// Wait blocks until the SizedWaitGroup counter is zero. +// See sync.WaitGroup documentation for more information. +func (s *SizedWaitGroup) Wait() { + s.wg.Wait() +}