Skip to content

SET TRANSACTION SNAPSHOT into a SERIALIZABLE transaction panics (snapshot import not ported) #62

Description

@MauricioPerera

Summary

SetSerializableTransactionSnapshot (crates/backend/storage/lmgr/predicate/src/engine.rs:648-660) handles establishing a SERIALIZABLE transaction's snapshot when a snapshot is being imported (SET TRANSACTION SNAPSHOT '...') rather than freshly taken. After checking the parallel-worker case and the READ ONLY DEFERRABLE incompatibility, the actual import path is a hard panic:

panic!("predicate.c SetSerializableTransactionSnapshot: snapshot import into a serializable transaction is not ported");

The comment directly above the function confirms this is a known, deliberate gap:

// SetSerializableTransactionSnapshot (predicate.c): in a parallel worker the
// leader's SERIALIZABLEXACT arrives via AttachSerializableXact, so there is
// nothing to do here. The snapshot-import arm (SET TRANSACTION SNAPSHOT,
// GetSerializableTransactionSnapshotInt's sourcevxid path) is unported.

Why this matters

SET TRANSACTION SNAPSHOT combined with SERIALIZABLE is valid, standard PostgreSQL syntax with real use cases — most notably tools that need multiple sessions/connections to observe an identical consistent view of the database (e.g. custom parallel dump/export tooling, or application code doing manual snapshot-sharing across connections for consistent reporting). PostgreSQL's own pg_dump/pg_restore --jobs machinery relies on the closely related pg_export_snapshot()/import flow, though typically at REPEATABLE READ rather than SERIALIZABLE — but nothing in SQL prevents a user from requesting SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, SNAPSHOT '...' and hitting this panic.

This crashes the backend rather than returning an error, which is a correctness/availability concern for any code path that reaches it.

Reproduction sketch

-- Session A
BEGIN ISOLATION LEVEL SERIALIZABLE;
SELECT pg_export_snapshot();  -- returns e.g. '00000003-00000001-1'

-- Session B
BEGIN ISOLATION LEVEL SERIALIZABLE;
SET TRANSACTION SNAPSHOT '00000003-00000001-1';  -- panics here

Suggested scope for a fix

Port GetSerializableTransactionSnapshotInt's sourcevxid/snapshot-import arm from predicate.c, wiring SetSerializableTransactionSnapshot to actually attach to the imported snapshot's SERIALIZABLEXACT state (including whatever conflict/RW-tracking bookkeeping the imported transaction needs to participate correctly in SSI) instead of panicking. At minimum, until ported, consider returning a normal ERRCODE_FEATURE_NOT_SUPPORTED error instead of a hard panic, consistent with how the adjacent READ ONLY DEFERRABLE case in the same function already does (engine.rs:658-660).

Environment / where found

Found via static source review of a fresh clone of this repo (part of a broader MVCC/procarray/SSI review — the core SSI dangerous-structure detection and write-skew handling were found to be genuinely and faithfully ported and tested under real concurrent threads). Have not attempted to build/run pgrust myself to runtime-confirm the panic; based on reading crates/backend/storage/lmgr/predicate/src/engine.rs directly.

Related: #61 (a separate unported pg_serial SLRU/SERIALIZABLEXACT-slot-exhaustion panic in the same file).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions