diff --git a/bitseq/sequence.go b/bitseq/sequence.go index 653a2cb..d71d76b 100644 --- a/bitseq/sequence.go +++ b/bitseq/sequence.go @@ -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) diff --git a/idm/idm.go b/idm/idm.go index 2fa3cff..8c15cfe 100644 --- a/idm/idm.go +++ b/idm/idm.go @@ -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) } diff --git a/ipam/allocator.go b/ipam/allocator.go index 2fee5ab..bf52dff 100644 --- a/ipam/allocator.go +++ b/ipam/allocator.go @@ -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