Skip to content

interconnect: prune cursor IC history table by local xid, not distributed xid - #1964

Open
yjhjstz wants to merge 1 commit into
apache:mainfrom
yjhjstz:fix/ic-cursor-history-prune-lxid
Open

interconnect: prune cursor IC history table by local xid, not distributed xid#1964
yjhjstz wants to merge 1 commit into
apache:mainfrom
yjhjstz:fix/ic-cursor-history-prune-lxid

Conversation

@yjhjstz

@yjhjstz yjhjstz commented Sep 4, 2026

Copy link
Copy Markdown
Member

SetupUDPIFCInterconnect_Internal() records one CursorICHistoryEntry per interconnect instance on the QD and prunes old entries only when the statement runs in a different transaction than the previous one, using the distributed xid as the transaction identity. Distributed xids are assigned lazily (only for transactions that write or are dispatched two-phase), so autocommit read-only statements always see InvalidDistributedTransactionId on both sides of the comparison. The table is therefore never pruned on read-only sessions and grows by one 48-byte entry per Motion-containing statement for the life of the backend (2.8 MB after 60000 statements, plus the heap fragmentation the steady stream of small long-lived allocations induces).

Use MyProc->lxid instead: it is assigned to every top-level transaction, including read-only ones, and stays constant within a transaction block, so entries belonging to cursors that are still open in the current transaction remain protected exactly as before.

Verified on a single long-lived session running the queries from #1947: UdpInterconnectMemContext grew 0 -> 2814 KB over 60000 statements before the change and stays at 12 KB after it; RssAnon went 12.7 -> 24.6 MB before and is flat at 14.4 MB after. Pruning still does not happen inside an explicit transaction block or while a cursor is open, and FETCH from an open cursor after 300 intervening statements works.

Fixes #1947

What does this PR do?

Type of Change

  • Bug fix (non-breaking change)
  • New feature (non-breaking change)
  • Breaking change (fix or feature with breaking changes)
  • Documentation update

Breaking Changes

Test Plan

  • Unit tests added/updated
  • Integration tests added/updated
  • Passed make installcheck
  • Passed make -C src/test installcheck-cbdb-parallel

Impact

Performance:

User-facing changes:

Dependencies:

Checklist

Additional Context

CI Skip Instructions


…uted xid

SetupUDPIFCInterconnect_Internal() records one CursorICHistoryEntry per
interconnect instance on the QD and prunes old entries only when the
statement runs in a different transaction than the previous one, using
the distributed xid as the transaction identity.  Distributed xids are
assigned lazily (only for transactions that write or are dispatched
two-phase), so autocommit read-only statements always see
InvalidDistributedTransactionId on both sides of the comparison.  The
table is therefore never pruned on read-only sessions and grows by one
48-byte entry per Motion-containing statement for the life of the
backend (2.8 MB after 60000 statements, plus the heap fragmentation the
steady stream of small long-lived allocations induces).

Use MyProc->lxid instead: it is assigned to every top-level transaction,
including read-only ones, and stays constant within a transaction block,
so entries belonging to cursors that are still open in the current
transaction remain protected exactly as before.

Verified on a single long-lived session running the queries from apache#1947:
UdpInterconnectMemContext grew 0 -> 2814 KB over 60000 statements before
the change and stays at 12 KB after it; RssAnon went 12.7 -> 24.6 MB
before and is flat at 14.4 MB after.  Pruning still does not happen
inside an explicit transaction block or while a cursor is open, and
FETCH from an open cursor after 300 intervening statements works.

Related: apache#1947
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] GPORCA long-lived backend leaks memory per query (process-level OptimizerMemoryContext, RSS never returned to OS)

1 participant