57 lines
1.5 KiB
Go
57 lines
1.5 KiB
Go
package routing
|
|
|
|
import "sync"
|
|
|
|
const DefaultRingCapacity = 1 << 8 // Best if power of 2 (or so I am told)
|
|
|
|
// Broker manages topics and issues publisher/subscriber handles.
|
|
type Broker struct {
|
|
mu sync.RWMutex
|
|
topics map[string]*TopicRing
|
|
}
|
|
|
|
func NewBroker() *Broker {
|
|
return &Broker{
|
|
topics: make(map[string]*TopicRing),
|
|
}
|
|
}
|
|
|
|
// getOrCreateRing handles the race condition where a subscriber might attach
|
|
// to a topic before the publisher has created it, and vice versa.
|
|
// This is because we allow either a publisher or a subscriber to 'create' the topic
|
|
func (b *Broker) getOrCreateRing(topicKey string, requestedCap int) *TopicRing {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
|
|
ring, exists := b.topics[topicKey]
|
|
if !exists {
|
|
cap := requestedCap
|
|
if cap <= 0 {
|
|
cap = DefaultRingCapacity
|
|
}
|
|
ring = newTopicRing(cap)
|
|
b.topics[topicKey] = ring
|
|
}
|
|
return ring
|
|
}
|
|
|
|
// RegisterPublisher returns a fast-path Publisher.
|
|
func (b *Broker) RegisterPublisher(topicKey string, capacity int) Publisher {
|
|
ring := b.getOrCreateRing(topicKey, capacity)
|
|
return &ringPublisher{
|
|
ring: ring,
|
|
}
|
|
}
|
|
|
|
// RegisterSubscriber attaches a consumer to a topic and returns a fast-path Subscriber.
|
|
// We don't allow subscribrs to specify a buffer capacity size.
|
|
// As a general rule, a publisher takes precedence over a subscriber
|
|
func (b *Broker) RegisterSubscriber(topicKey string) Subscriber {
|
|
ring := b.getOrCreateRing(topicKey, 0)
|
|
consumer := ring.addConsumer()
|
|
return &ringSubscriber{
|
|
ring: ring,
|
|
consumer: consumer,
|
|
}
|
|
}
|