Look up backend type in pg_signal_backend() more cheaply.
authorNathan Bossart <[email protected]>
Wed, 27 Nov 2024 16:32:25 +0000 (10:32 -0600)
committerNathan Bossart <[email protected]>
Wed, 27 Nov 2024 16:32:25 +0000 (10:32 -0600)
Commit ccd38024bc, which introduced the pg_signal_autovacuum_worker
role, added a call to pgstat_get_beentry_by_proc_number() for the
purpose of determining whether the process is an autovacuum worker.
This function calls pgstat_read_current_status(), which can be
fairly expensive and may return cached, out-of-date information.
Since we just need to look up the target backend's BackendType, and
we already know its ProcNumber, we can instead inspect the
BackendStatusArray directly, which is much less expensive and
possibly more up-to-date.  There are some caveats with this
approach (which are documented in the code), but it's still
substantially better than before.

Reported-by: Andres Freund
Reviewed-by: Andres Freund
Discussion: https://postgr.es/m/ujenaa2uabzfkwxwmfifawzdozh3ljr7geozlhftsuosgm7n7q%40g3utqqyyosb6

src/backend/storage/ipc/signalfuncs.c
src/backend/utils/activity/backend_status.c
src/include/utils/backend_status.h

index aa729a36e3921f387d5e67497d69c07cff6caf4d..d83532760079bceec37740769448df2054417ca4 100644 (file)
@@ -88,9 +88,9 @@ pg_signal_backend(int pid, int sig)
    if (!OidIsValid(proc->roleId) || superuser_arg(proc->roleId))
    {
        ProcNumber  procNumber = GetNumberFromPGProc(proc);
-       PgBackendStatus *procStatus = pgstat_get_beentry_by_proc_number(procNumber);
+       BackendType backendType = pgstat_get_backend_type_by_proc_number(procNumber);
 
-       if (procStatus && procStatus->st_backendType == B_AUTOVAC_WORKER)
+       if (backendType == B_AUTOVAC_WORKER)
        {
            if (!has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_AUTOVACUUM_WORKER))
                return SIGNAL_BACKEND_NOAUTOVAC;
index bdb3a296ca6710b476ef4da8a0839b0903d1cce9..22c6dc378c580dde7048f1f68de320a503515ba4 100644 (file)
@@ -1036,6 +1036,31 @@ pgstat_get_my_query_id(void)
    return MyBEEntry->st_query_id;
 }
 
+/* ----------
+ * pgstat_get_backend_type_by_proc_number() -
+ *
+ * Return the type of the backend with the specified ProcNumber.  This looks
+ * directly at the BackendStatusArray, so the return value may be out of date.
+ * The only current use of this function is in pg_signal_backend(), which is
+ * inherently racy, so we don't worry too much about this.
+ *
+ * It is the caller's responsibility to use this wisely; at minimum, callers
+ * should ensure that procNumber is valid and perform the required permissions
+ * checks.
+ * ----------
+ */
+BackendType
+pgstat_get_backend_type_by_proc_number(ProcNumber procNumber)
+{
+   volatile PgBackendStatus *status = &BackendStatusArray[procNumber];
+
+   /*
+    * We bypass the changecount mechanism since fetching and storing an int
+    * is almost certainly atomic.
+    */
+   return status->st_backendType;
+}
+
 /* ----------
  * cmp_lbestatus
  *
index 97874300c31de894a6a423e7e04ba6c904446d4f..4e8b39a66d56b23d3af827f5a0aa010a8f138a85 100644 (file)
@@ -323,6 +323,7 @@ extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
 extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer,
                                                       int buflen);
 extern uint64 pgstat_get_my_query_id(void);
+extern BackendType pgstat_get_backend_type_by_proc_number(ProcNumber procNumber);
 
 
 /* ----------