mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Refactored PortAllocator to allow for same-frontend constraint
This commit is contained in:
parent
f344212b93
commit
a5fb1d6c01
1 changed files with 44 additions and 27 deletions
71
network.go
71
network.go
|
@ -9,6 +9,7 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -160,39 +161,55 @@ func newPortMapper() (*PortMapper, error) {
|
||||||
|
|
||||||
// Port allocator: Atomatically allocate and release networking ports
|
// Port allocator: Atomatically allocate and release networking ports
|
||||||
type PortAllocator struct {
|
type PortAllocator struct {
|
||||||
ports chan (int)
|
inUse map[int]struct{}
|
||||||
|
fountain chan (int)
|
||||||
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (alloc *PortAllocator) run(start, end int) {
|
func (alloc *PortAllocator) runFountain() {
|
||||||
alloc.ports = make(chan int, end-start)
|
if alloc.fountain != nil {
|
||||||
for port := start; port < end; port++ {
|
return
|
||||||
alloc.ports <- port
|
}
|
||||||
|
alloc.fountain = make(chan int)
|
||||||
|
for {
|
||||||
|
for port := portRangeStart; port < portRangeEnd; port++ {
|
||||||
|
alloc.fountain <- port
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (alloc *PortAllocator) Acquire() (int, error) {
|
// FIXME: Release can no longer fail, change its prototype to reflect that.
|
||||||
select {
|
|
||||||
case port := <-alloc.ports:
|
|
||||||
return port, nil
|
|
||||||
default:
|
|
||||||
return -1, errors.New("No more ports available")
|
|
||||||
}
|
|
||||||
return -1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (alloc *PortAllocator) Release(port int) error {
|
func (alloc *PortAllocator) Release(port int) error {
|
||||||
select {
|
alloc.lock.Lock()
|
||||||
case alloc.ports <- port:
|
delete(alloc.inUse, port)
|
||||||
return nil
|
alloc.lock.Unlock()
|
||||||
default:
|
return nil
|
||||||
return errors.New("Too many ports have been released")
|
|
||||||
}
|
|
||||||
panic("unreachable")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPortAllocator(start, end int) (*PortAllocator, error) {
|
func (alloc *PortAllocator) Acquire(port int) (int, error) {
|
||||||
allocator := &PortAllocator{}
|
if port == 0 {
|
||||||
allocator.run(start, end)
|
// Allocate a port from the fountain
|
||||||
|
for port := range alloc.fountain {
|
||||||
|
if _, err := alloc.Acquire(port); err == nil {
|
||||||
|
return port, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1, fmt.Errorf("Port generator ended unexpectedly")
|
||||||
|
}
|
||||||
|
alloc.lock.Lock()
|
||||||
|
defer alloc.lock.Unlock()
|
||||||
|
if _, inUse := alloc.inUse[port]; inUse {
|
||||||
|
return -1, fmt.Errorf("Port already in use: %d", port)
|
||||||
|
}
|
||||||
|
alloc.inUse[port] = struct{}{}
|
||||||
|
return port, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPortAllocator() (*PortAllocator, error) {
|
||||||
|
allocator := &PortAllocator{
|
||||||
|
inUse: make(map[int]struct{}),
|
||||||
|
}
|
||||||
|
go allocator.runFountain()
|
||||||
return allocator, nil
|
return allocator, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +319,7 @@ type NetworkInterface struct {
|
||||||
|
|
||||||
// Allocate an external TCP port and map it to the interface
|
// Allocate an external TCP port and map it to the interface
|
||||||
func (iface *NetworkInterface) AllocatePort(port int) (int, error) {
|
func (iface *NetworkInterface) AllocatePort(port int) (int, error) {
|
||||||
extPort, err := iface.manager.portAllocator.Acquire()
|
extPort, err := iface.manager.portAllocator.Acquire(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
@ -363,7 +380,7 @@ func newNetworkManager(bridgeIface string) (*NetworkManager, error) {
|
||||||
|
|
||||||
ipAllocator := newIPAllocator(network)
|
ipAllocator := newIPAllocator(network)
|
||||||
|
|
||||||
portAllocator, err := newPortAllocator(portRangeStart, portRangeEnd)
|
portAllocator, err := newPortAllocator()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue