mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
2c8670b496
endpoint_cnt object is created during network create and destroyed when network is deleted. But the updateToStore function creates an object when it is not present in the store. endpoint_cnt is a mutable object and is updated during endpoint create and delete events. If endpoint create or delete happens after the network is deleted, it can incorrectly create an endpoint_cnt object in the store and that can cause problems when the same network is created again later. The fix is to not create the endpoint_cnt object when endpoint_cnt is incremented or decremented Signed-off-by: Madhu Venugopal <madhu@docker.com>
182 lines
3.4 KiB
Go
182 lines
3.4 KiB
Go
package libnetwork
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/docker/libnetwork/datastore"
|
|
)
|
|
|
|
type endpointCnt struct {
|
|
n *network
|
|
Count uint64
|
|
dbIndex uint64
|
|
dbExists bool
|
|
sync.Mutex
|
|
}
|
|
|
|
const epCntKeyPrefix = "endpoint_count"
|
|
|
|
func (ec *endpointCnt) Key() []string {
|
|
ec.Lock()
|
|
defer ec.Unlock()
|
|
|
|
return []string{epCntKeyPrefix, ec.n.id}
|
|
}
|
|
|
|
func (ec *endpointCnt) KeyPrefix() []string {
|
|
ec.Lock()
|
|
defer ec.Unlock()
|
|
|
|
return []string{epCntKeyPrefix, ec.n.id}
|
|
}
|
|
|
|
func (ec *endpointCnt) Value() []byte {
|
|
ec.Lock()
|
|
defer ec.Unlock()
|
|
|
|
b, err := json.Marshal(ec)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return b
|
|
}
|
|
|
|
func (ec *endpointCnt) SetValue(value []byte) error {
|
|
ec.Lock()
|
|
defer ec.Unlock()
|
|
|
|
return json.Unmarshal(value, &ec)
|
|
}
|
|
|
|
func (ec *endpointCnt) Index() uint64 {
|
|
ec.Lock()
|
|
defer ec.Unlock()
|
|
return ec.dbIndex
|
|
}
|
|
|
|
func (ec *endpointCnt) SetIndex(index uint64) {
|
|
ec.Lock()
|
|
ec.dbIndex = index
|
|
ec.dbExists = true
|
|
ec.Unlock()
|
|
}
|
|
|
|
func (ec *endpointCnt) Exists() bool {
|
|
ec.Lock()
|
|
defer ec.Unlock()
|
|
return ec.dbExists
|
|
}
|
|
|
|
func (ec *endpointCnt) Skip() bool {
|
|
ec.Lock()
|
|
defer ec.Unlock()
|
|
return !ec.n.persist
|
|
}
|
|
|
|
func (ec *endpointCnt) New() datastore.KVObject {
|
|
ec.Lock()
|
|
defer ec.Unlock()
|
|
|
|
return &endpointCnt{
|
|
n: ec.n,
|
|
}
|
|
}
|
|
|
|
func (ec *endpointCnt) CopyTo(o datastore.KVObject) error {
|
|
ec.Lock()
|
|
defer ec.Unlock()
|
|
|
|
dstEc := o.(*endpointCnt)
|
|
dstEc.n = ec.n
|
|
dstEc.Count = ec.Count
|
|
dstEc.dbExists = ec.dbExists
|
|
dstEc.dbIndex = ec.dbIndex
|
|
|
|
return nil
|
|
}
|
|
|
|
func (ec *endpointCnt) DataScope() string {
|
|
return ec.n.DataScope()
|
|
}
|
|
|
|
func (ec *endpointCnt) EndpointCnt() uint64 {
|
|
ec.Lock()
|
|
defer ec.Unlock()
|
|
|
|
return ec.Count
|
|
}
|
|
|
|
func (ec *endpointCnt) updateStore() error {
|
|
store := ec.n.getController().getStore(ec.DataScope())
|
|
if store == nil {
|
|
return fmt.Errorf("store not found for scope %s on endpoint count update", ec.DataScope())
|
|
}
|
|
// make a copy of count and n to avoid being overwritten by store.GetObject
|
|
count := ec.EndpointCnt()
|
|
n := ec.n
|
|
for {
|
|
if err := ec.n.getController().updateToStore(ec); err == nil || err != datastore.ErrKeyModified {
|
|
return err
|
|
}
|
|
if err := store.GetObject(datastore.Key(ec.Key()...), ec); err != nil {
|
|
return fmt.Errorf("could not update the kvobject to latest on endpoint count update: %v", err)
|
|
}
|
|
ec.Lock()
|
|
ec.Count = count
|
|
ec.n = n
|
|
ec.Unlock()
|
|
}
|
|
}
|
|
|
|
func (ec *endpointCnt) setCnt(cnt uint64) error {
|
|
ec.Lock()
|
|
ec.Count = cnt
|
|
ec.Unlock()
|
|
return ec.updateStore()
|
|
}
|
|
|
|
func (ec *endpointCnt) atomicIncDecEpCnt(inc bool) error {
|
|
store := ec.n.getController().getStore(ec.DataScope())
|
|
if store == nil {
|
|
return fmt.Errorf("store not found for scope %s", ec.DataScope())
|
|
}
|
|
|
|
tmp := &endpointCnt{n: ec.n}
|
|
if err := store.GetObject(datastore.Key(ec.Key()...), tmp); err != nil {
|
|
return err
|
|
}
|
|
retry:
|
|
ec.Lock()
|
|
if inc {
|
|
ec.Count++
|
|
} else {
|
|
if ec.Count > 0 {
|
|
ec.Count--
|
|
}
|
|
}
|
|
ec.Unlock()
|
|
|
|
if err := ec.n.getController().updateToStore(ec); err != nil {
|
|
if err == datastore.ErrKeyModified {
|
|
if err := store.GetObject(datastore.Key(ec.Key()...), ec); err != nil {
|
|
return fmt.Errorf("could not update the kvobject to latest when trying to atomic add endpoint count: %v", err)
|
|
}
|
|
|
|
goto retry
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (ec *endpointCnt) IncEndpointCnt() error {
|
|
return ec.atomicIncDecEpCnt(true)
|
|
}
|
|
|
|
func (ec *endpointCnt) DecEndpointCnt() error {
|
|
return ec.atomicIncDecEpCnt(false)
|
|
}
|