github.com/andy2046/gopie@v0.7.0/pkg/multilane/multilane.go (about)

     1  // Package multilane implements a concurrent blocking multiset.
     2  package multilane
     3  
     4  import (
     5  	"github.com/andy2046/gopie/pkg/spsc"
     6  	"runtime"
     7  )
     8  
     9  const (
    10  	defaultQSize uint32 = 1024
    11  	defaultWidth uint32 = 8
    12  )
    13  
    14  var defaultQueFunc = func(size uint32) Queue {
    15  	return spsc.New(size)
    16  }
    17  
    18  type (
    19  	// Queue represents the queue with Get / Put / Close methods.
    20  	Queue interface {
    21  		Get(interface{}) bool
    22  		Put(interface{})
    23  		Close()
    24  	}
    25  
    26  	// Config for MultiLane.
    27  	Config struct {
    28  		LaneWidth uint32 // number of queue for MultiLane
    29  		QueueSize uint32 // size of each queue in MultiLane
    30  		New       func(uint32) Queue
    31  	}
    32  
    33  	// MultiLane represents the concurrent multiset.
    34  	MultiLane struct {
    35  		_        [spsc.CacheLinePadSize]byte
    36  		lanes    []Queue
    37  		laneMask int64
    38  		putCh    chan int64
    39  		getCh    chan int64
    40  		queSize  uint32
    41  		_        [4]byte
    42  	}
    43  )
    44  
    45  // New create a new MultiLane.
    46  func New(conf Config) *MultiLane {
    47  	m := MultiLane{}
    48  	qs, w, queFunc := defaultQSize, defaultWidth, defaultQueFunc
    49  	if conf.New != nil {
    50  		queFunc = conf.New
    51  	}
    52  	if conf.QueueSize > 7 {
    53  		qs = conf.QueueSize
    54  	}
    55  	if conf.LaneWidth > 0 {
    56  		w = conf.LaneWidth
    57  	}
    58  	m.queSize = nextPowerOf2(qs)
    59  	m.lanes = make([]Queue, nextPowerOf2(w))
    60  	m.laneMask = int64(len(m.lanes) - 1)
    61  	m.putCh = make(chan int64, len(m.lanes))
    62  	m.getCh = make(chan int64, len(m.lanes))
    63  	for i := range m.lanes {
    64  		m.lanes[i] = queFunc(m.queSize)
    65  		m.putCh <- int64(i)
    66  		m.getCh <- int64(i)
    67  	}
    68  	return &m
    69  }
    70  
    71  // GetLane get the value at the provided lane to given variable,
    72  // blocking.
    73  func (m *MultiLane) GetLane(lane uint32, i interface{}) bool {
    74  	return m.lanes[int64(lane)&m.laneMask].Get(i)
    75  }
    76  
    77  // PutLane put given variable at the provided lane,
    78  // blocking.
    79  func (m *MultiLane) PutLane(lane uint32, i interface{}) {
    80  	m.lanes[int64(lane)&m.laneMask].Put(i)
    81  }
    82  
    83  // Get the value at one of the lanes pointed by the cursor to given variable,
    84  // blocking.
    85  func (m *MultiLane) Get(i interface{}) bool {
    86  	for {
    87  		select {
    88  		case curs := <-m.getCh:
    89  			r := m.lanes[curs&m.laneMask].Get(i)
    90  			m.getCh <- curs
    91  			return r
    92  		default:
    93  			runtime.Gosched()
    94  		}
    95  	}
    96  }
    97  
    98  // Put given variable at one of the lanes pointed by the cursor,
    99  // blocking.
   100  func (m *MultiLane) Put(i interface{}) {
   101  	for {
   102  		select {
   103  		case curs := <-m.putCh:
   104  			m.lanes[curs&m.laneMask].Put(i)
   105  			m.putCh <- curs
   106  			return
   107  		default:
   108  			runtime.Gosched()
   109  		}
   110  	}
   111  }
   112  
   113  // Close the MultiLane, it shall NOT be called before `Put()`.
   114  func (m *MultiLane) Close() {
   115  	for _, l := range m.lanes {
   116  		l.Close()
   117  	}
   118  }
   119  
   120  // LaneWidth is the number of lanes.
   121  func (m *MultiLane) LaneWidth() uint32 {
   122  	return uint32(m.laneMask + 1)
   123  }
   124  
   125  // QueueSize is the size of the underlying queue.
   126  func (m *MultiLane) QueueSize() uint32 {
   127  	return m.queSize
   128  }
   129  
   130  func nextPowerOf2(v uint32) uint32 {
   131  	v--
   132  	v |= v >> 1
   133  	v |= v >> 2
   134  	v |= v >> 4
   135  	v |= v >> 8
   136  	v |= v >> 16
   137  	return v + 1
   138  }