mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-04 03:27:23 -05:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									6fe5c1a69f
								
							
						
					
					
						commit
						a50462974c
					
				@ -1,6 +1,7 @@
 | 
				
			|||||||
package proxy
 | 
					package proxy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
	"math/rand"
 | 
						"math/rand"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -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{}
 | 
				
			|||||||
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
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user