Files
hse-2026/materials/07-naming-lookup/seminar/chord/demo.py
T
2026-10-21 23:03:28 +03:00

69 lines
2.5 KiB
Python

"""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()