Skip to content

Group slots: group-safe WAL retention for Spock multi-master clusters.#546

Open
ibrarahmad wants to merge 5 commits into
mainfrom
GROUP_SLOTS
Open

Group slots: group-safe WAL retention for Spock multi-master clusters.#546
ibrarahmad wants to merge 5 commits into
mainfrom
GROUP_SLOTS

Conversation

@ibrarahmad

Copy link
Copy Markdown
Contributor

This change adds group replication slots to Spock: one internally managed, permanently inactive logical slot per Spock database that pins WAL at the group-safe position for a multi-master mesh. It protects WAL retention across membership changes so a node can rejoin and catch up after downtime without WAL being removed too early, while avoiding over-retention when a downstream is merely slow. The feature is off by default (spock.group_slots_enabled) and adds no overhead unless enabled. A per-database group-slot background worker is started and stopped by the Spock manager based on the toggle, and the manager reloads configuration on SIGHUP so the setting takes effect without a restart.

Catalog state tracks group membership, membership generations, and per-member replay progress, and explicit node lifecycle handling (active, joining, parting) ensures membership churn does not lose or strand WAL. Testing adds the TAP test 105_group_slots and runs against the existing suite. The branch also includes a small commit that aligns include ordering in src/spock_manager.c and the entries in tests/tap/schedule with main, so it merges into main with no conflicts.

Ibrar Ahmed added 3 commits July 22, 2026 18:53
Introduce the group-slot mechanism (spock_group_slot.c) wired through the
manager and worker, with the 6.0.0--6.0.1 catalog upgrade and a TAP test.
Also document large-transaction apply and failover slots.
The remove path now freezes via begin_part before slot teardown and
resumes via complete_part, and join captures safe_horizon as the base
point, so no defined group-slot function is left uncalled. Per-member
confirmed_lsn is set NULL since it is not attributable from local
catalogs. Comments are cut to the repo's minimal style.
The group replication slots branch and main independently inserted
lines at the same locations in src/spock_manager.c and
tests/tap/schedule, which produced merge conflicts.

Reorder the additions so this branch matches main at those points.
In spock_manager.c, keep utils/lsyscache.h immediately before
utils/memutils.h and move utils/guc.h after it.  In
tests/tap/schedule, add the 032_lolor_largeobject_repset,
033_zodan_lolor_add_node, and
105_sub_disable_retransmit_after_disconnect entries and move the
group replication slots test ahead of the regression tests section.

This only reorders #include and test-schedule lines; there is no
change in behavior.
@ibrarahmad
ibrarahmad requested a review from mason-sharp July 25, 2026 06:17
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 91c0b69b-0f7e-495f-a302-2454edd0b81d

📥 Commits

Reviewing files that changed from the base of the PR and between 4b2cbc4 and 1703d21.

📒 Files selected for processing (1)
  • src/spock_group_slot.c

📝 Walkthrough

Walkthrough

Changes

The PR adds opt-in group replication slots with durable SQL state, safe advancement and repair controls, background workers, node lifecycle integration, documentation, and TAP coverage. It also adds large-transaction guidance, Zodan failover-slot documentation, and updates the Spock version to 6.0.1.

Group replication slots

Layer / File(s) Summary
Public contracts and configuration
include/spock*.h, src/spock.c, include/spock.h, docs/spock_release_notes.md
Adds group-slot interfaces, safety modes, GUCs, worker lookup, and 6.0.1 release metadata.
SQL state and advancement control
sql/spock--6.0.0--6.0.1.sql
Creates group-slot catalogs and implements safe-horizon evaluation, advancement, repair, membership transitions, and access restrictions.
Worker and node lifecycle
src/spock_group_slot.c, src/spock_manager.c, src/spock_worker.c, src/spock_functions.c
Adds local slot management, per-database worker execution, manager wiring, reload handling, and node create/drop integration.
Node membership workflows
samples/Z0DAN/zodan.sql, samples/Z0DAN/zodremove.sql
Adds guarded group-slot join and part begin/complete calls to node addition and removal workflows.
Group-slot validation
tests/tap/t/105_group_slots.pl, tests/tap/schedule
Tests naming, persistence, blockers, membership generations, advancement, retention, repair, and worker shutdown.
Group-slot operational documentation
docs/managing/group_slots.md, docs/managing/index.md
Documents configuration, state evaluation, lifecycle procedures, repair controls, and disabled-feature behavior.

Large transaction apply guidance

Layer / File(s) Summary
Large transaction mitigation guidance
docs/large_transaction_apply.md
Documents apply delays, WAL pinning, batching, index and collation costs, conflict logging, streaming, and mitigation priorities.

Zodan failover slot documentation

Layer / File(s) Summary
Failover slot operations
docs/modify/zodan/failover_slots.md
Documents PG15/16 and PG17/18 configuration differences, Zodan slot creation behavior, verification queries, and related guides.

Poem

I’m a rabbit with a slot in the ground,
Safe LSN carrots hop round and round.
Workers wake, joins pause, parts complete,
WAL stays tucked beneath my feet.
Six-point-zero-one—what a treat!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: group replication slots for group-safe WAL retention.
Description check ✅ Passed The description matches the changeset, covering group slots, worker behavior, membership handling, and tests.
Docstring Coverage ✅ Passed Docstring coverage is 93.75% 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.
✨ 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 GROUP_SLOTS

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.

@codacy-production

codacy-production Bot commented Jul 25, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 1 medium

Results:
1 new issue

Category Results
Complexity 1 medium

View in Codacy

🟢 Metrics 34 complexity · 0 duplication

Metric Results
Complexity 34
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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 14

🧹 Nitpick comments (4)
sql/spock--6.0.0--6.0.1.sql (3)

68-72: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Dead exclusion clause.

spkgrp_… can never match LIKE 'spk\_%' (the escaped _ requires a literal underscore at position 4), so the slot_name <> COALESCE(spock.local_group_slot_name(), '') guard is unreachable. Harmless, but it costs a local_group_slot_name() call per row and obscures intent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sql/spock--6.0.0--6.0.1.sql` around lines 68 - 72, Remove the unreachable
slot_name <> COALESCE(spock.local_group_slot_name(), '') predicate from the
logical replication slot query, leaving the database, plugin, slot_type, and
slot_name LIKE filters unchanged.

11-54: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Consider marking the new state tables as extension config so they survive pg_dump.

Without pg_catalog.pg_extension_config_dump(), group_slot_state, group_slot_membership, and group_slot_member_progress are recreated empty on restore, losing membership generation and freeze state. Other Spock catalog tables use this pattern.

♻️ Suggested addition after the table definitions
SELECT pg_catalog.pg_extension_config_dump('spock.group_slot_state', '');
SELECT pg_catalog.pg_extension_config_dump('spock.group_slot_membership', '');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sql/spock--6.0.0--6.0.1.sql` around lines 11 - 54, Mark all three new state
tables—spock.group_slot_state, spock.group_slot_membership, and
spock.group_slot_member_progress—as extension configuration tables by adding
pg_catalog.pg_extension_config_dump calls after their definitions, so their data
is included in pg_dump and restored.

781-788: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

group_slot_refresh_members() is left executable by PUBLIC.

It is an internal mutator of the group-slot catalog tables; revoke it alongside the other maintenance functions for a consistent surface.

🔒️ Proposed addition
 REVOKE ALL ON FUNCTION spock.group_slot_complete_part(name) FROM PUBLIC;
+REVOKE ALL ON FUNCTION spock.group_slot_refresh_members(bigint, interval) FROM PUBLIC;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sql/spock--6.0.0--6.0.1.sql` around lines 781 - 788, Add a REVOKE ALL
statement for spock.group_slot_refresh_members() FROM PUBLIC alongside the
existing group-slot maintenance function revocations, preserving the same
privilege-restriction pattern.
docs/managing/group_slots.md (1)

58-72: 🩺 Stability & Availability | 🔵 Trivial

Add WAL-retention guidance for a persistently blocked horizon.

While stale_progress (or a join/part) holds, the slot never advances and pg_wal grows without bound. Worth documenting monitoring of spock.group_slot_status() / pg_replication_slots.restart_lsn plus the interaction with max_slot_wal_keep_size (which can invalidate the group slot and require spock.repair_group_slot('recreate')).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/managing/group_slots.md` around lines 58 - 72, The “When advancement is
refused” section should add WAL-retention guidance for persistently blocked
horizons, especially stale_progress, join, and part states. Document monitoring
spock.group_slot_status() and pg_replication_slots.restart_lsn, and explain that
max_slot_wal_keep_size may invalidate the group slot, requiring
spock.repair_group_slot('recreate').
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/large_transaction_apply.md`:
- Around line 14-15: Update the compound modifier in the reproduction
description to hyphenate “600,000-row INSERT,” preserving the surrounding
wording and meaning.
- Around line 102-125: Revise the “Turn off spock.check_all_uc_indexes” section
to state that ALTER SYSTEM changes persistent subscriber-wide server
configuration, affecting all relevant apply workers rather than only the load
session. Instruct operators to record and explicitly restore the previous
setting after the load, and warn that an interrupted load may leave
secondary-unique conflict checking disabled.
- Around line 127-136: Update the unique-index conflict explanation in the
TRANSDISCARD section to identify TRANSDISCARD as the default
spock.exception_behaviour. Describe that failed apply rows are skipped and
logged, and only state that the subscription is disabled when configuration
explicitly sets sub_disable; remove the claim that sub_disable is the default.
- Around line 64-76: Update the transaction batching example in
docs/large_transaction_apply.md to state that the DO block must execute
top-level with auto-commit enabled, not inside an existing transaction. Document
that transaction-wrapped scripts or framework migrations should use client-side
batching instead.

In `@docs/managing/group_slots.md`:
- Around line 48-51: Update the safe LSN description to state that
spock.group_slot_min_downstream_lsn() considers the minimum confirmed_flush_lsn
across every spk_* logical slot in the database, including leftover or slow
subscription slots. Add spock.group_slot_safe_horizon() and the relevant
join/part functions to the Functions section where they are referenced.

In `@docs/modify/zodan/failover_slots.md`:
- Around line 115-118: Update the explanatory comment above primary_conninfo to
remove the blanket claim that pg_basebackup -R does not include dbname, and
accurately state that PostgreSQL 17+ records dbname only when it was explicitly
provided through the connection string or environment.
- Around line 8-15: Update the introductory mechanism statement in
failover_slots.md to say that PostgreSQL introduced native failover-slot
synchronization in PG17 and retained sync_replication_slots in PG18, then
separately identify the PG18 Spock worker registration change. Keep the numbered
PG15/16 and PG17/18 scope descriptions unchanged.
- Around line 210-218: Update the standby slot readiness query to exclude
temporary slots, evaluate only rows whose invalidation_reason is null, and
require both synced and failover to be true for the remaining logical slots.
Ensure the PG17/18 readiness check fails when any eligible slot violates these
conditions.

In `@samples/Z0DAN/zodremove.sql`:
- Around line 490-492: Update the RAISE NOTICE statement in the group-slot
completion flow to generate the recovery command with a valid SQL-literal
argument. Replace the unsupported %L placeholder usage by pre-formatting or
quote-escaping target_node_name with format(... %L ...) or quote_literal(),
while preserving the existing notice text and command.

In `@sql/spock--6.0.0--6.0.1.sql`:
- Around line 751-753: Update the generation-handling flow around the
group_slot_state lookup and v_newgen assignment to explicitly detect when no
metadata row exists, matching the guard and error behavior of
group_slot_begin_part(). Raise that error before evaluating v_gen + 1, while
preserving the existing increment path when metadata is present.
- Around line 476-499: Guard against a NULL v_target after assigning
COALESCE(target_lsn, v_safe) in the slot-advance flow. Before the
pg_replication_slots lookup and spock.group_slot_state UPDATE, raise a clear
exception when both target_lsn and the evaluated safe_lsn are NULL, preserving
the existing advance and update behavior for non-NULL targets.
- Around line 624-632: Update group_slot_begin_join so its missing-metadata
branch does not call spock.group_slot_worker_tick(). Seed the required
group_slot_state row directly using the existing metadata initialization path,
or raise the established directive error, then reread membership_generation
before computing v_newgen. Preserve the existing generation increment behavior.

In `@src/spock_group_slot.c`:
- Around line 161-176: Update the teardown SQL in the SPI_execute block so
group_slot_state rows are deleted only for replication slots successfully
selected and dropped by the NOT s.active cleanup query. Preserve metadata for
active slots and emit a warning when any slot remains active or otherwise was
not dropped, preventing orphaned slots from losing their cleanup metadata.
- Around line 133-140: Guard the metadata seed INSERT in the surrounding
initialization path before calling SPI_execute_with_args, using a to_regclass()
check for spock.group_slot_state. If the catalog table is absent, skip the
INSERT and emit only a warning so spock.create_node() continues; preserve the
existing result-code warning for executed INSERTs.

---

Nitpick comments:
In `@docs/managing/group_slots.md`:
- Around line 58-72: The “When advancement is refused” section should add
WAL-retention guidance for persistently blocked horizons, especially
stale_progress, join, and part states. Document monitoring
spock.group_slot_status() and pg_replication_slots.restart_lsn, and explain that
max_slot_wal_keep_size may invalidate the group slot, requiring
spock.repair_group_slot('recreate').

In `@sql/spock--6.0.0--6.0.1.sql`:
- Around line 68-72: Remove the unreachable slot_name <>
COALESCE(spock.local_group_slot_name(), '') predicate from the logical
replication slot query, leaving the database, plugin, slot_type, and slot_name
LIKE filters unchanged.
- Around line 11-54: Mark all three new state tables—spock.group_slot_state,
spock.group_slot_membership, and spock.group_slot_member_progress—as extension
configuration tables by adding pg_catalog.pg_extension_config_dump calls after
their definitions, so their data is included in pg_dump and restored.
- Around line 781-788: Add a REVOKE ALL statement for
spock.group_slot_refresh_members() FROM PUBLIC alongside the existing group-slot
maintenance function revocations, preserving the same privilege-restriction
pattern.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8dd116ca-d70d-4222-ad11-ff3477c37afa

📥 Commits

Reviewing files that changed from the base of the PR and between e8916f9 and 9c9335a.

📒 Files selected for processing (18)
  • docs/large_transaction_apply.md
  • docs/managing/group_slots.md
  • docs/managing/index.md
  • docs/modify/zodan/failover_slots.md
  • docs/spock_release_notes.md
  • include/spock.h
  • include/spock_group_slot.h
  • include/spock_worker.h
  • samples/Z0DAN/zodan.sql
  • samples/Z0DAN/zodremove.sql
  • sql/spock--6.0.0--6.0.1.sql
  • src/spock.c
  • src/spock_functions.c
  • src/spock_group_slot.c
  • src/spock_manager.c
  • src/spock_worker.c
  • tests/tap/schedule
  • tests/tap/t/105_group_slots.pl

Comment thread docs/large_transaction_apply.md Outdated
Comment on lines +64 to +76
```sql
-- instead of one big INSERT
DO $$
DECLARE
batch_size int := 5000;
start_id int;
BEGIN
FOR start_id IN 1 .. 60000 BY batch_size LOOP
INSERT INTO my_table SELECT ... FROM ... WHERE id BETWEEN start_id
AND start_id + batch_size - 1;
COMMIT;
END LOOP;
END $$;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Repository files around target:\n'
git ls-files | rg '(^|/)large_transaction_apply\.md$|docs/large_transaction_apply\.md' || true

printf '\nTarget document excerpt:\n'
sed -n '1,120p' docs/large_transaction_apply.md 2>/dev/null | cat -n

printf '\nSearch for transaction/top-level mentions:\n'
rg -n -i 'transaction|top[- ]level|autocommit|commit|nested|DO \$\$|block' docs -S || true

printf '\nPostgreSQL relevant behavior from installed psql if available:\n'
if command -v psql >/dev/null 2>&1; then
  psql --version || true
  cat >/tmp/postgres_commit_in_do.sql <<'SQL'
\echo 'outside transaction 1'
DO $$
BEGIN
  RAISE NOTICE 'block executed';
END $$;
\echo 'outside transaction 2'
BEGIN;
DO $$
BEGIN
  RAISE NOTICE 'inside transaction';
END $$;
ROLLBACK;
SQL
  psql -h localhost -U postgres -f /tmp/postgres_commit_in_do.sql 2>&1 || true
else
  echo 'psql not available'
fi

Repository: pgEdge/spock

Length of output: 50370


🌐 Web query:

PostgreSQL DO block COMMIT transaction control top-level query invalid transaction context ERROR

💡 Result:

The PostgreSQL error "invalid transaction context" (SQLSTATE 2D000) when using COMMIT or ROLLBACK within a DO block occurs because transaction control commands are only permitted when the DO block is executed in its own transaction [1][2]. If a DO block is executed inside an existing transaction block (e.g., if you have issued BEGIN or are running within a wrapper that starts a transaction), the code inside the DO block cannot commit or roll back that transaction [1][2]. To resolve this: 1. Execute the DO block at the top level: Ensure the DO command is not wrapped in an explicit BEGIN...COMMIT block or any other surrounding transaction [1][2]. 2. Avoid nested calls: Transaction control is only possible in DO or CALL invocations from the top level, or within nested CALL/DO chains that do not have any other intervening commands (such as SELECT or DML statements) [2][3]. 3. Check your client/environment: Some interfaces or GUI tools (like certain modes in pgAdmin or transaction-wrapped scripts) automatically start a transaction, which triggers this error [4]. Running the command directly in psql or ensuring the transaction is not auto-started is often necessary [4]. Essentially, COMMIT/ROLLBACK in a DO block is only valid if PostgreSQL can manage the transaction boundaries for that block itself [1][5]. If the block is already part of a larger, client-initiated transaction, it lacks the authority to terminate it [1][6].

Citations:


Document the top-level execution requirement.

COMMIT inside this DO block fails when the statement is run inside an existing BEGIN/transaction block, which is common in scripts or framework migrations. State that the example requires auto-commit/top-level execution and that transaction-wrapped environments need client-side batching instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/large_transaction_apply.md` around lines 64 - 76, Update the transaction
batching example in docs/large_transaction_apply.md to state that the DO block
must execute top-level with auto-commit enabled, not inside an existing
transaction. Document that transaction-wrapped scripts or framework migrations
should use client-side batching instead.

Comment thread docs/large_transaction_apply.md
Comment on lines +127 to +136
**Important: you lose unique-index conflict protection while it is
off.** With the GUC on, Spock catches the case where an incoming row
collides with an existing local row on a secondary unique index (not
the primary key or replica identity) and resolves it through the normal
conflict path. With the GUC off, that detection does not happen. If
a colliding row arrives, the apply worker still tries the INSERT, the
heap rejects it with a duplicate-key violation, and (because the
default `spock.exception_behaviour` is `sub_disable`) the subscription
is disabled until an operator inspects `spock.exception_log` and
re-enables it.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
git ls-files | rg '(^|/)large_transaction_apply\.md$|docs/'

echo "== target section =="
if [ -f docs/large_transaction_apply.md ]; then
  sed -n '110,155p' docs/large_transaction_apply.md | nl -ba -v110
else
  echo "docs/large_transaction_apply.md not found"
fi

echo "== search exception_behaviour mentions =="
rg -n --hidden --glob '!/.git' 'spock\.exception_behaviour|exception_behaviour|TRANSDISCARD|sub_disable|exception_log' . | head -200

Repository: pgEdge/spock

Length of output: 4233


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== target section =="
python3 - <<'PY'
from pathlib import Path
p = Path('docs/large_transaction_apply.md')
lines = p.read_text().splitlines()
for i in range(120, 145+1):
    print(f"{i}: {lines[i-1]}")
PY

echo "== exception_behaviour/sub_disable/TRANSDISCARD/exception_log =="
rg -n --hidden --glob '!/.git' 'spock\.exception_behaviour|exception_behaviour|TRANSDISCARD|sub_disable|exception_log' ./src ./spock ./pg 2>/dev/null || true

echo "== likely source files near exception_behaviour =="
rg -n --hidden --glob '!/.git' 'spock_exception_behaviour|sub_disable|TRANSDISCARD' . 2>/dev/null | head -300

Repository: pgEdge/spock

Length of output: 33078


Don’t describe TRANSDISCARD as sub_disable.

spock.exception_behaviour defaults to TRANSDISCARD; in that mode failed apply rows are skipped and logged, not the whole transaction discarded from PostgreSQL, and the apply worker does not reach sub_disable unless configuration explicitly sets it. Update this section to state the actual default and avoid calling it sub_disable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/large_transaction_apply.md` around lines 127 - 136, Update the
unique-index conflict explanation in the TRANSDISCARD section to identify
TRANSDISCARD as the default spock.exception_behaviour. Describe that failed
apply rows are skipped and logged, and only state that the subscription is
disabled when configuration explicitly sets sub_disable; remove the claim that
sub_disable is the default.

Comment thread docs/managing/group_slots.md Outdated
Comment on lines +48 to +51
* A per-database background worker periodically computes the **safe LSN** as the
minimum confirmed flush/replay LSN across all active and relevant downstream
members, and advances the group slot to that horizon — but only when it is
safe to do so.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Horizon description is looser than the implementation.

spock.group_slot_min_downstream_lsn() takes the minimum confirmed_flush_lsn over every spk_* logical slot in the database, not only slots for active/relevant members — any leftover or slow subscription slot pins the horizon. Also, spock.group_slot_safe_horizon() and the join/part functions are referenced elsewhere in this page but absent from the Functions section.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/managing/group_slots.md` around lines 48 - 51, Update the safe LSN
description to state that spock.group_slot_min_downstream_lsn() considers the
minimum confirmed_flush_lsn across every spk_* logical slot in the database,
including leftover or slow subscription slots. Add
spock.group_slot_safe_horizon() and the relevant join/part functions to the
Functions section where they are referenced.

Comment thread sql/spock--6.0.0--6.0.1.sql
Comment thread sql/spock--6.0.0--6.0.1.sql
Comment thread sql/spock--6.0.0--6.0.1.sql
Comment thread src/spock_group_slot.c
Comment thread src/spock_group_slot.c
Ibrar Ahmed added 2 commits July 25, 2026 22:18
Add the missing utils/snapmgr.h include so the extension builds under
-Werror=implicit-function-declaration (this was failing every CI job).

Also fix the review findings: keep group-slot metadata for a still-active
slot instead of orphaning it, guard the metadata seed against a missing
catalog during version skew, raise clear errors when group-slot metadata
is absent (advance, begin_join, complete_part) instead of NOT NULL
violations or creating a slot inside a write transaction, quote the
recovery command in zodremove, and tighten the docs.
get_database_name() moved from commands/dbcommands.h to utils/lsyscache.h
in PG19. Without it the PG19 build fails with an implicit-declaration
error (and silently truncates the returned pointer under older compilers).
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.

1 participant