Documentation
¶
Overview ¶
Package stream carries answered queries to whoever is watching them.
It is the second consumer of the query path's observer (architecture §2.9), beside the metrics. A watcher subscribes with a filter, and what it gets is a live tail of the exchanges that matched: the question, the answer, where it came from and how long it took.
Three properties are load-bearing, and all three come from docs/decisions.md D9. The filter is applied here, before anything is buffered, so a watcher looking at one zone gets a complete stream however busy the rest of the server is. When even the filtered stream is faster than a watcher can read, the stream samples rather than blocking, and says what ratio it is sampling at: a stream that silently drops while looking complete is worse than one that admits to showing every fiftieth query. And when a watcher falls behind anyway, its oldest events are dropped, never the newest: it is a live view, and the answer to "what is happening now" is not last minute's queries.
Nothing here may block the query path. Hub.Observe runs on the goroutine that read the query.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrTooManyWatchers = errors.New("stream: too many watchers")
ErrTooManyWatchers is returned by Hub.Subscribe when the bound is reached.
Functions ¶
This section is empty.
Types ¶
type Filter ¶
type Filter struct {
// Name selects the exchanges asking about a name or anything below it. The
// zero name matches every question.
Name zone.Name
// Types and Rcodes select question types and response codes. An empty list
// matches every one of them.
Types []zone.RRType
Rcodes []int
// Client selects the exchanges from a network. The zero prefix matches
// every address.
Client netip.Prefix
}
Filter selects which exchanges a watcher sees. The zero value matches everything.
type Hub ¶
type Hub struct {
// contains filtered or unexported fields
}
Hub fans exchanges out to the watchers whose filters they match.
func (*Hub) Observe ¶
Observe offers one exchange to every watcher. It is what a dns.Server is given as its observer, and it never blocks.
func (*Hub) Subscribe ¶
func (h *Hub) Subscribe(f Filter) (*Subscription, error)
Subscribe opens a live tail of the exchanges matching f.
The caller reads from Subscription.Events and must call Subscription.Close when it is done, or the query path goes on evaluating a filter for a watcher that left.
type Options ¶
type Options struct {
// Buffer is how many exchanges a watcher may fall behind by.
Buffer int
// MaxRate is how many exchanges a second a watcher is sent before the
// stream begins sampling.
MaxRate int
// MaxWatchers is how many watchers may exist at once.
MaxWatchers int
}
Options configure a Hub. The zero value is usable and takes every default.
type Stats ¶
type Stats struct {
// Matched is how many exchanges passed the filter, Sent how many of those
// reached the watcher.
Matched uint64
Sent uint64
// Sampled is how many were left out because the filtered stream was
// faster than MaxRate, and Dropped how many were thrown away because the
// watcher was not reading fast enough. The two are different failures and
// a person acts differently on each.
Sampled uint64
Dropped uint64
// Ratio is what the stream is sampling at now: 1 is everything, 50 means
// one exchange in fifty is being sent.
Ratio int
}
Stats is what a watcher's stream has done so far. It is part of the interface rather than a debug detail: a stream that is sampling has to say so, or what it shows reads as everything that happened (D9).
type Subscription ¶
type Subscription struct {
// contains filtered or unexported fields
}
Subscription is one watcher's live tail.
func (*Subscription) Close ¶
func (s *Subscription) Close()
Close ends the subscription. It is safe to call more than once, and safe to call while the query path is offering an exchange.
func (*Subscription) Done ¶
func (s *Subscription) Done() <-chan struct{}
Done is closed when the subscription ends. A reader selects on it beside Subscription.Events.
func (*Subscription) Events ¶
func (s *Subscription) Events() <-chan dns.Event
Events is the stream.
It is never closed. The query path sends into it from several goroutines at once, and closing a channel somebody may be sending on is a panic waiting for the moment a watcher leaves while a query is in flight. Subscription.Done is what says the stream has ended.
func (*Subscription) Stats ¶
func (s *Subscription) Stats() Stats
Stats reports what this stream has done. It may be read at any time.