diff --git a/chord/topology.go b/chord/topology.go new file mode 100644 index 0000000..41684c7 --- /dev/null +++ b/chord/topology.go @@ -0,0 +1,62 @@ +package chord + +import ( + "errors" + "net/netip" +) + +// Node represents a node's topological relations within a Chord network. +type Node struct { + // self is the node's own address. + self Peer + // pred is the node's predecessor. + // If not valid, the predecessor is not currently known. + pred Peer + // succ is the node's immediate successors for replication. Its capacity + // is the replication factor for the network. + // There is always at least one successor. If the number of nodes in the + // network is not larger than the replication factor, then this node will + // appear in its own successor list. + succ []Peer + // fingers is the node's finger table. + fingers []Peer +} + +func (n *Node) Successor() Peer { + return n.succ[0] +} + +// IsLocal reports whether this node owns the given key. +func (n *Node) IsLocal(key string) bool { + id := keyID(key) + return contains(n.self.id, n.Successor().id, id) +} + +// Peer is the ID and address of a node. +type Peer struct { + id ID + addr netip.AddrPort +} + +// Address constructs a peer from an address and port. +func Address(addr netip.AddrPort) Peer { + return Peer{id: addrID(addr), addr: addr} +} + +// IsValid reports whether the peer was created using [Address] with an address +// which was valid. +func (p Peer) IsValid() bool { return p.addr.IsValid() && p.addr.Port() != 0 } + +// Create creates a new Chord network using the given address as the initial node. +func Create(addr netip.AddrPort) (*Node, error) { + if !addr.IsValid() { + return nil, errors.New("chord: cannot create with invalid address") + } + self := Address(addr) + n := &Node{ + self: self, + succ: []Peer{self}[:1:1], // extra cautious about capacity + fingers: make([]Peer, len(ID{})*8), + } + return n, nil +}