Skip to content

Avoid using TopMemoryContext#451

Open
mason-sharp wants to merge 1 commit intomainfrom
queue_memory_followup
Open

Avoid using TopMemoryContext#451
mason-sharp wants to merge 1 commit intomainfrom
queue_memory_followup

Conversation

@mason-sharp
Copy link
Copy Markdown
Member

  • Eliminate TopMemoryContext usage for spilled and spill-read entries. Entries now live in ApplyReplayContext and are cleaned up by its reset. Spill-read entries during replay are freed immediately after replication_handler, bounding replay memory to one entry at a time.

  • Fix int overflow on apply_replay_bytes. Was int, wrapped negative at ~2GB causing the spill threshold check to silently fail to activate spilling for very large in-memory queues. Changed to int64.

  • Simplify apply_replay_queue_append_entry signature from double pointers to direct pass-through, since the entry no longer needs to be relocated across memory contexts when spilled.

  • Track the in-flight spilled PQ buffer via apply_replay_pending_pqfree so it can be freed if replication_handler throws ERROR before the caller's PQfreemem runs. Defensive guard against malloc leaks on the exception path.

  • Cleaner separation of stream-path and replay-path entry cleanup in the main apply loop.

  • Fix mis-indented ConfigReloadPending check.

* Eliminate TopMemoryContext usage for spilled and spill-read entries.
  Entries now live in ApplyReplayContext and are cleaned up by its reset.
  Spill-read entries during replay are freed immediately after
  replication_handler, bounding replay memory to one entry at a time.

* Fix int overflow on apply_replay_bytes.  Was int, wrapped negative
  at ~2GB causing the spill threshold check to silently fail to
  activate spilling for very large in-memory queues.  Changed to int64.

* Simplify apply_replay_queue_append_entry signature from double
  pointers to direct pass-through, since the entry no longer needs to
  be relocated across memory contexts when spilled.

* Track the in-flight spilled PQ buffer via apply_replay_pending_pqfree
  so it can be freed if replication_handler throws ERROR before the
  caller's PQfreemem runs.  Defensive guard against malloc leaks on the
  exception path.

* Cleaner separation of stream-path and replay-path entry cleanup in
  the main apply loop.

* Fix mis-indented ConfigReloadPending check.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

📝 Walkthrough

Walkthrough

The replay-queue and spilling logic is refactored to track libpq "orphan" buffers across handler boundaries. The apply_replay_queue_append_entry API now takes entry and message directly and returns a boolean indicating spill status. In-memory queue entries are allocated in ApplyReplayContext and freed on reset, while spill-read entries are freed immediately when consumed. A deferred orphan PQ buffer is freed after replication_handler() completes.

Changes

Replay-Queue & Spill Memory Management

Layer / File(s) Summary
Global State & API
src/spock_apply.c (lines 138–146, 253–255)
New global apply_replay_pending_pqfree tracks deferred PQ buffer cleanup. Function signature of apply_replay_queue_append_entry changes to take (ApplyReplayEntry *entry, StringInfo msg) and return a boolean for spill status.
Core Queue & Spill Functions
src/spock_apply.c (lines 4336–4379, 4237–4260, 4184–4212)
apply_replay_queue_append_entry now writes spill files directly and returns boolean; apply_replay_queue_reset frees the orphaned PQ buffer and all queued from_pq buffers; apply_replay_spill_read_entry allocates entry structs in ApplyReplayContext for unified cleanup.
Apply Loop Wiring
src/spock_apply.c (lines 3058–3070, 3186–3201, 3220–3237)
Main apply loop captures spill status from append call, defers freeing of orphaned PQ buffer after replication_handler() returns, and immediately frees spill-read entries and their buffers when consumed.
Memory Ownership & Documentation
src/spock_apply.c (lines 4143–4147, 4283–4285, 4401)
Comments clarify that in-memory entries are allocated in ApplyReplayContext and freed on reset; spill-read entries are immediately freed; non-queued messages retain prior freeing semantics.

Poem

🐰 A rabbit hops through queues with care,
Freeing buffers, spilling with flair—
In contexts tidy, orphans deferred,
Till handlers finish their work, assured!
Now memory dances in harmony there. 🎭

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The PR title 'Avoid using TopMemoryContext' is related to one aspect of the changeset but does not capture the main objectives. The primary goals include memory management improvements, integer overflow fixes, and API simplification, while the title focuses narrowly on one specific change. Consider a more comprehensive title like 'Improve replay queue memory handling and fix integer overflow' to better reflect the main changes and objectives of the PR.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description comprehensively relates to the changeset, covering all major changes including memory context fixes, integer overflow fixes, API simplifications, and exception handling improvements.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch queue_memory_followup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codacy-production
Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 duplication

Metric Results
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@mason-sharp mason-sharp changed the title Improve replay queue memory handling Avoid using TopMemoryContext May 4, 2026
@mason-sharp mason-sharp requested a review from danolivo May 4, 2026 04:12
Comment thread src/spock_apply.c
static int apply_replay_spill_count = 0;
static int apply_replay_spill_read = 0;
/* In-flight spilled PQ buffer; freed by reset if ERROR skips PQfreemem. */
static char *apply_replay_pending_pqfree = NULL;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a reason we declined such an approach in Spock before: having free/reset machinery at two levels of the code hierarchy is hard to support and tends to be buggy. For example, this specific implementation doesn't free the entry structure itself after the apply.
One more issue - if spilling fails for some reason, it causes a memory leak of the pq-allocated data.

Another reason why we used TopMemoryContext is to highlight the general memory management issues: MessageContext is a core Context and can't be reallocated/reset by an extension. Multiple context switches are also not nice.

The better approach is to use a SpillMemoryContext that lives at the same level as the message-receiving code, more strictly caps memory usage, and does not depend on the COMMIT command. But it should be introduced after (or with) the memory management refactoring procedure.

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.

2 participants