Skip to content

symfonic.memory.backends.postgres_auxiliary_retirement

postgres_auxiliary_retirement

Bounded native auxiliary erasure for explicitly migrated tenant retirement.

At most BUDGET rows per installed table are erased in the initial permanent job transaction, under the graph lock shared by the mandatory writer fence. Larger histories refuse before permanent intent; durable auxiliary keyset jobs remain future work. Unsupported invocation journal stores stay refused.

bounded_sql

bounded_sql(table: str) -> str

Production owner-range probe; live tests EXPLAIN this exact text.

Source code in src/symfonic/memory/backends/postgres_auxiliary_retirement.py
def bounded_sql(table: str) -> str:
    """Production owner-range probe; live tests EXPLAIN this exact text."""
    return (f'SELECT ctid FROM {table} WHERE erase_scope COLLATE "C">=$1 '
            'AND erase_scope COLLATE "C"<$2 ORDER BY erase_scope COLLATE "C" '
            f"LIMIT {BUDGET + 1}")

erase async

erase(conn: Any, schema: str, scope: Any) -> None

Initial retirement transaction only; caller holds EXCLUSIVE graph lock.

Source code in src/symfonic/memory/backends/postgres_auxiliary_retirement.py
async def erase(conn: Any, schema: str, scope: Any) -> None:
    """Initial retirement transaction only; caller holds EXCLUSIVE graph lock."""
    tables = await require_ready(conn, schema)
    async with index_probes(conn, ordered=True, presorted=True):
        for table in tables:
            # The bounded CTE and Tid Scan delete no unselected owner or history.
            # The final count also refuses/rolls back if the budget changed.
            count = await conn.fetchval(
                "WITH selected AS MATERIALIZED (" + bounded_sql(table) + "), "
                f"erased AS (DELETE FROM {table} t USING selected s WHERE t.ctid=s.ctid "
                "RETURNING 1) SELECT count(*) FROM erased",
                scope.subtree_prefix, scope.subtree_prefix[:-1] + "0",
            )
            if count > BUDGET:
                raise MemoryContractError(EXCEEDED)