Skip to content

Reduce coordinator metadata cache growth during shard moves#8652

Draft
ihalatci with Copilot wants to merge 7 commits into
mainfrom
copilot/fix-citus-move-shard-placement-memory-usage
Draft

Reduce coordinator metadata cache growth during shard moves#8652
ihalatci with Copilot wants to merge 7 commits into
mainfrom
copilot/fix-citus-move-shard-placement-memory-usage

Conversation

Copilot AI commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Description

Reduce coordinator memory retained during shard transfers, including the logical-replication path reported in #8145.

Large colocation groups caused shard-transfer helpers to populate full session-lifetime CitusTableCacheEntry objects when they only needed one colocated shard interval or a shard placement. The change uses direct catalog reads for those narrow lookups and resets temporary memory between tables/shards.

Changes

  • Load colocated shard intervals directly from catalogs and retain only the matching interval.
  • Read shard placements directly during transfer validation and placement deletion.
  • Reset temporary memory contexts between colocated tables and shards.
  • Preserve inactive-node and placement-validation behavior.

Validation

Compared unpatched and patched builds under PostgreSQL 16.14 in WSL using fresh coordinator backends, two workers, forced logical moves, and increasingly large partitioned colocation groups.

Colocated relations Total shards Baseline metadata cache Patched metadata cache Baseline RSS growth Patched RSS growth
51 1,632 2 MiB 0.5 MiB 7.7 MiB 7.4 MiB
151 9,664 8 MiB 4 MiB 15.1 MiB 9.6 MiB
301 19,264 16 MiB 8 MiB 22.9 MiB 12.4 MiB

At the largest scale, retained MetadataCacheMemoryContext growth was 50.1% lower, total measured backend memory-context growth was 39.1% lower, and backend RSS growth was 45.9% lower.

Every case preserved row counts, created one target placement per colocated relation, and left no source placements. Retained metadata still grows with metadata size; this change removes a substantial amplification source rather than making memory usage flat.

Copilot AI changed the title [WIP] Fix memory usage in citus_move_shard_placement() Reduce coordinator memory growth in citus_move_shard_placement Jul 8, 2026
Copilot AI requested a review from ihalatci July 8, 2026 13:26
DESCRIPTION: Re-range sequences to the new group id when promoting a
clone node so distributed, reference and Citus local tables keep
globally-unique sequence values

citus_promote_clone_and_rebalance promotes a physical streaming replica
to a new primary with a freshly-allocated group id, but the clone's
sequence objects are byte-for-byte copies of the source primary's and
keep the old primary's (groupId << 48) value window. 
The classical add/activate-node path re-ranges sequences per group id via
AlterSequenceMinMax, the clone path did not, so the promoted clone and
the original primary emitted values from the same window, breaking the
global-uniqueness invariant for bigserial / bigint nextval(...) defaults
and GENERATED ... AS IDENTITY columns.

Add SequenceRangeAdjustCommandList() (mirrors
IdentitySequenceDependencyCommandList for nextval/serial sequences) and
a promotion-path helper AdjustCloneSequenceRangesForNewGroup() that
re-ranges the clone's sequences to its new group-id window. To stay in
parity with the classical add/activate-node path, it selects tables via
ShouldSyncTableMetadata(), so distributed, reference and Citus local tables are all covered.
The helper runs after SyncNodeMetadataToNodes() over the reused metadata
connection, so the clone's corrected local group id is visible when
AlterSequenceMinMax executes.

Reuses the existing citus_internal.adjust_identity_column_seq_settings
UDF so no SQL migration or catalog change.
…or (#8651)

DESCRIPTION: Drop orphaned Citus local table shard copies on a worker
promoted from a clone of the coordinator

A clone node is a byte-for-byte physical replica, so a clone of the
coordinator also carries the coordinator's Citus local table shard data.
Citus local tables live only on the coordinator: the promotion
shard-split (AdjustShardsForPrimaryCloneNodeSplit) relocates distributed
shards and replicates reference tables, but it left the clone's physical
copies of Citus local shards in place. Their metadata placement
correctly stays on the coordinator, so the copies became untracked
orphans on the new worker.

When the split source is the coordinator, schedule cleanup of the Citus
local tables' shard copies from the clone group; the shell table and its
sequences remain, exactly as on any other worker. The metadata needs no
adjustment, since the single placement stays on the coordinator.

Add regression coverage (multi_add_node_from_backup_coordinator) that
clones and promotes the coordinator with distributed, reference and
Citus local tables present, asserting: the Citus local placement stays
on group 0, the orphaned shard copy is cleaned up on the clone while the
shell remains, the clone becomes a worker, and the coordinator keeps
serving the Citus local table. Without the fix the orphaned copy
lingers, so the test guards the change.
@codeforall

Copy link
Copy Markdown
Contributor

Thanks for the effort @copilot, but I don't think this change addresses the issue it's linked to (#8145).

Path mismatch. The reporter explicitly stated the move ran with shard_transfer_mode = auto and "it used logical replication for the job." That means the exercised path is CopyShardTablesViaLogicalReplication → LogicallyReplicateShards → CompleteNonBlockingShardTransfer. This PR only modifies CopyShardTablesViaBlockWrites, which that run never enters, so against the reported repro it's effectively a no-op.

The pattern is already handled on the real path. The logical-replication path already releases transient per-shard DDL memory everywhere via a localContext + per-iteration MemoryContextReset (e.g. ExecuteCreateConstraintsBackedByIndexCommands, CreatePartitioningHierarchy, index/FK creation, and the shard-table-creation loop in CopyShardTablesViaLogicalReplication itself). So the transient DDL buffering this PR removes isn't where the reported memory goes.

Data doesn't flow through the coordinator either. CopyShardsToNode dispatches SELECT worker_copy_table_to_node(...) tasks; the bytes are copied worker→worker. So a 70 GB coordinator peak is not data buffering, and it's not the per-shard command lists (a few KB × shards = MBs, not tens of GBs).

Given all transient contexts are already reset, the growth almost certainly lives in a session-lifetime context (CacheMemoryContext — relcache/catcache + Citus CitusTableCacheEntry for the whole colocation group of a deeply-partitioned 80 TB DB), or a genuine leak into a long-lived context, neither touched here.

Suggested next step before iterating on a fix: reproduce with logical replication on a many-partition colocation group and capture, during the climb:

SELECT * FROM pg_backend_memory_contexts ORDER BY total_bytes DESC LIMIT 30;

(or a MemoryContextStats(TopMemoryContext) dump). That will show which context actually dominates and point the fix at the right place.

The block-writes cleanup itself looks safe and reasonable as a standalone minor improvement, but I'd unlink it from #8145 rather than close the issue with it.

Copilot AI commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the effort @copilot, but I don't think this change addresses the issue it's linked to (#8145).

Path mismatch. The reporter explicitly stated the move ran with shard_transfer_mode = a...

Addressed by reverting the block-writes-only change in commit 62a05d0, since it does not affect the logical-replication path used in #8145. This PR is now decoupled from closing #8145.

Copilot AI changed the title Reduce coordinator memory growth in citus_move_shard_placement Revert block-writes shard-move memory change from this PR Jul 10, 2026
Copilot AI requested a review from codeforall July 10, 2026 13:14
Avoid populating full table cache entries when shard transfer only needs colocated intervals or placement metadata. Use resettable contexts for per-shard catalog reads to limit retained coordinator memory during logical moves.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: e5252196-f883-432f-970a-c1fd4f02e919
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: e5252196-f883-432f-970a-c1fd4f02e919
@ihalatci ihalatci changed the title Revert block-writes shard-move memory change from this PR Reduce coordinator metadata cache growth during shard moves Jul 14, 2026
@ihalatci

Copy link
Copy Markdown
Contributor

@codeforall how about this attempt?

@codecov

codecov Bot commented Jul 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.22807% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.72%. Comparing base (204ce6f) to head (a4fcba0).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8652   +/-   ##
=======================================
  Coverage   88.72%   88.72%           
=======================================
  Files         288      288           
  Lines       64385    64469   +84     
  Branches     8108     8119   +11     
=======================================
+ Hits        57125    57200   +75     
- Misses       4915     4924    +9     
  Partials     2345     2345           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

citus_move_shard_placement() uses lots of memory on the coordinator

4 participants