Concept
Graceful Departure and Hinted Handoff
In production, a node leaving the ring should hand off its data to its successor before going offline. This prevents data loss and avoids forcing the successor to recover data from replicas.
The Handoff Protocol
- Identify the departing node's successor on the ring.
- Stream all keys in the departing node's range to the successor.
- Remove the departing node from the membership.
- Acknowledge departure to the cluster coordinator.
What Happens to the Ring?
After departure, the predecessor of the departed node now has a larger ownership range — it stretches all the way to the next surviving node. No other node is affected.
Before: n1@200 --- n2@400 --- n3@700
After n2 leaves:
n1@200 -------- n3@700
n1 still owns (700,200]; n3 now owns (200,700]
Contrast with Failure
A graceful departure allows data handoff before removal. A sudden failure (crash, network partition) does not — the successor must reconstruct the data from replicas. This is why Dynamo maintains N=3 replicas: even if the primary fails without a handoff, two other copies survive.
main.py
python1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/env python3
"""
Key Migration on Node Departure
Commands:
ADD <node> <position> - add a node to the ring
KEY <keyname> <position> - register a key
LEAVE <node> - node departs; print migration plan
Output per LEAVE: sorted "MOVE <key> FROM <leaving> TO <successor>" lines
"""
import sys
import bisect
class DepartureRing:
def __init__(self):
self.positions = []
self.ring = {}
self.keys = {}
def add_node(self, node_id: str, position: int) -> None:
bisect.insort(self.positions, position)
self.ring[position] = node_id
def add_key(self, keyname: str, position: int) -> None:
self.keys[keyname] = position
def owner(self, key_pos: int) -> str:
if not self.positions:
return ''
idx = bisect.bisect_left(self.positions, key_pos)
if idx == len(self.positions):
idx = 0
return self.ring[self.positions[idx]]
def successor_of(self, node_id: str) -> str:
Sign in to run and submit code.