forked from cwtch.im/cwtch
autoblocking
parent
dfcf7f8777
commit
bd75e44555
@ -1,31 +0,0 @@
|
||||
package event
|
||||
|
||||
// Queue is a wrapper around a channel for handling Events in a consistent way across subsystems.
|
||||
// The expectation is that each subsystem in Cwtch will manage a given an event.Queue fed from
|
||||
// the event.Manager.
|
||||
type Queue struct {
|
||||
EventChannel chan Event
|
||||
}
|
||||
|
||||
// NewEventQueue initializes an event.Queue of the given buffer size.
|
||||
func NewEventQueue(buffer int) *Queue {
|
||||
queue := new(Queue)
|
||||
queue.EventChannel = make(chan Event, buffer)
|
||||
return queue
|
||||
}
|
||||
|
||||
// Backlog returns the length of the queue backlog
|
||||
func (eq *Queue) Backlog() int {
|
||||
return len(eq.EventChannel)
|
||||
}
|
||||
|
||||
// Next returns the next available event from the front of the queue
|
||||
func (eq *Queue) Next() (event Event) {
|
||||
event = <-eq.EventChannel
|
||||
return
|
||||
}
|
||||
|
||||
// Shutdown closes our EventChannel
|
||||
func (eq *Queue) Shutdown() {
|
||||
close(eq.EventChannel)
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package event
|
||||
|
||||
type queue struct {
|
||||
infChan infiniteChannel
|
||||
}
|
||||
|
||||
type simpleQueue struct {
|
||||
eventChannel chan Event
|
||||
}
|
||||
|
||||
// Queue is a wrapper around a channel for handling Events in a consistent way across subsystems.
|
||||
// The expectation is that each subsystem in Cwtch will manage a given an event.Queue fed from
|
||||
// the event.Manager.
|
||||
type Queue interface {
|
||||
InChan() chan<- Event
|
||||
OutChan() <-chan Event
|
||||
Next() *Event
|
||||
Shutdown()
|
||||
Len() int
|
||||
}
|
||||
|
||||
// NewQueue initializes an event.Queue
|
||||
func NewQueue() Queue {
|
||||
queue := &queue{infChan: *newInfiniteChannel()}
|
||||
return queue
|
||||
}
|
||||
|
||||
// NewSimpleQueue initializes an event.Queue of the given buffer size.
|
||||
func NewSimpleQueue(buffer int) Queue {
|
||||
queue := new(simpleQueue)
|
||||
queue.eventChannel = make(chan Event, buffer)
|
||||
return queue
|
||||
}
|
||||
|
||||
func (sq *simpleQueue) InChan() chan<- Event {
|
||||
return sq.eventChannel
|
||||
}
|
||||
|
||||
func (sq *simpleQueue) OutChan() <-chan Event {
|
||||
return sq.eventChannel
|
||||
}
|
||||
|
||||
// Backlog returns the length of the queue backlog
|
||||
func (sq *simpleQueue) Len() int {
|
||||
return len(sq.eventChannel)
|
||||
}
|
||||
|
||||
// Next returns the next available event from the front of the queue
|
||||
func (sq *simpleQueue) Next() *Event {
|
||||
event := <-sq.eventChannel
|
||||
return &event
|
||||
}
|
||||
|
||||
// Shutdown closes our eventChannel
|
||||
func (sq *simpleQueue) Shutdown() {
|
||||
close(sq.eventChannel)
|
||||
}
|
||||
|
||||
func (iq *queue) InChan() chan<- Event {
|
||||
return iq.infChan.In()
|
||||
}
|
||||
|
||||
func (iq *queue) OutChan() <-chan Event {
|
||||
return iq.infChan.Out()
|
||||
}
|
||||
|
||||
// Out returns the next available event from the front of the queue
|
||||
func (iq *queue) Next() *Event {
|
||||
event := <-iq.infChan.Out()
|
||||
return &event
|
||||
}
|
||||
|
||||
func (iq *queue) Len() int {
|
||||
return iq.infChan.Len()
|
||||
}
|
||||
|
||||
// Shutdown closes our eventChannel
|
||||
func (iq *queue) Shutdown() {
|
||||
iq.infChan.Close()
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package event
|
||||
|
||||
/*
|
||||
This package is taken from https://github.com/eapache/channels
|
||||
as per their suggestion we are not importing the entire package and instead cherry picking and adapting what is needed
|
||||
|
||||
It is covered by the MIT License https://github.com/eapache/channels/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
// infiniteChannel implements the Channel interface with an infinite buffer between the input and the output.
|
||||
type infiniteChannel struct {
|
||||
input, output chan Event
|
||||
length chan int
|
||||
buffer *infiniteQueue
|
||||
}
|
||||
|
||||
func newInfiniteChannel() *infiniteChannel {
|
||||
ch := &infiniteChannel{
|
||||
input: make(chan Event),
|
||||
output: make(chan Event),
|
||||
length: make(chan int),
|
||||
buffer: newInfinitQueue(),
|
||||
}
|
||||
go ch.infiniteBuffer()
|
||||
return ch
|
||||
}
|
||||
|
||||
func (ch *infiniteChannel) In() chan<- Event {
|
||||
return ch.input
|
||||
}
|
||||
|
||||
func (ch *infiniteChannel) Out() <-chan Event {
|
||||
return ch.output
|
||||
}
|
||||
|
||||
func (ch *infiniteChannel) Len() int {
|
||||
return <-ch.length
|
||||
}
|
||||
|
||||
func (ch *infiniteChannel) Close() {
|
||||
close(ch.input)
|
||||
}
|
||||
|
||||
func (ch *infiniteChannel) infiniteBuffer() {
|
||||
var input, output chan Event
|
||||
var next Event
|
||||
input = ch.input
|
||||
|
||||
for input != nil || output != nil {
|
||||
select {
|
||||
case elem, open := <-input:
|
||||
if open {
|
||||
ch.buffer.Add(elem)
|
||||
} else {
|
||||
input = nil
|
||||
}
|
||||
case output <- next:
|
||||
ch.buffer.Remove()
|
||||
case ch.length <- ch.buffer.Length():
|
||||
}
|
||||
|
||||
if ch.buffer.Length() > 0 {
|
||||
output = ch.output
|
||||
next = ch.buffer.Peek()
|
||||
} else {
|
||||
output = nil
|
||||
//next = nil
|
||||
}
|
||||
}
|
||||
|
||||
close(ch.output)
|
||||
close(ch.length)
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package event
|
||||
|
||||
/*
|
||||
This package is taken from https://github.com/eapache/channels
|
||||
as per their suggestion we are not importing the entire package and instead cherry picking and adapting what is needed
|
||||
|
||||
It is covered by the MIT License https://github.com/eapache/channels/blob/master/LICENSE
|
||||
*/
|
||||
/*
|
||||
Package queue provides a fast, ring-buffer queue based on the version suggested by Dariusz Górecki.
|
||||
Using this instead of other, simpler, queue implementations (slice+append or linked list) provides
|
||||
substantial memory and time benefits, and fewer GC pauses.
|
||||
The queue implemented here is as fast as it is for an additional reason: it is *not* thread-safe.
|
||||
*/
|
||||
|
||||
// minQueueLen is smallest capacity that queue may have.
|
||||
// Must be power of 2 for bitwise modulus: x % n == x & (n - 1).
|
||||
const minQueueLen = 16
|
||||
|
||||
// Queue represents a single instance of the queue data structure.
|
||||
type infiniteQueue struct {
|
||||
buf []Event
|
||||
head, tail, count int
|
||||
}
|
||||
|
||||
// New constructs and returns a new Queue.
|
||||
func newInfinitQueue() *infiniteQueue {
|
||||
return &infiniteQueue{
|
||||
buf: make([]Event, minQueueLen),
|
||||
}
|
||||
}
|
||||
|
||||
// Length returns the number of elements currently stored in the queue.
|
||||
func (q *infiniteQueue) Length() int {
|
||||
return q.count
|
||||
}
|
||||
|
||||
// resizes the queue to fit exactly twice its current contents
|
||||
// this can result in shrinking if the queue is less than half-full
|
||||
func (q *infiniteQueue) resize() {
|
||||
newBuf := make([]Event, q.count<<1)
|
||||
|
||||
if q.tail > q.head {
|
||||
copy(newBuf, q.buf[q.head:q.tail])
|
||||
} else {
|
||||
n := copy(newBuf, q.buf[q.head:])
|
||||
copy(newBuf[n:], q.buf[:q.tail])
|
||||
}
|
||||
|
||||
q.head = 0
|
||||
q.tail = q.count
|
||||
q.buf = newBuf
|
||||
}
|
||||
|
||||
// Add puts an element on the end of the queue.
|
||||
func (q *infiniteQueue) Add(elem Event) {
|
||||
if q.count == len(q.buf) {
|
||||
q.resize()
|
||||
}
|
||||
|
||||
q.buf[q.tail] = elem
|
||||
// bitwise modulus
|
||||
q.tail = (q.tail + 1) & (len(q.buf) - 1)
|
||||
q.count++
|
||||
}
|
||||
|
||||
// Peek returns the element at the head of the queue. This call panics
|
||||
// if the queue is empty.
|
||||
func (q *infiniteQueue) Peek() Event {
|
||||
if q.count <= 0 {
|
||||
panic("queue: Peek() called on empty queue")
|
||||
}
|
||||
return q.buf[q.head]
|
||||
}
|
||||
|
||||
// Get returns the element at index i in the queue. If the index is
|
||||
// invalid, the call will panic. This method accepts both positive and
|
||||
// negative index values. Index 0 refers to the first element, and
|
||||
// index -1 refers to the last.
|
||||
func (q *infiniteQueue) Get(i int) Event {
|
||||
// If indexing backwards, convert to positive index.
|
||||
if i < 0 {
|
||||
i += q.count
|
||||
}
|
||||
if i < 0 || i >= q.count {
|
||||
panic("queue: Get() called with index out of range")
|
||||
}
|
||||
// bitwise modulus
|
||||
return q.buf[(q.head+i)&(len(q.buf)-1)]
|
||||
}
|
||||
|
||||
// Remove removes and returns the element from the front of the queue. If the
|
||||
// queue is empty, the call will panic.
|
||||
func (q *infiniteQueue) Remove() Event {
|
||||
if q.count <= 0 {
|
||||
panic("queue: Remove() called on empty queue")
|
||||
}
|
||||
ret := q.buf[q.head]
|
||||
//q.buf[q.head] = nil
|
||||
// bitwise modulus
|
||||
q.head = (q.head + 1) & (len(q.buf) - 1)
|
||||
q.count--
|
||||
// Resize down if buffer 1/4 full.
|
||||
if len(q.buf) > minQueueLen && (q.count<<2) == len(q.buf) {
|
||||
q.resize()
|
||||
}
|
||||
return ret
|
||||
}
|
Loading…
Reference in new issue