Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Paquier2022-08-24 03:57:13 +0000
committerMichael Paquier2022-08-24 03:57:13 +0000
commitd951052a9e02bfacad8bd6f0f53a4dcd3b7e6d1f (patch)
tree3191caa0fb1cff85f349f3cdbb111ceca995f85c /src/backend
parent421892a192b8f95ab96c5edb61d424f80a4221d0 (diff)
Allow parallel workers to retrieve some data from Port
This commit moves authn_id into a new global structure called ClientConnectionInfo (mapping to a MyClientConnectionInfo for each backend) which is intended to hold all the client information that should be shared between the backend and any of its parallel workers, access for extensions and triggers being the primary use case. There is no need to push all the data of Port to the workers, and authn_id is quite a generic concept so using a separate structure provides the best balance (the name of the structure has been suggested by Robert Haas). While on it, and per discussion as this would be useful for a potential SYSTEM_USER that can be accessed through parallel workers, a second field is added for the authentication method, copied directly from Port. ClientConnectionInfo is serialized and restored using a new parallel key and a structure tracks the length of the authn_id, making the addition of more fields straight-forward. Author: Jacob Champion Reviewed-by: Bertrand Drouvot, Stephen Frost, Robert Haas, Tom Lane, Michael Paquier, Julien Rouhaud Discussion: https://postgr.es/m/793d990837ae5c06a558d58d62de9378ab525d83.camel@vmware.com
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/transam/parallel.c19
-rw-r--r--src/backend/libpq/auth.c23
-rw-r--r--src/backend/postmaster/postmaster.c1
-rw-r--r--src/backend/utils/init/miscinit.c93
4 files changed, 125 insertions, 11 deletions
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index df0cd775588..bc93101ff71 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -76,6 +76,7 @@
#define PARALLEL_KEY_REINDEX_STATE UINT64CONST(0xFFFFFFFFFFFF000C)
#define PARALLEL_KEY_RELMAPPER_STATE UINT64CONST(0xFFFFFFFFFFFF000D)
#define PARALLEL_KEY_UNCOMMITTEDENUMS UINT64CONST(0xFFFFFFFFFFFF000E)
+#define PARALLEL_KEY_CLIENTCONNINFO UINT64CONST(0xFFFFFFFFFFFF000F)
/* Fixed-size parallel state. */
typedef struct FixedParallelState
@@ -212,6 +213,7 @@ InitializeParallelDSM(ParallelContext *pcxt)
Size reindexlen = 0;
Size relmapperlen = 0;
Size uncommittedenumslen = 0;
+ Size clientconninfolen = 0;
Size segsize = 0;
int i;
FixedParallelState *fps;
@@ -272,8 +274,10 @@ InitializeParallelDSM(ParallelContext *pcxt)
shm_toc_estimate_chunk(&pcxt->estimator, relmapperlen);
uncommittedenumslen = EstimateUncommittedEnumsSpace();
shm_toc_estimate_chunk(&pcxt->estimator, uncommittedenumslen);
+ clientconninfolen = EstimateClientConnectionInfoSpace();
+ shm_toc_estimate_chunk(&pcxt->estimator, clientconninfolen);
/* If you add more chunks here, you probably need to add keys. */
- shm_toc_estimate_keys(&pcxt->estimator, 11);
+ shm_toc_estimate_keys(&pcxt->estimator, 12);
/* Estimate space need for error queues. */
StaticAssertStmt(BUFFERALIGN(PARALLEL_ERROR_QUEUE_SIZE) ==
@@ -352,6 +356,7 @@ InitializeParallelDSM(ParallelContext *pcxt)
char *session_dsm_handle_space;
char *entrypointstate;
char *uncommittedenumsspace;
+ char *clientconninfospace;
Size lnamelen;
/* Serialize shared libraries we have loaded. */
@@ -422,6 +427,12 @@ InitializeParallelDSM(ParallelContext *pcxt)
shm_toc_insert(pcxt->toc, PARALLEL_KEY_UNCOMMITTEDENUMS,
uncommittedenumsspace);
+ /* Serialize our ClientConnectionInfo. */
+ clientconninfospace = shm_toc_allocate(pcxt->toc, clientconninfolen);
+ SerializeClientConnectionInfo(clientconninfolen, clientconninfospace);
+ shm_toc_insert(pcxt->toc, PARALLEL_KEY_CLIENTCONNINFO,
+ clientconninfospace);
+
/* Allocate space for worker information. */
pcxt->worker = palloc0(sizeof(ParallelWorkerInfo) * pcxt->nworkers);
@@ -1270,6 +1281,7 @@ ParallelWorkerMain(Datum main_arg)
char *reindexspace;
char *relmapperspace;
char *uncommittedenumsspace;
+ char *clientconninfospace;
StringInfoData msgbuf;
char *session_dsm_handle_space;
Snapshot tsnapshot;
@@ -1479,6 +1491,11 @@ ParallelWorkerMain(Datum main_arg)
false);
RestoreUncommittedEnums(uncommittedenumsspace);
+ /* Restore the ClientConnectionInfo. */
+ clientconninfospace = shm_toc_lookup(toc, PARALLEL_KEY_CLIENTCONNINFO,
+ false);
+ RestoreClientConnectionInfo(clientconninfospace);
+
/* Attach to the leader's serializable transaction, if SERIALIZABLE. */
AttachSerializableXact(fps->serializable_xact_handle);
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 1545ff9f161..2e7330f7bc6 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -333,23 +333,23 @@ auth_failed(Port *port, int status, const char *logdetail)
/*
* Sets the authenticated identity for the current user. The provided string
- * will be copied into the TopMemoryContext. The ID will be logged if
- * log_connections is enabled.
+ * will be stored into MyClientConnectionInfo, alongside the current HBA
+ * method in use. The ID will be logged if log_connections is enabled.
*
* Auth methods should call this routine exactly once, as soon as the user is
* successfully authenticated, even if they have reasons to know that
* authorization will fail later.
*
* The provided string will be copied into TopMemoryContext, to match the
- * lifetime of the Port, so it is safe to pass a string that is managed by an
- * external library.
+ * lifetime of MyClientConnectionInfo, so it is safe to pass a string that is
+ * managed by an external library.
*/
static void
set_authn_id(Port *port, const char *id)
{
Assert(id);
- if (port->authn_id)
+ if (MyClientConnectionInfo.authn_id)
{
/*
* An existing authn_id should never be overwritten; that means two
@@ -360,18 +360,20 @@ set_authn_id(Port *port, const char *id)
ereport(FATAL,
(errmsg("authentication identifier set more than once"),
errdetail_log("previous identifier: \"%s\"; new identifier: \"%s\"",
- port->authn_id, id)));
+ MyClientConnectionInfo.authn_id, id)));
}
- port->authn_id = MemoryContextStrdup(TopMemoryContext, id);
+ MyClientConnectionInfo.authn_id = MemoryContextStrdup(TopMemoryContext, id);
+ MyClientConnectionInfo.auth_method = port->hba->auth_method;
if (Log_connections)
{
ereport(LOG,
errmsg("connection authenticated: identity=\"%s\" method=%s "
"(%s:%d)",
- port->authn_id, hba_authname(port->hba->auth_method), HbaFileName,
- port->hba->linenumber));
+ MyClientConnectionInfo.authn_id,
+ hba_authname(MyClientConnectionInfo.auth_method),
+ HbaFileName, port->hba->linenumber));
}
}
@@ -1907,7 +1909,8 @@ auth_peer(hbaPort *port)
*/
set_authn_id(port, pw->pw_name);
- ret = check_usermap(port->hba->usermap, port->user_name, port->authn_id, false);
+ ret = check_usermap(port->hba->usermap, port->user_name,
+ MyClientConnectionInfo.authn_id, false);
return ret;
#else
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 1664fcee2a7..53f02241632 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -4305,6 +4305,7 @@ BackendInitialize(Port *port)
/* Save port etc. for ps status */
MyProcPort = port;
+ memset(&MyClientConnectionInfo, 0, sizeof(MyClientConnectionInfo));
/* Tell fd.c about the long-lived FD associated with the port */
ReserveExternalFD();
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index bf3871a774b..683f616b1a8 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -936,6 +936,99 @@ GetUserNameFromId(Oid roleid, bool noerr)
return result;
}
+/* ------------------------------------------------------------------------
+ * Client connection state shared with parallel workers
+ *
+ * ClientConnectionInfo contains pieces of information about the client that
+ * need to be synced to parallel workers when they initialize.
+ *-------------------------------------------------------------------------
+ */
+
+ClientConnectionInfo MyClientConnectionInfo;
+
+/*
+ * Intermediate representation of ClientConnectionInfo for easier
+ * serialization. Variable-length fields are allocated right after this
+ * header.
+ */
+typedef struct SerializedClientConnectionInfo
+{
+ int32 authn_id_len; /* strlen(authn_id), or -1 if NULL */
+ UserAuth auth_method;
+} SerializedClientConnectionInfo;
+
+/*
+ * Calculate the space needed to serialize MyClientConnectionInfo.
+ */
+Size
+EstimateClientConnectionInfoSpace(void)
+{
+ Size size = 0;
+
+ size = add_size(size, sizeof(SerializedClientConnectionInfo));
+
+ if (MyClientConnectionInfo.authn_id)
+ size = add_size(size, strlen(MyClientConnectionInfo.authn_id) + 1);
+
+ return size;
+}
+
+/*
+ * Serialize MyClientConnectionInfo for use by parallel workers.
+ */
+void
+SerializeClientConnectionInfo(Size maxsize, char *start_address)
+{
+ SerializedClientConnectionInfo serialized = {0};
+
+ serialized.authn_id_len = -1;
+ serialized.auth_method = MyClientConnectionInfo.auth_method;
+
+ if (MyClientConnectionInfo.authn_id)
+ serialized.authn_id_len = strlen(MyClientConnectionInfo.authn_id);
+
+ /* Copy serialized representation to buffer */
+ Assert(maxsize >= sizeof(serialized));
+ memcpy(start_address, &serialized, sizeof(serialized));
+
+ maxsize -= sizeof(serialized);
+ start_address += sizeof(serialized);
+
+ /* Copy authn_id into the space after the struct */
+ if (serialized.authn_id_len >= 0)
+ {
+ Assert(maxsize >= (serialized.authn_id_len + 1));
+ memcpy(start_address,
+ MyClientConnectionInfo.authn_id,
+ /* include the NULL terminator to ease deserialization */
+ serialized.authn_id_len + 1);
+ }
+}
+
+/*
+ * Restore MyClientConnectionInfo from its serialized representation.
+ */
+void
+RestoreClientConnectionInfo(char *conninfo)
+{
+ SerializedClientConnectionInfo serialized;
+
+ memcpy(&serialized, conninfo, sizeof(serialized));
+
+ /* Copy the fields back into place */
+ MyClientConnectionInfo.authn_id = NULL;
+ MyClientConnectionInfo.auth_method = serialized.auth_method;
+
+ if (serialized.authn_id_len >= 0)
+ {
+ char *authn_id;
+
+ authn_id = conninfo + sizeof(serialized);
+ MyClientConnectionInfo.authn_id = MemoryContextStrdup(TopMemoryContext,
+ authn_id);
+ }
+}
+
/*-------------------------------------------------------------------------
* Interlock-file support