Summary
SmRegistry is currently a process-wide singleton (SmRegistry::instance()), so every E3Interface in a process shares one SM table. PR #29 proposed making it a per-E3Interface member. That's a structural change to a public header and ~10 call sites, unrelated to the setup-wedge bug (#28) it was bundled with, so we're splitting it out for its own discussion and review.
Motivation (to be confirmed)
A process-wide registry breaks any process hosting more than one E3 agent:
- Registering an SM with the same
ran_function_id on a second, independent agent fails with SM_ALREADY_REGISTERED.
E3Interface::stop() clears the shared registry, wiping the Service Models of every other RAN-role agent still running in the process.
The scenarios where this matters are multi-agent-in-one-process: integration tests, the latency benchmark, and colocated RAN+dApp deployments.
Open question: is multi-agent-in-one-process a configuration we want to officially support and commit to maintaining? The answer decides whether this refactor is worth its cost.
Proposed change (if we proceed)
- Each
E3Interface owns an SmRegistry member; all e3_interface.cpp call sites route through the owning interface's registry; stop() clears only the agent's own SMs.
SmRegistry loses instance() and gets a public constructor.
Notes / caveats
- Behavioral change: with
clear() only invoked from stop(), destroying an E3Interface without calling stop() would destroy the SM objects via their C++ destructors but never call their destroy() lifecycle hook (the singleton previously lived for the whole process).
- ABI:
SmRegistry is a public header symbol, but no external consumer references SmRegistry::instance() (OAI / spear-dApp are clean), so the API break is internal-only.
- A regression test (
test_multi_agent_registry) accompanies the change and moves with it.
Context
Split out of PR #29 review.
Summary
SmRegistryis currently a process-wide singleton (SmRegistry::instance()), so everyE3Interfacein a process shares one SM table. PR #29 proposed making it a per-E3Interfacemember. That's a structural change to a public header and ~10 call sites, unrelated to the setup-wedge bug (#28) it was bundled with, so we're splitting it out for its own discussion and review.Motivation (to be confirmed)
A process-wide registry breaks any process hosting more than one E3 agent:
ran_function_idon a second, independent agent fails withSM_ALREADY_REGISTERED.E3Interface::stop()clears the shared registry, wiping the Service Models of every other RAN-role agent still running in the process.The scenarios where this matters are multi-agent-in-one-process: integration tests, the latency benchmark, and colocated RAN+dApp deployments.
Open question: is multi-agent-in-one-process a configuration we want to officially support and commit to maintaining? The answer decides whether this refactor is worth its cost.
Proposed change (if we proceed)
E3Interfaceowns anSmRegistrymember; alle3_interface.cppcall sites route through the owning interface's registry;stop()clears only the agent's own SMs.SmRegistrylosesinstance()and gets a public constructor.Notes / caveats
clear()only invoked fromstop(), destroying anE3Interfacewithout callingstop()would destroy the SM objects via their C++ destructors but never call theirdestroy()lifecycle hook (the singleton previously lived for the whole process).SmRegistryis a public header symbol, but no external consumer referencesSmRegistry::instance()(OAI / spear-dApp are clean), so the API break is internal-only.test_multi_agent_registry) accompanies the change and moves with it.Context
Split out of PR #29 review.