Browse Source

bitseq to provide handle

- Handle contains sequence and identifier.
  This way datastore integration can be done
  at bitseq level.

Signed-off-by: Alessandro Boch <aboch@docker.com>
Alessandro Boch 10 years ago
parent
commit
1f76a79bf7
3 changed files with 46 additions and 12 deletions
  1. 36 2
      libnetwork/bitseq/sequence.go
  2. 6 6
      libnetwork/ipam/allocator.go
  3. 4 4
      libnetwork/ipam/allocator_test.go

+ 36 - 2
libnetwork/bitseq/sequence.go

@@ -18,6 +18,24 @@ const (
 	blockFirstBit = 1 << (blockLen - 1)
 )
 
+// Handle contains the sequece representing the bitmask and its identifier
+type Handle struct {
+	ID   string
+	Head *Sequence
+}
+
+// NewHandle returns an instance of the bitmask handler
+func NewHandle(id string, numElements uint32) *Handle {
+	return &Handle{
+		ID: id,
+		Head: &Sequence{
+			Block: 0x0,
+			Count: getNumBlocks(numElements),
+			Next:  nil,
+		},
+	}
+}
+
 // Sequence reresents a recurring sequence of 32 bits long bitmasks
 type Sequence struct {
 	Block uint32    // block representing 4 byte long allocation bitmask
@@ -25,8 +43,8 @@ type Sequence struct {
 	Next  *Sequence // next sequence
 }
 
-// New returns a sequence initialized to represent a bitmaks of numElements bits
-func New(numElements uint32) *Sequence {
+// NewSequence returns a sequence initialized to represent a bitmaks of numElements bits
+func NewSequence(numElements uint32) *Sequence {
 	return &Sequence{Block: 0x0, Count: getNumBlocks(numElements), Next: nil}
 }
 
@@ -115,6 +133,22 @@ func (s *Sequence) FromByteArray(data []byte) error {
 	return nil
 }
 
+// GetFirstAvailable returns the byte and bit position of the first unset bit
+func (h *Handle) GetFirstAvailable() (int, int) {
+	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
+func (h *Handle) CheckIfAvailable(ordinal int) (int, int) {
+	return CheckIfAvailable(h.Head, ordinal)
+}
+
+// PushReservation pushes the bit reservation inside the bitmask.
+func (h *Handle) PushReservation(bytePos, bitPos int, release bool) {
+	h.Head = PushReservation(bytePos, bitPos, h.Head, release)
+}
+
 // GetFirstAvailable looks for the first unset bit in passed mask
 func GetFirstAvailable(head *Sequence) (int, int) {
 	byteIndex := 0

+ 6 - 6
libnetwork/ipam/allocator.go

@@ -52,7 +52,7 @@ func (s *subnetKey) String() string {
 // The bitmask is stored a run-length encoded seq.Sequence of 4 bytes blcoks.
 type bitmask struct {
 	subnet        *net.IPNet
-	addressMask   *bitseq.Sequence
+	addressMask   *bitseq.Handle
 	freeAddresses int
 }
 
@@ -102,7 +102,7 @@ func (a *Allocator) AddSubnet(addrSpace AddressSpace, subnetInfo *SubnetInfo) er
 		a.Lock()
 		a.addresses[smallKey] = &bitmask{
 			subnet:        sub,
-			addressMask:   bitseq.New(uint32(numAddresses)),
+			addressMask:   bitseq.NewHandle(smallKey.String(), uint32(numAddresses)),
 			freeAddresses: numAddresses,
 		}
 		a.Unlock()
@@ -293,7 +293,7 @@ func (a *Allocator) Release(addrSpace AddressSpace, address net.IP) {
 			space := a.addresses[subnetKey{addrSpace, sub.String()}]
 			ordinal := ipToInt(getHostPortionIP(address, space.subnet))
 			// Release it
-			space.addressMask = bitseq.PushReservation(ordinal/8, ordinal%8, space.addressMask, true)
+			space.addressMask.PushReservation(ordinal/8, ordinal%8, true)
 			space.freeAddresses++
 			return
 		}
@@ -362,17 +362,17 @@ again:
 		return nil, ErrNoAvailableIPs
 	}
 	if prefAddress == nil {
-		bytePos, bitPos = bitseq.GetFirstAvailable(smallSubnet.addressMask)
+		bytePos, bitPos = smallSubnet.addressMask.GetFirstAvailable()
 	} else {
 		ordinal := ipToInt(getHostPortionIP(prefAddress, smallSubnet.subnet))
-		bytePos, bitPos = bitseq.CheckIfAvailable(smallSubnet.addressMask, ordinal)
+		bytePos, bitPos = smallSubnet.addressMask.CheckIfAvailable(ordinal)
 	}
 	if bytePos == -1 {
 		return nil, ErrNoAvailableIPs
 	}
 
 	// Lock it
-	smallSubnet.addressMask = bitseq.PushReservation(bytePos, bitPos, smallSubnet.addressMask, false)
+	smallSubnet.addressMask.PushReservation(bytePos, bitPos, false)
 	smallSubnet.freeAddresses--
 
 	// Build IP ordinal

+ 4 - 4
libnetwork/ipam/allocator_test.go

@@ -462,10 +462,10 @@ func assertGetAddress(t *testing.T, subnet string) {
 
 	bm := &bitmask{
 		subnet:        sub,
-		addressMask:   bitseq.New(uint32(numAddresses)),
+		addressMask:   bitseq.NewHandle("default/192.168.0.0/24", uint32(numAddresses)),
 		freeAddresses: numAddresses,
 	}
-	numBlocks := bm.addressMask.Count
+	numBlocks := bm.addressMask.Head.Count
 
 	start := time.Now()
 	run := 0
@@ -476,9 +476,9 @@ func assertGetAddress(t *testing.T, subnet string) {
 	if printTime {
 		fmt.Printf("\nTaken %v, to allocate all addresses on %s. (nemAddresses: %d. Runs: %d)", time.Since(start), subnet, numAddresses, run)
 	}
-	if bm.addressMask.Block != expectedMax || bm.addressMask.Count != numBlocks {
+	if bm.addressMask.Head.Block != expectedMax || bm.addressMask.Head.Count != numBlocks {
 		t.Fatalf("Failed to effectively reserve all addresses on %s. Expected (0x%x, %d) as first sequence. Found (0x%x,%d)",
-			subnet, expectedMax, numBlocks, bm.addressMask.Block, bm.addressMask.Count)
+			subnet, expectedMax, numBlocks, bm.addressMask.Head.Block, bm.addressMask.Head.Count)
 	}
 }