Re: Summary function for pg_buffercache - Mailing list pgsql-hackers

From Andres Freund
Subject Re: Summary function for pg_buffercache
Date
Msg-id 20220921005808.bbi7ieycmqg4pxsh@awork3.anarazel.de
Whole thread Raw
In response to Re: Summary function for pg_buffercache  (Aleksander Alekseev <aleksander@timescale.com>)
Responses Re: Summary function for pg_buffercache
List pgsql-hackers
Hi,

On 2022-09-20 12:45:24 +0300, Aleksander Alekseev wrote:
> > I'm not sure how to avoid any undefined behaviour without locks though.
> > Even with locks, performance is much better. But is it good enough for production?
>
> Potentially you could avoid taking locks by utilizing atomic
> operations and lock-free algorithms. But these algorithms are
> typically error-prone and not always produce a faster code than the
> lock-based ones. I'm pretty confident this is out of scope of this
> particular patch.

Why would you need lockfree operations?  All you need to do is to read
BufferDesc->state into a local variable and then make decisions based on that?


> +    for (int i = 0; i < NBuffers; i++)
> +    {
> +        BufferDesc *bufHdr;
> +        uint32        buf_state;
> +
> +        bufHdr = GetBufferDescriptor(i);
> +
> +        /* Lock each buffer header before inspecting. */
> +        buf_state = LockBufHdr(bufHdr);
> +
> +        /* Invalid RelFileNumber means the buffer is unused */
> +        if (RelFileNumberIsValid(BufTagGetRelNumber(&bufHdr->tag)))
> +        {
> +            buffers_used++;
> +            usagecount_avg += BUF_STATE_GET_USAGECOUNT(buf_state);
> +
> +            if (buf_state & BM_DIRTY)
> +                buffers_dirty++;
> +        }
> +        else
> +            buffers_unused++;
> +
> +        if (BUF_STATE_GET_REFCOUNT(buf_state) > 0)
> +            buffers_pinned++;
> +
> +        UnlockBufHdr(bufHdr, buf_state);
> +    }

I.e. instead of locking the buffer header as done above, this could just do
something along these lines:

        BufferDesc *bufHdr;
        uint32      buf_state;

        bufHdr = GetBufferDescriptor(i);

        buf_state = pg_atomic_read_u32(&bufHdr->state);

        if (buf_state & BM_VALID)
        {
            buffers_used++;
            usagecount_avg += BUF_STATE_GET_USAGECOUNT(buf_state);

            if (buf_state & BM_DIRTY)
                buffers_dirty++;
        }
        else
            buffers_unused++;

        if (BUF_STATE_GET_REFCOUNT(buf_state) > 0)
            buffers_pinned++;


Without a memory barrier you can get very slightly "out-of-date" values of the
state, but that's fine in this case.

Greetings,

Andres Freund



pgsql-hackers by date:

Previous
From: Peter Smith
Date:
Subject: Re: [PATCH] Use indexes on the subscriber when REPLICA IDENTITY is full on the publisher
Next
From: Michael Paquier
Date:
Subject: Re: Support pg_attribute_aligned and noreturn in MSVC