@@ -237,7 +237,7 @@ class TransactionCursor:
237237
238238 Post-commit hooks registered via :meth:`on_commit` run after the wrapping
239239 ``ControllerDB.transaction()`` block commits successfully. They are used
240- by caches (e.g. ``EndpointRegistry ``) to update in-memory state atomically
240+ by caches (e.g. ``EndpointStore ``) to update in-memory state atomically
241241 with the DB write: rollback suppresses the hook so memory never drifts
242242 from disk.
243243 """
@@ -258,6 +258,14 @@ def executescript(self, sql: str) -> sqlite3.Cursor:
258258 """Raw SQL script escape hatch."""
259259 return self ._cursor .executescript (sql )
260260
261+ def fetchall (self , sql : str , params : tuple = ()) -> list [sqlite3 .Row ]:
262+ """Execute ``sql`` and return all rows. Mirrors :meth:`QuerySnapshot.fetchall`."""
263+ return list (self ._cursor .execute (sql , params ).fetchall ())
264+
265+ def fetchone (self , sql : str , params : tuple = ()) -> sqlite3 .Row | None :
266+ """Execute ``sql`` and return the first row, or None. Mirrors :meth:`QuerySnapshot.fetchone`."""
267+ return self ._cursor .execute (sql , params ).fetchone ()
268+
261269 def on_commit (self , hook : Callable [[], None ]) -> None :
262270 """Register ``hook`` to run after the transaction commits successfully."""
263271 self ._commit_hooks .append (hook )
@@ -321,19 +329,14 @@ def __init__(self, db_dir: Path):
321329 self ._attr_cache : dict [WorkerId , dict [str , AttributeValue ]] | None = None
322330 self ._attr_cache_lock = Lock ()
323331
324- # Write-through in-memory cache over the ``endpoints `` table. Imported
325- # locally to break the ``db -> endpoint_registry -> db`` import cycle;
326- # this is the single exception to "no local imports" (see AGENTS.md) .
327- from iris . cluster . controller . endpoint_registry import EndpointRegistry
332+ # Callables invoked at the end of ``replace_from `` so callers with
333+ # caches over DB contents (e.g. ``ControllerStore``) can reload them
334+ # after a checkpoint restore. Registered via ``register_reopen_hook`` .
335+ self . _reopen_hooks : list [ Callable [[], None ]] = []
328336
329- t0 = time .monotonic ()
330- self ._endpoint_registry = EndpointRegistry (self )
331- logger .info ("EndpointRegistry initialized in %.2fs" , time .monotonic () - t0 )
332-
333- @property
334- def endpoints (self ) -> EndpointRegistry : # noqa: F821
335- """Process-local cache for the ``endpoints`` table; authoritative for reads."""
336- return self ._endpoint_registry
337+ def register_reopen_hook (self , hook : Callable [[], None ]) -> None :
338+ """Register a no-arg callable to run at the end of ``replace_from``."""
339+ self ._reopen_hooks .append (hook )
337340
338341 def _populate_attr_cache (self ) -> dict [WorkerId , dict [str , AttributeValue ]]:
339342 """Load all worker attributes from the DB into the cache.
@@ -454,7 +457,7 @@ def transaction(self):
454457
455458 On successful commit, any hooks registered via ``TransactionCursor.on_commit``
456459 fire while the write lock is still held — keeping in-memory caches
457- (e.g. ``EndpointRegistry ``) in sync with the DB without exposing a
460+ (e.g. ``EndpointStore ``) in sync with the DB without exposing a
458461 torn snapshot to concurrent readers.
459462 """
460463 with self ._lock :
@@ -751,7 +754,8 @@ def replace_from(self, source_dir: str | Path) -> None:
751754 self ._conn .execute ("ATTACH DATABASE ? AS profiles" , (str (self ._profiles_db_path ),))
752755 self ._init_read_pool ()
753756 self .apply_migrations ()
754- self ._endpoint_registry ._load_all ()
757+ for hook in self ._reopen_hooks :
758+ hook ()
755759
756760 # SQL-canonical read access is exposed through ``snapshot()`` and typed table
757761 # metadata at module scope. Legacy list/get/count helper methods were removed
0 commit comments