Bläddra i källkod

idm and ipam to use bitseq atomic APIs

Signed-off-by: Alessandro Boch <aboch@docker.com>
Alessandro Boch 10 år sedan
förälder
incheckning
5c926bb344
3 ändrade filer med 17 tillägg och 121 borttagningar
  1. 7 54
      libnetwork/bitseq/sequence.go
  2. 5 39
      libnetwork/idm/idm.go
  3. 5 28
      libnetwork/ipam/allocator.go

+ 7 - 54
libnetwork/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)

+ 5 - 39
libnetwork/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)
 }

+ 5 - 28
libnetwork/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