Re: pg_atomic_compare_exchange_*() and memory barriers - Mailing list pgsql-hackers

From Alexander Korotkov
Subject Re: pg_atomic_compare_exchange_*() and memory barriers
Date
Msg-id CAPpHfduxVxkZpCaYRv_whvNyPxCTSyEgXR02sbo=mhGF0MDQEg@mail.gmail.com
Whole thread Raw
In response to Re: pg_atomic_compare_exchange_*() and memory barriers  (Andres Freund <andres@anarazel.de>)
List pgsql-hackers
On Fri, Mar 7, 2025 at 7:46 PM Andres Freund <andres@anarazel.de> wrote:
> On 2025-03-07 19:44:20 +0200, Alexander Korotkov wrote:
> > On Fri, Mar 7, 2025 at 7:38 PM Andres Freund <andres@anarazel.de> wrote:
> > > On 2025-03-07 19:15:23 +0200, Alexander Korotkov wrote:
> > > > On Fri, Mar 7, 2025 at 7:07 PM Andres Freund <andres@anarazel.de> wrote:
> > > > > What is the access pattern and the observed problems with it that made you
> > > > > look at the disassembly?
> > > >
> > > > Check this code.
> > > >
> > > > l1:     pg_atomic_write_u64(&XLogCtl->xlblocks[nextidx], NewPageEndPtr);
> > >
> > > >         /*
> > > >          * Try to advance XLogCtl->InitializedUpTo.
> > > >          *
> > > >          * If the CAS operation failed, then some of previous pages are not
> > > >          * initialized yet, and this backend gives up.
> > > >          *
> > > >          * Since initializer of next page might give up on advancing of
> > > >          * InitializedUpTo, this backend have to attempt advancing until it
> > > >          * find page "in the past" or concurrent backend succeeded at
> > > >          * advancing.  When we finish advancing XLogCtl->InitializedUpTo, we
> > > >          * notify all the waiters with XLogCtl->InitializedUpToCondVar.
> > > >          */
> > > > l2:     while (pg_atomic_compare_exchange_u64(&XLogCtl->InitializedUpTo,
> > > > &NewPageBeginPtr, NewPageEndPtr))
> > > >         {
> > > >             NewPageBeginPtr = NewPageEndPtr;
> > > >             NewPageEndPtr = NewPageBeginPtr + XLOG_BLCKSZ;
> > > >             nextidx = XLogRecPtrToBufIdx(NewPageBeginPtr);
> > > >
> > > > l3:         if (pg_atomic_read_u64(&XLogCtl->xlblocks[nextidx]) !=
> > > > NewPageEndPtr)
> > > >             {
> > > >                 /*
> > > >                  * Page at nextidx wasn't initialized yet, so we cann't move
> > > >                  * InitializedUpto further. It will be moved by backend
> > > > which
> > > >                  * will initialize nextidx.
> > > >                  */
> > > >
> > > > ConditionVariableBroadcast(&XLogCtl->InitializedUpToCondVar);
> > > >                 break;
> > > >             }
> > > >         }
> > > >
> > > > Consider the following execution order with process 1 (p1) and process 2
> > > > (p2).
> > >
> > > On 2025-03-07 19:24:39 +0200, Alexander Korotkov wrote:
> > > > Sorry, I messed this up.
> > > > The correct sequence is following.
> > > >
> > > > 1. p1 executes l1
> > > > 2. p1 executes l2 with failure
> > > > 3. p2 executes l2 with success
> > > > 4. p2 execute l3, but doesn't see the results of step 1, because 3
> > > > didn't provide enough of memory barrier
> > >
> > > Did you mean because 2) didn't provide enough of a memory barrier? Because 3)
> > > does, right?
> >
> > Yes, exactly.
> >
> > > You could get in exactly same the situation if the p1 is scheduled out by the
> > > OS after step 1, no?
> >
> > No. In that case, p1 will execute l2 with success.  p1 executes l2
> > with failure only because it goes before p2 executes l2.
>
> In my scenario p1 will not execute l2 because p2 gets scheduled before it can
> do so. So p1 cant yet execute l2 before p2 executes l2.

In my scenario p1.l2 will be successful if executed after p2.l2 and
failed if executed before p2.l2.  Imagine initial value is 0.  p1
tries to change 1=>2, while p2 tries to change 0 => 1.

------
Regards,
Alexander Korotkov
Supabase



pgsql-hackers by date:

Previous
From: Jelte Fennema-Nio
Date:
Subject: Re: Commitfest app release on Feb 17 with many improvements
Next
From: Tom Lane
Date:
Subject: Re: Commitfest app release on Feb 17 with many improvements