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>
This commit is contained in:
Alessandro Boch 2015-06-13 13:35:43 -07:00
parent 3ff75bd42d
commit 1f76a79bf7
3 changed files with 46 additions and 12 deletions

View File

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

View File

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

View File

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