1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #550 from sanimej/ext_conn

Serialize the endpoint join/leave at the sandbox level
This commit is contained in:
Madhu Venugopal 2015-09-22 13:39:35 -07:00
commit 01a0be8e33
3 changed files with 86 additions and 59 deletions

View file

@ -68,8 +68,9 @@ func (sb *sandbox) setupDefaultGW(srcEp *endpoint) error {
if err != nil { if err != nil {
return fmt.Errorf("container %s: endpoint create on GW Network failed: %v", sb.containerID, err) return fmt.Errorf("container %s: endpoint create on GW Network failed: %v", sb.containerID, err)
} }
epLocal := newEp.(*endpoint)
if err := newEp.Join(sb); err != nil { if err := epLocal.sbJoin(sb); err != nil {
return fmt.Errorf("container %s: endpoint join on GW Network failed: %v", sb.containerID, err) return fmt.Errorf("container %s: endpoint join on GW Network failed: %v", sb.containerID, err)
} }
return nil return nil
@ -82,7 +83,7 @@ func (sb *sandbox) clearDefaultGW() error {
return nil return nil
} }
if err := ep.Leave(sb); err != nil { if err := ep.sbLeave(sb); err != nil {
return fmt.Errorf("container %s: endpoint leaving GW Network failed: %v", sb.containerID, err) return fmt.Errorf("container %s: endpoint leaving GW Network failed: %v", sb.containerID, err)
} }
if err := ep.Delete(); err != nil { if err := ep.Delete(); err != nil {

View file

@ -188,40 +188,7 @@ func (ep *endpoint) processOptions(options ...EndpointOption) {
} }
} }
// joinLeaveStart waits to ensure there are no joins or leaves in progress and
// marks this join/leave in progress without race
func (ep *endpoint) joinLeaveStart() {
ep.Lock()
defer ep.Unlock()
for ep.joinLeaveDone != nil {
joinLeaveDone := ep.joinLeaveDone
ep.Unlock()
select {
case <-joinLeaveDone:
}
ep.Lock()
}
ep.joinLeaveDone = make(chan struct{})
}
// joinLeaveEnd marks the end of this join/leave operation and
// signals the same without race to other join and leave waiters
func (ep *endpoint) joinLeaveEnd() {
ep.Lock()
defer ep.Unlock()
if ep.joinLeaveDone != nil {
close(ep.joinLeaveDone)
ep.joinLeaveDone = nil
}
}
func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error { func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
var err error
if sbox == nil { if sbox == nil {
return types.BadRequestErrorf("endpoint cannot be joined by nil container") return types.BadRequestErrorf("endpoint cannot be joined by nil container")
@ -232,8 +199,18 @@ func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
return types.BadRequestErrorf("not a valid Sandbox interface") return types.BadRequestErrorf("not a valid Sandbox interface")
} }
ep.joinLeaveStart() sb.joinLeaveStart()
defer ep.joinLeaveEnd() defer sb.joinLeaveEnd()
return ep.sbJoin(sbox, options...)
}
func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
var err error
sb, ok := sbox.(*sandbox)
if !ok {
return types.BadRequestErrorf("not a valid Sandbox interface")
}
ep.Lock() ep.Lock()
if ep.sandboxID != "" { if ep.sandboxID != "" {
@ -326,9 +303,6 @@ func (ep *endpoint) hasInterface(iName string) bool {
} }
func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error { func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error {
ep.joinLeaveStart()
defer ep.joinLeaveEnd()
if sbox == nil || sbox.ID() == "" || sbox.Key() == "" { if sbox == nil || sbox.ID() == "" || sbox.Key() == "" {
return types.BadRequestErrorf("invalid Sandbox passed to enpoint leave: %v", sbox) return types.BadRequestErrorf("invalid Sandbox passed to enpoint leave: %v", sbox)
} }
@ -338,6 +312,18 @@ func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error {
return types.BadRequestErrorf("not a valid Sandbox interface") return types.BadRequestErrorf("not a valid Sandbox interface")
} }
sb.joinLeaveStart()
defer sb.joinLeaveEnd()
return ep.sbLeave(sbox, options...)
}
func (ep *endpoint) sbLeave(sbox Sandbox, options ...EndpointOption) error {
sb, ok := sbox.(*sandbox)
if !ok {
return types.BadRequestErrorf("not a valid Sandbox interface")
}
ep.Lock() ep.Lock()
sid := ep.sandboxID sid := ep.sandboxID
ep.Unlock() ep.Unlock()

View file

@ -347,15 +347,16 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
} }
} }
sb.Lock() for _, gwep := range sb.getConnectedEndpoints() {
highEp := sb.endpoints[0] if len(gwep.Gateway()) > 0 {
sb.Unlock() if gwep != ep {
if ep == highEp { return nil
if err := sb.updateGateway(ep); err != nil { }
return err if err := sb.updateGateway(gwep); err != nil {
return err
}
} }
} }
return nil return nil
} }
@ -394,26 +395,33 @@ func (sb *sandbox) clearNetworkResources(ep *endpoint) error {
return nil return nil
} }
highEpBefore := sb.endpoints[0]
var ( var (
i int gwepBefore, gwepAfter *endpoint
e *endpoint index = -1
) )
for i, e = range sb.endpoints { for i, e := range sb.endpoints {
if e == ep { if e == ep {
index = i
}
if len(e.Gateway()) > 0 && gwepBefore == nil {
gwepBefore = e
}
if index != -1 && gwepBefore != nil {
break break
} }
} }
heap.Remove(&sb.endpoints, i) heap.Remove(&sb.endpoints, index)
var highEpAfter *endpoint for _, e := range sb.endpoints {
if len(sb.endpoints) > 0 { if len(e.Gateway()) > 0 {
highEpAfter = sb.endpoints[0] gwepAfter = e
break
}
} }
delete(sb.epPriority, ep.ID()) delete(sb.epPriority, ep.ID())
sb.Unlock() sb.Unlock()
if highEpBefore != highEpAfter { if gwepAfter != nil && gwepBefore != gwepAfter {
sb.updateGateway(highEpAfter) sb.updateGateway(gwepAfter)
} }
return nil return nil
@ -634,6 +642,38 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
return os.Rename(tmpResolvFile.Name(), sb.config.resolvConfPath) return os.Rename(tmpResolvFile.Name(), sb.config.resolvConfPath)
} }
// joinLeaveStart waits to ensure there are no joins or leaves in progress and
// marks this join/leave in progress without race
func (sb *sandbox) joinLeaveStart() {
sb.Lock()
defer sb.Unlock()
for sb.joinLeaveDone != nil {
joinLeaveDone := sb.joinLeaveDone
sb.Unlock()
select {
case <-joinLeaveDone:
}
sb.Lock()
}
sb.joinLeaveDone = make(chan struct{})
}
// joinLeaveEnd marks the end of this join/leave operation and
// signals the same without race to other join and leave waiters
func (sb *sandbox) joinLeaveEnd() {
sb.Lock()
defer sb.Unlock()
if sb.joinLeaveDone != nil {
close(sb.joinLeaveDone)
sb.joinLeaveDone = nil
}
}
// OptionHostname function returns an option setter for hostname option to // OptionHostname function returns an option setter for hostname option to
// be passed to NewSandbox method. // be passed to NewSandbox method.
func OptionHostname(name string) SandboxOption { func OptionHostname(name string) SandboxOption {
@ -757,11 +797,11 @@ func (eh epHeap) Less(i, j int) bool {
epj := eh[j] epj := eh[j]
if epi.endpointInGWNetwork() { if epi.endpointInGWNetwork() {
return true return false
} }
if epj.endpointInGWNetwork() { if epj.endpointInGWNetwork() {
return false return true
} }
cip, ok := ci.epPriority[eh[i].ID()] cip, ok := ci.epPriority[eh[i].ID()]