github.com/m3db/m3@v1.5.0/src/query/pools/pool_wrapper.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package pools
    22  
    23  import (
    24  	"errors"
    25  	"sync"
    26  	"time"
    27  
    28  	"github.com/m3db/m3/src/dbnode/encoding"
    29  )
    30  
    31  // PoolWrapper is an asynchronous wrapper for iterator pools.
    32  type PoolWrapper struct {
    33  	mu          sync.Mutex
    34  	watchers    []chan encoding.IteratorPools
    35  	watchersErr []chan error
    36  	pools       encoding.IteratorPools
    37  	err         error
    38  }
    39  
    40  // NewPoolsWrapper creates an initialized pool wrapper.
    41  func NewPoolsWrapper(pools encoding.IteratorPools) *PoolWrapper {
    42  	return &PoolWrapper{pools: pools}
    43  }
    44  
    45  // NewAsyncPoolsWrapper creates a pool wrapper which must be initialized.
    46  func NewAsyncPoolsWrapper() *PoolWrapper {
    47  	return &PoolWrapper{}
    48  }
    49  
    50  // Init initializes the wrapper with iterator pools and notifies any watchers.
    51  func (w *PoolWrapper) Init(
    52  	sessionPools encoding.IteratorPools,
    53  	err error,
    54  ) {
    55  	w.mu.Lock()
    56  	w.pools, w.err = sessionPools, err
    57  	for _, watcher := range w.watchers {
    58  		watcher <- w.pools
    59  	}
    60  	for _, watcherErr := range w.watchersErr {
    61  		watcherErr <- w.err
    62  	}
    63  	w.mu.Unlock()
    64  }
    65  
    66  // IteratorPools either returns iterator pools and errors, or channels that will
    67  // be notified when iterator pools become available.
    68  func (w *PoolWrapper) IteratorPools() (
    69  	bool, encoding.IteratorPools, error, <-chan encoding.IteratorPools, <-chan error) {
    70  	w.mu.Lock()
    71  	defer w.mu.Unlock()
    72  	if w.pools != nil || w.err != nil {
    73  		return true, w.pools, w.err, nil, nil
    74  	}
    75  	watcher := make(chan encoding.IteratorPools)
    76  	w.watchers = append(w.watchers, watcher)
    77  	watcherErr := make(chan error)
    78  	w.watchersErr = append(w.watchersErr, watcherErr)
    79  	return false, nil, nil, watcher, watcherErr
    80  }
    81  
    82  // WaitForIteratorPools will block until iterator pools are available.
    83  // If given a timeout of 0, will block indefinitely.
    84  func (w *PoolWrapper) WaitForIteratorPools(
    85  	timeout time.Duration,
    86  ) (encoding.IteratorPools, error) {
    87  	available, pools, err, poolCh, errCh := w.IteratorPools()
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	if !available {
    93  		if timeout == 0 {
    94  			select {
    95  			case pools = <-poolCh:
    96  			case err = <-errCh:
    97  				return nil, err
    98  			}
    99  		}
   100  
   101  		select {
   102  		case pools = <-poolCh:
   103  		case err = <-errCh:
   104  			return nil, err
   105  		case <-time.After(timeout):
   106  			return nil, errors.New("timeout waiting for iterator pools")
   107  		}
   108  	}
   109  
   110  	return pools, err
   111  }