mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
* Add (commented out) linters that we should introduce I went through the available linters and added (commented out) the ones I think we should work on in the near term. In other words, fix them, then uncomment them so they are enabled in CI. * linter: errchkjson * linter: ineffassign * linter: gosimple * linter: errname
111 lines
1.8 KiB
Go
111 lines
1.8 KiB
Go
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
package egpool
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
type Group struct {
|
|
PoolSize int
|
|
|
|
jobs chan func() error
|
|
|
|
sema chan struct{}
|
|
errMu sync.Mutex
|
|
firstErr error
|
|
errs []error
|
|
}
|
|
|
|
func (eg *Group) Go(f func() error) {
|
|
if eg.PoolSize <= 0 {
|
|
eg.PoolSize = 1
|
|
}
|
|
|
|
if eg.jobs == nil {
|
|
eg.jobs = make(chan func() error)
|
|
eg.sema = make(chan struct{}, eg.PoolSize)
|
|
}
|
|
|
|
// Start the job in an idle worker if possible.
|
|
select {
|
|
case eg.jobs <- f:
|
|
return
|
|
default:
|
|
}
|
|
|
|
// Start a new worker if necessary.
|
|
select {
|
|
case eg.jobs <- f:
|
|
// A worker finished its previous job and took this one over.
|
|
return
|
|
case eg.sema <- struct{}{}:
|
|
// Start a new worker.
|
|
go eg.processJobs()
|
|
eg.jobs <- f
|
|
}
|
|
}
|
|
|
|
func (eg *Group) err(err error) {
|
|
eg.errMu.Lock()
|
|
defer eg.errMu.Unlock()
|
|
|
|
if eg.firstErr == nil {
|
|
eg.firstErr = err
|
|
}
|
|
eg.errs = append(eg.errs, err)
|
|
}
|
|
|
|
type PanicError struct {
|
|
Value interface{}
|
|
}
|
|
|
|
func (p PanicError) Error() string {
|
|
return fmt.Sprintf("panic: %v", p.Value)
|
|
}
|
|
|
|
var ErrGoexit = errors.New("runtime.Goexit used in job function")
|
|
|
|
func (eg *Group) processJobs() {
|
|
// Notify pool of shutdown.
|
|
defer func() { <-eg.sema }()
|
|
|
|
// Handle panic and Goexit.
|
|
var finished bool
|
|
defer func() {
|
|
if !finished {
|
|
if p := recover(); p != nil {
|
|
eg.err(PanicError{p})
|
|
} else {
|
|
eg.err(ErrGoexit)
|
|
}
|
|
}
|
|
}()
|
|
|
|
// Run jobs from queue.
|
|
for jobFn := range eg.jobs {
|
|
err := jobFn()
|
|
if err != nil {
|
|
eg.err(err)
|
|
}
|
|
}
|
|
|
|
finished = true
|
|
}
|
|
|
|
func (eg *Group) Wait() error {
|
|
if eg.jobs == nil {
|
|
return nil
|
|
}
|
|
close(eg.jobs)
|
|
for i := 0; i < eg.PoolSize; i++ {
|
|
eg.sema <- struct{}{}
|
|
}
|
|
return eg.firstErr
|
|
}
|
|
|
|
func (eg *Group) Errors() []error {
|
|
return eg.errs
|
|
}
|