Commit a5046297 authored by Andrew Hamon's avatar Andrew Hamon

Refactor and clean up policy code

This commit shouldn't change any behavior. It is simply a cleanup of
the different proxy policies. It also adds some comments explaining the
sampling method used, since on first inspection it might not appear to
be a uniformly random selection.
parent 6fe5c1a6
package proxy package proxy
import ( import (
"math"
"math/rand" "math/rand"
"sync" "sync"
) )
...@@ -24,22 +25,23 @@ type Random struct{} ...@@ -24,22 +25,23 @@ type Random struct{}
// Select selects an up host at random from the specified pool. // Select selects an up host at random from the specified pool.
func (r *Random) Select(pool HostPool) *UpstreamHost { func (r *Random) Select(pool HostPool) *UpstreamHost {
// instead of just generating a random index
// this is done to prevent selecting a unavailable host // Because the number of available hosts isn't known
// up front, the host is selected via reservoir sampling
// https://en.wikipedia.org/wiki/Reservoir_sampling
var randHost *UpstreamHost var randHost *UpstreamHost
count := 0 count := 0
for _, host := range pool { for _, host := range pool {
if !host.Available() { if !host.Available() {
continue continue
} }
// (n % 1 == 0) holds for all n, therefore randHost
// will always get assigned a value if there is
// at least 1 available host
count++ count++
if count == 1 { if (rand.Int() % count) == 0 {
randHost = host randHost = host
} else {
r := rand.Int() % count
if r == (count - 1) {
randHost = host
}
} }
} }
return randHost return randHost
...@@ -54,26 +56,23 @@ type LeastConn struct{} ...@@ -54,26 +56,23 @@ type LeastConn struct{}
func (r *LeastConn) Select(pool HostPool) *UpstreamHost { func (r *LeastConn) Select(pool HostPool) *UpstreamHost {
var bestHost *UpstreamHost var bestHost *UpstreamHost
count := 0 count := 0
leastConn := int64(1<<63 - 1) leastConn := int64(math.MaxInt64)
for _, host := range pool { for _, host := range pool {
if !host.Available() { if !host.Available() {
continue continue
} }
hostConns := host.Conns
if hostConns < leastConn { if host.Conns < leastConn {
bestHost = host leastConn = host.Conns
leastConn = hostConns count = 0
count = 1 }
} else if hostConns == leastConn {
// randomly select host among hosts with least connections // Among hosts with same least connections, perform a reservoir
// sample: https://en.wikipedia.org/wiki/Reservoir_sampling
if host.Conns == leastConn {
count++ count++
if count == 1 { if (rand.Int() % count) == 0 {
bestHost = host bestHost = host
} else {
r := rand.Int() % count
if r == (count - 1) {
bestHost = host
}
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment