github.com/Cloud-Foundations/Dominator@v0.3.4/lib/concurrent/incrementer.go (about)

     1  package concurrent
     2  
     3  import "sync"
     4  
     5  type incrementer struct {
     6  	state              *State
     7  	mutex              sync.Mutex // Protect the following fields.
     8  	completionCount    uint
     9  	currentConcurrency uint
    10  }
    11  
    12  func newStateWithLinearConcurrencyIncrease(initialNumConcurrent uint,
    13  	maximumNumConcurrent uint) *State {
    14  	if initialNumConcurrent < 1 {
    15  		panic("initialNumConcurrent must not be zero")
    16  	}
    17  	p := &incrementer{currentConcurrency: initialNumConcurrent}
    18  	state := newState(maximumNumConcurrent, p)
    19  	p.state = state
    20  	if initialNumConcurrent > uint(cap(state.semaphore)) {
    21  		panic("initialNumConcurrent must not exceed concurrency")
    22  	}
    23  	numToBlock := uint(cap(state.semaphore)) - initialNumConcurrent
    24  	for count := uint(0); count < numToBlock; count++ {
    25  		state.semaphore <- struct{}{}
    26  	}
    27  	return state
    28  }
    29  
    30  // This is called from a goroutine.
    31  func (p *incrementer) put() {
    32  	p.mutex.Lock()
    33  	defer p.mutex.Unlock()
    34  	if p.currentConcurrency >= uint(cap(p.state.semaphore)) {
    35  		return
    36  	}
    37  	p.completionCount++
    38  	if p.completionCount < p.currentConcurrency {
    39  		return
    40  	}
    41  	p.completionCount = 0
    42  	p.currentConcurrency++
    43  	select {
    44  	case <-p.state.semaphore:
    45  	default:
    46  		panic("no concurrency limits to remove")
    47  	}
    48  }