Skip to content

Make large object migration node-local#38

Open
danolivo wants to merge 1 commit into
mainfrom
spoc-583
Open

Make large object migration node-local#38
danolivo wants to merge 1 commit into
mainfrom
spoc-583

Conversation

@danolivo

Copy link
Copy Markdown
Contributor

The migration functions shuffle rows between pg_catalog.pg_largeobject and the lolor tables. The native side is a system catalog that logical decoding never streams, so each node holds an independent set of native large objects and the migration can only ever be performed per node. The lolor side, however, consists of ordinary replicated tables, so the bulk migration DML used to leak to subscribers: migrate_from_native() fanned out rows that remote nodes must produce themselves, and migrate_to_native() replicated its deletes while the re-created native objects stayed local, destroying large objects on the subscriber side.

When spock is installed, run both functions under spock.repair_mode() so the migration DML is excluded from logical decoding. Enter repair mode only when spock is fully operational (extension installed, function present, library preloaded) and leave it again right after the migration DML, so statements later in the caller's transaction replicate normally. The pg_extension check also prevents a planted 'spock' schema from being executed with superuser rights.

Without spock the DML cannot be excluded from decoding, so refuse to migrate while logical replication slots exist in the database: migrate_from_native() warns and returns -1 (0 stays reserved for "nothing to migrate"), migrate_to_native() raises an error, which also makes DROP EXTENSION fail instead of silently dropping the lolor tables with the objects still inside.

After a successful migration, emit a NOTICE reminding the operator to run the same migration on each replica before modifying large objects.

Update README, docs and release notes accordingly: the previous "migrate on one node and let the rows replicate" model is replaced by the node-local model, orchestrated e.g. via spock.replicate_ddl().

The migration functions shuffle rows between pg_catalog.pg_largeobject
and the lolor tables. The native side is a system catalog that logical
decoding never streams, so each node holds an independent set of native
large objects and the migration can only ever be performed per node.
The lolor side, however, consists of ordinary replicated tables, so the
bulk migration DML used to leak to subscribers: migrate_from_native()
fanned out rows that remote nodes must produce themselves, and
migrate_to_native() replicated its deletes while the re-created native
objects stayed local, destroying large objects on the subscriber side.

When spock is installed, run both functions under spock.repair_mode()
so the migration DML is excluded from logical decoding. Enter repair
mode only when spock is fully operational (extension installed,
function present, library preloaded) and leave it again right after the
migration DML, so statements later in the caller's transaction
replicate normally. The pg_extension check also prevents a planted
'spock' schema from being executed with superuser rights.

Without spock the DML cannot be excluded from decoding, so refuse to
migrate while logical replication slots exist in the database:
migrate_from_native() warns and returns -1 (0 stays reserved for
"nothing to migrate"), migrate_to_native() raises an error, which also
makes DROP EXTENSION fail instead of silently dropping the lolor tables
with the objects still inside.

After a successful migration, emit a NOTICE reminding the operator to
run the same migration on each replica before modifying large objects.

Update README, docs and release notes accordingly: the previous
"migrate on one node and let the rows replicate" model is replaced by
the node-local model, orchestrated e.g. via spock.replicate_ddl().
@danolivo danolivo requested a review from mason-sharp June 10, 2026 13:01
@danolivo danolivo self-assigned this Jun 10, 2026
@danolivo danolivo added the bug Something isn't working label Jun 10, 2026
@coderabbitai

coderabbitai Bot commented Jun 10, 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

Run ID: 367e0a41-887c-427a-958e-62bf5bd394d1

📥 Commits

Reviewing files that changed from the base of the PR and between 3f0dd90 and 79f3cda.

📒 Files selected for processing (4)
  • README.md
  • docs/index.md
  • docs/lolor_release_notes.md
  • lolor--1.2.2--1.3.0.sql

📝 Walkthrough

Walkthrough

This PR adds logical replication awareness to large-object migration functions by detecting replication slots and conditionally using spock.repair_mode() to suppress migration DML replication. When spock is unavailable and slots exist, the behavior differs: migrate_from_native() warns and returns -1, while migrate_to_native() raises an exception. Documentation is updated across README, index, and release notes to clarify node-local migration semantics and OID collision handling.

Changes

Replication-safe large-object migration with spock repair mode

Layer / File(s) Summary
Migration function replication safety logic
lolor--1.2.2--1.3.0.sql
lolor.migrate_from_native() and lolor.migrate_to_native() now detect logical replication slots and conditionally enable spock.repair_mode() to prevent migration DML replication. When spock is unavailable and slots exist, migrate_from_native() warns and returns -1, while migrate_to_native() raises an exception with hint. Both functions emit notices indicating local-only execution and re-disable repair mode after migration.
Replication behavior documentation
README.md, docs/index.md, docs/lolor_release_notes.md
Documentation clarifies that spock.repair_mode() suppresses migration DML replication, explains failure/warning behavior when spock is absent and replication slots exist, documents that large-object migration is node-local (native pg_largeobject objects never replicate), and describes OID collision risks for preserved native OIDs versus collision-free behavior for newly created node-encoded objects.

Poem

🐰 Through slots and modes the objects hop,
With spock repair they never stop,
Each node migrates its local store,
No replication, safe and sure!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Make large object migration node-local' directly summarizes the main architectural change in the changeset, clearly identifying the primary shift from cross-node replication to node-local migration.
Description check ✅ Passed The description comprehensively explains the rationale, implementation, and behavior changes related to making large object migration node-local, including spock integration, error handling, and documentation updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch spoc-583

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

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant