ETS-based implementation of ClusterHelper.RoleStore.
Maintains three named ETS tables:
ClusterHelper.NodeConfig— an:ordered_setholding one row per fact. Each fact is stored as a single-element tuple whose composite term is the ETS key, so every key is unique and every read/write is O(log n):{:role, scope, role, node}— node carries role in scope{:node, scope, node, role}— the mirrored index for reverse lookups
Because the leading tag (
:role/:node) plus scope are bound in lookups,:ets.select/2prunes to the matching key range instead of scanning the table. Unique keys also mean inserts never pay duplicate scans and deletes never amplify, which keeps bulk operations linear even for nodes carrying thousands of roles.ClusterHelper.NodeConfig_nodes— a:settable with{:scope, scope, node}entries for O(1) node enumeration per scope
Read operations (get_my_roles/1, get_nodes/2, get_roles/2, all_nodes/1)
bypass any GenServer and read directly from ETS with read_concurrency: true.
All writes flow through the ClusterHelper.NodeConfig GenServer (single
writer); reads are lock-free from any process.
Table names
Table names are kept as ClusterHelper.NodeConfig and its derived name
for backward compatibility with any code that references the ETS tables
directly. Note the row shape changed in v1.1 (flat unique keys replacing
the previous bag layout).