commit 753c46352adc967a903a60ea65a3068252d685e6 Author: Jacob Champion Date: Tue Aug 16 09:14:58 2022 -0700 squash! Allow parallel workers to read authn_id Per review, - add an intermediate struct for serialization, - switch to length-prefixing for the authn_id string, and - make sure `struct ClientConnectionInfo` is declared for use elsewhere. diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 155ba92c67..58772d0a4a 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -943,19 +943,29 @@ GetUserNameFromId(Oid roleid, bool noerr) 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 = 1; + Size size = 0; + + size = add_size(size, sizeof(SerializedClientConnectionInfo)); if (MyClientConnectionInfo.authn_id) size = add_size(size, strlen(MyClientConnectionInfo.authn_id) + 1); - size = add_size(size, sizeof(UserAuth)); - return size; } @@ -965,32 +975,29 @@ EstimateClientConnectionInfoSpace(void) void SerializeClientConnectionInfo(Size maxsize, char *start_address) { - /* - * First byte is an indication of whether or not authn_id has been set to - * non-NULL, to differentiate that case from the empty string. - */ - Assert(maxsize > 0); - start_address[0] = MyClientConnectionInfo.authn_id ? 1 : 0; - start_address++; - maxsize--; + SerializedClientConnectionInfo serialized = {0}; + + serialized.authn_id_len = -1; + serialized.auth_method = MyClientConnectionInfo.auth_method; if (MyClientConnectionInfo.authn_id) - { - Size len; + serialized.authn_id_len = strlen(MyClientConnectionInfo.authn_id); - len = strlcpy(start_address, MyClientConnectionInfo.authn_id, maxsize) + 1; - Assert(len <= maxsize); - maxsize -= len; - start_address += len; - } + /* Copy serialized representation to buffer */ + Assert(maxsize >= sizeof(serialized)); + memcpy(start_address, &serialized, sizeof(serialized)); - { - UserAuth *auth_method = (UserAuth*) start_address; + maxsize -= sizeof(serialized); + start_address += sizeof(serialized); - Assert(sizeof(*auth_method) <= maxsize); - *auth_method = MyClientConnectionInfo.auth_method; - maxsize -= sizeof(*auth_method); - start_address += sizeof(*auth_method); + /* 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); } } @@ -1000,25 +1007,19 @@ SerializeClientConnectionInfo(Size maxsize, char *start_address) void RestoreClientConnectionInfo(char *conninfo) { - if (conninfo[0] == 0) - { - MyClientConnectionInfo.authn_id = NULL; - conninfo++; - } - else - { - conninfo++; - MyClientConnectionInfo.authn_id = MemoryContextStrdup(TopMemoryContext, - conninfo); - conninfo += strlen(conninfo) + 1; - } + SerializedClientConnectionInfo serialized; + char *authn_id; - { - UserAuth *auth_method = (UserAuth*) conninfo; + memcpy(&serialized, conninfo, sizeof(serialized)); + authn_id = conninfo + sizeof(serialized); - MyClientConnectionInfo.auth_method = *auth_method; - conninfo += sizeof(*auth_method); - } + /* Copy the fields back into place. */ + MyClientConnectionInfo.authn_id = NULL; + MyClientConnectionInfo.auth_method = serialized.auth_method; + + if (serialized.authn_id_len >= 0) + MyClientConnectionInfo.authn_id = MemoryContextStrdup(TopMemoryContext, + authn_id); } diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h index 0643733765..84a6bdea6f 100644 --- a/src/include/libpq/libpq-be.h +++ b/src/include/libpq/libpq-be.h @@ -107,7 +107,7 @@ typedef struct * If you add a struct member here, remember to also handle serialization in * SerializeClientConnectionInfo() et al. */ -typedef struct +typedef struct ClientConnectionInfo { /* * Authenticated identity. The meaning of this identifier is dependent on