// Merges two leafsets and returns the result. func (o *Overlay) mergeLeaves(a, b []*big.Int) []*big.Int { // Append, circular sort and fetch uniques res := append(a, b...) sort.Sort(idSlice{o.nodeId, res}) res = res[:sortext.Unique(idSlice{o.nodeId, res})] // Look for the origin point origin := 0 for o.nodeId.Cmp(res[origin]) != 0 { origin++ } // Fetch the nearest nodes in both directions min := mathext.MaxInt(0, origin-config.PastryLeaves/2) max := mathext.MinInt(len(res), origin+config.PastryLeaves/2) return res[min:max] }
func checkRoutes(t *testing.T, nodes []*Overlay) { // Synchronize overlay states for _, o := range nodes { o.lock.RLock() defer o.lock.RUnlock() } // Extract the ids from the running nodes ids := make([]*big.Int, len(nodes)) for i, o := range nodes { ids[i] = o.nodeId } // Assemble the leafset of each node and verify for _, o := range nodes { sort.Sort(idSlice{o.nodeId, ids}) origin := 0 for o.nodeId.Cmp(ids[origin]) != 0 { origin++ } min := mathext.MaxInt(0, origin-config.PastryLeaves/2) max := mathext.MinInt(len(ids), origin+config.PastryLeaves/2) leaves := ids[min:max] if len(leaves) != len(o.routes.leaves) { t.Fatalf("overlay %v: leafset mismatch: have %v, want %v.", o.nodeId, o.routes.leaves, leaves) } else { for i, leaf := range leaves { if leaf.Cmp(o.routes.leaves[i]) != 0 { t.Fatalf("overlay %v: leafset mismatch: have %v, want %v.", o.nodeId, o.routes.leaves, leaves) break } } } } // Check the routing table for each node for _, o := range nodes { for r, row := range o.routes.routes { for c, p := range row { if p == nil { // Check that indeed no id is valid for this entry for _, id := range ids { if id.Cmp(o.nodeId) != 0 { if pre, dig := prefix(o.nodeId, id); pre == r && dig == c { t.Fatalf("overlay %v: entry {%v, %v} missing: %v.", o.nodeId, r, c, id) } } } } else { // Check that the id is valid and indeed not some leftover if pre, dig := prefix(o.nodeId, p); pre != r || dig != c { t.Fatalf("overlay %v: entry {%v, %v} invalid: %v.", o.nodeId, r, c, p) } alive := false for _, id := range ids { if id.Cmp(p) == 0 { alive = true break } } if !alive { t.Fatalf("overlay %v: entry {%v, %v} already dead: %v.", o.nodeId, r, c, p) } } } } } }