chordnet

A Python Library for Distributed Computing

ChordNet implements the chord protocol, introduced by Stoica et al. It implements a distributed hash table.

Installation

pip install chordnet

uv add chordnet

Usage

To stay consistent with the language from the original paper, we recommend naming your chordnet attribute ring:

from chordnet import ChordNet

ring = new ChordNet(...)
ring.create() # or ring.join(...)
#...application logic...
ring.leave()
# end program

This fits with the concept of "joining" an existing ring network, or creating a new one. Examples follow this practice.

At present, this package only supports IP lookup. All application-dependent logic (state transfer, etc) must be handled by the application. The easiest way to do this is to initialize ChordNet as an attribute on an application class:

class App:
    """An example/template application that uses ChordNet."""
    def __init__(self, ip: str, chordnet_port: int) -> None:
        """Creates a new insance of the app."""
        self._ring = ChordNet(ip, chordnet_port)

    def start(
        self, ip = None: str | None, port = None: int | None
    ) -> None:
        """Starts the app by joining an existing ring or creating a new one."""
        if ip and port:
            self._ring.join(ip, port)
            # ...any state transfer logic, if part of this app...
        elif not ip and not port:
            self._ring.create()
        else:
            print("need both or neither")
            return

    #...application logic (probably using self._ring.lookup()...

    def stop(self) -> None:
        """Gracefully leaves the ring."""
        # ...any state transfer logic (if using)...
        self._ring.leave()

Not all distributed applications that ChordNet is suitable for will require state transfer logic (for example, search problems), and the nature of that logic will likely vary by app. In future versions, we hope to support in-library state transfer.

class ChordNet:

Interface for interacting with Chord networks.

ChordNet(ip: str, port: int, interval: float = 1.0)

Initializes a new Chord node.

Arguments:
  • ip: IP address for the node. This should be the public IP (unless the whole ring is local, it is unlikely to be 127.0.0.1)
  • port: Port number to listen on.
  • interval: daemon interval (how often to 'sync' with the network)
def create(self) -> None:

Create a new ChordNet network (a new "ring").

This creates a new network with one node (this one), using the ip and port passed to the class constructor.

def join(self, known_ip: str, known_port: int) -> None:

Joins an existing ChordNet network (an existing ring).

An existing chordnet can be joined through any node already on running on the ring. Note that this means a node cannot join itself to create a ring, and trivially, joining itself once running is meaningless.

Arguments:
  • known_ip: IP address of an existing node in the Chord ring.
  • known_port: Port number of the existing node.
def lookup(self, key: int) -> Tuple[str, int]:

Finds the ip address of the node responsible for the given key.

Arguments:
  • key: the value to look up (the hash)

Returns: the IP address of the node responsible for the given key, and the port that key is listening for ChordNet traffic on.

def leave(self) -> None:

Leave the current network.

Allows for a graceful shutdown of this node. This is optional and can help the ring recover faster. It should be called before program exit (or before a node shuts down in the network), but the network can still recover if this does not happen.