github.com/pharosnet/flyline@v1.0.2/array_buffer.go (about)

     1  package flyline
     2  
     3  import (
     4  	"context"
     5  	"runtime"
     6  	"sync"
     7  	"time"
     8  )
     9  
    10  // Note: The array capacity must be a power of two, e.g. 2, 4, 8, 16, 32, 64, etc.
    11  func NewArrayBuffer(capacity int64) Buffer {
    12  	b := &arrayBuffer{
    13  		capacity: capacity,
    14  		buffer:   newArray(capacity),
    15  		wdSeq:    NewSequence(),
    16  		wpSeq:    NewSequence(),
    17  		rdSeq:    NewSequence(),
    18  		rpSeq:    NewSequence(),
    19  		sts:      &status{},
    20  		mutex:    &sync.Mutex{},
    21  	}
    22  	b.sts.setRunning()
    23  	return b
    24  }
    25  
    26  type arrayBuffer struct {
    27  	capacity int64
    28  	buffer   *array
    29  	wpSeq    *Sequence
    30  	wdSeq    *Sequence
    31  	rpSeq    *Sequence
    32  	rdSeq    *Sequence
    33  	sts      *status
    34  	mutex    *sync.Mutex
    35  }
    36  
    37  func (b *arrayBuffer) Send(i interface{}) (err error) {
    38  	if b.sts.isClosed() {
    39  		err = ErrBufSendClosed
    40  		return
    41  	}
    42  	next := b.wpSeq.Incr()
    43  	times := 10
    44  	for {
    45  		times--
    46  		if next-b.capacity-b.rdSeq.Get() <= 0 && next-(b.wdSeq.Get()+1) == 0 {
    47  			b.buffer.set(next, i)
    48  			b.wdSeq.Incr()
    49  			break
    50  		}
    51  		time.Sleep(ns1)
    52  		if times <= 0 {
    53  			runtime.Gosched()
    54  			times = 10
    55  		}
    56  	}
    57  	return
    58  }
    59  
    60  func (b *arrayBuffer) Recv() (value interface{}, active bool) {
    61  	active = true
    62  	if b.sts.isClosed() && b.Len() == int64(0) {
    63  		active = false
    64  		return
    65  	}
    66  	times := 10
    67  	next := b.rpSeq.Incr()
    68  	for {
    69  		if next-b.wdSeq.Get() <= 0 && next-(b.rdSeq.Get()+1) == 0 {
    70  			value = b.buffer.get(next)
    71  			b.rdSeq.Incr()
    72  			break
    73  		}
    74  		time.Sleep(ns1)
    75  		if times <= 0 {
    76  			runtime.Gosched()
    77  			times = 10
    78  		}
    79  	}
    80  	return
    81  }
    82  
    83  func (b *arrayBuffer) Len() (length int64) {
    84  	length = b.wpSeq.Get() - b.rdSeq.Get()
    85  	return
    86  }
    87  
    88  func (b *arrayBuffer) Close() (err error) {
    89  	b.mutex.Lock()
    90  	defer b.mutex.Unlock()
    91  	if b.sts.isClosed() {
    92  		err = ErrBufCloseClosed
    93  		return
    94  	}
    95  	b.sts.setClosed()
    96  	return
    97  }
    98  
    99  func (b *arrayBuffer) Sync(ctx context.Context) (err error) {
   100  	b.mutex.Lock()
   101  	defer b.mutex.Unlock()
   102  	if b.sts.isRunning() {
   103  		err = ErrBufSyncUnclosed
   104  		return
   105  	}
   106  	for {
   107  		ok := false
   108  		select {
   109  		case <-ctx.Done():
   110  			ok = true
   111  			break
   112  		default:
   113  			if b.Len() == int64(0) {
   114  				ok = true
   115  				break
   116  			}
   117  			time.Sleep(ms500)
   118  		}
   119  		if ok {
   120  			break
   121  		}
   122  	}
   123  	return
   124  }