fix(cluster): ClusterRoleInfo._roleLeaders stays Ordinal — Akka tracks role-leadership per exact gossiped role string (review finding, R3-04)
This commit is contained in:
@@ -23,12 +23,21 @@ public sealed class ClusterRoleInfo : IClusterRoleInfo, IDisposable
|
||||
private readonly string? _clusterRole;
|
||||
private readonly string? _clusterId;
|
||||
private readonly object _lock = new();
|
||||
// R3-04 (01/C-9, census row 17): OrdinalIgnoreCase — Akka compares gossiped role names ordinally,
|
||||
// so a PEER running an older build can still gossip a miscased plain role during a rolling
|
||||
// upgrade. Keying these by the exact-cased role string would leave MembersWithRole("driver") and
|
||||
// RoleLeader("driver") blind to a peer that gossips "Driver", the same class of gap #532 closed
|
||||
// for _localRoles above.
|
||||
private readonly Dictionary<string, Member?> _roleLeaders = new(StringComparer.OrdinalIgnoreCase);
|
||||
// R3-04 (01/C-9, census row 17) — the two dictionaries below have DIFFERENT correct comparers,
|
||||
// and that split is deliberate, not an oversight (review finding, 2026-08-20).
|
||||
//
|
||||
// _membersByRole answers "every member carrying (a spelling of) this role" — OrdinalIgnoreCase,
|
||||
// so a PEER running an older build that still gossips a miscased plain role during a rolling
|
||||
// upgrade is not invisible to MembersWithRole("driver"). Merging casings IS the point here.
|
||||
//
|
||||
// _roleLeaders must stay Ordinal. Akka computes — and raises RoleLeaderChanged for — role
|
||||
// leadership PER EXACT GOSSIPED ROLE STRING: "driver" and "Driver" are two entirely distinct
|
||||
// roles to Akka's own role-leader machinery, each independently electing its own leader. An
|
||||
// OrdinalIgnoreCase dictionary here would collapse both onto ONE key, so whichever
|
||||
// RoleLeaderChanged event landed last would silently overwrite the other's leader — turning two
|
||||
// real, independent facts Akka tracks separately into one, wrong, merged one. Pinned by
|
||||
// ClusterRoleInfoRoleLeaderCaseTests.RoleLeaderChanged_for_driver_then_Driver_keeps_distinct_entries.
|
||||
private readonly Dictionary<string, Member?> _roleLeaders = new(StringComparer.Ordinal);
|
||||
private readonly Dictionary<string, HashSet<Member>> _membersByRole = new(StringComparer.OrdinalIgnoreCase);
|
||||
private IActorRef? _subscriber;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user