func()

in oss/utils_pool.go [39:107]


func (p *maxSlicePool) Get(ctx context.Context) (*[]byte, error) {
	// check if context is canceled before attempting to get a slice
	// this ensures priority is given to the cancel case first
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}

	p.mtx.RLock()

	for {
		select {
		case bs, ok := <-p.slices:
			p.mtx.RUnlock()
			if !ok {
				// attempt to get on a zero capacity pool
				return nil, errZeroCapacity
			}
			return bs, nil
		case <-ctx.Done():
			p.mtx.RUnlock()
			return nil, ctx.Err()
		default:
			// pass
		}

		select {
		case _, ok := <-p.allocations:
			p.mtx.RUnlock()
			if !ok {
				// attempt to get on a zero capacity pool
				return nil, errZeroCapacity
			}
			return p.allocator(), nil
		case <-ctx.Done():
			p.mtx.RUnlock()
			return nil, ctx.Err()
		default:
			// In the event that there are no slices or allocations available
			// This prevents some deadlock situations that can occur around sync.RWMutex
			// When a lock request occurs on ModifyCapacity, no new readers are allowed to acquire a read lock.
			// By releasing the read lock here and waiting for a notification, we prevent a deadlock situation where
			// Get could hold the read lock indefinitely waiting for capacity, ModifyCapacity is waiting for a write lock,
			// and a Put is blocked trying to get a read-lock which is blocked by ModifyCapacity.

			// Short-circuit if the pool capacity is zero.
			if p.max == 0 {
				p.mtx.RUnlock()
				return nil, errZeroCapacity
			}

			// Since we will be releasing the read-lock we need to take the reference to the channel.
			// Since channels are references we will still get notified if slices are added, or if
			// the channel is closed due to a capacity modification. This specifically avoids a data race condition
			// where ModifyCapacity both closes a channel and initializes a new one while we don't have a read-lock.
			c := p.capacityChange

			p.mtx.RUnlock()

			select {
			case _ = <-c:
				p.mtx.RLock()
			case <-ctx.Done():
				return nil, ctx.Err()
			}
		}
	}
}