Class ConsistentHashRing

java.lang.Object
com.loomcache.server.partition.ConsistentHashRing

public class ConsistentHashRing extends Object
Consistent Hash Ring with Virtual Nodes.

Architecture:

  • Each physical node gets VNODES_PER_NODE (256) virtual positions on the ring
  • Ring is a sorted TreeMap<Integer, String> mapping hash → nodeId
  • Lookup: hash(key) → find next clockwise vnode → that node is the owner
  • Backup: the NEXT node clockwise after the primary (different physical node)

Adding a node: 256 new vnodes on ring, ~1/N data migrates. Removing a node: 256 vnodes removed, data shifts to next clockwise.

Thread safety: ReadWriteLock allows concurrent reads during lookups and exclusive access during topology changes.

Since:
1.0
See Also:
  • Field Details

  • Constructor Details

    • ConsistentHashRing

      public ConsistentHashRing(int instanceNumber)
    • ConsistentHashRing

      public ConsistentHashRing(int instanceNumber, PartitionGroupType partitionGroupType)
    • ConsistentHashRing

      public ConsistentHashRing(int instanceNumber, PartitionGroupConfig partitionGroupConfig)
  • Method Details

    • partitionGroupType

      public PartitionGroupType partitionGroupType()
    • partitionGroupConfig

      public PartitionGroupConfig partitionGroupConfig()
    • addNode

      public void addNode(NodeInfo node)
      Add a physical node to the ring.

      Places VNODES_PER_NODE (256) virtual positions on the consistent hash ring. If the node is already on the ring, this is a no-op and logged as a warning.

      Parameters:
      node - the node to add (must not be null)
      Throws:
      IllegalArgumentException - if node is null
    • removeNode

      public void removeNode(String nodeId)
      Remove a physical node and all its virtual positions from the ring.

      After removal, all keys that were owned by this node will migrate to the next node clockwise on the ring. If the node is not on the ring, this is a no-op and logged as a warning.

      Parameters:
      nodeId - the ID of the node to remove (must not be null)
      Throws:
      IllegalArgumentException - if nodeId is null
    • getPrimaryNode

      public @Nullable String getPrimaryNode(String key)
      Find the PRIMARY owner of a key.

      Returns the first node clockwise from hash(key) on the consistent hash ring.

      Parameters:
      key - the key to hash and locate (must not be null)
      Returns:
      the primary node ID, or null if the ring is empty
    • getBackupNode

      public @Nullable String getBackupNode(String key)
      Find the BACKUP owner of a key.

      Returns the next DIFFERENT physical node clockwise after the primary. This ensures primary and backup are always on different physical nodes, providing resilience against single-node failure.

      Parameters:
      key - the key to hash and locate (must not be null)
      Returns:
      the backup node ID, or null if invalid input: '<' 2 nodes on ring
    • getOwners

      public @Nullable String[] getOwners(String key)
      Get both primary and backup for a key. Returns [primary, backup] or [primary, null] if only 1 node.
    • getKeysOwnedBy

      public Set<String> getKeysOwnedBy(String nodeId, Set<String> allKeys)
      Get all keys that should be owned by a specific node. Used during rebalancing when nodes join/leave.
    • getDistribution

      public Map<String,Integer> getDistribution()
      Calculate the distribution of vnodes across physical nodes. Useful for monitoring balance.
    • ringSize

      public int ringSize()
      Total number of virtual nodes on the ring.
    • nodeCount

      public int nodeCount()
      Number of distinct physical nodes on the ring.
    • getNodes

      public Collection<NodeInfo> getNodes()
      Snapshot of all physical nodes currently on the ring.
    • getNodeInfo

      public @Nullable NodeInfo getNodeInfo(String nodeId)
      Get metadata for a specific node, or null if not on the ring.