diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/postmaster/pgstat.c | 288 |
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... */ |