-
Notifications
You must be signed in to change notification settings - Fork 0
/
pool.go
95 lines (81 loc) · 2.23 KB
/
pool.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package fireload
import (
"container/ring"
"errors"
"math/rand"
)
// Pool represents a pool of Firebase Namespaces, with an associated Strategy
// for load balancing in the pool.
type Pool struct {
Nodes *ring.Ring
Strategy
}
// NewPool returns a Pool with the given namespaces.
func NewPool(nodes ...Namespace) (*Pool, error) {
r := ring.New(len(nodes))
for _, node := range nodes {
r.Value = node
r = r.Next()
}
return &Pool{Nodes: r}, nil
}
// ErrInvalidStrategy is returned by `Pool.SetStrategy` when the given strategy is invalid.
var ErrInvalidStrategy = errors.New("Invalid strategy")
// SetStrategy sets the strategy of the pool to the given strategy.
func (p *Pool) SetStrategy(strategy Strategy) error {
switch strategy {
case StrategyRandom, StrategyRoundRobin:
p.Strategy = strategy
default:
return ErrInvalidStrategy
}
return nil
}
// Add inserts the given namespace into the pool.
//
// The Nodes in a Pool are considered to be unordered, so the Namespace is inserted at the
// "next" position (i.e. a subsequent call to NextRoundRobin would return the inserted Namespace).
func (p *Pool) Add(ns Namespace) {
s := &ring.Ring{Value: ns}
r := p.Nodes.Link(s)
s.Link(r)
}
// Drop removes all Namespaces with the given domain from the pool.
func (p *Pool) Drop(domain string) error {
for i := 0; i < p.Nodes.Len(); i++ {
ns, ok := p.Nodes.Value.(Namespace)
if !ok {
return errors.New("Could not typecast Ring.Value to Namespace")
}
if ns.Domain == domain {
prev := p.Nodes.Prev()
next := p.Nodes.Next()
prev.Link(next)
p.Nodes = nil
p.Nodes = prev
}
p.Nodes = p.Nodes.Next()
}
return nil
}
// Next returns from the pool the Namespace deemed to be "next" according to the
// pool's strategy.
func (p *Pool) Next() Namespace {
switch p.Strategy {
case StrategyRoundRobin:
return p.NextRoundRobin()
default:
return p.NextRandom()
}
}
// NextRandom returns a random Namespace from the pool
func (p *Pool) NextRandom() Namespace {
n := rand.Intn(p.Nodes.Len())
p.Nodes = p.Nodes.Move(n)
return p.Nodes.Value.(Namespace)
}
// NextRoundRobin returns a Namespace in "round-robin" fashion
func (p *Pool) NextRoundRobin() Namespace {
p.Nodes = p.Nodes.Next()
return p.Nodes.Value.(Namespace)
}