Thread

  1. Re: Buffer locking is special (hints, checksums, AIO writes)

    Andres Freund <andres@anarazel.de> — 2025-12-18T22:06:43Z

    Hi,
    
    On 2025-12-18 19:20:38 +0200, Heikki Linnakangas wrote:
    > On 18/12/2025 19:03, Andres Freund wrote:
    > > On 2025-12-17 09:54:32 -0500, Andres Freund wrote:
    > > > On 2025-12-17 11:25:50 +0200, Heikki Linnakangas wrote:
    > > > > - LWLockWaitListLock() uses pg_atomic_read_u32() after spinning,
    > > > > LockBufHdr() retries directly with pg_atomic_fetch_or_u32().
    > > >
    > > > I think here LWLockWaitListLock() is likely right - but it seems like a change
    > > > to LockBufHdr() that I would probably make in a separate commit?
    > >
    > > FWIW, I couldn't come up with a scenario where it makes a performance
    > > difference - exclusive content locks just aren't *that* frequent. And because
    > > of that the wait list lock doesn't have similar contention as some non-content
    > > lwlocks (like XidGenLock). The most extreme workload I could think of was
    > > pgbench hammering a single sequence across many sessions. While the exclusive
    > > locks show up in wait events, the buffer header spinlock itself doesn't..
    > >
    > > So I'm inclined to not change anything about this for now.
    >
    > Ok. My thinking was just that LockBufHdr() and LWLockWaitListLock() should
    > be consistent with each other. Otherwise anyone reading the code will ask
    > the question "why are they different?". They're the only two things using
    > the spin delay mechanism in our codebase, in addition to actual spinlocks.
    
    I guess for me it didn't really seem like this patch's job to fix
    that. Regardless of that, here's a version that tries to make them more
    similar.
    
    I did check, adding a likely() to LWLockWaitListLock()'s break does improve
    code generation (verified by looking at the generated code) and seems to
    improve performance in some very extreme workloads (e.g. [1]) a bit.
    
    I'll try to come up with a combined patch that applies the optimizations in
    LWLockWaitListLock() and LockBufHdr() to each other.
    
    
    > BTW, I wonder if it would be worthwhile to have an inlineable fast-path of
    > LockBufHdr() for the common case that the lock is free? I see that
    > UnlockBufHdr() is already a static inline function.
    
    I tried that a while ago and couldn't see any improvement, I think because all
    the performance relevant callers are in bufmgr.c and thus can already inline
    [parts of] the implementation.  I guess you could make the generated code a
    bit smaller if you use pg_noinline on the slowpath, but that seems like a
    separate project / effort to me.
    
    Greetings,
    
    Andres Freund
    
    
    [1] Many connections doing
    DO $do$
        BEGIN
            FOR i IN 1 .. 1000 LOOP
                PERFORM txid_current();
    	    COMMIT;
    	END LOOP;
         END;
    $do$;