Re: Reconcile stats in find_tabstat_entry() and get rid of PgStat_BackendFunctionEntry

From: "Drouvot, Bertrand" <bertranddrouvot(dot)pg(at)gmail(dot)com>
To: Andres Freund <andres(at)anarazel(dot)de>
Cc: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: Reconcile stats in find_tabstat_entry() and get rid of PgStat_BackendFunctionEntry
Date: 2023-02-13 07:09:50
Message-ID: 24df8560-c519-85ce-7a88-d6dd8ddfa1a2@gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

On 2/10/23 10:46 PM, Andres Freund wrote:
> Hi,
>
> On 2023-02-09 11:38:18 +0100, Drouvot, Bertrand wrote:
>> Please find attached a patch proposal for $SUBJECT.
>>
>> The idea has been raised in [1] by Andres: it would allow to simplify even more the work done to
>> generate pg_stat_get_xact*() functions with Macros.
>
> Thanks!
>

Thanks for looking at it!

> I think this is useful beyond being able to generate those functions with
> macros. The fact that we had to deal with transactional code in pgstatfuncs.c
> meant that a lot of the relevant itnernals had to be exposed "outside" pgstat,
> which seems architecturally not great.
>

Right, good point.

>> Indeed, with the reconciliation done in find_tabstat_entry() then all the pg_stat_get_xact*() functions
>> (making use of find_tabstat_entry()) now "look the same" (should they take into account live subtransactions or not).
>
> I'm not bothered by making all of pg_stat_get_xact* functions more expensive,
> they're not a hot code path. But if we need to, we could just add a parameter
> to find_tabstat_entry() indicating whether we need to reconcile or not.
>

I think that's a good idea to avoid doing extra work if not needed.
V2 adds such a bool.

>> /* save stats for this function, later used to compensate for recursion */
>> - fcu->save_f_total_time = pending->f_counts.f_total_time;
>> + fcu->save_f_total_time = pending->f_total_time;
>>
>> /* save current backend-wide total time */
>> fcu->save_total = total_func_time;
>
> The diff is noisy due to all the mechanical changes like the above. Could that
> be split into a separate commit?
>

Fully agree, the PgStat_BackendFunctionEntry stuff will be done in a separate patch.

>
>> find_tabstat_entry(Oid rel_id)
>> {
>> PgStat_EntryRef *entry_ref;
>> + PgStat_TableStatus *tablestatus = NULL;
>>
>> entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_RELATION, MyDatabaseId, rel_id);
>> if (!entry_ref)
>> entry_ref = pgstat_fetch_pending_entry(PGSTAT_KIND_RELATION, InvalidOid, rel_id);
>>
>> if (entry_ref)
>> - return entry_ref->pending;
>> - return NULL;
>> + {
>> + PgStat_TableStatus *tabentry = (PgStat_TableStatus *) entry_ref->pending;
>
> I'd add an early return for the !entry_ref case, that way you don't need to
> indent the bulk of the function.
>

Good point, done in V2.

>
>> + PgStat_TableXactStatus *trans;
>> +
>> + tablestatus = palloc(sizeof(PgStat_TableStatus));
>> + memcpy(tablestatus, tabentry, sizeof(PgStat_TableStatus));
>
> For things like this I'd use
> *tablestatus = *tabentry;
>
> that way the compiler will warn you about mismatching types, and you don't
> need the sizeof().
>
>

Good point, done in V2.

>> + /* live subtransactions' counts aren't in t_counts yet */
>> + for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
>> + {
>> + tablestatus->t_counts.t_tuples_inserted += trans->tuples_inserted;
>> + tablestatus->t_counts.t_tuples_updated += trans->tuples_updated;
>> + tablestatus->t_counts.t_tuples_deleted += trans->tuples_deleted;
>> + }
>> + }
>
> Hm, why do we end uup with t_counts still being used here, but removed other
> places?
>

t_counts are not removed, maybe you are confused with the "f_counts" that were removed
in V1 due to the PgStat_BackendFunctionEntry related changes?

>
>> diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
>> index 6737493402..40a6fbf871 100644
>> --- a/src/backend/utils/adt/pgstatfuncs.c
>> +++ b/src/backend/utils/adt/pgstatfuncs.c
>> @@ -1366,7 +1366,10 @@ pg_stat_get_xact_numscans(PG_FUNCTION_ARGS)
>> if ((tabentry = find_tabstat_entry(relid)) == NULL)
>> result = 0;
>> else
>> + {
>> result = (int64) (tabentry->t_counts.t_numscans);
>> + pfree(tabentry);
>> + }
>>
>> PG_RETURN_INT64(result);
>> }
>
> I don't think we need to bother with individual pfrees in this path. The
> caller will call the function in a dedicated memory context, that'll be reset
> very soon after this.

Oh right, the palloc is done in the ExprContext memory context that is reset soon after.
Removing the pfrees in V2 attached.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachment Content-Type Size
v2-0001-find_tabstat_entry_recon.patch text/plain 5.9 KB

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Richard Guo 2023-02-13 07:33:15 Re: Making Vars outer-join aware
Previous Message Bharath Rupireddy 2023-02-13 06:01:03 Re: Introduce a new view for checkpointer related stats