github.com/micro/go-micro/v2@v2.9.1/util/ring/buffer.go (about)

     1  // Package ring provides a simple ring buffer for storing local data
     2  package ring
     3  
     4  import (
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/google/uuid"
     9  )
    10  
    11  // Buffer is ring buffer
    12  type Buffer struct {
    13  	size int
    14  
    15  	sync.RWMutex
    16  	vals    []*Entry
    17  	streams map[string]*Stream
    18  }
    19  
    20  // Entry is ring buffer data entry
    21  type Entry struct {
    22  	Value     interface{}
    23  	Timestamp time.Time
    24  }
    25  
    26  // Stream is used to stream the buffer
    27  type Stream struct {
    28  	// Id of the stream
    29  	Id string
    30  	// Buffered entries
    31  	Entries chan *Entry
    32  	// Stop channel
    33  	Stop chan bool
    34  }
    35  
    36  // Put adds a new value to ring buffer
    37  func (b *Buffer) Put(v interface{}) {
    38  	b.Lock()
    39  	defer b.Unlock()
    40  
    41  	// append to values
    42  	entry := &Entry{
    43  		Value:     v,
    44  		Timestamp: time.Now(),
    45  	}
    46  	b.vals = append(b.vals, entry)
    47  
    48  	// trim if bigger than size required
    49  	if len(b.vals) > b.size {
    50  		b.vals = b.vals[1:]
    51  	}
    52  
    53  	// send to every stream
    54  	for _, stream := range b.streams {
    55  		select {
    56  		case <-stream.Stop:
    57  			delete(b.streams, stream.Id)
    58  			close(stream.Entries)
    59  		case stream.Entries <- entry:
    60  		}
    61  	}
    62  }
    63  
    64  // Get returns the last n entries
    65  func (b *Buffer) Get(n int) []*Entry {
    66  	b.RLock()
    67  	defer b.RUnlock()
    68  
    69  	// reset any invalid values
    70  	if n > len(b.vals) || n < 0 {
    71  		n = len(b.vals)
    72  	}
    73  
    74  	// create a delta
    75  	delta := len(b.vals) - n
    76  
    77  	// return the delta set
    78  	return b.vals[delta:]
    79  }
    80  
    81  // Return the entries since a specific time
    82  func (b *Buffer) Since(t time.Time) []*Entry {
    83  	b.RLock()
    84  	defer b.RUnlock()
    85  
    86  	// return all the values
    87  	if t.IsZero() {
    88  		return b.vals
    89  	}
    90  
    91  	// if its in the future return nothing
    92  	if time.Since(t).Seconds() < 0.0 {
    93  		return nil
    94  	}
    95  
    96  	for i, v := range b.vals {
    97  		// find the starting point
    98  		d := v.Timestamp.Sub(t)
    99  
   100  		// return the values
   101  		if d.Seconds() > 0.0 {
   102  			return b.vals[i:]
   103  		}
   104  	}
   105  
   106  	return nil
   107  }
   108  
   109  // Stream logs from the buffer
   110  // Close the channel when you want to stop
   111  func (b *Buffer) Stream() (<-chan *Entry, chan bool) {
   112  	b.Lock()
   113  	defer b.Unlock()
   114  
   115  	entries := make(chan *Entry, 128)
   116  	id := uuid.New().String()
   117  	stop := make(chan bool)
   118  
   119  	b.streams[id] = &Stream{
   120  		Id:      id,
   121  		Entries: entries,
   122  		Stop:    stop,
   123  	}
   124  
   125  	return entries, stop
   126  }
   127  
   128  // Size returns the size of the ring buffer
   129  func (b *Buffer) Size() int {
   130  	return b.size
   131  }
   132  
   133  // New returns a new buffer of the given size
   134  func New(i int) *Buffer {
   135  	return &Buffer{
   136  		size:    i,
   137  		streams: make(map[string]*Stream),
   138  	}
   139  }