idm and ipam to use bitseq atomic APIs

Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
Alessandro Boch 2015-06-24 15:02:08 -07:00
parent 01d6585a31
commit 5c926bb344
3 changed files with 17 additions and 121 deletions

View file

@ -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)

View file

@ -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)
}

View file

@ -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