mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
commit
1bb664f689
12 changed files with 450 additions and 72 deletions
|
@ -41,6 +41,7 @@ type Handle struct {
|
|||
id string
|
||||
dbIndex uint64
|
||||
dbExists bool
|
||||
curr uint64
|
||||
store datastore.DataStore
|
||||
sync.Mutex
|
||||
}
|
||||
|
@ -193,26 +194,27 @@ func (h *Handle) getCopy() *Handle {
|
|||
dbIndex: h.dbIndex,
|
||||
dbExists: h.dbExists,
|
||||
store: h.store,
|
||||
curr: h.curr,
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return invalidPos, fmt.Errorf("invalid bit range [%d, %d]", start, end)
|
||||
}
|
||||
if h.Unselected() == 0 {
|
||||
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
|
||||
func (h *Handle) SetAny() (uint64, error) {
|
||||
func (h *Handle) SetAny(serial bool) (uint64, error) {
|
||||
if h.Unselected() == 0 {
|
||||
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
|
||||
|
@ -220,7 +222,7 @@ func (h *Handle) Set(ordinal uint64) error {
|
|||
if err := h.validateOrdinal(ordinal); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := h.set(ordinal, 0, 0, false, false)
|
||||
_, err := h.set(ordinal, 0, 0, false, false, false)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -229,7 +231,7 @@ func (h *Handle) Unset(ordinal uint64) error {
|
|||
if err := h.validateOrdinal(ordinal); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := h.set(ordinal, 0, 0, false, true)
|
||||
_, err := h.set(ordinal, 0, 0, false, true, false)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -298,7 +300,7 @@ func (h *Handle) CheckConsistency() error {
|
|||
}
|
||||
|
||||
// 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 (
|
||||
bitPos uint64
|
||||
bytePos uint64
|
||||
|
@ -308,6 +310,7 @@ func (h *Handle) set(ordinal, start, end uint64, any bool, release bool) (uint64
|
|||
|
||||
for {
|
||||
var store datastore.DataStore
|
||||
curr := uint64(0)
|
||||
h.Lock()
|
||||
store = h.store
|
||||
h.Unlock()
|
||||
|
@ -318,15 +321,18 @@ func (h *Handle) set(ordinal, start, end uint64, any bool, release bool) (uint64
|
|||
}
|
||||
|
||||
h.Lock()
|
||||
if serial {
|
||||
curr = h.curr
|
||||
}
|
||||
// Get position if available
|
||||
if release {
|
||||
bytePos, bitPos = ordinalToPos(ordinal)
|
||||
} else {
|
||||
if any {
|
||||
bytePos, bitPos, err = getFirstAvailable(h.head, start)
|
||||
bytePos, bitPos, err = getAvailableFromCurrent(h.head, start, curr, end)
|
||||
ret = posToOrdinal(bytePos, bitPos)
|
||||
if end < ret {
|
||||
err = ErrNoBitAvailable
|
||||
if err == nil {
|
||||
h.curr = ret + 1
|
||||
}
|
||||
} else {
|
||||
bytePos, bitPos, err = checkIfAvailable(h.head, ordinal)
|
||||
|
@ -515,6 +521,29 @@ func getFirstAvailable(head *sequence, start uint64) (uint64, uint64, error) {
|
|||
return invalidPos, invalidPos, ErrNoBitAvailable
|
||||
}
|
||||
|
||||
// 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.
|
||||
// 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) {
|
||||
var bytePos, bitPos uint64
|
||||
if curr != 0 && curr > start {
|
||||
bytePos, bitPos, _ = getFirstAvailable(head, curr)
|
||||
ret := posToOrdinal(bytePos, bitPos)
|
||||
if end < ret {
|
||||
goto begin
|
||||
}
|
||||
return bytePos, bitPos, nil
|
||||
}
|
||||
|
||||
begin:
|
||||
bytePos, bitPos, _ = getFirstAvailable(head, start)
|
||||
ret := posToOrdinal(bytePos, bitPos)
|
||||
if end < ret {
|
||||
return invalidPos, invalidPos, ErrNoBitAvailable
|
||||
}
|
||||
return bytePos, bitPos, nil
|
||||
}
|
||||
|
||||
// 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 checkIfAvailable(head *sequence, ordinal uint64) (uint64, uint64, error) {
|
||||
|
|
|
@ -562,7 +562,7 @@ func TestSet(t *testing.T) {
|
|||
t.Fatal("Expected failure, but succeeded")
|
||||
}
|
||||
|
||||
os, err := hnd.SetAny()
|
||||
os, err := hnd.SetAny(false)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure: %v", err)
|
||||
}
|
||||
|
@ -606,14 +606,14 @@ func TestSetUnset(t *testing.T) {
|
|||
|
||||
// set and unset all one by one
|
||||
for hnd.Unselected() > 0 {
|
||||
if _, err := hnd.SetAny(); err != nil {
|
||||
if _, err := hnd.SetAny(false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if _, err := hnd.SetAny(); err != ErrNoBitAvailable {
|
||||
if _, err := hnd.SetAny(false); err != ErrNoBitAvailable {
|
||||
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")
|
||||
}
|
||||
if err := hnd.Set(50); err != ErrBitAllocated {
|
||||
|
@ -638,16 +638,16 @@ func TestOffsetSetUnset(t *testing.T) {
|
|||
|
||||
// set and unset all one by one
|
||||
for hnd.Unselected() > 0 {
|
||||
if _, err := hnd.SetAny(); err != nil {
|
||||
if _, err := hnd.SetAny(false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := hnd.SetAny(); err != ErrNoBitAvailable {
|
||||
if _, err := hnd.SetAny(false); err != ErrNoBitAvailable {
|
||||
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")
|
||||
}
|
||||
|
||||
|
@ -656,7 +656,7 @@ func TestOffsetSetUnset(t *testing.T) {
|
|||
}
|
||||
|
||||
//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)
|
||||
}
|
||||
|
||||
|
@ -675,15 +675,15 @@ func TestSetInRange(t *testing.T) {
|
|||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
o, err := hnd.SetAnyInRange(100*uint64(blockLen), 101*uint64(blockLen))
|
||||
o, err := hnd.SetAnyInRange(100*uint64(blockLen), 101*uint64(blockLen), false)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure: (%d, %v)", o, err)
|
||||
}
|
||||
|
@ -691,19 +691,19 @@ func TestSetInRange(t *testing.T) {
|
|||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
o, err = hnd.SetAnyInRange(161*uint64(blockLen), 162*uint64(blockLen))
|
||||
o, err = hnd.SetAnyInRange(161*uint64(blockLen), 162*uint64(blockLen), false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -711,7 +711,7 @@ func TestSetInRange(t *testing.T) {
|
|||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -719,17 +719,17 @@ func TestSetInRange(t *testing.T) {
|
|||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
|
@ -741,12 +741,12 @@ func TestSetInRange(t *testing.T) {
|
|||
|
||||
// set all bit in the first range
|
||||
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)
|
||||
}
|
||||
}
|
||||
// try one more set, which should fail
|
||||
o, err = hnd.SetAnyInRange(0, 7)
|
||||
o, err = hnd.SetAnyInRange(0, 7, false)
|
||||
if err == nil {
|
||||
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
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// try one more set, which should fail
|
||||
o, err = hnd.SetAnyInRange(0, 15)
|
||||
o, err = hnd.SetAnyInRange(0, 15, false)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected failure. Got success with ordinal:%d", o)
|
||||
}
|
||||
|
@ -772,11 +772,11 @@ func TestSetInRange(t *testing.T) {
|
|||
|
||||
// set all bit in a range which includes the last bit
|
||||
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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
@ -806,7 +806,7 @@ func TestSetAnyInRange(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
o, err := hnd.SetAnyInRange(128, 255)
|
||||
o, err := hnd.SetAnyInRange(128, 255, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -814,7 +814,7 @@ func TestSetAnyInRange(t *testing.T) {
|
|||
t.Fatalf("Unexpected ordinal: %d", o)
|
||||
}
|
||||
|
||||
o, err = hnd.SetAnyInRange(128, 255)
|
||||
o, err = hnd.SetAnyInRange(128, 255, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -823,7 +823,7 @@ func TestSetAnyInRange(t *testing.T) {
|
|||
t.Fatalf("Unexpected ordinal: %d", o)
|
||||
}
|
||||
|
||||
o, err = hnd.SetAnyInRange(246, 255)
|
||||
o, err = hnd.SetAnyInRange(246, 255, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -831,7 +831,7 @@ func TestSetAnyInRange(t *testing.T) {
|
|||
t.Fatalf("Unexpected ordinal: %d", o)
|
||||
}
|
||||
|
||||
o, err = hnd.SetAnyInRange(246, 255)
|
||||
o, err = hnd.SetAnyInRange(246, 255, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -861,7 +861,7 @@ func TestMethods(t *testing.T) {
|
|||
}
|
||||
|
||||
for i := 0; i < 192; i++ {
|
||||
_, err := hnd.SetAny()
|
||||
_, err := hnd.SetAny(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -941,7 +941,7 @@ func TestAllocateRandomDeallocate(t *testing.T) {
|
|||
|
||||
// Allocate first half of the bits
|
||||
for i := 0; i < numBits/2; i++ {
|
||||
_, err := hnd.SetAny()
|
||||
_, err := hnd.SetAny(false)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure on allocation %d: %v\n%s", i, err, hnd)
|
||||
}
|
||||
|
@ -971,7 +971,7 @@ func TestAllocateRandomDeallocate(t *testing.T) {
|
|||
|
||||
// Request a quarter of bits
|
||||
for i := 0; i < numBits/4; i++ {
|
||||
_, err := hnd.SetAny()
|
||||
_, err := hnd.SetAny(false)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure on allocation %d: %v\nSeed: %d\n%s", i, err, seed, hnd)
|
||||
}
|
||||
|
@ -989,6 +989,69 @@ func TestAllocateRandomDeallocate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAllocateRandomDeallocateSerialize(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)
|
||||
}
|
||||
|
||||
expected := &sequence{block: 0xffffffff, count: uint64(numBlocks / 2), next: &sequence{block: 0x0, count: uint64(numBlocks / 2)}}
|
||||
|
||||
// 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)
|
||||
}
|
||||
if !hnd.head.equal(expected) {
|
||||
t.Fatalf("Unexpected sequence. Got:\n%s", 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 a quarter of bits
|
||||
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)
|
||||
}
|
||||
}
|
||||
if hnd.Unselected() != uint64(numBits/2) {
|
||||
t.Fatalf("Expected half sequence. Instead found %d free bits.\nSeed: %d\n%s", hnd.unselected, seed, hnd)
|
||||
}
|
||||
|
||||
err = hnd.Destroy()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveFromStore(t *testing.T) {
|
||||
ds, err := randomLocalStore()
|
||||
if err != nil {
|
||||
|
@ -1003,7 +1066,7 @@ func TestRetrieveFromStore(t *testing.T) {
|
|||
|
||||
// Allocate first half of the bits
|
||||
for i := 0; i < numBits/2; i++ {
|
||||
_, err := hnd.SetAny()
|
||||
_, err := hnd.SetAny(false)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure on allocation %d: %v\n%s", i, err, hnd)
|
||||
}
|
||||
|
@ -1174,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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@ func (h *Handle) CopyTo(o datastore.KVObject) error {
|
|||
dstH.dbIndex = h.dbIndex
|
||||
dstH.dbExists = h.dbExists
|
||||
dstH.store = h.store
|
||||
dstH.curr = h.curr
|
||||
dstH.Unlock()
|
||||
|
||||
return nil
|
||||
|
|
|
@ -1035,7 +1035,7 @@ func (n *network) obtainVxlanID(s *subnet) error {
|
|||
}
|
||||
|
||||
if s.vni == 0 {
|
||||
vxlanID, err := n.driver.vxlanIdm.GetID()
|
||||
vxlanID, err := n.driver.vxlanIdm.GetID(true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to allocate vxlan id: %v", err)
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ func (n *network) obtainVxlanID(s *subnet) error {
|
|||
n.Unlock()
|
||||
|
||||
if vni == 0 {
|
||||
vni, err = n.driver.vxlanIdm.GetIDInRange(vxlanIDStart, vxlanIDEnd)
|
||||
vni, err = n.driver.vxlanIdm.GetIDInRange(vxlanIDStart, vxlanIDEnd, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -718,7 +718,7 @@ func (n *network) obtainVxlanID(s *subnet) error {
|
|||
}
|
||||
|
||||
if s.vni == 0 {
|
||||
vxlanID, err := n.driver.vxlanIdm.GetID()
|
||||
vxlanID, err := n.driver.vxlanIdm.GetID(true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to allocate vxlan id: %v", err)
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ func (n *network) obtainVxlanID(s *subnet) error {
|
|||
n.Unlock()
|
||||
|
||||
if vni == 0 {
|
||||
vni, err = n.driver.vxlanIdm.GetID()
|
||||
vni, err = n.driver.vxlanIdm.GetID(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -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
|
||||
func (i *Idm) GetID() (uint64, error) {
|
||||
func (i *Idm) GetID(serial bool) (uint64, error) {
|
||||
if i.handle == nil {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
func (i *Idm) GetIDInRange(start, end uint64) (uint64, error) {
|
||||
func (i *Idm) GetIDInRange(start, end uint64, serial bool) (uint64, error) {
|
||||
if i.handle == nil {
|
||||
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")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ func TestAllocate(t *testing.T) {
|
|||
t.Fatal("Expected failure but succeeded")
|
||||
}
|
||||
|
||||
o, err := i.GetID()
|
||||
o, err := i.GetID(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ func TestAllocate(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
o, err = i.GetID()
|
||||
o, err = i.GetID(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ func TestAllocate(t *testing.T) {
|
|||
t.Fatalf("Unexpected id returned: %d", o)
|
||||
}
|
||||
|
||||
o, err = i.GetID()
|
||||
o, err = i.GetID(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -75,14 +75,14 @@ func TestAllocate(t *testing.T) {
|
|||
t.Fatalf("Unexpected id returned: %d", o)
|
||||
}
|
||||
|
||||
o, err = i.GetID()
|
||||
o, err = i.GetID(false)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected failure but succeeded: %d", o)
|
||||
}
|
||||
|
||||
i.Release(50)
|
||||
|
||||
o, err = i.GetID()
|
||||
o, err = i.GetID(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ func TestAllocate(t *testing.T) {
|
|||
func TestUninitialized(t *testing.T) {
|
||||
i := &Idm{}
|
||||
|
||||
if _, err := i.GetID(); err == nil {
|
||||
if _, err := i.GetID(false); err == nil {
|
||||
t.Fatal("Expected failure but succeeded")
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ func TestAllocateInRange(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
o, err := i.GetIDInRange(6, 6)
|
||||
o, err := i.GetIDInRange(6, 6, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ func TestAllocateInRange(t *testing.T) {
|
|||
t.Fatalf("Expected failure but succeeded")
|
||||
}
|
||||
|
||||
o, err = i.GetID()
|
||||
o, err = i.GetID(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ func TestAllocateInRange(t *testing.T) {
|
|||
|
||||
i.Release(6)
|
||||
|
||||
o, err = i.GetID()
|
||||
o, err = i.GetID(false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ func TestAllocateInRange(t *testing.T) {
|
|||
}
|
||||
|
||||
for n := 7; n <= 10; n++ {
|
||||
o, err := i.GetIDInRange(7, 10)
|
||||
o, err := i.GetIDInRange(7, 10, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ func TestAllocateInRange(t *testing.T) {
|
|||
|
||||
i.Release(10)
|
||||
|
||||
o, err = i.GetIDInRange(5, 10)
|
||||
o, err = i.GetIDInRange(5, 10, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ func TestAllocateInRange(t *testing.T) {
|
|||
|
||||
i.Release(5)
|
||||
|
||||
o, err = i.GetIDInRange(5, 10)
|
||||
o, err = i.GetIDInRange(5, 10, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ func TestAllocateInRange(t *testing.T) {
|
|||
}
|
||||
|
||||
for n := 5; n <= 10; n++ {
|
||||
o, err := i.GetIDInRange(5, 10)
|
||||
o, err := i.GetIDInRange(5, 10, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ func TestAllocateInRange(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
o, err = i.GetIDInRange(4096, ul)
|
||||
o, err = i.GetIDInRange(4096, ul, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ func TestAllocateInRange(t *testing.T) {
|
|||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ func TestAllocateInRange(t *testing.T) {
|
|||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -234,3 +234,63 @@ func TestAllocateInRange(t *testing.T) {
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
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 {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -522,7 +530,7 @@ func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
|
|||
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 (
|
||||
ordinal uint64
|
||||
err error
|
||||
|
@ -535,7 +543,7 @@ func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddres
|
|||
return nil, ipamapi.ErrNoAvailableIPs
|
||||
}
|
||||
if ipr == nil && prefAddress == nil {
|
||||
ordinal, err = bitmask.SetAny()
|
||||
ordinal, err = bitmask.SetAny(serial)
|
||||
} else if prefAddress != nil {
|
||||
hostPart, e := types.GetHostPartIP(prefAddress, base.Mask)
|
||||
if e != nil {
|
||||
|
@ -544,7 +552,7 @@ func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddres
|
|||
ordinal = ipToUint64(types.GetMinimalIP(hostPart))
|
||||
err = bitmask.Set(ordinal)
|
||||
} else {
|
||||
ordinal, err = bitmask.SetAnyInRange(ipr.Start, ipr.End)
|
||||
ordinal, err = bitmask.SetAnyInRange(ipr.Start, ipr.End, serial)
|
||||
}
|
||||
|
||||
switch err {
|
||||
|
|
|
@ -644,6 +644,7 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
unoExp, _ := types.ParseCIDR("10.2.2.0/16")
|
||||
dueExp, _ := types.ParseCIDR("10.2.2.2/16")
|
||||
treExp, _ := types.ParseCIDR("10.2.2.1/16")
|
||||
|
||||
if poolID, _, _, err = a.RequestPool("rosso", "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -694,6 +695,139 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) {
|
||||
opts := map[string]string{
|
||||
ipamapi.AllocSerialPrefix: "true"}
|
||||
a, err := getAllocator()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
a.addrSpaces["rosso"] = &addrSpace{
|
||||
id: dsConfigKey + "/" + "rosso",
|
||||
ds: a.addrSpaces[localAddressSpace].ds,
|
||||
alloc: a.addrSpaces[localAddressSpace].alloc,
|
||||
scope: a.addrSpaces[localAddressSpace].scope,
|
||||
subnets: map[SubnetKey]*PoolData{},
|
||||
}
|
||||
|
||||
poolID, _, _, err := a.RequestPool("rosso", "172.28.0.0/16", "172.28.30.0/24", nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var ip *net.IPNet
|
||||
expected := &net.IPNet{IP: net.IP{172, 28, 30, 255}, Mask: net.IPMask{255, 255, 0, 0}}
|
||||
for err == nil {
|
||||
var c *net.IPNet
|
||||
if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil {
|
||||
ip = c
|
||||
}
|
||||
}
|
||||
if err != ipamapi.ErrNoAvailableIPs {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(expected, ip) {
|
||||
t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
|
||||
}
|
||||
rp := &net.IPNet{IP: net.IP{172, 28, 30, 97}, Mask: net.IPMask{255, 255, 0, 0}}
|
||||
if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(rp, ip) {
|
||||
t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
|
||||
}
|
||||
|
||||
_, _, _, err = a.RequestPool("rosso", "10.0.0.0/8", "10.0.0.0/16", nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
poolID, _, _, err = a.RequestPool("rosso", "10.0.0.0/16", "10.0.0.0/24", nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected = &net.IPNet{IP: net.IP{10, 0, 0, 255}, Mask: net.IPMask{255, 255, 0, 0}}
|
||||
for err == nil {
|
||||
var c *net.IPNet
|
||||
if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil {
|
||||
ip = c
|
||||
}
|
||||
}
|
||||
if err != ipamapi.ErrNoAvailableIPs {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(expected, ip) {
|
||||
t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
|
||||
}
|
||||
rp = &net.IPNet{IP: net.IP{10, 0, 0, 79}, Mask: net.IPMask{255, 255, 0, 0}}
|
||||
if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(rp, ip) {
|
||||
t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
|
||||
}
|
||||
|
||||
// Request any addresses from subpool after explicit address request
|
||||
unoExp, _ := types.ParseCIDR("10.2.2.0/16")
|
||||
dueExp, _ := types.ParseCIDR("10.2.2.2/16")
|
||||
treExp, _ := types.ParseCIDR("10.2.2.1/16")
|
||||
quaExp, _ := types.ParseCIDR("10.2.2.3/16")
|
||||
fivExp, _ := types.ParseCIDR("10.2.2.4/16")
|
||||
if poolID, _, _, err = a.RequestPool("rosso", "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tre, _, err := a.RequestAddress(poolID, treExp.IP, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(tre, treExp) {
|
||||
t.Fatalf("Unexpected address: %v", tre)
|
||||
}
|
||||
|
||||
uno, _, err := a.RequestAddress(poolID, nil, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(uno, unoExp) {
|
||||
t.Fatalf("Unexpected address: %v", uno)
|
||||
}
|
||||
|
||||
due, _, err := a.RequestAddress(poolID, nil, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(due, dueExp) {
|
||||
t.Fatalf("Unexpected address: %v", due)
|
||||
}
|
||||
|
||||
if err = a.ReleaseAddress(poolID, uno.IP); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
uno, _, err = a.RequestAddress(poolID, nil, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(uno, quaExp) {
|
||||
t.Fatalf("Unexpected address: %v", uno)
|
||||
}
|
||||
|
||||
if err = a.ReleaseAddress(poolID, tre.IP); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tre, _, err = a.RequestAddress(poolID, nil, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !types.CompareIPNet(tre, fivExp) {
|
||||
t.Fatalf("Unexpected address: %v", tre)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAddress(t *testing.T) {
|
||||
input := []string{
|
||||
/*"10.0.0.0/8", "10.0.0.0/9", "10.0.0.0/10",*/ "10.0.0.0/11", "10.0.0.0/12", "10.0.0.0/13", "10.0.0.0/14",
|
||||
|
@ -899,7 +1033,7 @@ func assertGetAddress(t *testing.T, subnet string) {
|
|||
start := time.Now()
|
||||
run := 0
|
||||
for err != ipamapi.ErrNoAvailableIPs {
|
||||
_, err = a.getAddress(sub, bm, nil, nil)
|
||||
_, err = a.getAddress(sub, bm, nil, nil, false)
|
||||
run++
|
||||
}
|
||||
if printTime {
|
||||
|
|
10
libnetwork/ipamapi/labels.go
Normal file
10
libnetwork/ipamapi/labels.go
Normal 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"
|
||||
)
|
Loading…
Add table
Reference in a new issue