Skip to content

parallel_export_parquet: six follow-ups from the #329 review, on merged code #332

Description

@jdatcmd

parallel_export_parquet landed via #329/#331. The blocker found in review (a
cross-backend snapshot handoff that duplicated the table and dropped the caller's
uncommitted rows) was fixed and I verified it against the original reproduction.

These six were raised in that review, judged non-blocking, and are now on main.
Filing so they are not lost with the closed PR. Roughly in order of how much I
would care.

1. Partitioned export re-derives the leaf list from the live catalog. Each
worker enumerates leaves itself rather than receiving the set the dispatcher
computed. A concurrent ATTACH or DETACH CONCURRENTLY is not blocked by the
dispatcher's AccessShareLock, so workers can disagree about the relation set.
Note the snapshot fix does not cover this: an MVCC snapshot governs row
visibility, not which relations are enumerated. The fix is to ship the actual leaf
OIDs in the DSM rather than a recipe for recomputing them, which also makes the
split self-describing instead of positional.

2. No cleanup of partial output on failure. The require-empty-directory guard
protects entry but not exit. A worker failing mid-export leaves part files that
pgcolumnar.read_parquet will union as if the export were complete, and the
directory then fails the empty check on retry. Silent wrong answers on read-back
is the bad shape here.

3. ColumnarParquetCheckExportable validates the parent's tupdesc, the writer
runs per leaf.
A leaf whose column shape differs from the parent passes the
fail-fast pre-check and then fails or misbehaves inside a worker, which is the
worst place to discover it.

4. Workers register as BgWorkerStart_RecoveryFinished. A read-only export
cannot run on a hot standby, which is exactly where you would want to run one.
BgWorkerStart_ConsistentState is the plausible value.

5. No dsm-detach callback. A FATAL in the dispatcher orphans the workers and
drops the snapshot's horizon protection while they are still reading.

6. ColumnarWriteParquetFile frees none of its per-call buffers, and the
partitioned worker calls it in a loop, so memory grows with the partition count
rather than staying flat.

Testing note, since it is the reason the original blocker survived to review: every
fixture in test/parallel_export_parquet.sh ran the export as a standalone
autocommit statement against a quiet table, which is the one configuration where
the snapshot handoff is a no-op. The in-transaction case is covered now. Items 1
and 2 above have the same property: neither is reachable by a fixture that does not
have something else happening at the same time, or a failure injected mid-run.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions