Re: pgstat: don't assert on dropped entries when writing stats file

From: Sami Imseih <samimseih(dot)pg(at)gmail(dot)com>
To: Michael Paquier <michael(at)paquier(dot)xyz>
Cc: Postgres hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: pgstat: don't assert on dropped entries when writing stats file
Date: 2026-10-20 16:07:21
Message-ID: CAN12+Y+rZ7Cd1Q29z7JZBGD75HwJ5buTRP4YdY6UpV2xWXrRLw@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

> > On top of the generation check, how about doing something in
> > pgstat_release_entry_ref() if we have a dropped entry with a refcount
> > of 0 and the generation does not match? Hence, I'd suggest that we
> > should free the entry more aggressively, perhaps.. I have not tested
> > this idea, but just getting rid of this assertion does not feel like
> > the right move to me as it means that we leave in the shared hashtable
> > entries that should be gone, and that these entries will never be gone
> > until the same key is reused. For the replication slots or an
> > index-based logic, the turnover should be quick, but that may not be
> > the case for all stats kinds.
>
> I have done some testing by reusing your test case with pgbench and a
> combination of things, like:
> - slot peeks and sleeps to maintain references
> - Concurrent activity creates and drops the slots
> - Hardcoded sleep in pgstat_release_entry_ref() before the
> dshash_find() to let concurrent activity mess more easily with a
> backend doing a release.
>
> And this has uncovered two more things, pointing at real issues that
> your assertion was a consequence of:
> - elog(ERROR) could be hit during backend exit, due to a concurrent
> reinit and drop. We need to make the code slightly sloppier, that
> should not fail.

Good point on the elog(ERROR). If another backend reinitializes and
drops the same key after we decrement the refcount to 0 but before
dshash_find(), then a missing entry is valid and should not fail. That
is a very narrow window, but your stress test shows that it is possible.

> - The generation match check should be a secondary check, after
> checking that the entry has not been marked for drop. That could
> trigger the assertion.

I am not sure we need the generation check here:

+ else if (pg_atomic_read_u32(&shent->generation) ==
+ entry_ref->generation)
+ {
+ /* Another entry, created again with the same key. */
+
dshash_release_lock(pgStatLocal.kind_hash[key.kind], shent);
+ }
+ else
+ {
+ /* Entry reinitialized, still in use. */
+
dshash_release_lock(pgStatLocal.kind_hash[key.kind], shent);
+ }

Generation does not really tell us that this is another entry created
with the same key. It could be the same entry with the same generation,
right?

So, I don't think we need to inspect generation here. If the entry is
dropped and refcount is 0, free it. Otherwise just release the lock.
Maybe something like:

+ else
+ {
+ /* Entry reinitialized or created again, still in use. */
+
dshash_release_lock(pgStatLocal.kind_hash[key.kind], shent);
+ }

Anyhow, the else-if and else branches do the same thing as it stands.

--
Sami Imseih
Amazon Web Services (AWS)

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Bharath Rupireddy 2026-10-20 16:38:16 Re: Parallel vacuum: workers together with leader could overrun cost budget
Previous Message Greg Burd 2026-10-20 15:57:37 Re: ILIKE '%' never matches a non-ASCII byte in single-byte C-ctype databases