Skip to content

symfonic.memory.backends.in_memory_positional_rows

in_memory_positional_rows

In-process rows for the CORE-171 positional migration, read and re-keyed.

Every session holds the backend's writer lock, and nothing between reading and re-keying awaits, so a plan computed here and the re-key it authorises see the same rows. A session refuses to open while any in-process lease table holds a live lease on the tenant; planning refuses a pending (unflushed) candidate row, and rollback a pending moved row, as the PostgreSQL and Mongo adapters do. Owner paths only move between values the caller names: a change whose current value differs from its expected one refuses the whole batch before any row moves, which is what makes apply and rollback all-or-nothing without a transaction to roll back.

Apply and rollback refuse inside a caller-owned graph transaction (CALLER_TRANSACTION): the writer lock admits every task joined to it, so only outside one is the window between proof and re-key closed to forgets. Apply records each row it quarantines, with its origin and the tenant's erase epoch: every public deletion of the graph (subtree, node or edge, whatever it finds) advances that epoch, and every native subtree erase is recorded by key. A rollback restores a present row only when that record proves this store's apply quarantined it and nothing could have erased it since: the epoch is unchanged and no recorded native erase covers an owner its origin could map to. Otherwise it refuses (RESTORE_UNPROVEN) before the audit trail. The records live in the store, as long as its rows do.

InMemoryPositionalRows

InMemoryPositionalRows(store: Any)

Sessions over one exact InMemoryGraphBackend under its writer lock.

Source code in src/symfonic/memory/backends/in_memory_positional_rows.py
def __init__(self, store: Any) -> None:
    self._store = store

refuse_caller_transaction

refuse_caller_transaction() -> None

Refuse when this task holds or joined the graph's transaction (CALLER_TRANSACTION).

The writer lock admits every task joined to that transaction, so it would not keep a joined forget out of the window between this store's proof and its re-key. The adapter itself opens no transaction, so this never sees its own.

Source code in src/symfonic/memory/backends/in_memory_positional_rows.py
def refuse_caller_transaction(self) -> None:
    """Refuse when this task holds or joined the graph's transaction (CALLER_TRANSACTION).

    The writer lock admits every task joined to that transaction, so it
    would not keep a joined forget out of the window between this
    store's proof and its re-key. The adapter itself opens no
    transaction, so this never sees its own.
    """
    from symfonic.memory.backends.in_memory_transaction import _owns

    if _owns(self._store):
        raise MemoryContractError(CALLER_TRANSACTION)