v2-01-fix-pgstat-sfc.patch
text/x-patch
Filename: v2-01-fix-pgstat-sfc.patch
Type: text/x-patch
Part: 0
Patch
Format: unified
Series: patch v2
| File | + | − |
|---|---|---|
| src/backend/utils/activity/pgstat.c | 31 | 2 |
| src/backend/utils/misc/guc_tables.c | 1 | 1 |
| src/include/utils/guc_hooks.h | 1 | 0 |
| src/test/regress/expected/stats.out | 29 | 0 |
| src/test/regress/sql/stats.sql | 15 | 0 |
diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c
index b125802b21..cfc6511093 100644
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -103,7 +103,7 @@
#include "storage/lwlock.h"
#include "storage/pg_shmem.h"
#include "storage/shmem.h"
-#include "utils/guc.h"
+#include "utils/guc_hooks.h"
#include "utils/memutils.h"
#include "utils/pgstat_internal.h"
#include "utils/timestamp.h"
@@ -187,7 +187,6 @@ static inline bool pgstat_is_kind_valid(int ikind);
bool pgstat_track_counts = false;
int pgstat_fetch_consistency = PGSTAT_FETCH_CONSISTENCY_CACHE;
-
/* ----------
* state shared with pgstat_*.c
* ----------
@@ -227,6 +226,13 @@ static dlist_head pgStatPending = DLIST_STATIC_INIT(pgStatPending);
*/
static bool pgStatForceNextFlush = false;
+/*
+ * Force-clear existing snapshot before next use to prevent in-transaction
+ * change of stats_fetch_consistency from causing cache mechanism issues.
+ */
+static bool clear_existing_snapshot = false;
+
+
/*
* For assertions that check pgstat is not used before initialization / after
* shutdown.
@@ -787,6 +793,8 @@ pgstat_clear_snapshot(void)
* forward the reset request.
*/
pgstat_clear_backend_activity_snapshot();
+
+ clear_existing_snapshot = false;
}
void *
@@ -885,6 +893,9 @@ pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
TimestampTz
pgstat_get_stat_snapshot_timestamp(bool *have_snapshot)
{
+ if (clear_existing_snapshot)
+ pgstat_clear_snapshot();
+
if (pgStatLocal.snapshot.mode == PGSTAT_FETCH_CONSISTENCY_SNAPSHOT)
{
*have_snapshot = true;
@@ -929,6 +940,9 @@ pgstat_snapshot_fixed(PgStat_Kind kind)
static void
pgstat_prep_snapshot(void)
{
+ if (clear_existing_snapshot)
+ pgstat_clear_snapshot();
+
if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_NONE ||
pgStatLocal.snapshot.stats != NULL)
return;
@@ -1671,3 +1685,18 @@ pgstat_reset_after_failure(void)
/* and drop variable-numbered ones */
pgstat_drop_all_entries();
}
+
+/*
+ * GUC assign_hook for stats_fetch_consistency
+ */
+void
+assign_stats_fetch_consistency(int newval, void *extra)
+{
+ /*
+ * Changing this value in a transaction may cause snapshot state
+ * inconsistencies. Clear the current snapshot to avoid issues before the
+ * next snapshot use.
+ */
+ if (pgstat_fetch_consistency != newval)
+ clear_existing_snapshot = true;
+}
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 2f42cebaf6..5f90aecd47 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -4821,7 +4821,7 @@ struct config_enum ConfigureNamesEnum[] =
},
&pgstat_fetch_consistency,
PGSTAT_FETCH_CONSISTENCY_CACHE, stats_fetch_consistency,
- NULL, NULL, NULL
+ NULL, assign_stats_fetch_consistency, NULL
},
{
diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h
index a82a85c940..2ecb9fc086 100644
--- a/src/include/utils/guc_hooks.h
+++ b/src/include/utils/guc_hooks.h
@@ -121,6 +121,7 @@ extern void assign_search_path(const char *newval, void *extra);
extern bool check_session_authorization(char **newval, void **extra, GucSource source);
extern void assign_session_authorization(const char *newval, void *extra);
extern void assign_session_replication_role(int newval, void *extra);
+extern void assign_stats_fetch_consistency(int newval, void *extra);
extern bool check_ssl(bool *newval, void **extra, GucSource source);
extern bool check_stage_log_stats(bool *newval, void **extra, GucSource source);
extern bool check_synchronous_standby_names(char **newval, void **extra,
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 813d6d39ea..d62a923cac 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -985,6 +985,35 @@ SELECT pg_stat_get_snapshot_timestamp();
COMMIT;
----
+-- Changing fetch consistency mode inside transaction doesn't cause crash
+----
+BEGIN;
+SET LOCAL stats_fetch_consistency = cache;
+-- filling stats for the cache mode
+SELECT pg_stat_get_function_calls(0);
+ pg_stat_get_function_calls
+----------------------------
+
+(1 row)
+
+SET LOCAL stats_fetch_consistency = snapshot;
+-- verify that there is no failure on accessing pre-existing snapshot
+SELECT pg_stat_get_function_calls(0);
+ pg_stat_get_function_calls
+----------------------------
+
+(1 row)
+
+SET LOCAL stats_fetch_consistency = none;
+-- verify that snapshot is cleared on changing stats_fetch_consistency
+SELECT pg_stat_get_snapshot_timestamp();
+ pg_stat_get_snapshot_timestamp
+--------------------------------
+
+(1 row)
+
+ROLLBACK;
+----
-- pg_stat_have_stats behavior
----
-- fixed-numbered stats exist
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 99a28bb79c..4ead6b16ca 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -476,6 +476,21 @@ SELECT pg_stat_clear_snapshot();
SELECT pg_stat_get_snapshot_timestamp();
COMMIT;
+----
+-- Changing fetch consistency mode inside transaction doesn't cause crash
+----
+BEGIN;
+SET LOCAL stats_fetch_consistency = cache;
+-- filling stats for the cache mode
+SELECT pg_stat_get_function_calls(0);
+SET LOCAL stats_fetch_consistency = snapshot;
+-- verify that there is no failure on accessing pre-existing snapshot
+SELECT pg_stat_get_function_calls(0);
+SET LOCAL stats_fetch_consistency = none;
+-- verify that snapshot is cleared on changing stats_fetch_consistency
+SELECT pg_stat_get_snapshot_timestamp();
+ROLLBACK;
+
----
-- pg_stat_have_stats behavior
----