Re: shared-memory based stats collector - v68
Andres Freund <andres@anarazel.de>
Hi,
On 2022-04-05 01:16:04 +1200, Thomas Munro wrote:
> On Mon, Apr 4, 2022 at 4:16 PM Andres Freund <andres@anarazel.de> wrote:
> > Please take a look!
>
> A few superficial comments:
>
> > [PATCH v68 01/31] pgstat: consistent function header formatting.
> > [PATCH v68 02/31] pgstat: remove some superflous comments from pgstat.h.
>
> +1
Planning to commit these after making another coffee and proof reading them
some more.
> > [PATCH v68 03/31] dshash: revise sequential scan support.
>
> Logic looks good. That is,
> lock-0-and-ensure_valid_bucket_pointers()-only-once makes sense. Just
> some comment trivia:
>
> + * dshash_seq_term needs to be called when a scan finished. The caller may
> + * delete returned elements midst of a scan by using dshash_delete_current()
> + * if exclusive = true.
>
> s/scan finished/scan is finished/
> s/midst of/during/ (or /in the middle of/, ...)
>
> > [PATCH v68 04/31] dsm: allow use in single user mode.
>
> LGTM.
> + Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
> (Not this patch's fault, but I wish we had a more explicit way to say "am
> single user".)
Agreed.
> > [PATCH v68 05/31] pgstat: stats collector references in comments
>
> LGTM. I could think of some alternative suggested names for this subsystem,
> but don't think it would be helpful at this juncture so I will refrain :-)
Heh. I did start a thread about it a while ago :)
> > [PATCH v68 08/31] pgstat: introduce PgStat_Kind enum.
>
> +#define PGSTAT_KIND_FIRST PGSTAT_KIND_DATABASE
> +#define PGSTAT_KIND_LAST PGSTAT_KIND_WAL
> +#define PGSTAT_NUM_KINDS (PGSTAT_KIND_LAST + 1)
>
> It's a little confusing that PGSTAT_NUM_KINDS isn't really the number of kinds,
> because there is no kind 0. For the two users of it... maybe just use
> pgstat_kind_infos[] = {...}, and
> global_valid[PGSTAT_KIND_LAST + 1]?
Maybe the whole justification for not defining an invalid kind is moot
now. There's not a single switch covering all kinds of stats left, and I hope
that we don't introduce one again...
> > [PATCH v68 10/31] pgstat: scaffolding for transactional stats creation / drop.
>
> + /*
> + * Dropping the statistics for objects that dropped transactionally itself
> + * needs to be transactional. ...
>
> Hard to parse. How about: "Objects are dropped transactionally, so
> related statistics need to be dropped transactionally too."
Not all objects are dropped transactionally. But I agree it reads awkwardly. I
now, incorporating feedback from Justin as well, rephrased it to:
/*
* Statistics for transactionally dropped objects need to be
* transactionally dropped as well. Collect the stats dropped in the
* current (sub-)transaction and only execute the stats drop when we know
* if the transaction commits/aborts. To handle replicas and crashes,
* stats drops are included in commit / abort records.
*/
A few too many "drop"s in there, but maybe that's unavoidable.
> + /*
> + * Whenever the for a dropped stats entry could not be freed (because
> + * backends still have references), this is incremented, causing backends
> + * to run pgstat_gc_entry_refs(), allowing that memory to be reclaimed.
> + */
> + pg_atomic_uint64 gc_count;
>
> Whenever the ...?
* Whenever statistics for dropped objects could not be freed - because
* backends still have references - the dropping backend calls
* pgstat_request_entry_refs_gc() incrementing this counter. Eventually
* that causes backends to run pgstat_gc_entry_refs(), allowing memory to
* be reclaimed.
> Would it be better to call this variable gc_request_count?
Agreed.
> + * Initialize refcount to 1, marking it as valid / not tdroped. The entry
>
> s/tdroped/dropped/
>
> + * further if a longer lived references is needed.
>
> s/references/reference/
Fixed.
> + /*
> + * There are legitimate cases where the old stats entry might not
> + * yet have been dropped by the time it's reused. The easiest case
> + * are replication slot stats. But oid wraparound can lead to
> + * other cases as well. We just reset the stats to their plain
> + * state.
> + */
> + shheader = pgstat_reinit_entry(kind, shhashent);
>
> This whole comment is repeated in pgstat_reinit_entry and its caller.
I guess I felt as indecisive about where to place it between the two locations
when I wrote it as I do now. Left it at the callsite for now.
> + /*
> + * XXX: Might be worth adding some frobbing of the allocation before
> + * freeing, to make it easier to detect use-after-free style bugs.
> + */
> + dsa_free(pgStatLocal.dsa, pdsa);
>
> FWIW dsa_free() clobbers memory in assert builds, just like pfree().
Oh. I could swear I saw that not being the case a while ago. But clearly it is
the case. Removed.
> +static Size
> +pgstat_dsa_init_size(void)
> +{
> + Size sz;
> +
> + /*
> + * The dshash header / initial buckets array needs to fit into "plain"
> + * shared memory, but it's beneficial to not need dsm segments
> + * immediately. A size of 256kB seems works well and is not
> + * disproportional compared to other constant sized shared memory
> + * allocations. NB: To avoid DSMs further, the user can configure
> + * min_dynamic_shared_memory.
> + */
> + sz = 256 * 1024;
>
> It kinda bothers me that the memory reserved by
> min_dynamic_shared_memory might eventually fill up with stats, and not
> be available for temporary use by parallel queries (which can benefit
> more from fast acquire/release on DSMs, and probably also huge pages,
> or maybe not...), and that's hard to diagnose.
It's not great, but I don't really see an alternative? The saving grace is
that it's hard to imagine "real" usages of min_dynamic_shared_memory being
used up by stats.
> + * (4) turn off the idle-in-transaction, idle-session and
> + * idle-state-update timeouts if active. We do this before step (5) so
>
> s/idle-state-/idle-stats-/
>
> + /*
> + * Some of the pending stats may have not been flushed due to lock
> + * contention. If we have such pending stats here, let the caller know
> + * the retry interval.
> + */
> + if (partial_flush)
> + {
>
> I think it's better for a comment that is outside the block to say "If
> some of the pending...". Or the comment should be inside the blocks.
The comment says "if" in the second sentence? But it's a bit awkward anyway,
rephrased to:
* If some of the pending stats could not be flushed due to lock
* contention, let the caller know when to retry.
> +static void
> +pgstat_build_snapshot(void)
> +{
> ...
> + dshash_seq_init(&hstat, pgStatLocal.shared_hash, false);
> + while ((p = dshash_seq_next(&hstat)) != NULL)
> + {
> ...
> + entry->data = MemoryContextAlloc(pgStatLocal.snapshot.context,
> ...
> + }
> + dshash_seq_term(&hstat);
>
> Doesn't allocation failure leave the shared hash table locked?
The shared table itself not - the error path does LWLockReleaseAll(). The
problem is the backend local dshash_table, specifically
find_[exclusively_]locked will stay set, and then cause assertion failures
when used next.
I think we need to fix that in dshash.c. We have code in released branches
that's vulnerable to this problem. E.g.
ensure_record_cache_typmod_slot_exists() in lookup_rowtype_tupdesc_internal().
See also
https://postgr.es/m/20220311012712.botrpsikaufzteyt%40alap3.anarazel.de
Afaics the only real choice is to remove find_[exclusively_]locked and rely on
LWLockHeldByMeInMode() instead.
> > PATCH v68 16/31] pgstat: add pg_stat_exists_stat() for easier testing.
>
> pg_stat_exists_stat() is a weird name, ... would it be better as
> pg_stat_object_exists()?
I was fighting with this one a bunch :). Earlier it was called
pg_stat_stats_exist() I think. "object" makes it sound a bit too much like
it's the database object?
Maybe pg_stat_have_stat()?
> > [PATCH v68 28/31] pgstat: update docs.
>
> + Determines the behaviour when cumulative statistics are accessed
>
> AFAIK our manual is written in en_US, so s/behaviour/behavior/.
Fixed like 10 instances of this in the patchset. Not sure why I just can't
make myself type behavior.
> + memory. When set to <literal>cache</literal>, the first access to
> + statistics for an object caches those statistics until the end of the
> + transaction / until <function>pg_stat_clear_snapshot()</function> is
>
> s|/|unless|
>
> + <literal>none</literal> is most suitable for monitoring solutions. If
>
> I'd change "solutions" to "tools" or maybe "systems".
Done.
> + When using the accumulated statistics views and functions to
> monitor collected data, it is important
>
> Did you intend to write "accumulated" instead of "cumulative" here?
Not sure. I think I got bored of the word at some point :P
> + You can invoke <function>pg_stat_clear_snapshot</function>() to discard the
> + current transaction's statistics snapshot / cache (if any). The next use
>
> I'd change s|/ cache|or cached values|. I think "/" like this is an informal
> thing.
I think we have a few other uses of it. But anyway, changed.
Thanks!
Andres
Commits
-
Improve comment about dropped entries in pgstat.c
- a0ab20f16541 15.11 landed
- ec194b448cbc 16.7 landed
- bb93b33d7e39 17.3 landed
- 001a537b83ec 18.0 landed
-
Fix temporary memory leak in system table index scans
- 1acf10549e64 18.0 cited
-
pgstat: set timestamps of fixed-numbered stats after a crash.
- 5cd1c40b3ce9 15.0 landed
-
pgstat: Update docs to match the shared memory stats reality.
- b3abca68106d 15.0 landed
-
pgstat: Hide instability in stats.spec with -DCATCACHE_FORCE_RELEASE.
- d6c0db14836c 15.0 cited
-
pgstat: add/extend tests for resetting various kinds of stats.
- 5264add78478 15.0 landed
-
Add minimal tests for recovery conflict handling.
- 9f8a050f68dc 15.0 landed
-
pgstat: test stats interactions with physical replication.
- 53b9cd20d414 15.0 landed
-
pgstat: add tests for handling of restarts, including crashes.
- 16acf7f1aaea 15.0 landed
-
pgstat: add tests for transaction behaviour, 2PC, function stats.
- e349c95d3e91 15.0 landed
-
pgstat: add pg_stat_have_stats() test helper.
- ad401664b801 15.0 landed
-
pgstat: add pg_stat_force_next_flush(), use it to simplify tests.
- 0f96965c6581 15.0 landed
-
pgstat: move pgstat.c to utils/activity.
- fbfe6910eca0 15.0 landed
-
pgstat: store statistics in shared memory.
- 5891c7a8ed8f 15.0 landed
-
pgstat: remove stats_temp_directory.
- 6f0cf87872ab 15.0 landed
-
pgstat: rename STATS_COLLECTOR GUC group to STATS_CUMULATIVE.
- 1db4e5a4eeec 15.0 landed
-
pgstat: revise replication slot API in preparation for shared memory stats.
- e41aed674f35 15.0 landed
-
pgstat: scaffolding for transactional stats creation / drop.
- 8b1dccd37c71 15.0 landed
-
pgstat: introduce PgStat_Kind enum.
- 997afad89d12 15.0 landed
-
pgstat: prepare APIs used by pgstatfuncs for shared memory stats.
- 8fb580a35ce3 15.0 landed
-
pgstat: add pgstat_copy_relation_stats().
- 8ea7963fc741 15.0 landed
-
pgstat: rename some pgstat_send_* functions to pgstat_report_*.
- cc96373cf39b 15.0 landed
-
pgstat: stats collector references in comments.
- bdbd3d9064f9 15.0 landed
-
pgstat: move transactional code into pgstat_xact.c.
- ab62a642d52c 15.0 landed
-
dsm: allow use in single user mode.
- 46a2d2499a64 15.0 landed
-
dshash: revise sequential scan support.
- 909eebf27b9e 15.0 landed
-
pgstat: remove some superflous comments from pgstat.h.
- 55e566fc4bc8 15.0 landed
-
pgstat: reorder pgstat.[ch] contents.
- 315ae75e9b6d 15.0 landed
-
pgstat: split different types of stats into separate files.
- 13619598f108 15.0 landed
-
pgstat: introduce pgstat_relation_should_count().
- 8363102009d8 15.0 landed
-
pgstat: separate "xact level" handling out of relation specific functions.
- d4ba8b51c763 15.0 landed
-
pgstat: rename pgstat_initstats() to pgstat_relation_init().
- bff258a2732e 15.0 landed
-
pgstat: split out WAL handling from pgstat_{initialize,report_stat}.
- 78f9506b380f 15.0 landed
-
pgstat: run pgindent on pgstat.c/h.
- a3a75b982b5b 15.0 landed
-
pgstat: split relation, database handling out of pgstat_report_stat().
- 89c546c29489 15.0 landed
-
Move code around in StartupXLOG().
- be1c00ab13a7 15.0 cited
-
pgstat: Prepare to use mechanism for truncated rels also for droppped rels.
- 6b9501660c93 15.0 landed
-
pgstat: Split out relation stats handling from AtEO[Sub]Xact_PgStat() etc.
- e1f958d759ff 15.0 landed
-
pgstat: Schedule per-backend pgstat shutdown via before_shmem_exit().
- fb2c5028e635 15.0 landed
-
Schedule ShutdownXLOG() in single user mode using before_shmem_exit().
- a1bb3d5dbe6a 15.0 landed
-
Make parallel worker shutdown complete entirely via before_shmem_exit().
- fa91d4c91f28 15.0 landed
-
pgstat: Bring up pgstat in BaseInit() to fix uninitialized use of pgstat by AV.
- ee3f8d3d3aec 15.0 landed
-
pgstat: split reporting/fetching of bgwriter and checkpointer stats.
- 1bc8e7b0991c 15.0 landed
-
Split backend status and progress related functionality out of pgstat.c.
- e1025044cd4e 14.0 landed
-
Split wait event related code from pgstat.[ch] into wait_event.[ch].
- a333476b9251 14.0 landed
-
Make archiver process an auxiliary process.
- d75288fb27b8 14.0 landed
-
Force to send remaining WAL stats to the stats collector at walwriter exit.
- 33394ee6f243 14.0 cited
-
Add pg_stat_database counters for sessions and session time
- 960869da0803 14.0 cited
-
Collect statistics about SLRU caches
- 28cac71bd368 13.0 cited
-
Don't run atexit callbacks in quickdie signal handlers.
- 8e19a82640d3 12.0 cited
-
Create a "fast path" for acquiring weak relation locks.
- 3cba8999b343 9.2.0 cited