pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Heikki Linnakangas <hlinnaka@iki.fi>
To: Alexander Korotkov <aekorotkov@gmail.com>
To: Alvaro Herrera <alvherre@alvh.no-ip.org>
Cc: Pavel Borisov <pashkin.elfe@gmail.com>
Cc: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Cc: Kartyshov Ivan <i.kartyshov@postgrespro.ru>
Cc: Euler Taveira <euler@eulerto.com>
Cc: Thomas Munro <thomas.munro@gmail.com>
Cc: Peter Eisentraut <peter@eisentraut.org>
Cc: Amit Kapila <amit.kapila16@gmail.com>
Cc: Dilip Kumar <dilipbalaut@gmail.com>
Cc: Peter Smith <smithpb2250@gmail.com>
Cc: pgsql-hackers@lists.postgresql.org
Subject: Re: [HACKERS] make async slave to wait for lsn to be replayed
Date: Thu, 11 Apr 2024 01:46:04 +0300
Message-ID: <b155606b-e744-4218-bda5-29379779da1a@iki.fi> (raw)
In-Reply-To: <CAPpHfdtS4RPw3XpNL2zbS+jipm9mx=4Nv6zvyEdR4fRPvb0wrw@mail.gmail.com>
References: <CAPpHfdvnaDextc4oV6cajLbq1Om4_q+LE+tSCnk2defY2TKD4w@mail.gmail.com>
	<202404051815.eri4u5q6oj26@alvherre.pgsql>
	<CAPpHfdtS4RPw3XpNL2zbS+jipm9mx=4Nv6zvyEdR4fRPvb0wrw@mail.gmail.com>

On 07/04/2024 00:52, Alexander Korotkov wrote:
> On Fri, Apr 5, 2024 at 9:15 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
>> I'm still concerned that WaitLSNCleanup is only called in ProcKill.
>> Does this mean that if a process throws an error while waiting, it'll
>> not get cleaned up until it exits?  Maybe this is not a big deal, but it
>> seems odd.
> 
> I've added WaitLSNCleanup() to the AbortTransaction().  Just pushed
> that together with the improvements upthread.

Race condition:

1. backend: pg_wal_replay_wait('0/1234') is called. It calls WaitForLSN
2. backend: WaitForLSN calls addLSNWaiter('0/1234'). It adds the backend 
process to the LSN heap and returns
3. replay:  rm_redo record '0/1234'
4. backend: WaitForLSN enters for-loop, calls GetXLogReplayRecPtr()
5. backend: current replay LSN location is '0/1234', so we exit the loop
6. replay: calls WaitLSNSetLatches()

In a nutshell, it's possible for the loop in WaitForLSN to exit without 
cleaning up the process from the heap. I was able to hit that by adding 
a delay after the addLSNWaiter() call:

> TRAP: failed Assert("!procInfo->inHeap"), File: "../src/backend/commands/waitlsn.c", Line: 114, PID: 1936152
> postgres: heikki postgres [local] CALL(ExceptionalCondition+0xab)[0x55da1f68787b]
> postgres: heikki postgres [local] CALL(+0x331ec8)[0x55da1f204ec8]
> postgres: heikki postgres [local] CALL(WaitForLSN+0x139)[0x55da1f2052cc]
> postgres: heikki postgres [local] CALL(pg_wal_replay_wait+0x18b)[0x55da1f2056e5]
> postgres: heikki postgres [local] CALL(ExecuteCallStmt+0x46e)[0x55da1f18031a]
> postgres: heikki postgres [local] CALL(standard_ProcessUtility+0x8cf)[0x55da1f4b26c9]

I think there's a similar race condition if the timeout is reached at 
the same time that the startup process wakes up the process.

> 	 * At first, we check that pg_wal_replay_wait() is called in a non-atomic
> 	 * context.  That is, a procedure call isn't wrapped into a transaction,
> 	 * another procedure call, or a function call.
> 	 *

It's pretty unfortunate to have all these restrictions. It would be nice 
to do:

select pg_wal_replay_wait('0/1234'); select * from foo;

in a single multi-query call, to avoid the round-trip to the client. You 
can avoid it with libpq or protocol level pipelining, too, but it's more 
complicated.

> 	 * Secondly, according to PlannedStmtRequiresSnapshot(), even in an atomic
> 	 * context, CallStmt is processed with a snapshot.  Thankfully, we can pop
> 	 * this snapshot, because PortalRunUtility() can tolerate this.

This assumption that PortalRunUtility() can tolerate us popping the 
snapshot sounds very fishy. I haven't looked at what's going on there, 
but doesn't sound like a great assumption.

If recovery ends while a process is waiting for an LSN to arrive, does 
it ever get woken up?

The docs could use some-copy-editing, but just to point out one issue:

> There are also procedures to control the progress of recovery.

That's copy-pasted from an earlier sentence at the table that lists 
functions like pg_promote(), pg_wal_replay_pause(), and 
pg_is_wal_replay_paused(). The pg_wal_replay_wait() doesn't control the 
progress of recovery like those functions do, it only causes the calling 
backend to wait.

Overall, this feature doesn't feel quite ready for v17, and IMHO should 
be reverted. It's a nice feature, so I'd love to have it fixed and 
reviewed early in the v18 cycle.

-- 
Heikki Linnakangas
Neon (https://neon.tech)






view thread (216+ messages)  latest in thread

Message-ID: <b155606b-e744-4218-bda5-29379779da1a@iki.fi>
Permalink:  ../b155606b-e744-4218-bda5-29379779da1a@iki.fi/
Also on:    postgresql.org/message-id/b155606b-e744-4218-bda5-29379779da1a@iki.fi

 · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-hackers@postgresql.org
  Cc: hlinnaka@iki.fi, aekorotkov@gmail.com, alvherre@alvh.no-ip.org, pashkin.elfe@gmail.com, bharath.rupireddyforpostgres@gmail.com, i.kartyshov@postgrespro.ru, euler@eulerto.com, thomas.munro@gmail.com, peter@eisentraut.org, amit.kapila16@gmail.com, dilipbalaut@gmail.com, smithpb2250@gmail.com, pgsql-hackers@lists.postgresql.org
  Subject: Re: [HACKERS] make async slave to wait for lsn to be replayed
  In-Reply-To: <b155606b-e744-4218-bda5-29379779da1a@iki.fi>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox