|
|
@ -2,7 +2,7 @@ package selector |
|
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
import ( |
|
|
|
"context" |
|
|
|
"context" |
|
|
|
"sync" |
|
|
|
"sync/atomic" |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
// Default is composite selector.
|
|
|
|
// Default is composite selector.
|
|
|
@ -11,29 +11,40 @@ type Default struct { |
|
|
|
Balancer Balancer |
|
|
|
Balancer Balancer |
|
|
|
Filters []Filter |
|
|
|
Filters []Filter |
|
|
|
|
|
|
|
|
|
|
|
lk sync.RWMutex |
|
|
|
nodes atomic.Value |
|
|
|
weightedNodes []Node |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Select select one node.
|
|
|
|
// Select select one node.
|
|
|
|
func (d *Default) Select(ctx context.Context, opts ...SelectOption) (selected Node, done DoneFunc, err error) { |
|
|
|
func (d *Default) Select(ctx context.Context, opts ...SelectOption) (selected Node, done DoneFunc, err error) { |
|
|
|
d.lk.RLock() |
|
|
|
var ( |
|
|
|
weightedNodes := d.weightedNodes |
|
|
|
options SelectOptions |
|
|
|
d.lk.RUnlock() |
|
|
|
candidates []WeightedNode |
|
|
|
|
|
|
|
) |
|
|
|
for _, f := range d.Filters { |
|
|
|
nodes, ok := d.nodes.Load().([]WeightedNode) |
|
|
|
weightedNodes = f(ctx, weightedNodes) |
|
|
|
if !ok { |
|
|
|
|
|
|
|
return nil, nil, ErrNoAvailable |
|
|
|
} |
|
|
|
} |
|
|
|
var options SelectOptions |
|
|
|
|
|
|
|
for _, o := range opts { |
|
|
|
for _, o := range opts { |
|
|
|
o(&options) |
|
|
|
o(&options) |
|
|
|
} |
|
|
|
} |
|
|
|
for _, f := range options.Filters { |
|
|
|
if len(d.Filters) > 0 { |
|
|
|
weightedNodes = f(ctx, weightedNodes) |
|
|
|
newNodes := make([]Node, len(nodes)) |
|
|
|
|
|
|
|
for i, wc := range nodes { |
|
|
|
|
|
|
|
newNodes[i] = wc |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for _, f := range d.Filters { |
|
|
|
|
|
|
|
newNodes = f(ctx, newNodes) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
candidates = make([]WeightedNode, len(newNodes)) |
|
|
|
|
|
|
|
for i, n := range newNodes { |
|
|
|
|
|
|
|
candidates[i] = n.(WeightedNode) |
|
|
|
} |
|
|
|
} |
|
|
|
candidates := make([]WeightedNode, 0, len(weightedNodes)) |
|
|
|
} else { |
|
|
|
for _, n := range weightedNodes { |
|
|
|
candidates = nodes |
|
|
|
candidates = append(candidates, n.(WeightedNode)) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if len(options.Filters) > 0 { |
|
|
|
|
|
|
|
candidates = d.nodeFilter(options.Filters, candidates) |
|
|
|
} |
|
|
|
} |
|
|
|
if len(candidates) == 0 { |
|
|
|
if len(candidates) == 0 { |
|
|
|
return nil, nil, ErrNoAvailable |
|
|
|
return nil, nil, ErrNoAvailable |
|
|
@ -45,16 +56,31 @@ func (d *Default) Select(ctx context.Context, opts ...SelectOption) (selected No |
|
|
|
return wn.Raw(), done, nil |
|
|
|
return wn.Raw(), done, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (d *Default) nodeFilter(filters []NodeFilter, nodes []WeightedNode) []WeightedNode { |
|
|
|
|
|
|
|
newNodes := make([]WeightedNode, 0, len(nodes)) |
|
|
|
|
|
|
|
for _, n := range nodes { |
|
|
|
|
|
|
|
var remove bool |
|
|
|
|
|
|
|
for _, f := range filters { |
|
|
|
|
|
|
|
if !f(n) { |
|
|
|
|
|
|
|
remove = true |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if !remove { |
|
|
|
|
|
|
|
newNodes = append(newNodes, n) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return newNodes |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Apply update nodes info.
|
|
|
|
// Apply update nodes info.
|
|
|
|
func (d *Default) Apply(nodes []Node) { |
|
|
|
func (d *Default) Apply(nodes []Node) { |
|
|
|
weightedNodes := make([]Node, 0, len(nodes)) |
|
|
|
weightedNodes := make([]WeightedNode, 0, len(nodes)) |
|
|
|
for _, n := range nodes { |
|
|
|
for _, n := range nodes { |
|
|
|
weightedNodes = append(weightedNodes, d.NodeBuilder.Build(n)) |
|
|
|
weightedNodes = append(weightedNodes, d.NodeBuilder.Build(n)) |
|
|
|
} |
|
|
|
} |
|
|
|
d.lk.Lock() |
|
|
|
|
|
|
|
// TODO: Do not delete unchanged nodes
|
|
|
|
// TODO: Do not delete unchanged nodes
|
|
|
|
d.weightedNodes = weightedNodes |
|
|
|
d.nodes.Store(weightedNodes) |
|
|
|
d.lk.Unlock() |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// DefaultBuilder is de
|
|
|
|
// DefaultBuilder is de
|
|
|
|