func TestDonateSimple(t *testing.T) { const ( testAddr1 = "10.0.1.0" testAddr2 = "10.0.1.32" size = 64 ) var ( ipAddr1 = ip(testAddr1) ) ps1 := makeSpace(ipAddr1, size) // Empty space set should split in two and give me the second half r, ok := ps1.Donate(address.NewRange(ip(testAddr1), size)) numGivenUp := r.Size() require.True(t, ok, "Donate result") require.Equal(t, "10.0.1.32", r.Start.String(), "Invalid start") require.Equal(t, address.Count(size/2), numGivenUp) require.Equal(t, address.Count(size/2), ps1.NumFreeAddresses()) // Now check we can give the rest up. count := 0 // count to avoid infinite loop for ; count < 1000; count++ { r, ok := ps1.Donate(address.NewRange(ip(testAddr1), size)) if !ok { break } numGivenUp += r.Size() } require.Equal(t, address.Count(0), ps1.NumFreeAddresses()) require.Equal(t, address.Count(size), numGivenUp) }
func TestDonateHard(t *testing.T) { //common.InitDefaultLogging(true) var ( start = ip("10.0.1.0") size address.Offset = 48 ) // Fill a fresh space spaceset := makeSpace(start, size) for i := address.Offset(0); i < size; i++ { ok, _ := spaceset.Allocate(address.NewRange(start, size)) require.True(t, ok, "Failed to get IP!") } require.Equal(t, address.Count(0), spaceset.NumFreeAddresses()) // Now free all but the last address // this will force us to split the free list for i := address.Offset(0); i < size-1; i++ { require.NoError(t, spaceset.Free(address.Add(start, i))) } // Now split newRange, ok := spaceset.Donate(address.NewRange(start, size)) require.True(t, ok, "GiveUpSpace result") require.Equal(t, address.NewRange(ip("10.0.1.16"), 16), newRange, "Wrong space") require.Equal(t, address.Count(31), spaceset.NumFreeAddresses()) //Space set should now have 3 spaces expected := &Space{ ours: add(nil, ip("10.0.1.47"), ip("10.0.1.48")), free: add(add(nil, ip("10.0.1.0"), ip("10.0.1.16")), ip("10.0.1.32"), ip("10.0.1.47")), } require.Equal(t, expected, spaceset) }
func TestSpaceFree(t *testing.T) { const ( testAddr1 = "10.0.3.16" testAddrx = "10.0.3.19" testAddry = "10.0.9.19" containerID = "deadbeef" size = 16 ) entireRange := address.NewRange(ip(testAddr1), size) space := makeSpace(ip(testAddr1), size) // Check we are prepared to give up the entire space r := space.biggestFreeRange(entireRange) require.Equal(t, address.NewRange(ip(testAddr1), size), r, "Wrong space") for i := 0; i < size; i++ { ok, _ := space.Allocate(entireRange) require.True(t, ok, "Failed to get address") } // Check we are full ok, _ := space.Allocate(entireRange) require.True(t, !ok, "Should have failed to get address") r, _ = space.Donate(entireRange) require.True(t, r.Size() == 0, "Wrong space") // Free in the middle require.NoError(t, space.Free(ip("10.0.3.23"))) r = space.biggestFreeRange(entireRange) require.True(t, r.Start == ip("10.0.3.23") && r.Size() == 1, "Wrong space") // Free one at the end require.NoError(t, space.Free(ip("10.0.3.31"))) r = space.biggestFreeRange(entireRange) require.True(t, r.Start == ip("10.0.3.31") && r.Size() == 1, "Wrong space") // Now free a few at the end require.NoError(t, space.Free(ip("10.0.3.30"))) require.NoError(t, space.Free(ip("10.0.3.29"))) require.Equal(t, address.Count(4), space.NumFreeAddresses()) // Now get the biggest free space; should be 3.30 r = space.biggestFreeRange(entireRange) require.Equal(t, address.NewRange(ip("10.0.3.30"), 2), r, "Wrong space") // Now free a few in the middle require.NoError(t, space.Free(ip("10.0.3.24"))) require.NoError(t, space.Free(ip("10.0.3.22"))) require.NoError(t, space.Free(ip("10.0.3.21"))) require.Equal(t, address.Count(7), space.NumFreeAddresses()) // Now get the biggest free space; should be 3.30 r = space.biggestFreeRange(entireRange) require.Equal(t, address.NewRange(ip("10.0.3.30"), 2), r, "Wrong space") require.Equal(t, []address.Range{{Start: ip("10.0.3.16"), End: ip("10.0.3.32")}}, space.OwnedRanges()) }
// AdminTakeoverRanges (Sync) - take over the ranges owned by a given // peer, and return how much space was transferred in the process. // Only done on administrator command. func (alloc *Allocator) AdminTakeoverRanges(peerNameOrNickname string) address.Count { resultChan := make(chan address.Count) alloc.actionChan <- func() { peername, err := alloc.lookupPeername(peerNameOrNickname) if err != nil { alloc.warnf("attempt to take over range from unknown peer '%s'", peerNameOrNickname) resultChan <- address.Count(0) return } alloc.debugln("AdminTakeoverRanges:", peername) if peername == alloc.ourName { alloc.warnf("attempt to take over range from ourself") resultChan <- address.Count(0) return } newRanges := alloc.ring.Transfer(peername, alloc.ourName) if len(newRanges) == 0 { resultChan <- address.Count(0) return } before := alloc.space.NumFreeAddresses() alloc.ringUpdated() after := alloc.space.NumFreeAddresses() alloc.gossip.GossipBroadcast(alloc.Gossip()) resultChan <- after - before } return <-resultChan }
// Returns the distance between two tokens on this ring, dealing // with ranges which cross the origin func (r *Ring) distance(start, end address.Address) address.Count { if end > start { return address.Count(end - start) } return address.Count((r.End - start) + (end - r.Start)) }
func TestSpaceAllocate(t *testing.T) { const ( testAddr1 = "10.0.3.4" testAddr2 = "10.0.3.5" testAddrx = "10.0.3.19" testAddry = "10.0.9.19" containerID = "deadbeef" size = 20 ) var ( start = ip(testAddr1) ) space1 := makeSpace(start, size) require.Equal(t, address.Count(20), space1.NumFreeAddresses()) space1.assertInvariants() _, addr1 := space1.Allocate(address.NewRange(start, size)) require.Equal(t, testAddr1, addr1.String(), "address") require.Equal(t, address.Count(19), space1.NumFreeAddresses()) space1.assertInvariants() _, addr2 := space1.Allocate(address.NewRange(start, size)) require.False(t, addr2.String() == testAddr1, "address") require.Equal(t, address.Count(18), space1.NumFreeAddresses()) require.Equal(t, address.Count(13), space1.NumFreeAddressesInRange(address.Range{Start: ip(testAddr1), End: ip(testAddrx)})) require.Equal(t, address.Count(18), space1.NumFreeAddressesInRange(address.Range{Start: ip(testAddr1), End: ip(testAddry)})) space1.assertInvariants() space1.Free(addr2) space1.assertInvariants() wt.AssertErrorInterface(t, (*error)(nil), space1.Free(addr2), "double free") wt.AssertErrorInterface(t, (*error)(nil), space1.Free(ip(testAddrx)), "address not allocated") wt.AssertErrorInterface(t, (*error)(nil), space1.Free(ip(testAddry)), "wrong out of range") space1.assertInvariants() }
// ReportFree is used by the allocator to tell the ring how many free // ips are in a given range, so that ChoosePeersToAskForSpace can make // more intelligent decisions. Returns true if any changes made. func (r *Ring) ReportFree(freespace map[address.Address]address.Count) (updated bool) { r.assertInvariants() defer r.assertInvariants() defer r.updateExportedVariables() common.Assert(!r.Empty()) entries := r.Entries // As OwnedRanges splits around the origin, we need to // detect that here and fix up freespace if free, found := freespace[r.Start]; found && entries.entry(0).Token != r.Start { lastToken := entries.entry(-1).Token prevFree, found := freespace[lastToken] common.Assert(found) freespace[lastToken] = prevFree + free delete(freespace, r.Start) } for start, free := range freespace { // Look for entry i := sort.Search(len(entries), func(j int) bool { return entries[j].Token >= start }) // Are you trying to report free on space I don't own? common.Assert(i < len(entries) && entries[i].Token == start && entries[i].Peer == r.Peer) // Check we're not reporting more space than the range entry, next := entries.entry(i), entries.entry(i+1) maxSize := r.distance(entry.Token, next.Token) common.Assert(free <= address.Count(maxSize)) if entries[i].Free == free { continue } entries[i].Free = free entries[i].Version++ updated = true } return }
func TestTransfer(t *testing.T) { const cidr = "10.0.4.0/22" allocs, router, subnet := makeNetworkOfAllocators(3, cidr) defer stopNetworkOfAllocators(allocs, router) alloc0 := allocs[0] alloc1 := allocs[1] alloc2 := allocs[2] _, err := alloc1.Allocate("foo", subnet, true, returnFalse) require.True(t, err == nil, "Failed to get address") _, err = alloc2.Allocate("bar", subnet, true, returnFalse) require.True(t, err == nil, "Failed to get address") // simulation of periodic gossip alloc2.gossip.GossipBroadcast(alloc2.Gossip()) router.Flush() alloc1.gossip.GossipBroadcast(alloc1.Gossip()) router.Flush() free1 := alloc1.NumFreeAddresses(subnet.Range()) free2 := alloc2.NumFreeAddresses(subnet.Range()) router.RemovePeer(alloc1.ourName) router.RemovePeer(alloc2.ourName) alloc1.Stop() alloc2.Stop() router.Flush() require.Equal(t, free1+1, alloc0.AdminTakeoverRanges(alloc1.ourName.String())) require.Equal(t, free2+1, alloc0.AdminTakeoverRanges(alloc2.ourName.String())) router.Flush() require.Equal(t, address.Count(1024), alloc0.NumFreeAddresses(subnet.Range())) _, err = alloc0.Allocate("foo", subnet, true, returnFalse) require.True(t, err == nil, "Failed to get address") alloc0.Stop() }
func TestAllocFree(t *testing.T) { const ( container1 = "abcdef" container2 = "baddf00d" container3 = "b01df00d" universe = "10.0.3.0/26" subnet1 = "10.0.3.0/28" subnet2 = "10.0.3.32/28" testAddr1 = "10.0.3.1" testAddr2 = "10.0.3.33" spaceSize = 62 // 64 IP addresses in /26, minus .0 and .63 ) alloc, subnet := makeAllocatorWithMockGossip(t, "01:00:00:01:00:00", universe, 1) defer alloc.Stop() cidr1, _ := address.ParseCIDR(subnet1) cidr2, _ := address.ParseCIDR(subnet2) alloc.claimRingForTesting() addr1, err := alloc.SimplyAllocate(container1, cidr1) require.NoError(t, err) require.Equal(t, testAddr1, addr1.String(), "address") addr2, err := alloc.SimplyAllocate(container1, cidr2) require.NoError(t, err) require.Equal(t, testAddr2, addr2.String(), "address") addrs, err := alloc.Lookup(container1, subnet.Range()) require.NoError(t, err) require.Equal(t, []address.CIDR{address.MakeCIDR(cidr1, addr1), address.MakeCIDR(cidr2, addr2)}, addrs) // Ask for another address for a different container and check it's different addr1b, _ := alloc.SimplyAllocate(container2, cidr1) if addr1b.String() == testAddr1 { t.Fatalf("Expected different address but got %s", addr1b.String()) } // Ask for the first container again and we should get the same addresses again addr1a, _ := alloc.SimplyAllocate(container1, cidr1) require.Equal(t, testAddr1, addr1a.String(), "address") addr2a, _ := alloc.SimplyAllocate(container1, cidr2) require.Equal(t, testAddr2, addr2a.String(), "address") // Now delete the first container, and we should get its addresses back require.NoError(t, alloc.Delete(container1)) addr3, _ := alloc.SimplyAllocate(container3, cidr1) require.Equal(t, testAddr1, addr3.String(), "address") addr4, _ := alloc.SimplyAllocate(container3, cidr2) require.Equal(t, testAddr2, addr4.String(), "address") alloc.ContainerDied(container2) // Resurrect addr1c, err := alloc.SimplyAllocate(container2, cidr1) require.NoError(t, err) require.Equal(t, addr1b, addr1c, "address") alloc.ContainerDied(container3) alloc.Encode() // sync up // Move the clock forward and clear out the dead container alloc.actionChan <- func() { alloc.now = func() time.Time { return time.Now().Add(containerDiedTimeout * 2) } } alloc.actionChan <- func() { alloc.removeDeadContainers() } require.Equal(t, address.Count(spaceSize+1), alloc.NumFreeAddresses(subnet.Range())) }
func TestLowlevel(t *testing.T) { a := []address.Address{} a = add(a, 100, 200) require.Equal(t, []address.Address{100, 200}, a) require.True(t, !contains(a, 99), "") require.True(t, contains(a, 100), "") require.True(t, contains(a, 199), "") require.True(t, !contains(a, 200), "") a = add(a, 700, 800) require.Equal(t, []address.Address{100, 200, 700, 800}, a) a = add(a, 300, 400) require.Equal(t, []address.Address{100, 200, 300, 400, 700, 800}, a) a = add(a, 400, 500) require.Equal(t, []address.Address{100, 200, 300, 500, 700, 800}, a) a = add(a, 600, 700) require.Equal(t, []address.Address{100, 200, 300, 500, 600, 800}, a) a = add(a, 500, 600) require.Equal(t, []address.Address{100, 200, 300, 800}, a) a = subtract(a, 500, 600) require.Equal(t, []address.Address{100, 200, 300, 500, 600, 800}, a) a = subtract(a, 600, 700) require.Equal(t, []address.Address{100, 200, 300, 500, 700, 800}, a) a = subtract(a, 400, 500) require.Equal(t, []address.Address{100, 200, 300, 400, 700, 800}, a) a = subtract(a, 300, 400) require.Equal(t, []address.Address{100, 200, 700, 800}, a) a = subtract(a, 700, 800) require.Equal(t, []address.Address{100, 200}, a) a = subtract(a, 100, 200) require.Equal(t, []address.Address{}, a) s := New() require.Equal(t, address.Count(0), s.NumFreeAddresses()) ok, got := s.Allocate(address.NewRange(0, 1000)) require.False(t, ok, "allocate in empty space should fail") s.Add(100, 100) require.Equal(t, address.Count(100), s.NumFreeAddresses()) ok, got = s.Allocate(address.NewRange(0, 1000)) require.True(t, ok && got == 100, "allocate") require.Equal(t, address.Count(99), s.NumFreeAddresses()) require.NoError(t, s.Claim(150)) require.Equal(t, address.Count(98), s.NumFreeAddresses()) require.NoError(t, s.Free(100)) require.Equal(t, address.Count(99), s.NumFreeAddresses()) wt.AssertErrorInterface(t, (*error)(nil), s.Free(0), "free not allocated") wt.AssertErrorInterface(t, (*error)(nil), s.Free(100), "double free") r, ok := s.Donate(address.NewRange(0, 1000)) require.Equal(t, address.NewRange(0xa0, 0x20), r, "donate") // test Donate when addresses are scarce s = New() r, ok = s.Donate(address.NewRange(0, 1000)) require.True(t, !ok, "donate on empty space should fail") s.Add(0, 3) require.NoError(t, s.Claim(0)) require.NoError(t, s.Claim(2)) r, ok = s.Donate(address.NewRange(0, 1000)) require.Equal(t, address.NewRange(1, 1), r, "donate") r, ok = s.Donate(address.NewRange(0, 1000)) require.True(t, !ok, "donate should fail") }