btc-crawl/queue/queue.go

98 lines
1.7 KiB
Go
Raw Normal View History

2014-05-10 20:48:33 -05:00
package queue
// A single goroutine manages the overflow queue for thread-safety, funneling
// data between the Input and Output channels through a specified filter.
type Queue struct {
Input chan string
Output chan string
overflow []string
filter func(string) *string
2014-05-15 19:59:01 -05:00
count int
2014-05-10 20:48:33 -05:00
}
func NewQueue(filter func(string) *string, bufferSize int) *Queue {
q := Queue{
Input: make(chan string, bufferSize),
Output: make(chan string, bufferSize),
overflow: []string{},
filter: filter,
}
2014-05-17 18:24:12 -05:00
go func() {
2014-05-10 20:48:33 -05:00
// Block until we have a next item
nextItem := q.next()
for {
select {
2014-05-17 18:24:12 -05:00
case item := <-q.Input:
2014-05-10 20:48:33 -05:00
// New input
2014-05-15 19:59:01 -05:00
r := q.filter(item)
2014-05-10 20:48:33 -05:00
if r != nil {
// Store in the overflow
q.overflow = append(q.overflow, *r)
2014-05-15 19:59:01 -05:00
q.count++
2014-05-10 20:48:33 -05:00
}
2014-05-17 18:24:12 -05:00
case q.Output <- nextItem:
2014-05-10 20:48:33 -05:00
// Block until we have more inputs
nextItem = q.next()
}
}
2014-05-17 18:24:12 -05:00
}()
2014-05-10 20:48:33 -05:00
return &q
}
func (q *Queue) next() string {
// Block until a next item is available.
if len(q.overflow) > 0 {
// Pop off the overflow queue.
r := q.overflow[0]
q.overflow = q.overflow[1:]
return r
}
for {
// Block until we have a viable output
r := q.filter(<-q.Input)
if r != nil {
2014-05-15 19:59:01 -05:00
q.count++
2014-05-10 20:48:33 -05:00
return *r
}
}
}
func (q *Queue) IsEmpty() bool {
2014-05-17 18:24:12 -05:00
// FIXME: This breaks everything, get rid of it.
2014-05-15 19:04:09 -05:00
if len(q.overflow) > 0 {
2014-05-15 19:59:01 -05:00
return false
2014-05-15 19:04:09 -05:00
}
select {
case r := <-q.Output:
go func() {
// Put it back
q.Output <- r
}()
return false
2014-05-15 19:59:01 -05:00
default:
return true
2014-05-15 19:04:09 -05:00
}
}
func (q *Queue) Wait() {
// Wait until there is an Output. Useful for blocking until the queue is
// ramped up.
r := <-q.Output
go func() {
q.Output <- r
}()
2014-05-10 20:48:33 -05:00
}
2014-05-15 19:59:01 -05:00
func (q *Queue) Count() int {
// Number of outputs produced.
return q.count
}