Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/postmaster/pgstat.c288
1 files changed, 179 insertions, 109 deletions
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 64986b17c87..285def556b6 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -2849,66 +2849,80 @@ pgstat_initialize(void)
* Apart from auxiliary processes, MyBackendId, MyDatabaseId,
* session userid, and application_name must be set for a
* backend (hence, this cannot be combined with pgstat_initialize).
+ * Note also that we must be inside a transaction if this isn't an aux
+ * process, as we may need to do encoding conversion on some strings.
* ----------
*/
void
pgstat_bestart(void)
{
- SockAddr clientaddr;
- volatile PgBackendStatus *beentry;
+ volatile PgBackendStatus *vbeentry = MyBEEntry;
+ PgBackendStatus lbeentry;
+#ifdef USE_SSL
+ PgBackendSSLStatus lsslstatus;
+#endif
+#ifdef ENABLE_GSS
+ PgBackendGSSStatus lgssstatus;
+#endif
- /*
- * To minimize the time spent modifying the PgBackendStatus entry, fetch
- * all the needed data first.
- */
+ /* pgstats state must be initialized from pgstat_initialize() */
+ Assert(vbeentry != NULL);
/*
- * We may not have a MyProcPort (eg, if this is the autovacuum process).
- * If so, use all-zeroes client address, which is dealt with specially in
- * pg_stat_get_backend_client_addr and pg_stat_get_backend_client_port.
+ * To minimize the time spent modifying the PgBackendStatus entry, and
+ * avoid risk of errors inside the critical section, we first copy the
+ * shared-memory struct to a local variable, then modify the data in the
+ * local variable, then copy the local variable back to shared memory.
+ * Only the last step has to be inside the critical section.
+ *
+ * Most of the data we copy from shared memory is just going to be
+ * overwritten, but the struct's not so large that it's worth the
+ * maintenance hassle to copy only the needful fields.
*/
- if (MyProcPort)
- memcpy(&clientaddr, &MyProcPort->raddr, sizeof(clientaddr));
- else
- MemSet(&clientaddr, 0, sizeof(clientaddr));
+ memcpy(&lbeentry,
+ unvolatize(PgBackendStatus *, vbeentry),
+ sizeof(PgBackendStatus));
+
+ /* These structs can just start from zeroes each time, though */
+#ifdef USE_SSL
+ memset(&lsslstatus, 0, sizeof(lsslstatus));
+#endif
+#ifdef ENABLE_GSS
+ memset(&lgssstatus, 0, sizeof(lgssstatus));
+#endif
/*
- * Initialize my status entry, following the protocol of bumping
- * st_changecount before and after; and make sure it's even afterwards. We
- * use a volatile pointer here to ensure the compiler doesn't try to get
- * cute.
+ * Now fill in all the fields of lbeentry, except for strings that are
+ * out-of-line data. Those have to be handled separately, below.
*/
- beentry = MyBEEntry;
-
- /* pgstats state must be initialized from pgstat_initialize() */
- Assert(beentry != NULL);
+ lbeentry.st_procpid = MyProcPid;
if (MyBackendId != InvalidBackendId)
{
if (IsAutoVacuumLauncherProcess())
{
/* Autovacuum Launcher */
- beentry->st_backendType = B_AUTOVAC_LAUNCHER;
+ lbeentry.st_backendType = B_AUTOVAC_LAUNCHER;
}
else if (IsAutoVacuumWorkerProcess())
{
/* Autovacuum Worker */
- beentry->st_backendType = B_AUTOVAC_WORKER;
+ lbeentry.st_backendType = B_AUTOVAC_WORKER;
}
else if (am_walsender)
{
/* Wal sender */
- beentry->st_backendType = B_WAL_SENDER;
+ lbeentry.st_backendType = B_WAL_SENDER;
}
else if (IsBackgroundWorker)
{
/* bgworker */
- beentry->st_backendType = B_BG_WORKER;
+ lbeentry.st_backendType = B_BG_WORKER;
}
else
{
/* client-backend */
- beentry->st_backendType = B_BACKEND;
+ lbeentry.st_backendType = B_BACKEND;
}
}
else
@@ -2918,99 +2932,92 @@ pgstat_bestart(void)
switch (MyAuxProcType)
{
case StartupProcess:
- beentry->st_backendType = B_STARTUP;
+ lbeentry.st_backendType = B_STARTUP;
break;
case BgWriterProcess:
- beentry->st_backendType = B_BG_WRITER;
+ lbeentry.st_backendType = B_BG_WRITER;
break;
case CheckpointerProcess:
- beentry->st_backendType = B_CHECKPOINTER;
+ lbeentry.st_backendType = B_CHECKPOINTER;
break;
case WalWriterProcess:
- beentry->st_backendType = B_WAL_WRITER;
+ lbeentry.st_backendType = B_WAL_WRITER;
break;
case WalReceiverProcess:
- beentry->st_backendType = B_WAL_RECEIVER;
+ lbeentry.st_backendType = B_WAL_RECEIVER;
break;
default:
elog(FATAL, "unrecognized process type: %d",
(int) MyAuxProcType);
- proc_exit(1);
}
}
- do
- {
- pgstat_increment_changecount_before(beentry);
- } while ((beentry->st_changecount & 1) == 0);
-
- beentry->st_procpid = MyProcPid;
- beentry->st_proc_start_timestamp = MyStartTimestamp;
- beentry->st_activity_start_timestamp = 0;
- beentry->st_state_start_timestamp = 0;
- beentry->st_xact_start_timestamp = 0;
- beentry->st_databaseid = MyDatabaseId;
+ lbeentry.st_proc_start_timestamp = MyStartTimestamp;
+ lbeentry.st_activity_start_timestamp = 0;
+ lbeentry.st_state_start_timestamp = 0;
+ lbeentry.st_xact_start_timestamp = 0;
+ lbeentry.st_databaseid = MyDatabaseId;
/* We have userid for client-backends, wal-sender and bgworker processes */
- if (beentry->st_backendType == B_BACKEND
- || beentry->st_backendType == B_WAL_SENDER
- || beentry->st_backendType == B_BG_WORKER)
- beentry->st_userid = GetSessionUserId();
+ if (lbeentry.st_backendType == B_BACKEND
+ || lbeentry.st_backendType == B_WAL_SENDER
+ || lbeentry.st_backendType == B_BG_WORKER)
+ lbeentry.st_userid = GetSessionUserId();
else
- beentry->st_userid = InvalidOid;
+ lbeentry.st_userid = InvalidOid;
- beentry->st_clientaddr = clientaddr;
- if (MyProcPort && MyProcPort->remote_hostname)
- strlcpy(beentry->st_clienthostname, MyProcPort->remote_hostname,
- NAMEDATALEN);
+ /*
+ * We may not have a MyProcPort (eg, if this is the autovacuum process).
+ * If so, use all-zeroes client address, which is dealt with specially in
+ * pg_stat_get_backend_client_addr and pg_stat_get_backend_client_port.
+ */
+ if (MyProcPort)
+ memcpy(&lbeentry.st_clientaddr, &MyProcPort->raddr,
+ sizeof(lbeentry.st_clientaddr));
else
- beentry->st_clienthostname[0] = '\0';
+ MemSet(&lbeentry.st_clientaddr, 0, sizeof(lbeentry.st_clientaddr));
+
#ifdef USE_SSL
if (MyProcPort && MyProcPort->ssl != NULL)
{
- beentry->st_ssl = true;
- beentry->st_sslstatus->ssl_bits = be_tls_get_cipher_bits(MyProcPort);
- beentry->st_sslstatus->ssl_compression = be_tls_get_compression(MyProcPort);
- strlcpy(beentry->st_sslstatus->ssl_version, be_tls_get_version(MyProcPort), NAMEDATALEN);
- strlcpy(beentry->st_sslstatus->ssl_cipher, be_tls_get_cipher(MyProcPort), NAMEDATALEN);
- be_tls_get_peer_subject_name(MyProcPort, beentry->st_sslstatus->ssl_client_dn, NAMEDATALEN);
- be_tls_get_peer_serial(MyProcPort, beentry->st_sslstatus->ssl_client_serial, NAMEDATALEN);
- be_tls_get_peer_issuer_name(MyProcPort, beentry->st_sslstatus->ssl_issuer_dn, NAMEDATALEN);
+ lbeentry.st_ssl = true;
+ lsslstatus.ssl_bits = be_tls_get_cipher_bits(MyProcPort);
+ lsslstatus.ssl_compression = be_tls_get_compression(MyProcPort);
+ strlcpy(lsslstatus.ssl_version, be_tls_get_version(MyProcPort), NAMEDATALEN);
+ strlcpy(lsslstatus.ssl_cipher, be_tls_get_cipher(MyProcPort), NAMEDATALEN);
+ be_tls_get_peer_subject_name(MyProcPort, lsslstatus.ssl_client_dn, NAMEDATALEN);
+ be_tls_get_peer_serial(MyProcPort, lsslstatus.ssl_client_serial, NAMEDATALEN);
+ be_tls_get_peer_issuer_name(MyProcPort, lsslstatus.ssl_issuer_dn, NAMEDATALEN);
}
else
{
- beentry->st_ssl = false;
+ lbeentry.st_ssl = false;
}
#else
- beentry->st_ssl = false;
+ lbeentry.st_ssl = false;
#endif
#ifdef ENABLE_GSS
if (MyProcPort && MyProcPort->gss != NULL)
{
- beentry->st_gss = true;
- beentry->st_gssstatus->gss_auth = be_gssapi_get_auth(MyProcPort);
- beentry->st_gssstatus->gss_enc = be_gssapi_get_enc(MyProcPort);
+ lbeentry.st_gss = true;
+ lgssstatus.gss_auth = be_gssapi_get_auth(MyProcPort);
+ lgssstatus.gss_enc = be_gssapi_get_enc(MyProcPort);
- if (beentry->st_gssstatus->gss_auth)
- strlcpy(beentry->st_gssstatus->gss_princ, be_gssapi_get_princ(MyProcPort), NAMEDATALEN);
+ if (lgssstatus.gss_auth)
+ strlcpy(lgssstatus.gss_princ, be_gssapi_get_princ(MyProcPort), NAMEDATALEN);
}
else
{
- beentry->st_gss = false;
+ lbeentry.st_gss = false;
}
#else
- beentry->st_gss = false;
+ lbeentry.st_gss = false;
#endif
- beentry->st_state = STATE_UNDEFINED;
- beentry->st_appname[0] = '\0';
- beentry->st_activity_raw[0] = '\0';
- /* Also make sure the last byte in each string area is always 0 */
- beentry->st_clienthostname[NAMEDATALEN - 1] = '\0';
- beentry->st_appname[NAMEDATALEN - 1] = '\0';
- beentry->st_activity_raw[pgstat_track_activity_query_size - 1] = '\0';
- beentry->st_progress_command = PROGRESS_COMMAND_INVALID;
- beentry->st_progress_command_target = InvalidOid;
+
+ lbeentry.st_state = STATE_UNDEFINED;
+ lbeentry.st_progress_command = PROGRESS_COMMAND_INVALID;
+ lbeentry.st_progress_command_target = InvalidOid;
/*
* we don't zero st_progress_param here to save cycles; nobody should
@@ -3018,7 +3025,45 @@ pgstat_bestart(void)
* than PROGRESS_COMMAND_INVALID
*/
- pgstat_increment_changecount_after(beentry);
+ /*
+ * We're ready to enter the critical section that fills the shared-memory
+ * status entry. We follow the protocol of bumping st_changecount before
+ * and after; and make sure it's even afterwards. We use a volatile
+ * pointer here to ensure the compiler doesn't try to get cute.
+ */
+ PGSTAT_BEGIN_WRITE_ACTIVITY(vbeentry);
+
+ /* make sure we'll memcpy the same st_changecount back */
+ lbeentry.st_changecount = vbeentry->st_changecount;
+
+ memcpy(unvolatize(PgBackendStatus *, vbeentry),
+ &lbeentry,
+ sizeof(PgBackendStatus));
+
+ /*
+ * We can write the out-of-line strings and structs using the pointers
+ * that are in lbeentry; this saves some de-volatilizing messiness.
+ */
+ lbeentry.st_appname[0] = '\0';
+ if (MyProcPort && MyProcPort->remote_hostname)
+ strlcpy(lbeentry.st_clienthostname, MyProcPort->remote_hostname,
+ NAMEDATALEN);
+ else
+ lbeentry.st_clienthostname[0] = '\0';
+ lbeentry.st_activity_raw[0] = '\0';
+ /* Also make sure the last byte in each string area is always 0 */
+ lbeentry.st_appname[NAMEDATALEN - 1] = '\0';
+ lbeentry.st_clienthostname[NAMEDATALEN - 1] = '\0';
+ lbeentry.st_activity_raw[pgstat_track_activity_query_size - 1] = '\0';
+
+#ifdef USE_SSL
+ memcpy(lbeentry.st_sslstatus, &lsslstatus, sizeof(PgBackendSSLStatus));
+#endif
+#ifdef ENABLE_GSS
+ memcpy(lbeentry.st_gssstatus, &lgssstatus, sizeof(PgBackendGSSStatus));
+#endif
+
+ PGSTAT_END_WRITE_ACTIVITY(vbeentry);
/* Update app name to current GUC setting */
if (application_name)
@@ -3053,11 +3098,11 @@ pgstat_beshutdown_hook(int code, Datum arg)
* before and after. We use a volatile pointer here to ensure the
* compiler doesn't try to get cute.
*/
- pgstat_increment_changecount_before(beentry);
+ PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
beentry->st_procpid = 0; /* mark invalid */
- pgstat_increment_changecount_after(beentry);
+ PGSTAT_END_WRITE_ACTIVITY(beentry);
}
@@ -3096,7 +3141,7 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
* non-disabled state. As our final update, change the state and
* clear fields we will not be updating anymore.
*/
- pgstat_increment_changecount_before(beentry);
+ PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
beentry->st_state = STATE_DISABLED;
beentry->st_state_start_timestamp = 0;
beentry->st_activity_raw[0] = '\0';
@@ -3104,14 +3149,14 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
/* st_xact_start_timestamp and wait_event_info are also disabled */
beentry->st_xact_start_timestamp = 0;
proc->wait_event_info = 0;
- pgstat_increment_changecount_after(beentry);
+ PGSTAT_END_WRITE_ACTIVITY(beentry);
}
return;
}
/*
- * To minimize the time spent modifying the entry, fetch all the needed
- * data first.
+ * To minimize the time spent modifying the entry, and avoid risk of
+ * errors inside the critical section, fetch all the needed data first.
*/
start_timestamp = GetCurrentStatementStartTimestamp();
if (cmd_str != NULL)
@@ -3128,7 +3173,7 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
/*
* Now update the status entry
*/
- pgstat_increment_changecount_before(beentry);
+ PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
beentry->st_state = state;
beentry->st_state_start_timestamp = current_timestamp;
@@ -3140,7 +3185,7 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
beentry->st_activity_start_timestamp = start_timestamp;
}
- pgstat_increment_changecount_after(beentry);
+ PGSTAT_END_WRITE_ACTIVITY(beentry);
}
/*-----------
@@ -3158,11 +3203,11 @@ pgstat_progress_start_command(ProgressCommandType cmdtype, Oid relid)
if (!beentry || !pgstat_track_activities)
return;
- pgstat_increment_changecount_before(beentry);
+ PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
beentry->st_progress_command = cmdtype;
beentry->st_progress_command_target = relid;
MemSet(&beentry->st_progress_param, 0, sizeof(beentry->st_progress_param));
- pgstat_increment_changecount_after(beentry);
+ PGSTAT_END_WRITE_ACTIVITY(beentry);
}
/*-----------
@@ -3181,9 +3226,9 @@ pgstat_progress_update_param(int index, int64 val)
if (!beentry || !pgstat_track_activities)
return;
- pgstat_increment_changecount_before(beentry);
+ PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
beentry->st_progress_param[index] = val;
- pgstat_increment_changecount_after(beentry);
+ PGSTAT_END_WRITE_ACTIVITY(beentry);
}
/*-----------
@@ -3203,7 +3248,7 @@ pgstat_progress_update_multi_param(int nparam, const int *index,
if (!beentry || !pgstat_track_activities || nparam == 0)
return;
- pgstat_increment_changecount_before(beentry);
+ PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
for (i = 0; i < nparam; ++i)
{
@@ -3212,7 +3257,7 @@ pgstat_progress_update_multi_param(int nparam, const int *index,
beentry->st_progress_param[index[i]] = val[i];
}
- pgstat_increment_changecount_after(beentry);
+ PGSTAT_END_WRITE_ACTIVITY(beentry);
}
/*-----------
@@ -3233,10 +3278,10 @@ pgstat_progress_end_command(void)
&& beentry->st_progress_command == PROGRESS_COMMAND_INVALID)
return;
- pgstat_increment_changecount_before(beentry);
+ PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
beentry->st_progress_command = PROGRESS_COMMAND_INVALID;
beentry->st_progress_command_target = InvalidOid;
- pgstat_increment_changecount_after(beentry);
+ PGSTAT_END_WRITE_ACTIVITY(beentry);
}
/* ----------
@@ -3262,12 +3307,12 @@ pgstat_report_appname(const char *appname)
* st_changecount before and after. We use a volatile pointer here to
* ensure the compiler doesn't try to get cute.
*/
- pgstat_increment_changecount_before(beentry);
+ PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
memcpy((char *) beentry->st_appname, appname, len);
beentry->st_appname[len] = '\0';
- pgstat_increment_changecount_after(beentry);
+ PGSTAT_END_WRITE_ACTIVITY(beentry);
}
/*
@@ -3287,9 +3332,11 @@ pgstat_report_xact_timestamp(TimestampTz tstamp)
* st_changecount before and after. We use a volatile pointer here to
* ensure the compiler doesn't try to get cute.
*/
- pgstat_increment_changecount_before(beentry);
+ PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
+
beentry->st_xact_start_timestamp = tstamp;
- pgstat_increment_changecount_after(beentry);
+
+ PGSTAT_END_WRITE_ACTIVITY(beentry);
}
/* ----------
@@ -3311,6 +3358,9 @@ pgstat_read_current_status(void)
#ifdef USE_SSL
PgBackendSSLStatus *localsslstatus;
#endif
+#ifdef ENABLE_GSS
+ PgBackendGSSStatus *localgssstatus;
+#endif
int i;
Assert(!pgStatRunningInCollector);
@@ -3344,6 +3394,11 @@ pgstat_read_current_status(void)
MemoryContextAlloc(pgStatLocalContext,
sizeof(PgBackendSSLStatus) * NumBackendStatSlots);
#endif
+#ifdef ENABLE_GSS
+ localgssstatus = (PgBackendGSSStatus *)
+ MemoryContextAlloc(pgStatLocalContext,
+ sizeof(PgBackendGSSStatus) * NumBackendStatSlots);
+#endif
localNumBackends = 0;
@@ -3363,14 +3418,19 @@ pgstat_read_current_status(void)
int before_changecount;
int after_changecount;
- pgstat_save_changecount_before(beentry, before_changecount);
+ pgstat_begin_read_activity(beentry, before_changecount);
localentry->backendStatus.st_procpid = beentry->st_procpid;
+ /* Skip all the data-copying work if entry is not in use */
if (localentry->backendStatus.st_procpid > 0)
{
memcpy(&localentry->backendStatus, unvolatize(PgBackendStatus *, beentry), sizeof(PgBackendStatus));
/*
+ * For each PgBackendStatus field that is a pointer, copy the
+ * pointed-to data, then adjust the local copy of the pointer
+ * field to point at the local copy of the data.
+ *
* strcpy is safe even if the string is modified concurrently,
* because there's always a \0 at the end of the buffer.
*/
@@ -3380,7 +3440,6 @@ pgstat_read_current_status(void)
localentry->backendStatus.st_clienthostname = localclienthostname;
strcpy(localactivity, (char *) beentry->st_activity_raw);
localentry->backendStatus.st_activity_raw = localactivity;
- localentry->backendStatus.st_ssl = beentry->st_ssl;
#ifdef USE_SSL
if (beentry->st_ssl)
{
@@ -3388,11 +3447,19 @@ pgstat_read_current_status(void)
localentry->backendStatus.st_sslstatus = localsslstatus;
}
#endif
+#ifdef ENABLE_GSS
+ if (beentry->st_gss)
+ {
+ memcpy(localgssstatus, beentry->st_gssstatus, sizeof(PgBackendGSSStatus));
+ localentry->backendStatus.st_gssstatus = localgssstatus;
+ }
+#endif
}
- pgstat_save_changecount_after(beentry, after_changecount);
- if (before_changecount == after_changecount &&
- (before_changecount & 1) == 0)
+ pgstat_end_read_activity(beentry, after_changecount);
+
+ if (pgstat_read_activity_complete(before_changecount,
+ after_changecount))
break;
/* Make sure we can break out of loop if stuck... */
@@ -3414,6 +3481,9 @@ pgstat_read_current_status(void)
#ifdef USE_SSL
localsslstatus++;
#endif
+#ifdef ENABLE_GSS
+ localgssstatus++;
+#endif
localNumBackends++;
}
}
@@ -4090,14 +4160,14 @@ pgstat_get_backend_current_activity(int pid, bool checkUser)
int before_changecount;
int after_changecount;
- pgstat_save_changecount_before(vbeentry, before_changecount);
+ pgstat_begin_read_activity(vbeentry, before_changecount);
found = (vbeentry->st_procpid == pid);
- pgstat_save_changecount_after(vbeentry, after_changecount);
+ pgstat_end_read_activity(vbeentry, after_changecount);
- if (before_changecount == after_changecount &&
- (before_changecount & 1) == 0)
+ if (pgstat_read_activity_complete(before_changecount,
+ after_changecount))
break;
/* Make sure we can break out of loop if stuck... */