Adding a unit case to verify rollover

Signed-off-by: Abhinandan Prativadi <abhi@docker.com>
This commit is contained in:
Abhinandan Prativadi 2017-05-31 19:41:21 -07:00
parent 813a24a51c
commit 3d44975995
12 changed files with 221 additions and 185 deletions

View file

@ -199,22 +199,22 @@ func (h *Handle) getCopy() *Handle {
} }
// SetAnyInRange atomically sets the first unset bit in the specified range in the sequence and returns the corresponding ordinal // SetAnyInRange atomically sets the first unset bit in the specified range in the sequence and returns the corresponding ordinal
func (h *Handle) SetAnyInRange(start, end uint64) (uint64, error) { func (h *Handle) SetAnyInRange(start, end uint64, serial bool) (uint64, error) {
if end < start || end >= h.bits { if end < start || end >= h.bits {
return invalidPos, fmt.Errorf("invalid bit range [%d, %d]", start, end) return invalidPos, fmt.Errorf("invalid bit range [%d, %d]", start, end)
} }
if h.Unselected() == 0 { if h.Unselected() == 0 {
return invalidPos, ErrNoBitAvailable return invalidPos, ErrNoBitAvailable
} }
return h.set(0, start, end, true, false) return h.set(0, start, end, true, false, serial)
} }
// SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal // SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal
func (h *Handle) SetAny() (uint64, error) { func (h *Handle) SetAny(serial bool) (uint64, error) {
if h.Unselected() == 0 { if h.Unselected() == 0 {
return invalidPos, ErrNoBitAvailable return invalidPos, ErrNoBitAvailable
} }
return h.set(0, 0, h.bits-1, true, false) return h.set(0, 0, h.bits-1, true, false, serial)
} }
// Set atomically sets the corresponding bit in the sequence // Set atomically sets the corresponding bit in the sequence
@ -222,7 +222,7 @@ func (h *Handle) Set(ordinal uint64) error {
if err := h.validateOrdinal(ordinal); err != nil { if err := h.validateOrdinal(ordinal); err != nil {
return err return err
} }
_, err := h.set(ordinal, 0, 0, false, false) _, err := h.set(ordinal, 0, 0, false, false, false)
return err return err
} }
@ -231,7 +231,7 @@ func (h *Handle) Unset(ordinal uint64) error {
if err := h.validateOrdinal(ordinal); err != nil { if err := h.validateOrdinal(ordinal); err != nil {
return err return err
} }
_, err := h.set(ordinal, 0, 0, false, true) _, err := h.set(ordinal, 0, 0, false, true, false)
return err return err
} }
@ -300,7 +300,7 @@ func (h *Handle) CheckConsistency() error {
} }
// set/reset the bit // set/reset the bit
func (h *Handle) set(ordinal, start, end uint64, any bool, release bool) (uint64, error) { func (h *Handle) set(ordinal, start, end uint64, any bool, release bool, serial bool) (uint64, error) {
var ( var (
bitPos uint64 bitPos uint64
bytePos uint64 bytePos uint64
@ -310,6 +310,7 @@ func (h *Handle) set(ordinal, start, end uint64, any bool, release bool) (uint64
for { for {
var store datastore.DataStore var store datastore.DataStore
curr := uint64(0)
h.Lock() h.Lock()
store = h.store store = h.store
h.Unlock() h.Unlock()
@ -320,12 +321,15 @@ func (h *Handle) set(ordinal, start, end uint64, any bool, release bool) (uint64
} }
h.Lock() h.Lock()
if serial {
curr = h.curr
}
// Get position if available // Get position if available
if release { if release {
bytePos, bitPos = ordinalToPos(ordinal) bytePos, bitPos = ordinalToPos(ordinal)
} else { } else {
if any { if any {
bytePos, bitPos, err = getAvailableFromCurrent(h.head, start, h.curr, end) bytePos, bitPos, err = getAvailableFromCurrent(h.head, start, curr, end)
ret = posToOrdinal(bytePos, bitPos) ret = posToOrdinal(bytePos, bitPos)
if err == nil { if err == nil {
h.curr = ret + 1 h.curr = ret + 1
@ -517,9 +521,9 @@ func getFirstAvailable(head *sequence, start uint64) (uint64, uint64, error) {
return invalidPos, invalidPos, ErrNoBitAvailable return invalidPos, invalidPos, ErrNoBitAvailable
} }
//getAvailableFromCurrent will look for available ordinal from the current ordinal. // getAvailableFromCurrent will look for available ordinal from the current ordinal.
// If none found then it will loop back to the start to check of the available bit. // If none found then it will loop back to the start to check of the available bit.
//This can be further optimized to check from start till curr in case of a rollover // This can be further optimized to check from start till curr in case of a rollover
func getAvailableFromCurrent(head *sequence, start, curr, end uint64) (uint64, uint64, error) { func getAvailableFromCurrent(head *sequence, start, curr, end uint64) (uint64, uint64, error) {
var bytePos, bitPos uint64 var bytePos, bitPos uint64
if curr != 0 && curr > start { if curr != 0 && curr > start {

View file

@ -1,4 +1,4 @@
SetAny(false)package bitseq package bitseq
import ( import (
"fmt" "fmt"
@ -613,7 +613,7 @@ func TestSetUnset(t *testing.T) {
if _, err := hnd.SetAny(false); err != ErrNoBitAvailable { if _, err := hnd.SetAny(false); err != ErrNoBitAvailable {
t.Fatal("Expected error. Got success") t.Fatal("Expected error. Got success")
} }
if _, err := hnd.SetAnyInRange(10, 20); err != ErrNoBitAvailable { if _, err := hnd.SetAnyInRange(10, 20, false); err != ErrNoBitAvailable {
t.Fatal("Expected error. Got success") t.Fatal("Expected error. Got success")
} }
if err := hnd.Set(50); err != ErrBitAllocated { if err := hnd.Set(50); err != ErrBitAllocated {
@ -647,7 +647,7 @@ func TestOffsetSetUnset(t *testing.T) {
t.Fatal("Expected error. Got success") t.Fatal("Expected error. Got success")
} }
if _, err := hnd.SetAnyInRange(10, 20); err != ErrNoBitAvailable { if _, err := hnd.SetAnyInRange(10, 20, false); err != ErrNoBitAvailable {
t.Fatal("Expected error. Got success") t.Fatal("Expected error. Got success")
} }
@ -656,7 +656,7 @@ func TestOffsetSetUnset(t *testing.T) {
} }
//At this point sequence is (0xffffffff, 9)->(0x7fffffff, 1)->(0xffffffff, 22)->end //At this point sequence is (0xffffffff, 9)->(0x7fffffff, 1)->(0xffffffff, 22)->end
if o, err = hnd.SetAnyInRange(32, 500); err != nil { if o, err = hnd.SetAnyInRange(32, 500, false); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -675,15 +675,15 @@ func TestSetInRange(t *testing.T) {
firstAv := uint64(100*blockLen + blockLen - 1) firstAv := uint64(100*blockLen + blockLen - 1)
if o, err := hnd.SetAnyInRange(4, 3); err == nil { if o, err := hnd.SetAnyInRange(4, 3, false); err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o) t.Fatalf("Expected failure. Got success with ordinal:%d", o)
} }
if o, err := hnd.SetAnyInRange(0, numBits); err == nil { if o, err := hnd.SetAnyInRange(0, numBits, false); err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o) t.Fatalf("Expected failure. Got success with ordinal:%d", o)
} }
o, err := hnd.SetAnyInRange(100*uint64(blockLen), 101*uint64(blockLen)) o, err := hnd.SetAnyInRange(100*uint64(blockLen), 101*uint64(blockLen), false)
if err != nil { if err != nil {
t.Fatalf("Unexpected failure: (%d, %v)", o, err) t.Fatalf("Unexpected failure: (%d, %v)", o, err)
} }
@ -691,19 +691,19 @@ func TestSetInRange(t *testing.T) {
t.Fatalf("Unexpected ordinal: %d", o) t.Fatalf("Unexpected ordinal: %d", o)
} }
if o, err := hnd.SetAnyInRange(0, uint64(blockLen)); err == nil { if o, err := hnd.SetAnyInRange(0, uint64(blockLen), false); err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o) t.Fatalf("Expected failure. Got success with ordinal:%d", o)
} }
if o, err := hnd.SetAnyInRange(0, firstAv-1); err == nil { if o, err := hnd.SetAnyInRange(0, firstAv-1, false); err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o) t.Fatalf("Expected failure. Got success with ordinal:%d", o)
} }
if o, err := hnd.SetAnyInRange(111*uint64(blockLen), 161*uint64(blockLen)); err == nil { if o, err := hnd.SetAnyInRange(111*uint64(blockLen), 161*uint64(blockLen), false); err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o) t.Fatalf("Expected failure. Got success with ordinal:%d", o)
} }
o, err = hnd.SetAnyInRange(161*uint64(blockLen), 162*uint64(blockLen)) o, err = hnd.SetAnyInRange(161*uint64(blockLen), 162*uint64(blockLen), false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -711,7 +711,7 @@ func TestSetInRange(t *testing.T) {
t.Fatalf("Unexpected ordinal: %d", o) t.Fatalf("Unexpected ordinal: %d", o)
} }
o, err = hnd.SetAnyInRange(161*uint64(blockLen), 162*uint64(blockLen)) o, err = hnd.SetAnyInRange(161*uint64(blockLen), 162*uint64(blockLen), false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -719,17 +719,17 @@ func TestSetInRange(t *testing.T) {
t.Fatalf("Unexpected ordinal: %d", o) t.Fatalf("Unexpected ordinal: %d", o)
} }
o, err = hnd.SetAnyInRange(161*uint64(blockLen), 162*uint64(blockLen)) o, err = hnd.SetAnyInRange(161*uint64(blockLen), 162*uint64(blockLen), false)
if err == nil { if err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o) t.Fatalf("Expected failure. Got success with ordinal:%d", o)
} }
if _, err := hnd.SetAnyInRange(0, numBits-1); err != nil { if _, err := hnd.SetAnyInRange(0, numBits-1, false); err != nil {
t.Fatalf("Unexpected failure: %v", err) t.Fatalf("Unexpected failure: %v", err)
} }
// set one bit using the set range with 1 bit size range // set one bit using the set range with 1 bit size range
if _, err := hnd.SetAnyInRange(uint64(163*blockLen-1), uint64(163*blockLen-1)); err != nil { if _, err := hnd.SetAnyInRange(uint64(163*blockLen-1), uint64(163*blockLen-1), false); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -741,12 +741,12 @@ func TestSetInRange(t *testing.T) {
// set all bit in the first range // set all bit in the first range
for hnd.Unselected() > 22 { for hnd.Unselected() > 22 {
if o, err := hnd.SetAnyInRange(0, 7); err != nil { if o, err := hnd.SetAnyInRange(0, 7, false); err != nil {
t.Fatalf("Unexpected failure: (%d, %v)", o, err) t.Fatalf("Unexpected failure: (%d, %v)", o, err)
} }
} }
// try one more set, which should fail // try one more set, which should fail
o, err = hnd.SetAnyInRange(0, 7) o, err = hnd.SetAnyInRange(0, 7, false)
if err == nil { if err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o) t.Fatalf("Expected failure. Got success with ordinal:%d", o)
} }
@ -756,13 +756,13 @@ func TestSetInRange(t *testing.T) {
// set all bit in a second range // set all bit in a second range
for hnd.Unselected() > 14 { for hnd.Unselected() > 14 {
if o, err := hnd.SetAnyInRange(8, 15); err != nil { if o, err := hnd.SetAnyInRange(8, 15, false); err != nil {
t.Fatalf("Unexpected failure: (%d, %v)", o, err) t.Fatalf("Unexpected failure: (%d, %v)", o, err)
} }
} }
// try one more set, which should fail // try one more set, which should fail
o, err = hnd.SetAnyInRange(0, 15) o, err = hnd.SetAnyInRange(0, 15, false)
if err == nil { if err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o) t.Fatalf("Expected failure. Got success with ordinal:%d", o)
} }
@ -772,131 +772,11 @@ func TestSetInRange(t *testing.T) {
// set all bit in a range which includes the last bit // set all bit in a range which includes the last bit
for hnd.Unselected() > 12 { for hnd.Unselected() > 12 {
if o, err := hnd.SetAnyInRange(28, 29); err != nil { if o, err := hnd.SetAnyInRange(28, 29, false); err != nil {
t.Fatalf("Unexpected failure: (%d, %v)", o, err) t.Fatalf("Unexpected failure: (%d, %v)", o, err)
} }
} }
o, err = hnd.SetAnyInRange(28, 29) o, err = hnd.SetAnyInRange(28, 29, false)
if err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o)
}
if err != ErrNoBitAvailable {
t.Fatalf("Unexpected error: %v", err)
}
}
func TestSetInRangeSerial(t *testing.T) {
numBits := uint64(1024 * blockLen)
hnd, err := NewHandle("", nil, "", numBits)
if err != nil {
t.Fatal(err)
}
hnd.head = getTestSequence()
firstAv := uint64(100*blockLen + blockLen - 1)
if o, err := hnd.SetAnyInRange(4, 3); err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o)
}
if o, err := hnd.SetAnyInRange(0, numBits); err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o)
}
o, err := hnd.SetAnyInRange(100*uint64(blockLen), 101*uint64(blockLen))
if err != nil {
t.Fatalf("Unexpected failure: (%d, %v)", o, err)
}
if o != firstAv {
t.Fatalf("Unexpected ordinal: %d", o)
}
if o, err := hnd.SetAnyInRange(0, uint64(blockLen)); err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o)
}
if o, err := hnd.SetAnyInRange(0, firstAv-1); err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o)
}
if o, err := hnd.SetAnyInRange(111*uint64(blockLen), 161*uint64(blockLen)); err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o)
}
o, err = hnd.SetAnyInRange(161*uint64(blockLen), 162*uint64(blockLen))
if err != nil {
t.Fatal(err)
}
if o != 161*uint64(blockLen)+30 {
t.Fatalf("Unexpected ordinal: %d", o)
}
o, err = hnd.SetAnyInRange(161*uint64(blockLen), 162*uint64(blockLen))
if err != nil {
t.Fatal(err)
}
if o != 161*uint64(blockLen)+31 {
t.Fatalf("Unexpected ordinal: %d", o)
}
o, err = hnd.SetAnyInRange(161*uint64(blockLen), 162*uint64(blockLen))
if err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o)
}
if _, err := hnd.SetAnyInRange(0, numBits-1); err != nil {
t.Fatalf("Unexpected failure: %v", err)
}
// set one bit using the set range with 1 bit size range
if _, err := hnd.SetAnyInRange(uint64(163*blockLen-1), uint64(163*blockLen-1)); err != nil {
t.Fatal(err)
}
// create a non multiple of 32 mask
hnd, err = NewHandle("", nil, "", 30)
if err != nil {
t.Fatal(err)
}
// set all bit in the first range
for hnd.Unselected() > 22 {
if o, err := hnd.SetAnyInRange(0, 7); err != nil {
t.Fatalf("Unexpected failure: (%d, %v)", o, err)
}
}
// try one more set, which should fail
o, err = hnd.SetAnyInRange(0, 7)
if err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o)
}
if err != ErrNoBitAvailable {
t.Fatalf("Unexpected error: %v", err)
}
// set all bit in a second range
for hnd.Unselected() > 14 {
if o, err := hnd.SetAnyInRange(8, 15); err != nil {
t.Fatalf("Unexpected failure: (%d, %v)", o, err)
}
}
// try one more set, which should fail
o, err = hnd.SetAnyInRange(0, 15)
if err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o)
}
if err != ErrNoBitAvailable {
t.Fatalf("Unexpected error: %v", err)
}
// set all bit in a range which includes the last bit
for hnd.Unselected() > 12 {
if o, err := hnd.SetAnyInRange(28, 29); err != nil {
t.Fatalf("Unexpected failure: (%d, %v)", o, err)
}
}
o, err = hnd.SetAnyInRange(28, 29)
if err == nil { if err == nil {
t.Fatalf("Expected failure. Got success with ordinal:%d", o) t.Fatalf("Expected failure. Got success with ordinal:%d", o)
} }
@ -926,7 +806,7 @@ func TestSetAnyInRange(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
o, err := hnd.SetAnyInRange(128, 255) o, err := hnd.SetAnyInRange(128, 255, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -934,7 +814,7 @@ func TestSetAnyInRange(t *testing.T) {
t.Fatalf("Unexpected ordinal: %d", o) t.Fatalf("Unexpected ordinal: %d", o)
} }
o, err = hnd.SetAnyInRange(128, 255) o, err = hnd.SetAnyInRange(128, 255, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -943,7 +823,7 @@ func TestSetAnyInRange(t *testing.T) {
t.Fatalf("Unexpected ordinal: %d", o) t.Fatalf("Unexpected ordinal: %d", o)
} }
o, err = hnd.SetAnyInRange(246, 255) o, err = hnd.SetAnyInRange(246, 255, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -951,7 +831,7 @@ func TestSetAnyInRange(t *testing.T) {
t.Fatalf("Unexpected ordinal: %d", o) t.Fatalf("Unexpected ordinal: %d", o)
} }
o, err = hnd.SetAnyInRange(246, 255) o, err = hnd.SetAnyInRange(246, 255, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1131,6 +1011,7 @@ func TestAllocateRandomDeallocateSerialize(t *testing.T) {
t.Fatalf("Unexpected failure on allocation %d: %v\n%s", i, err, hnd) t.Fatalf("Unexpected failure on allocation %d: %v\n%s", i, err, hnd)
} }
} }
if hnd.Unselected() != uint64(numBits/2) { if hnd.Unselected() != uint64(numBits/2) {
t.Fatalf("Expected full sequence. Instead found %d free bits. %s", hnd.unselected, hnd) t.Fatalf("Expected full sequence. Instead found %d free bits. %s", hnd.unselected, hnd)
} }
@ -1356,3 +1237,76 @@ func TestIsCorrupted(t *testing.T) {
} }
} }
} }
func TestSetRollover(t *testing.T) {
ds, err := randomLocalStore()
if err != nil {
t.Fatal(err)
}
numBlocks := uint32(8)
numBits := int(numBlocks * blockLen)
hnd, err := NewHandle("bitseq-test/data/", ds, "test1", uint64(numBits))
if err != nil {
t.Fatal(err)
}
// Allocate first half of the bits
for i := 0; i < numBits/2; i++ {
_, err := hnd.SetAny(true)
if err != nil {
t.Fatalf("Unexpected failure on allocation %d: %v\n%s", i, err, hnd)
}
}
if hnd.Unselected() != uint64(numBits/2) {
t.Fatalf("Expected full sequence. Instead found %d free bits. %s", hnd.unselected, hnd)
}
seed := time.Now().Unix()
rand.Seed(seed)
// Deallocate half of the allocated bits following a random pattern
pattern := rand.Perm(numBits / 2)
for i := 0; i < numBits/4; i++ {
bit := pattern[i]
err := hnd.Unset(uint64(bit))
if err != nil {
t.Fatalf("Unexpected failure on deallocation of %d: %v.\nSeed: %d.\n%s", bit, err, seed, hnd)
}
}
if hnd.Unselected() != uint64(3*numBits/4) {
t.Fatalf("Expected full sequence. Instead found %d free bits.\nSeed: %d.\n%s", hnd.unselected, seed, hnd)
}
//request to allocate for remaining half of the bits
for i := 0; i < numBits/2; i++ {
_, err := hnd.SetAny(true)
if err != nil {
t.Fatalf("Unexpected failure on allocation %d: %v\nSeed: %d\n%s", i, err, seed, hnd)
}
}
//At this point all the bits must be allocated except the randomly unallocated bits
//which were unallocated in the first half of the bit sequence
if hnd.Unselected() != uint64(numBits/4) {
t.Fatalf("Unexpected number of unselected bits %d, Expected %d", hnd.Unselected(), numBits/4)
}
for i := 0; i < numBits/4; i++ {
_, err := hnd.SetAny(true)
if err != nil {
t.Fatalf("Unexpected failure on allocation %d: %v\nSeed: %d\n%s", i, err, seed, hnd)
}
}
//Now requesting to allocate the unallocated random bits (qurter of the number of bits) should
//leave no more bits that can be allocated.
if hnd.Unselected() != 0 {
t.Fatalf("Unexpected number of unselected bits %d, Expected %d", hnd.Unselected(), numBits/4)
}
err = hnd.Destroy()
if err != nil {
t.Fatal(err)
}
}

View file

@ -1058,7 +1058,7 @@ func (n *network) obtainVxlanID(s *subnet) error {
} }
if s.vni == 0 { if s.vni == 0 {
vxlanID, err := n.driver.vxlanIdm.GetID() vxlanID, err := n.driver.vxlanIdm.GetID(true)
if err != nil { if err != nil {
return fmt.Errorf("failed to allocate vxlan id: %v", err) return fmt.Errorf("failed to allocate vxlan id: %v", err)
} }

View file

@ -165,7 +165,7 @@ func (n *network) obtainVxlanID(s *subnet) error {
n.Unlock() n.Unlock()
if vni == 0 { if vni == 0 {
vni, err = n.driver.vxlanIdm.GetIDInRange(vxlanIDStart, vxlanIDEnd) vni, err = n.driver.vxlanIdm.GetIDInRange(vxlanIDStart, vxlanIDEnd, true)
if err != nil { if err != nil {
return err return err
} }

View file

@ -718,7 +718,7 @@ func (n *network) obtainVxlanID(s *subnet) error {
} }
if s.vni == 0 { if s.vni == 0 {
vxlanID, err := n.driver.vxlanIdm.GetID() vxlanID, err := n.driver.vxlanIdm.GetID(true)
if err != nil { if err != nil {
return fmt.Errorf("failed to allocate vxlan id: %v", err) return fmt.Errorf("failed to allocate vxlan id: %v", err)
} }

View file

@ -165,7 +165,7 @@ func (n *network) obtainVxlanID(s *subnet) error {
n.Unlock() n.Unlock()
if vni == 0 { if vni == 0 {
vni, err = n.driver.vxlanIdm.GetID() vni, err = n.driver.vxlanIdm.GetID(true)
if err != nil { if err != nil {
return err return err
} }

View file

@ -34,11 +34,11 @@ func New(ds datastore.DataStore, id string, start, end uint64) (*Idm, error) {
} }
// GetID returns the first available id in the set // GetID returns the first available id in the set
func (i *Idm) GetID() (uint64, error) { func (i *Idm) GetID(serial bool) (uint64, error) {
if i.handle == nil { if i.handle == nil {
return 0, errors.New("ID set is not initialized") return 0, errors.New("ID set is not initialized")
} }
ordinal, err := i.handle.SetAny() ordinal, err := i.handle.SetAny(serial)
return i.start + ordinal, err return i.start + ordinal, err
} }
@ -56,7 +56,7 @@ func (i *Idm) GetSpecificID(id uint64) error {
} }
// GetIDInRange returns the first available id in the set within a [start,end] range // GetIDInRange returns the first available id in the set within a [start,end] range
func (i *Idm) GetIDInRange(start, end uint64) (uint64, error) { func (i *Idm) GetIDInRange(start, end uint64, serial bool) (uint64, error) {
if i.handle == nil { if i.handle == nil {
return 0, errors.New("ID set is not initialized") return 0, errors.New("ID set is not initialized")
} }
@ -65,7 +65,7 @@ func (i *Idm) GetIDInRange(start, end uint64) (uint64, error) {
return 0, errors.New("Requested range does not belong to the set") return 0, errors.New("Requested range does not belong to the set")
} }
ordinal, err := i.handle.SetAnyInRange(start-i.start, end-i.start) ordinal, err := i.handle.SetAnyInRange(start-i.start, end-i.start, serial)
return i.start + ordinal, err return i.start + ordinal, err
} }

View file

@ -46,7 +46,7 @@ func TestAllocate(t *testing.T) {
t.Fatal("Expected failure but succeeded") t.Fatal("Expected failure but succeeded")
} }
o, err := i.GetID() o, err := i.GetID(false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -59,7 +59,7 @@ func TestAllocate(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
o, err = i.GetID() o, err = i.GetID(false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -67,7 +67,7 @@ func TestAllocate(t *testing.T) {
t.Fatalf("Unexpected id returned: %d", o) t.Fatalf("Unexpected id returned: %d", o)
} }
o, err = i.GetID() o, err = i.GetID(false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -75,14 +75,14 @@ func TestAllocate(t *testing.T) {
t.Fatalf("Unexpected id returned: %d", o) t.Fatalf("Unexpected id returned: %d", o)
} }
o, err = i.GetID() o, err = i.GetID(false)
if err == nil { if err == nil {
t.Fatalf("Expected failure but succeeded: %d", o) t.Fatalf("Expected failure but succeeded: %d", o)
} }
i.Release(50) i.Release(50)
o, err = i.GetID() o, err = i.GetID(false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -100,7 +100,7 @@ func TestAllocate(t *testing.T) {
func TestUninitialized(t *testing.T) { func TestUninitialized(t *testing.T) {
i := &Idm{} i := &Idm{}
if _, err := i.GetID(); err == nil { if _, err := i.GetID(false); err == nil {
t.Fatal("Expected failure but succeeded") t.Fatal("Expected failure but succeeded")
} }
@ -115,7 +115,7 @@ func TestAllocateInRange(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
o, err := i.GetIDInRange(6, 6) o, err := i.GetIDInRange(6, 6, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -127,7 +127,7 @@ func TestAllocateInRange(t *testing.T) {
t.Fatalf("Expected failure but succeeded") t.Fatalf("Expected failure but succeeded")
} }
o, err = i.GetID() o, err = i.GetID(false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -137,7 +137,7 @@ func TestAllocateInRange(t *testing.T) {
i.Release(6) i.Release(6)
o, err = i.GetID() o, err = i.GetID(false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -146,7 +146,7 @@ func TestAllocateInRange(t *testing.T) {
} }
for n := 7; n <= 10; n++ { for n := 7; n <= 10; n++ {
o, err := i.GetIDInRange(7, 10) o, err := i.GetIDInRange(7, 10, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -165,7 +165,7 @@ func TestAllocateInRange(t *testing.T) {
i.Release(10) i.Release(10)
o, err = i.GetIDInRange(5, 10) o, err = i.GetIDInRange(5, 10, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -175,7 +175,7 @@ func TestAllocateInRange(t *testing.T) {
i.Release(5) i.Release(5)
o, err = i.GetIDInRange(5, 10) o, err = i.GetIDInRange(5, 10, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -188,7 +188,7 @@ func TestAllocateInRange(t *testing.T) {
} }
for n := 5; n <= 10; n++ { for n := 5; n <= 10; n++ {
o, err := i.GetIDInRange(5, 10) o, err := i.GetIDInRange(5, 10, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -210,7 +210,7 @@ func TestAllocateInRange(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
o, err = i.GetIDInRange(4096, ul) o, err = i.GetIDInRange(4096, ul, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -218,7 +218,7 @@ func TestAllocateInRange(t *testing.T) {
t.Fatalf("Unexpected id returned. Expected: 4096. Got: %d", o) t.Fatalf("Unexpected id returned. Expected: 4096. Got: %d", o)
} }
o, err = i.GetIDInRange(4096, ul) o, err = i.GetIDInRange(4096, ul, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -226,7 +226,7 @@ func TestAllocateInRange(t *testing.T) {
t.Fatalf("Unexpected id returned. Expected: 4097. Got: %d", o) t.Fatalf("Unexpected id returned. Expected: 4097. Got: %d", o)
} }
o, err = i.GetIDInRange(4096, ul) o, err = i.GetIDInRange(4096, ul, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -234,3 +234,63 @@ func TestAllocateInRange(t *testing.T) {
t.Fatalf("Unexpected id returned. Expected: 4098. Got: %d", o) t.Fatalf("Unexpected id returned. Expected: 4098. Got: %d", o)
} }
} }
func TestAllocateSerial(t *testing.T) {
i, err := New(nil, "myids", 50, 55)
if err != nil {
t.Fatal(err)
}
if err = i.GetSpecificID(49); err == nil {
t.Fatal("Expected failure but succeeded")
}
if err = i.GetSpecificID(56); err == nil {
t.Fatal("Expected failure but succeeded")
}
o, err := i.GetID(true)
if err != nil {
t.Fatal(err)
}
if o != 50 {
t.Fatalf("Unexpected first id returned: %d", o)
}
err = i.GetSpecificID(50)
if err == nil {
t.Fatal(err)
}
o, err = i.GetID(true)
if err != nil {
t.Fatal(err)
}
if o != 51 {
t.Fatalf("Unexpected id returned: %d", o)
}
o, err = i.GetID(true)
if err != nil {
t.Fatal(err)
}
if o != 52 {
t.Fatalf("Unexpected id returned: %d", o)
}
i.Release(50)
o, err = i.GetID(true)
if err != nil {
t.Fatal(err)
}
if o != 53 {
t.Fatal("Unexpected id returned")
}
i.Release(52)
err = i.GetSpecificID(52)
if err != nil {
t.Fatal(err)
}
}

View file

@ -457,7 +457,15 @@ func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[s
return nil, nil, types.InternalErrorf("could not find bitmask in datastore for %s on address %v request from pool %s: %v", return nil, nil, types.InternalErrorf("could not find bitmask in datastore for %s on address %v request from pool %s: %v",
k.String(), prefAddress, poolID, err) k.String(), prefAddress, poolID, err)
} }
ip, err := a.getAddress(p.Pool, bm, prefAddress, p.Range) // In order to request for a serial ip address allocation, callers can pass in the option to request
// IP allocation serially or first available IP in the subnet
var serial bool
if opts != nil {
if val, ok := opts[ipamapi.AllocSerialPrefix]; ok {
serial = (val == "true")
}
}
ip, err := a.getAddress(p.Pool, bm, prefAddress, p.Range, serial)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -522,7 +530,7 @@ func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
return bm.Unset(ipToUint64(h)) return bm.Unset(ipToUint64(h))
} }
func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddress net.IP, ipr *AddressRange) (net.IP, error) { func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddress net.IP, ipr *AddressRange, serial bool) (net.IP, error) {
var ( var (
ordinal uint64 ordinal uint64
err error err error
@ -535,7 +543,7 @@ func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddres
return nil, ipamapi.ErrNoAvailableIPs return nil, ipamapi.ErrNoAvailableIPs
} }
if ipr == nil && prefAddress == nil { if ipr == nil && prefAddress == nil {
ordinal, err = bitmask.SetAny() ordinal, err = bitmask.SetAny(serial)
} else if prefAddress != nil { } else if prefAddress != nil {
hostPart, e := types.GetHostPartIP(prefAddress, base.Mask) hostPart, e := types.GetHostPartIP(prefAddress, base.Mask)
if e != nil { if e != nil {
@ -544,7 +552,7 @@ func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddres
ordinal = ipToUint64(types.GetMinimalIP(hostPart)) ordinal = ipToUint64(types.GetMinimalIP(hostPart))
err = bitmask.Set(ordinal) err = bitmask.Set(ordinal)
} else { } else {
ordinal, err = bitmask.SetAnyInRange(ipr.Start, ipr.End) ordinal, err = bitmask.SetAnyInRange(ipr.Start, ipr.End, serial)
} }
switch err { switch err {

View file

@ -1033,7 +1033,7 @@ func assertGetAddress(t *testing.T, subnet string) {
start := time.Now() start := time.Now()
run := 0 run := 0
for err != ipamapi.ErrNoAvailableIPs { for err != ipamapi.ErrNoAvailableIPs {
_, err = a.getAddress(sub, bm, nil, nil) _, err = a.getAddress(sub, bm, nil, nil, false)
run++ run++
} }
if printTime { if printTime {

View file

@ -0,0 +1,10 @@
package ipamapi
const (
// Prefix constant marks the reserved label space for libnetwork
Prefix = "com.docker.network"
// AllocSerialPrefix constant marks the reserved label space for libnetwork ipam
// allocation ordering.(serial/first available)
AllocSerialPrefix = Prefix + ".ipam.serial"
)

View file

@ -614,7 +614,7 @@ func TestIpamReleaseOnNetDriverFailures(t *testing.T) {
} }
defer ep.Delete(false) defer ep.Delete(false)
expectedIP, _ := types.ParseCIDR("10.34.0.2/16") expectedIP, _ := types.ParseCIDR("10.34.0.1/16")
if !types.CompareIPNet(ep.Info().Iface().Address(), expectedIP) { if !types.CompareIPNet(ep.Info().Iface().Address(), expectedIP) {
t.Fatalf("Ipam release must have failed, endpoint has unexpected address: %v", ep.Info().Iface().Address()) t.Fatalf("Ipam release must have failed, endpoint has unexpected address: %v", ep.Info().Iface().Address())
} }