From 1f76a79bf7624b67d8474f32a95b90a37c09569a Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Sat, 13 Jun 2015 13:35:43 -0700 Subject: [PATCH] bitseq to provide handle - Handle contains sequence and identifier. This way datastore integration can be done at bitseq level. Signed-off-by: Alessandro Boch --- libnetwork/bitseq/sequence.go | 38 +++++++++++++++++++++++++++++-- libnetwork/ipam/allocator.go | 12 +++++----- libnetwork/ipam/allocator_test.go | 8 +++---- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/libnetwork/bitseq/sequence.go b/libnetwork/bitseq/sequence.go index ecbf634e65..d304f1c776 100644 --- a/libnetwork/bitseq/sequence.go +++ b/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 diff --git a/libnetwork/ipam/allocator.go b/libnetwork/ipam/allocator.go index 856d4e8aa8..3a132a7fe4 100644 --- a/libnetwork/ipam/allocator.go +++ b/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 diff --git a/libnetwork/ipam/allocator_test.go b/libnetwork/ipam/allocator_test.go index b193516a1c..32bc0d9e1c 100644 --- a/libnetwork/ipam/allocator_test.go +++ b/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) } }