Skip to content

fix pg14 recovery fix#5

Merged
gaoxueyu merged 4 commits into
IvorySQL:mainfrom
NotHimmel:main
Jul 23, 2026
Merged

fix pg14 recovery fix#5
gaoxueyu merged 4 commits into
IvorySQL:mainfrom
NotHimmel:main

Conversation

@NotHimmel

Copy link
Copy Markdown
Collaborator

No description provided.

Pulls in two fixes now merged upstream:
- Gate the pg_publication_rel.prattrs column-list lookup on PG15+,
  fixing schema fetch on PG14 where the column does not exist.
- Skip permanently unrecoverable tables during moonlink recovery
  instead of crash-looping the bgworker (e.g. after DROP DATABASE on
  a database that still contained mooncake tables).

Cargo.lock picks up the new tracing dependency of moonlink_backend.
propagate_compatible_mode read ivorysql.compatible_mode with
Spi::get_one, which pgrx routes through SpiClient::update. Its
mark_mutable call invokes GetCurrentTransactionId, assigning the
calling backend a real write transaction id as a side effect.

The moonlink RPC issued later in create_table makes the walsender run
CREATE_REPLICATION_SLOT ... USE_SNAPSHOT, whose snapshot builder waits
for every in-progress write transaction to finish - including ours -
while our backend sits in block_on waiting for that same RPC to
return. The resulting circular wait hangs create_table forever and is
invisible to the deadlock detector, since one side waits on a socket
rather than a lock.

Read the GUC through Spi::connect + client.select instead, which never
marks the transaction mutable, so the backend keeps its virtual xid and
the snapshot builder has nothing to wait for.
The moonlink bgworker binds its Unix socket asynchronously after
postmaster start, so the first mooncake call in a fresh cluster could
hit ECONNREFUSED and panic. Worse, the panic fired inside the STREAM
LazyLock initializer, poisoning it and permanently breaking every
subsequent mooncake call in that backend.

Retry the connect with exponential backoff (50ms doubling, capped at
1s) for up to 10 seconds before giving up.
The extension-drop watcher decided whether pg_mooncake itself was being
dropped with SELECT true INTO is_mooncake_drop ... LIMIT 1. When the
query returns zero rows, SELECT INTO overwrites the variable with NULL
even if it was initialized to false, and IF NOT NULL is not taken - so
the cleanup body ran on every sql_drop event. Any DROP TABLE would then
try to drop the moonlink replication slot and publication, and the
watcher self-removed, leaving nothing to clean up on a real
DROP EXTENSION.

Use IF NOT EXISTS (...) instead, which has no NULL case.
@gaoxueyu
gaoxueyu merged commit 1132ce1 into IvorySQL:main Jul 23, 2026
3 checks passed
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