Class RaftGroupManager

java.lang.Object
com.loomcache.server.consensus.RaftGroupManager
All Implemented Interfaces:
RaftGroupManagerApi

public class RaftGroupManager extends Object implements RaftGroupManagerApi
Manages multiple independent Raft groups for horizontal scalability.

Architecture:

  • Each Raft group is an independent RaftNode with its own election, log, and state machine.
  • Keys are routed to groups using consistent hashing: group = "raft-" + (hash(key) % numGroups)
  • The DEFAULT group ("raft-0") is always present for backward compatibility.
  • Removes the single-Raft-group bottleneck for large-scale deployments.

Design Decisions:

  • Consistent Hashing: Same key always routes to the same group, enabling sharding.
  • Independent Elections: Each group elects its own leader, reducing contention.
  • Backward Compatibility: Existing code continues to use the DEFAULT group if numGroups=1.
  • Configurable Scale: numGroups default is 1 (no sharding); multi-group sharding remains fail-closed for production until independent durability and recovery evidence is complete.

Thread Safety: All operations are thread-safe using ConcurrentHashMap and atomic comparisons. Multiple threads can safely create and use groups concurrently.

This class manages local sharding of independent RaftNode instances. It does not implement Raft cluster membership changes for a single group.

Since:
2.0
  • Field Details

    • DEFAULT_GROUP

      public static final String DEFAULT_GROUP
      The default/primary group name (used when numGroups=1 or for compatibility).
      See Also:
  • Constructor Details

    • RaftGroupManager

      public RaftGroupManager(String localNodeId, int numGroups, int instanceNumber)
      Creates a new RaftGroupManager with the specified configuration.
      Parameters:
      localNodeId - the ID of the local node for logging/identification (must not be null)
      numGroups - the number of Raft groups (1 = no sharding)
      instanceNumber - the instance number for logging (must be >= 0)
      Throws:
      NullPointerException - if localNodeId is null
      IllegalArgumentException - if numGroups invalid input: '<' 1 or instanceNumber invalid input: '<' 0
    • RaftGroupManager

      public RaftGroupManager(String localNodeId, int numGroups, int instanceNumber, long compactionThreshold)
  • Method Details

    • getOrCreateGroup

      public RaftNode getOrCreateGroup(String groupName)
      Gets or creates a Raft group by name using lazy initialization.

      Thread-safe: uses computeIfAbsent to ensure only one RaftNode is created per group name, even under concurrent access.

      Specified by:
      getOrCreateGroup in interface RaftGroupManagerApi
      Parameters:
      groupName - the group name (typically "raft-N" where N is 0-based index, must not be null)
      Returns:
      the RaftNode for this group, creating it on first access (never null)
      Throws:
      NullPointerException - if groupName is null
    • getGroupForKey

      public RaftNode getGroupForKey(String key)
      Routes a key to its Raft group using consistent hashing.

      Algorithm: groupIndex = Math.abs(key.hashCode()) % numGroups

      Guarantees:

      • The same key always routes to the same group (deterministic routing)
      • Different keys distribute roughly evenly across groups (load balancing)
      • Adding/removing groups causes minimal key remapping
      Specified by:
      getGroupForKey in interface RaftGroupManagerApi
      Parameters:
      key - the key to route (must not be null)
      Returns:
      the RaftNode for this key's group (never null)
      Throws:
      NullPointerException - if key is null
    • getDefaultGroup

      public RaftNode getDefaultGroup()
      Gets the default group (backward compatible accessor).

      Use this when you want the single primary group, without key-based routing. This is equivalent to the behavior when numGroups=1.

      Specified by:
      getDefaultGroup in interface RaftGroupManagerApi
      Returns:
      the DEFAULT RaftNode ("raft-0"), never null
    • listGroups

      public Collection<String> listGroups()
      Lists all active (created) Raft groups.
      Returns:
      an unmodifiable collection of group names that have been instantiated (never null)
    • getInstantiatedGroupCount

      public int getInstantiatedGroupCount()
      Gets the count of currently instantiated groups.
      Returns:
      the number of groups that have been created (0 to numGroups)
    • configuredGroupCount

      public int configuredGroupCount()
      Description copied from interface: RaftGroupManagerApi
      Returns the configured upper bound for Raft group IDs.

      Implementations that do not expose a fixed group count may return Integer.MAX_VALUE, which preserves permissive validation for tests and custom managers.

      Specified by:
      configuredGroupCount in interface RaftGroupManagerApi
    • getGroupIfExists

      public @Nullable RaftNode getGroupIfExists(String groupName)
      Gets a specific Raft group by name, or null if it hasn't been created yet.
      Specified by:
      getGroupIfExists in interface RaftGroupManagerApi
      Parameters:
      groupName - the group name (must not be null)
      Returns:
      the RaftNode if it exists, or null if not yet created
      Throws:
      NullPointerException - if groupName is null
    • hasGroup

      public boolean hasGroup(String groupName)
      Checks if a group has been instantiated.
      Specified by:
      hasGroup in interface RaftGroupManagerApi
      Parameters:
      groupName - the group name (must not be null)
      Returns:
      true if the group has been created, false otherwise
      Throws:
      NullPointerException - if groupName is null
    • shutdownAll

      public void shutdownAll()
      Shuts down all Raft groups gracefully.

      Calls stop() on each RaftNode. After this, the manager is no longer usable and a new instance should be created to continue operations.

      Errors stopping individual groups are logged but do not prevent shutdown of other groups.

    • getAllGroups

      public Collection<RaftNode> getAllGroups()
      Gets all active RaftNode instances.
      Returns:
      an unmodifiable collection of all instantiated RaftNodes (never null)
    • getGroupSnapshot

      public Map<String,RaftNode> getGroupSnapshot()
      Gets a snapshot of current group state for monitoring/debugging.
      Returns:
      a modifiable map of groupName → RaftNode containing all groups (never null)
    • createRaftNode

      protected RaftNode createRaftNode(String groupName)
      Creates a RaftNode instance for the given group.

      Package-private/protected extension point used by tests to inject controlled RaftNode behavior while keeping production construction in one place.