Hi,

This issue has bothered me in non-partitioned use-cases recently, so
thanks for taking it up.


On 2017-03-06 18:22:17 +0300, Aleksander Alekseev wrote:
> diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
> index 2fb9a8bf58..fa906e7930 100644
> --- a/src/backend/postmaster/pgstat.c
> +++ b/src/backend/postmaster/pgstat.c
> @@ -160,6 +160,16 @@ typedef struct TabStatusArray
>  
>  static TabStatusArray *pgStatTabList = NULL;

Why are we keeping that list / the "batch" allocation pattern? It
doesn't actually seem useful to me after these changes.  Given that we
don't shrink hash-tables, we could just use the hash-table memory for
this, no?

I think a separate list that only contains things that are "active" in
the current transaction makes sense, because the current logic requires
iterating over a potentially very large array at transaction commit.


> +/* pgStatTabHash entry */
> +typedef struct TabStatHashEntry
> +{
> +     Oid t_id;
> +     PgStat_TableStatus* tsa_entry;
> +} TabStatHashEntry;
> +
> +/* Hash table for faster t_id -> tsa_entry lookup */
> +static HTAB *pgStatTabHash = NULL;
> +

'faster ... lookup' doesn't strike me as a useful comment, because it's
only useful in relation of the current code to the new code.



>  /*
>   * Backends store per-function info that's waiting to be sent to the 
> collector
>   * in this hash table (indexed by function OID).
> @@ -815,7 +825,13 @@ pgstat_report_stat(bool force)
>                               pgstat_send_tabstat(this_msg);
>                               this_msg->m_nentries = 0;
>                       }
> +
> +                     /*
> +                      * Entry will be freed soon so we need to remove it 
> from the lookup table.
> +                      */
> +                     hash_search(pgStatTabHash, &entry->t_id, HASH_REMOVE, 
> NULL);
>               }

It's not really freed...


>  static PgStat_TableStatus *
>  get_tabstat_entry(Oid rel_id, bool isshared)
>  {
> +     TabStatHashEntry* hash_entry;
>       PgStat_TableStatus *entry;
>       TabStatusArray *tsa;
> -     TabStatusArray *prev_tsa;
> -     int                     i;
> +
> +     /* Try to find an entry */
> +     entry = find_tabstat_entry(rel_id);
> +     if(entry != NULL)
> +             return entry;

Arguably it'd be better to HASH_ENTER directly here, instead of doing
two lookups.


>       /*
> -      * Search the already-used tabstat slots for this relation.
> +      * Entry doesn't exist - creating one.
> +      * First make sure there is a free space in a last element of 
> pgStatTabList.
>        */
> -     prev_tsa = NULL;
> -     for (tsa = pgStatTabList; tsa != NULL; prev_tsa = tsa, tsa = 
> tsa->tsa_next)
> +     if (!pgStatTabList)
>       {
> -             for (i = 0; i < tsa->tsa_used; i++)
> -             {
> -                     entry = &tsa->tsa_entries[i];
> -                     if (entry->t_id == rel_id)
> -                             return entry;
> -             }
> +             HASHCTL     ctl;
>  
> -             if (tsa->tsa_used < TABSTAT_QUANTUM)
> +             Assert(!pgStatTabHash);
> +
> +             memset(&ctl, 0, sizeof(ctl));
> +             ctl.keysize = sizeof(Oid);
> +             ctl.entrysize = sizeof(TabStatHashEntry);
> +             ctl.hcxt = TopMemoryContext;
> +
> +             pgStatTabHash = hash_create("pgstat t_id to tsa_entry lookup 
> table",
> +                     TABSTAT_QUANTUM, &ctl, HASH_ELEM | HASH_BLOBS | 
> HASH_CONTEXT);

Think it'd be better to move the hash creation into its own function.


- Andres


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to