Skip to content

Conversation

@danolivo
Copy link
Contributor

No description provided.

The SpockGroupEntry structure contained a redundant key field that duplicated
the key already embedded in its progress member (SpockGroupEntry.key vs
SpockGroupEntry.progress.key). This redundancy violated the DRY principle and
created potential for inconsistency if the two keys ever diverged.

This commit removes the duplicate key field from SpockGroupEntry, relying
solely on the key embedded in SpockApplyProgress. The hash table already uses
SpockProgressKey (the first field of SpockApplyProgress) as the hash key,
making the separate SpockGroupEntry.key field unnecessary.

Changes:

1. Structural cleanup:
   - Removed SpockGroupEntry.key field (the duplicate)
   - Kept SpockApplyProgress.key as the single source of truth
   - Renamed SpockGroupKey to SpockProgressKey for clarity

2. Code quality improvements:
   - Created init_progress_fields() helper for safe initialization
   - Replaced fragile pointer arithmetic with explicit field initialization
   - Follows PostgreSQL conventions (similar to CommitTsShmemInit)
   - Added comprehensive documentation explaining hash table design

3. Documentation and comments:
   - Added header explaining Group Registry architecture
   - Clarified that SpockApplyProgress.key MUST be first field
   - Documented persistence strategy (WAL + file snapshot)
   - Improved TODO comments to be actionable

The functional behavior is unchanged; this is a refactoring that improves
code quality and reduces redundancy.
Being loaded via shared_preload_libraries, Spock always initializes its
shared memory segment and hash tables in the postmaster process during
shmem_startup_hook. The shmem_startup_hook is called exactly once per
postmaster lifetime while holding AddinShmemInitLock.

There is no case where the postmaster does not call shmem_startup_hook()
after allocating shared memory. Also, there is no case where the postmaster
performs any operations requiring Spock's shared memory before initialization.

During recovery, the evidence that shared memory is already initialized and
operable is the fact that redo operations can acquire locks and access the
hash tables.

This commit removes the redundant spock_shmem_attach() routine and its calls
from checkpoint hook, WAL redo startup, and bgworker initialization. This
simplifies the code by eliminating the attach/detach complexity.

Changes:

1. Removed spock_shmem_attach() function entirely
   - Startup process, checkpointer, and bgworkers no longer need to "attach"
   - All processes can directly access shared memory after postmaster init
   - Removed the static 'attached' flag tracking per-process attachment

2. Simplified spock_group_shmem_startup()
   - Removed 'found' parameter (always creating new structures)
   - Removed conditional file loading (always load on initialization)
   - The function is only called once via shmem_startup_hook, so checks
     for existing structures are unnecessary

3. Simplified spock_shmem_init_internal()
   - Removed 'found' return value and tracking
   - Removed conditional initialization (if (!SpockCtx), etc.)
   - ShmemInit* functions are safely called once under AddinShmemInitLock
   - Changed return type from bool to void

4. Code quality improvements
   - Updated comments to reflect simplified initialization model
   - Improved DEBUG log message clarity
   - Removed outdated references to 'all_found' parameter

Benefits:
- Eliminates ~70 lines of unnecessary attachment logic
- Makes initialization flow clearer and easier to understand
- Removes per-process attachment tracking overhead
- Prevents potential bugs from missed spock_shmem_attach() calls

The functional behavior is unchanged; all processes still have access to
Spock's shared memory structures after postmaster startup.
Shape the spock_group module a little:

* Remove unused lookup function.
* Make spock_group_foreach static, forasmuch as no one uses it outside
  the module.
* Add forgotten ‘extern’ declarations.
There are plenty of places where Spock touches shared memory structures that
may cause races. It is always an issue, even considering these structures are
rarely accessed for writing.

But the progress state is a high-frequency updated structure, and guarding it with a lock is critical.
After moving to HTAB implementation, we actually don't have a target
connection. So, remove it. While here, fix forgotten 'extern' declaration
in the 'spock_group.h' module.
In Spock 5, we used to employ a progress table and a transactional snapshot
to ensure that the progress corresponds to the replication slot
(snapshot, LSN), and we could request this state at any time until
the transaction ends.

With an HTAB, it's no longer true, and we need to invent extra hacks. With this
commit, we take the progress state right before LR slot creation, which is as
close as possible to the real state.

It is still not entirely consistent in the case of Z0DAN, but while we use it
just for information, it is ok.

XXX:
The code related to table syncing stays as is. Right now, we aren't sure if
the progress state needs to be corrected if we re-sync a single table from
the database. So, just keep the code untouched.
@danolivo danolivo requested a review from mason-sharp December 30, 2025 09:39
@danolivo danolivo self-assigned this Dec 30, 2025
@danolivo danolivo added the enhancement New feature or request label Dec 30, 2025
@danolivo danolivo marked this pull request as draft December 30, 2025 11:41
@danolivo danolivo marked this pull request as ready for review December 30, 2025 11:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants