"""A deterministic Chord routing exercise, not a network implementation.""" import argparse from bisect import bisect_left SIZE = 32 NODES = [2, 7, 13, 20, 27] def successor(nodes, key): return nodes[bisect_left(nodes, key) % len(nodes)] def fingers(nodes, node): return [(point, successor(nodes, point)) for point in ((node + (1 << i)) % SIZE for i in range(5))] def lookup(nodes, start, key, fast=True): current, route = start, [start] for _ in range(len(nodes) + 1): if key == current or len(nodes) == 1: return current, route next_node = nodes[(nodes.index(current) + 1) % len(nodes)] if (key - current) % SIZE <= (next_node - current) % SIZE: return next_node, route candidates = [n for _, n in fingers(nodes, current) if 0 < (n - current) % SIZE < (key - current) % SIZE] current = max(candidates, key=lambda n: (n - current) % SIZE) if fast and candidates else next_node route.append(current) raise RuntimeError("Routing loop") def check(): for nodes in (NODES, sorted(NODES + [24]), [2, 7, 13, 27], [2], [0, 31]): for start in nodes: for key in range(SIZE): for fast in (False, True): owner, _ = lookup(nodes, start, key, fast) assert owner == successor(nodes, key), (nodes, start, key, fast) print("PASS: all keys and start nodes, before/after join/failure, singleton and wraparound") def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--check", action="store_true") args = parser.parse_args() if args.check: check() return print("Ring 0..31; nodes:", NODES) for key in (0, 18, 26): print(f"key {key:2} -> owner {successor(NODES, key)}") print("\nFinger table of node 2 (start -> successor):") for point, node in fingers(NODES, 2): print(f"{point:2} -> {node:2}") for fast in (False, True): owner, route = lookup(NODES, 2, 26, fast) print(f"{'fingers' if fast else 'neighbors'}: route {route}; result {owner}; " f"forwarded requests {len(route) - 1}") joined = sorted(NODES + [24]) changed = [key for key in range(SIZE) if successor(NODES, key) != successor(joined, key)] print("\nJoin node 24; transferred keys:", changed) print("Fail node 24; after repairing the ring the owner is 27.") print("Routing references do not recreate lost values; replicas are a separate concern.") if __name__ == "__main__": main()