// ClaimForPeers claims the entire ring for the array of peers passed // in. Only works for empty rings. func (r *Ring) ClaimForPeers(peers []mesh.PeerName) { common.Assert(r.Empty()) defer r.assertInvariants() defer r.updateExportedVariables() totalSize := r.distance(r.Start, r.End) share := totalSize/address.Offset(len(peers)) + 1 remainder := totalSize % address.Offset(len(peers)) pos := r.Start for i, peer := range peers { if address.Offset(i) == remainder { share-- if share == 0 { break } } if e, found := r.Entries.get(pos); found { e.update(peer, share) } else { r.Entries.insert(entry{Token: pos, Peer: peer, Free: share}) } pos += address.Address(share) } common.Assert(pos == r.End) r.Seeds = peers }
// ClaimForPeers claims the entire ring for the array of peers passed // in. Only works for empty rings. Each claimed range is CIDR-aligned. func (r *Ring) ClaimForPeers(peers []mesh.PeerName) { common.Assert(r.Empty()) defer r.trackUpdates()() defer r.assertInvariants() defer r.updateExportedVariables() defer func() { e := r.Entries[len(r.Entries)-1] common.Assert(address.Add(e.Token, address.Offset(e.Free)) == r.End) }() r.subdivide(r.Start, r.End, peers) r.Seeds = peers }
func (alloc *Allocator) assertInvariants() { // We need to ensure all ranges the ring thinks we own have // a corresponding space in the space set, and vice versa checkSpace := space.New() checkSpace.AddRanges(alloc.ring.OwnedRanges()) ranges := checkSpace.OwnedRanges() spaces := alloc.space.OwnedRanges() common.Assert(len(ranges) == len(spaces)) for i := 0; i < len(ranges); i++ { r := ranges[i] s := spaces[i] common.Assert(s.Start == r.Start && s.End == r.End) } }
// New creates an empty ring belonging to peer. func New(start, end address.Address, peer mesh.PeerName) *Ring { common.Assert(start < end) ring := &Ring{Start: start, End: end, Peer: peer, Entries: make([]*entry, 0)} ring.updateExportedVariables() return ring }
// 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 }
// Owner returns the peername which owns the range containing addr func (r *Ring) Owner(token address.Address) mesh.PeerName { common.Assert(r.Start <= token && token < r.End) r.assertInvariants() // There can be no owners on an empty ring if r.Empty() { return mesh.UnknownPeerName } // Look for the right-most entry, less than or equal to token preceedingEntry := sort.Search(len(r.Entries), func(j int) bool { return r.Entries[j].Token > token }) preceedingEntry-- entry := r.Entries.entry(preceedingEntry) return entry.Peer }
func (alloc *Allocator) donateSpace(r address.Range, to router.PeerName) { // No matter what we do, we'll send a unicast gossip // of our ring back to tha chap who asked for space. // This serves to both tell him of any space we might // have given him, or tell him where he might find some // more. defer alloc.sendRingUpdate(to) alloc.debugln("Peer", to, "asked me for space") chunk, ok := alloc.space.Donate(r) if !ok { free := alloc.space.NumFreeAddressesInRange(r) common.Assert(free == 0) alloc.debugln("No space to give to peer", to) return } alloc.debugln("Giving range", chunk, "to", to) alloc.ring.GrantRangeToHost(chunk.Start, chunk.End, to) }
func (alloc *Allocator) donateSpace(r address.Range, to mesh.PeerName) { // No matter what we do, we'll send a unicast gossip // of our ring back to the chap who asked for space. // This serves to both tell him of any space we might // have given him, or tell him where he might find some // more. defer alloc.sendRingUpdate(to) alloc.debugln("Peer", to, "asked me for space") chunk, ok := alloc.space.Donate(r) if !ok { free := alloc.space.NumFreeAddressesInRange(r) common.Assert(free == 0) alloc.debugln("No space to give to peer", to) // separate message maintains backwards-compatibility: // down-level peers will ignore this and still get the ring update. alloc.sendSpaceRequestDenied(to, r) return } alloc.debugln("Giving range", chunk, "to", to) alloc.ring.GrantRangeToHost(chunk.Start, chunk.End, to) }
// Is token between entries at i and j? // NB i and j can overflow and will wrap // NBB this function does not work very well if there is only one // token on the ring; luckily an accurate answer is not needed // by the call sites in this case. func (es entries) between(token address.Address, i, j int) bool { common.Assert(i < j) first := es.entry(i) second := es.entry(j) switch { case first.Token == second.Token: // This implies there is only one token // on the ring (i < j and i.token == j.token) // In which case everything is between, expect // this one token return token != first.Token case first.Token < second.Token: return first.Token <= token && token < second.Token case second.Token < first.Token: return first.Token <= token || token < second.Token } panic("Should never get here - switch covers all possibilities.") }
// GrantRangeToHost modifies the ring such that range [start, end) // is assigned to peer. This may insert up to two new tokens. // Preconditions: // - start < end // - [start, end) must be owned by the calling peer func (r *Ring) GrantRangeToHost(start, end address.Address, peer mesh.PeerName) { //fmt.Printf("%s GrantRangeToHost [%v,%v) -> %s\n", r.Peer, start, end, peer) r.assertInvariants() defer r.assertInvariants() defer r.updateExportedVariables() // ----------------- Start of Checks ----------------- common.Assert(start < end) common.Assert(r.Start <= start && start < r.End) common.Assert(r.Start < end && end <= r.End) common.Assert(len(r.Entries) > 0) // Look for the left-most entry greater than start, then go one previous // to get the right-most entry less than or equal to start preceedingPos := sort.Search(len(r.Entries), func(j int) bool { return r.Entries[j].Token > start }) preceedingPos-- // Check all tokens up to end are owned by us for pos := preceedingPos; pos < len(r.Entries) && r.Entries.entry(pos).Token < end; pos++ { common.Assert(r.Entries.entry(pos).Peer == r.Peer) } // ----------------- End of Checks ----------------- // Free space at start is max(length of range, distance to next token) startFree := r.distance(start, r.Entries.entry(preceedingPos+1).Token) if length := r.distance(start, end); startFree > length { startFree = length } // Is there already a token at start, update it if previousEntry := r.Entries.entry(preceedingPos); previousEntry.Token == start { previousEntry.update(peer, startFree) } else { // Otherwise, these isn't a token here, insert a new one. r.Entries.insert(entry{Token: start, Peer: peer, Free: startFree}) preceedingPos++ // Reset free space on previous entry, which we own. previousEntry.update(r.Peer, r.distance(previousEntry.Token, start)) } // Give all intervening tokens to the other peer pos := preceedingPos + 1 for ; pos < len(r.Entries) && r.Entries.entry(pos).Token < end; pos++ { entry := r.Entries.entry(pos) entry.update(peer, address.Min(entry.Free, r.distance(entry.Token, end))) } // There is never an entry with a token of r.End, as the end of // the ring is exclusive. if end == r.End { end = r.Start } // If there is a token equal to the end of the range, we don't need to do anything further if _, found := r.Entries.get(end); found { return } // If not, we need to insert a token such that we claim this bit on the end. endFree := r.distance(end, r.Entries.entry(pos).Token) r.Entries.insert(entry{Token: end, Peer: r.Peer, Free: endFree}) }
func Subtract(a, b Address) Offset { common.Assert(a >= b) return Offset(a - b) }
func (s *Space) assertInvariants() { common.Assert(sort.IsSorted(addressSlice(s.ours))) common.Assert(sort.IsSorted(addressSlice(s.free))) }
func Length(a, b Address) Count { common.Assert(a >= b) return Count(a - b) }