Skip to content

Commit d951052

Browse files
committed
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/[email protected]
1 parent 421892a commit d951052

File tree

7 files changed

+163
-24
lines changed

7 files changed

+163
-24
lines changed

src/backend/access/transam/parallel.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
#define PARALLEL_KEY_REINDEX_STATE UINT64CONST(0xFFFFFFFFFFFF000C)
7777
#define PARALLEL_KEY_RELMAPPER_STATE UINT64CONST(0xFFFFFFFFFFFF000D)
7878
#define PARALLEL_KEY_UNCOMMITTEDENUMS UINT64CONST(0xFFFFFFFFFFFF000E)
79+
#define PARALLEL_KEY_CLIENTCONNINFO UINT64CONST(0xFFFFFFFFFFFF000F)
7980

8081
/* Fixed-size parallel state. */
8182
typedef struct FixedParallelState
@@ -212,6 +213,7 @@ InitializeParallelDSM(ParallelContext *pcxt)
212213
Size reindexlen = 0;
213214
Size relmapperlen = 0;
214215
Size uncommittedenumslen = 0;
216+
Size clientconninfolen = 0;
215217
Size segsize = 0;
216218
int i;
217219
FixedParallelState *fps;
@@ -272,8 +274,10 @@ InitializeParallelDSM(ParallelContext *pcxt)
272274
shm_toc_estimate_chunk(&pcxt->estimator, relmapperlen);
273275
uncommittedenumslen = EstimateUncommittedEnumsSpace();
274276
shm_toc_estimate_chunk(&pcxt->estimator, uncommittedenumslen);
277+
clientconninfolen = EstimateClientConnectionInfoSpace();
278+
shm_toc_estimate_chunk(&pcxt->estimator, clientconninfolen);
275279
/* If you add more chunks here, you probably need to add keys. */
276-
shm_toc_estimate_keys(&pcxt->estimator, 11);
280+
shm_toc_estimate_keys(&pcxt->estimator, 12);
277281

278282
/* Estimate space need for error queues. */
279283
StaticAssertStmt(BUFFERALIGN(PARALLEL_ERROR_QUEUE_SIZE) ==
@@ -352,6 +356,7 @@ InitializeParallelDSM(ParallelContext *pcxt)
352356
char *session_dsm_handle_space;
353357
char *entrypointstate;
354358
char *uncommittedenumsspace;
359+
char *clientconninfospace;
355360
Size lnamelen;
356361

357362
/* Serialize shared libraries we have loaded. */
@@ -422,6 +427,12 @@ InitializeParallelDSM(ParallelContext *pcxt)
422427
shm_toc_insert(pcxt->toc, PARALLEL_KEY_UNCOMMITTEDENUMS,
423428
uncommittedenumsspace);
424429

430+
/* Serialize our ClientConnectionInfo. */
431+
clientconninfospace = shm_toc_allocate(pcxt->toc, clientconninfolen);
432+
SerializeClientConnectionInfo(clientconninfolen, clientconninfospace);
433+
shm_toc_insert(pcxt->toc, PARALLEL_KEY_CLIENTCONNINFO,
434+
clientconninfospace);
435+
425436
/* Allocate space for worker information. */
426437
pcxt->worker = palloc0(sizeof(ParallelWorkerInfo) * pcxt->nworkers);
427438

@@ -1270,6 +1281,7 @@ ParallelWorkerMain(Datum main_arg)
12701281
char *reindexspace;
12711282
char *relmapperspace;
12721283
char *uncommittedenumsspace;
1284+
char *clientconninfospace;
12731285
StringInfoData msgbuf;
12741286
char *session_dsm_handle_space;
12751287
Snapshot tsnapshot;
@@ -1479,6 +1491,11 @@ ParallelWorkerMain(Datum main_arg)
14791491
false);
14801492
RestoreUncommittedEnums(uncommittedenumsspace);
14811493

1494+
/* Restore the ClientConnectionInfo. */
1495+
clientconninfospace = shm_toc_lookup(toc, PARALLEL_KEY_CLIENTCONNINFO,
1496+
false);
1497+
RestoreClientConnectionInfo(clientconninfospace);
1498+
14821499
/* Attach to the leader's serializable transaction, if SERIALIZABLE. */
14831500
AttachSerializableXact(fps->serializable_xact_handle);
14841501

src/backend/libpq/auth.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -333,23 +333,23 @@ auth_failed(Port *port, int status, const char *logdetail)
333333

334334
/*
335335
* Sets the authenticated identity for the current user. The provided string
336-
* will be copied into the TopMemoryContext. The ID will be logged if
337-
* log_connections is enabled.
336+
* will be stored into MyClientConnectionInfo, alongside the current HBA
337+
* method in use. The ID will be logged if log_connections is enabled.
338338
*
339339
* Auth methods should call this routine exactly once, as soon as the user is
340340
* successfully authenticated, even if they have reasons to know that
341341
* authorization will fail later.
342342
*
343343
* The provided string will be copied into TopMemoryContext, to match the
344-
* lifetime of the Port, so it is safe to pass a string that is managed by an
345-
* external library.
344+
* lifetime of MyClientConnectionInfo, so it is safe to pass a string that is
345+
* managed by an external library.
346346
*/
347347
static void
348348
set_authn_id(Port *port, const char *id)
349349
{
350350
Assert(id);
351351

352-
if (port->authn_id)
352+
if (MyClientConnectionInfo.authn_id)
353353
{
354354
/*
355355
* An existing authn_id should never be overwritten; that means two
@@ -360,18 +360,20 @@ set_authn_id(Port *port, const char *id)
360360
ereport(FATAL,
361361
(errmsg("authentication identifier set more than once"),
362362
errdetail_log("previous identifier: \"%s\"; new identifier: \"%s\"",
363-
port->authn_id, id)));
363+
MyClientConnectionInfo.authn_id, id)));
364364
}
365365

366-
port->authn_id = MemoryContextStrdup(TopMemoryContext, id);
366+
MyClientConnectionInfo.authn_id = MemoryContextStrdup(TopMemoryContext, id);
367+
MyClientConnectionInfo.auth_method = port->hba->auth_method;
367368

368369
if (Log_connections)
369370
{
370371
ereport(LOG,
371372
errmsg("connection authenticated: identity=\"%s\" method=%s "
372373
"(%s:%d)",
373-
port->authn_id, hba_authname(port->hba->auth_method), HbaFileName,
374-
port->hba->linenumber));
374+
MyClientConnectionInfo.authn_id,
375+
hba_authname(MyClientConnectionInfo.auth_method),
376+
HbaFileName, port->hba->linenumber));
375377
}
376378
}
377379

@@ -1907,7 +1909,8 @@ auth_peer(hbaPort *port)
19071909
*/
19081910
set_authn_id(port, pw->pw_name);
19091911

1910-
ret = check_usermap(port->hba->usermap, port->user_name, port->authn_id, false);
1912+
ret = check_usermap(port->hba->usermap, port->user_name,
1913+
MyClientConnectionInfo.authn_id, false);
19111914

19121915
return ret;
19131916
#else

src/backend/postmaster/postmaster.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4305,6 +4305,7 @@ BackendInitialize(Port *port)
43054305

43064306
/* Save port etc. for ps status */
43074307
MyProcPort = port;
4308+
memset(&MyClientConnectionInfo, 0, sizeof(MyClientConnectionInfo));
43084309

43094310
/* Tell fd.c about the long-lived FD associated with the port */
43104311
ReserveExternalFD();

src/backend/utils/init/miscinit.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,99 @@ GetUserNameFromId(Oid roleid, bool noerr)
936936
return result;
937937
}
938938

939+
/* ------------------------------------------------------------------------
940+
* Client connection state shared with parallel workers
941+
*
942+
* ClientConnectionInfo contains pieces of information about the client that
943+
* need to be synced to parallel workers when they initialize.
944+
*-------------------------------------------------------------------------
945+
*/
946+
947+
ClientConnectionInfo MyClientConnectionInfo;
948+
949+
/*
950+
* Intermediate representation of ClientConnectionInfo for easier
951+
* serialization. Variable-length fields are allocated right after this
952+
* header.
953+
*/
954+
typedef struct SerializedClientConnectionInfo
955+
{
956+
int32 authn_id_len; /* strlen(authn_id), or -1 if NULL */
957+
UserAuth auth_method;
958+
} SerializedClientConnectionInfo;
959+
960+
/*
961+
* Calculate the space needed to serialize MyClientConnectionInfo.
962+
*/
963+
Size
964+
EstimateClientConnectionInfoSpace(void)
965+
{
966+
Size size = 0;
967+
968+
size = add_size(size, sizeof(SerializedClientConnectionInfo));
969+
970+
if (MyClientConnectionInfo.authn_id)
971+
size = add_size(size, strlen(MyClientConnectionInfo.authn_id) + 1);
972+
973+
return size;
974+
}
975+
976+
/*
977+
* Serialize MyClientConnectionInfo for use by parallel workers.
978+
*/
979+
void
980+
SerializeClientConnectionInfo(Size maxsize, char *start_address)
981+
{
982+
SerializedClientConnectionInfo serialized = {0};
983+
984+
serialized.authn_id_len = -1;
985+
serialized.auth_method = MyClientConnectionInfo.auth_method;
986+
987+
if (MyClientConnectionInfo.authn_id)
988+
serialized.authn_id_len = strlen(MyClientConnectionInfo.authn_id);
989+
990+
/* Copy serialized representation to buffer */
991+
Assert(maxsize >= sizeof(serialized));
992+
memcpy(start_address, &serialized, sizeof(serialized));
993+
994+
maxsize -= sizeof(serialized);
995+
start_address += sizeof(serialized);
996+
997+
/* Copy authn_id into the space after the struct */
998+
if (serialized.authn_id_len >= 0)
999+
{
1000+
Assert(maxsize >= (serialized.authn_id_len + 1));
1001+
memcpy(start_address,
1002+
MyClientConnectionInfo.authn_id,
1003+
/* include the NULL terminator to ease deserialization */
1004+
serialized.authn_id_len + 1);
1005+
}
1006+
}
1007+
1008+
/*
1009+
* Restore MyClientConnectionInfo from its serialized representation.
1010+
*/
1011+
void
1012+
RestoreClientConnectionInfo(char *conninfo)
1013+
{
1014+
SerializedClientConnectionInfo serialized;
1015+
1016+
memcpy(&serialized, conninfo, sizeof(serialized));
1017+
1018+
/* Copy the fields back into place */
1019+
MyClientConnectionInfo.authn_id = NULL;
1020+
MyClientConnectionInfo.auth_method = serialized.auth_method;
1021+
1022+
if (serialized.authn_id_len >= 0)
1023+
{
1024+
char *authn_id;
1025+
1026+
authn_id = conninfo + sizeof(serialized);
1027+
MyClientConnectionInfo.authn_id = MemoryContextStrdup(TopMemoryContext,
1028+
authn_id);
1029+
}
1030+
}
1031+
9391032

9401033
/*-------------------------------------------------------------------------
9411034
* Interlock-file support

src/include/libpq/libpq-be.h

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,37 @@ typedef struct
8888
} pg_gssinfo;
8989
#endif
9090

91+
/*
92+
* ClientConnectionInfo includes the fields describing the client connection
93+
* that are copied over to parallel workers as nothing from Port does that.
94+
* The same rules apply for allocations here as for Port (everything must be
95+
* malloc'd or palloc'd in TopMemoryContext).
96+
*
97+
* If you add a struct member here, remember to also handle serialization in
98+
* SerializeClientConnectionInfo() and co.
99+
*/
100+
typedef struct ClientConnectionInfo
101+
{
102+
/*
103+
* Authenticated identity. The meaning of this identifier is dependent on
104+
* auth_method; it is the identity (if any) that the user presented during
105+
* the authentication cycle, before they were assigned a database role.
106+
* (It is effectively the "SYSTEM-USERNAME" of a pg_ident usermap --
107+
* though the exact string in use may be different, depending on pg_hba
108+
* options.)
109+
*
110+
* authn_id is NULL if the user has not actually been authenticated, for
111+
* example if the "trust" auth method is in use.
112+
*/
113+
const char *authn_id;
114+
115+
/*
116+
* The HBA method that determined the above authn_id. This only has
117+
* meaning if authn_id is not NULL; otherwise it's undefined.
118+
*/
119+
UserAuth auth_method;
120+
} ClientConnectionInfo;
121+
91122
/*
92123
* This is used by the postmaster in its communication with frontends. It
93124
* contains all state information needed during this communication before the
@@ -148,19 +179,6 @@ typedef struct Port
148179
*/
149180
HbaLine *hba;
150181

151-
/*
152-
* Authenticated identity. The meaning of this identifier is dependent on
153-
* hba->auth_method; it is the identity (if any) that the user presented
154-
* during the authentication cycle, before they were assigned a database
155-
* role. (It is effectively the "SYSTEM-USERNAME" of a pg_ident usermap
156-
* -- though the exact string in use may be different, depending on pg_hba
157-
* options.)
158-
*
159-
* authn_id is NULL if the user has not actually been authenticated, for
160-
* example if the "trust" auth method is in use.
161-
*/
162-
const char *authn_id;
163-
164182
/*
165183
* TCP keepalive and user timeout settings.
166184
*
@@ -317,6 +335,7 @@ extern ssize_t be_gssapi_write(Port *port, void *ptr, size_t len);
317335
#endif /* ENABLE_GSS */
318336

319337
extern PGDLLIMPORT ProtocolVersion FrontendProtocol;
338+
extern PGDLLIMPORT ClientConnectionInfo MyClientConnectionInfo;
320339

321340
/* TCP keepalives configuration. These are no-ops on an AF_UNIX socket. */
322341

src/include/miscadmin.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,10 @@ extern bool has_rolreplication(Oid roleid);
482482
typedef void (*shmem_request_hook_type) (void);
483483
extern PGDLLIMPORT shmem_request_hook_type shmem_request_hook;
484484

485+
extern Size EstimateClientConnectionInfoSpace(void);
486+
extern void SerializeClientConnectionInfo(Size maxsize, char *start_address);
487+
extern void RestoreClientConnectionInfo(char *conninfo);
488+
485489
/* in executor/nodeHash.c */
486490
extern size_t get_hash_memory_limit(void);
487491

src/tools/pgindent/typedefs.list

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ CkptTsStatus
373373
ClientAuthentication_hook_type
374374
ClientCertMode
375375
ClientCertName
376+
ClientConnectionInfo
376377
ClientData
377378
ClonePtrType
378379
ClosePortalStmt
@@ -2455,6 +2456,7 @@ SerCommitSeqNo
24552456
SerialControl
24562457
SerializableXactHandle
24572458
SerializedActiveRelMaps
2459+
SerializedClientConnectionInfo
24582460
SerializedRanges
24592461
SerializedReindexState
24602462
SerializedSnapshotData

0 commit comments

Comments
 (0)