idm and ipam to use bitseq atomic APIs
Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
parent
01d6585a31
commit
5c926bb344
3 changed files with 17 additions and 121 deletions
|
@ -186,26 +186,6 @@ func (h *Handle) getCopy() *Handle {
|
|||
}
|
||||
}
|
||||
|
||||
// GetFirstAvailable returns the byte and bit position of the first unset bit
|
||||
// @Deprecated Use SetAny() instead
|
||||
func (h *Handle) GetFirstAvailable() (uint32, uint32, error) {
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
return getFirstAvailable(h.head)
|
||||
}
|
||||
|
||||
// CheckIfAvailable checks if the bit correspondent to the specified ordinal is unset
|
||||
// If the ordinal is beyond the sequence limits, a negative response is returned
|
||||
// @Deprecated Use IsSet() instead
|
||||
func (h *Handle) CheckIfAvailable(ordinal uint32) (uint32, uint32, error) {
|
||||
if err := h.validateOrdinal(ordinal); err != nil {
|
||||
return invalidPos, invalidPos, err
|
||||
}
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
return checkIfAvailable(h.head, ordinal)
|
||||
}
|
||||
|
||||
// SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal
|
||||
func (h *Handle) SetAny() (uint32, error) {
|
||||
if h.Unselected() == 0 {
|
||||
|
@ -315,40 +295,6 @@ func (h *Handle) validateOrdinal(ordinal uint32) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// PushReservation pushes the bit reservation inside the bitmask.
|
||||
// @Deprecated Use Set() instead
|
||||
func (h *Handle) PushReservation(bytePos, bitPos uint32, release bool) error {
|
||||
// Create a private copy of h and work on it, also copy the current db index
|
||||
h.Lock()
|
||||
nh := h.getCopy()
|
||||
ci := h.dbIndex
|
||||
h.Unlock()
|
||||
|
||||
nh.head = pushReservation(bytePos, bitPos, nh.head, release)
|
||||
if release {
|
||||
nh.unselected++
|
||||
} else {
|
||||
nh.unselected--
|
||||
}
|
||||
|
||||
// Attempt to write private copy to store
|
||||
if err := nh.writeToStore(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Unless unexpected error, save private copy to local copy
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
if h.dbIndex != ci {
|
||||
return fmt.Errorf("unexected database index change")
|
||||
}
|
||||
h.unselected = nh.unselected
|
||||
h.head = nh.head
|
||||
h.dbExists = nh.dbExists
|
||||
h.dbIndex = nh.dbIndex
|
||||
return nil
|
||||
}
|
||||
|
||||
// Destroy removes from the datastore the data belonging to this handle
|
||||
func (h *Handle) Destroy() {
|
||||
h.deleteFromStore()
|
||||
|
@ -404,6 +350,13 @@ func (h *Handle) Unselected() uint32 {
|
|||
return h.unselected
|
||||
}
|
||||
|
||||
func (h *Handle) String() string {
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
return fmt.Sprintf("App: %s, ID: %s, DBIndex: 0x%x, bits: %d, unselected: %d, sequence: %s",
|
||||
h.app, h.id, h.dbIndex, h.bits, h.unselected, h.head.toString())
|
||||
}
|
||||
|
||||
// getFirstAvailable looks for the first unset bit in passed mask
|
||||
func getFirstAvailable(head *sequence) (uint32, uint32, error) {
|
||||
byteIndex := uint32(0)
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/docker/libnetwork/bitseq"
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
// Idm manages the reservation/release of numerical ids from a contiguos set
|
||||
|
@ -25,7 +24,7 @@ func New(ds datastore.DataStore, id string, start, end uint32) (*Idm, error) {
|
|||
return nil, fmt.Errorf("Invalid set range: [%d, %d]", start, end)
|
||||
}
|
||||
|
||||
h, err := bitseq.NewHandle("idm", ds, id, uint32(1+end-start))
|
||||
h, err := bitseq.NewHandle("idm", ds, id, 1+end-start)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize bit sequence handler: %s", err.Error())
|
||||
}
|
||||
|
@ -38,28 +37,8 @@ func (i *Idm) GetID() (uint32, error) {
|
|||
if i.handle == nil {
|
||||
return 0, fmt.Errorf("ID set is not initialized")
|
||||
}
|
||||
|
||||
for {
|
||||
bytePos, bitPos, err := i.handle.GetFirstAvailable()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("no available ids")
|
||||
}
|
||||
id := i.start + uint32(bitPos+bytePos*8)
|
||||
|
||||
// for sets which length is non multiple of 32 this check is needed
|
||||
if i.end < id {
|
||||
return 0, fmt.Errorf("no available ids")
|
||||
}
|
||||
|
||||
if err := i.handle.PushReservation(bytePos, bitPos, false); err != nil {
|
||||
if _, ok := err.(types.RetryError); !ok {
|
||||
return 0, fmt.Errorf("internal failure while reserving the id: %s", err.Error())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
ordinal, err := i.handle.SetAny()
|
||||
return i.start + ordinal, err
|
||||
}
|
||||
|
||||
// GetSpecificID tries to reserve the specified id
|
||||
|
@ -72,23 +51,10 @@ func (i *Idm) GetSpecificID(id uint32) error {
|
|||
return fmt.Errorf("Requested id does not belong to the set")
|
||||
}
|
||||
|
||||
for {
|
||||
bytePos, bitPos, err := i.handle.CheckIfAvailable(id - i.start)
|
||||
if err != nil {
|
||||
return fmt.Errorf("requested id is not available")
|
||||
}
|
||||
if err := i.handle.PushReservation(bytePos, bitPos, false); err != nil {
|
||||
if _, ok := err.(types.RetryError); !ok {
|
||||
return fmt.Errorf("internal failure while reserving the id: %s", err.Error())
|
||||
}
|
||||
continue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return i.handle.Set(id - i.start)
|
||||
}
|
||||
|
||||
// Release releases the specified id
|
||||
func (i *Idm) Release(id uint32) {
|
||||
ordinal := id - i.start
|
||||
i.handle.PushReservation(ordinal/8, ordinal%8, true)
|
||||
i.handle.Unset(id - i.start)
|
||||
}
|
||||
|
|
|
@ -433,21 +433,11 @@ func (a *Allocator) Release(addrSpace AddressSpace, address net.IP) {
|
|||
// Retrieve correspondent ordinal in the subnet
|
||||
ordinal := ipToUint32(getHostPortionIP(address, sub))
|
||||
// Release it
|
||||
for {
|
||||
var err error
|
||||
if err = space.PushReservation(ordinal/8, ordinal%8, true); err == nil {
|
||||
break
|
||||
}
|
||||
if _, ok := err.(types.RetryError); ok {
|
||||
// bitmask must have changed, retry delete
|
||||
continue
|
||||
}
|
||||
if err := space.Unset(ordinal); err != nil {
|
||||
log.Warnf("Failed to release address %s because of internal error: %s", address.String(), err.Error())
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -509,9 +499,8 @@ func (a *Allocator) getSubnetList(addrSpace AddressSpace, ver ipVersion) []subne
|
|||
|
||||
func (a *Allocator) getAddress(subnet *net.IPNet, bitmask *bitseq.Handle, prefAddress net.IP, ver ipVersion) (net.IP, error) {
|
||||
var (
|
||||
bytePos, bitPos uint32
|
||||
ordinal uint32
|
||||
err error
|
||||
ordinal uint32
|
||||
err error
|
||||
)
|
||||
|
||||
// Look for free IP, skip .0 and .255, they will be automatically reserved
|
||||
|
@ -520,26 +509,14 @@ func (a *Allocator) getAddress(subnet *net.IPNet, bitmask *bitseq.Handle, prefAd
|
|||
return nil, ErrNoAvailableIPs
|
||||
}
|
||||
if prefAddress == nil {
|
||||
bytePos, bitPos, err = bitmask.GetFirstAvailable()
|
||||
ordinal, err = bitmask.SetAny()
|
||||
} else {
|
||||
ordinal = ipToUint32(getHostPortionIP(prefAddress, subnet))
|
||||
bytePos, bitPos, err = bitmask.CheckIfAvailable(ordinal)
|
||||
err = bitmask.Set(ipToUint32(getHostPortionIP(prefAddress, subnet)))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, ErrNoAvailableIPs
|
||||
}
|
||||
|
||||
// Lock it
|
||||
if err = bitmask.PushReservation(bytePos, bitPos, false); err != nil {
|
||||
if _, ok := err.(types.RetryError); !ok {
|
||||
return nil, fmt.Errorf("internal failure while reserving the address: %s", err.Error())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Build IP ordinal
|
||||
ordinal = bitPos + bytePos*8
|
||||
|
||||
// For v4, let reservation of .0 and .255 happen automatically
|
||||
if ver == v4 && !isValidIP(ordinal) {
|
||||
continue
|
||||
|
|
Loading…
Add table
Reference in a new issue