aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeff Davis <jdavis@postgresql.org>2023-12-08 11:16:01 -0800
committerJeff Davis <jdavis@postgresql.org>2023-12-08 11:16:01 -0800
commit867dd2dc8704e58636b8599f61ada3d83c7e6473 (patch)
treedb81dcac5eef5d9d54dc2c5739808f50beb59907 /src
parentc9c0589fda0edc46b8f5e7362b04636c0c4f0723 (diff)
downloadpostgresql-867dd2dc8704e58636b8599f61ada3d83c7e6473.tar.gz
postgresql-867dd2dc8704e58636b8599f61ada3d83c7e6473.zip
Cache opaque handle for GUC option to avoid repeasted lookups.
When setting GUCs from proconfig, performance is important, and hash lookups in the GUC table are significant. Per suggestion from Robert Haas. Discussion: https://postgr.es/m/CA+TgmoYpKxhR3HOD9syK2XwcAUVPa0+ba0XPnwWBcYxtKLkyxA@mail.gmail.com Reviewed-by: John Naylor
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/fmgr/fmgr.c31
-rw-r--r--src/backend/utils/misc/guc.c57
-rw-r--r--src/include/utils/guc.h9
-rw-r--r--src/tools/pgindent/typedefs.list1
4 files changed, 84 insertions, 14 deletions
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 9dfdf890c51..f8f770fd5c0 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -613,6 +613,7 @@ struct fmgr_security_definer_cache
FmgrInfo flinfo; /* lookup info for target function */
Oid userid; /* userid to set, or InvalidOid */
List *configNames; /* GUC names to set, or NIL */
+ List *configHandles; /* GUC handles to set, or NIL */
List *configValues; /* GUC values to set, or NIL */
Datum arg; /* passthrough argument for plugin modules */
};
@@ -635,8 +636,9 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
FmgrInfo *save_flinfo;
Oid save_userid;
int save_sec_context;
- ListCell *lc1;
- ListCell *lc2;
+ ListCell *lc1,
+ *lc2,
+ *lc3;
volatile int save_nestlevel;
PgStat_FunctionCallUsage fcusage;
@@ -670,11 +672,23 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
if (!isnull)
{
ArrayType *array;
+ ListCell *lc;
oldcxt = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
array = DatumGetArrayTypeP(datum);
TransformGUCArray(array, &fcache->configNames,
&fcache->configValues);
+
+ /* transform names to config handles to avoid lookup cost */
+ fcache->configHandles = NIL;
+ foreach(lc, fcache->configNames)
+ {
+ char *name = (char *) lfirst(lc);
+
+ fcache->configHandles = lappend(fcache->configHandles,
+ get_config_handle(name));
+ }
+
MemoryContextSwitchTo(oldcxt);
}
@@ -696,17 +710,20 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
SetUserIdAndSecContext(fcache->userid,
save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
- forboth(lc1, fcache->configNames, lc2, fcache->configValues)
+ forthree(lc1, fcache->configNames,
+ lc2, fcache->configHandles,
+ lc3, fcache->configValues)
{
GucContext context = superuser() ? PGC_SUSET : PGC_USERSET;
GucSource source = PGC_S_SESSION;
GucAction action = GUC_ACTION_SAVE;
char *name = lfirst(lc1);
- char *value = lfirst(lc2);
+ config_handle *handle = lfirst(lc2);
+ char *value = lfirst(lc3);
- (void) set_config_option(name, value,
- context, source,
- action, true, 0, false);
+ (void) set_config_with_handle(name, handle, value,
+ context, source, GetUserId(),
+ action, true, 0, false);
}
/* function manager hook */
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index e76c0830035..959a1c76bff 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -3329,10 +3329,10 @@ set_config_option(const char *name, const char *value,
else
srole = BOOTSTRAP_SUPERUSERID;
- return set_config_option_ext(name, value,
- context, source, srole,
- action, changeVal, elevel,
- is_reload);
+ return set_config_with_handle(name, NULL, value,
+ context, source, srole,
+ action, changeVal, elevel,
+ is_reload);
}
/*
@@ -3356,6 +3356,27 @@ set_config_option_ext(const char *name, const char *value,
GucAction action, bool changeVal, int elevel,
bool is_reload)
{
+ return set_config_with_handle(name, NULL, value,
+ context, source, srole,
+ action, changeVal, elevel,
+ is_reload);
+}
+
+
+/*
+ * set_config_with_handle: takes an optional 'handle' argument, which can be
+ * obtained by the caller from get_config_handle().
+ *
+ * This should be used by callers which repeatedly set the same config
+ * option(s), and want to avoid the overhead of a hash lookup each time.
+ */
+int
+set_config_with_handle(const char *name, config_handle *handle,
+ const char *value,
+ GucContext context, GucSource source, Oid srole,
+ GucAction action, bool changeVal, int elevel,
+ bool is_reload)
+{
struct config_generic *record;
union config_var_val newval_union;
void *newextra = NULL;
@@ -3395,9 +3416,15 @@ set_config_option_ext(const char *name, const char *value,
(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
errmsg("cannot set parameters during a parallel operation")));
- record = find_option(name, true, false, elevel);
- if (record == NULL)
- return 0;
+ /* if handle is specified, no need to look up option */
+ if (!handle)
+ {
+ record = find_option(name, true, false, elevel);
+ if (record == NULL)
+ return 0;
+ }
+ else
+ record = handle;
/*
* Check if the option can be set at this time. See guc.h for the precise
@@ -4167,6 +4194,22 @@ set_config_option_ext(const char *name, const char *value,
/*
+ * Retrieve a config_handle for the given name, suitable for calling
+ * set_config_with_handle(). Only return handle to permanent GUC.
+ */
+config_handle *
+get_config_handle(const char *name)
+{
+ struct config_generic *gen = find_option(name, false, false, 0);
+
+ if (gen && ((gen->flags & GUC_CUSTOM_PLACEHOLDER) == 0))
+ return gen;
+
+ return NULL;
+}
+
+
+/*
* Set the fields for source file and line number the setting came from.
*/
static void
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 20fe13702b1..49ee046cf0f 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -144,6 +144,8 @@ typedef struct ConfigVariable
struct ConfigVariable *next;
} ConfigVariable;
+typedef struct config_generic config_handle;
+
extern bool ParseConfigFile(const char *config_file, bool strict,
const char *calling_file, int calling_lineno,
int depth, int elevel,
@@ -387,6 +389,13 @@ extern int set_config_option_ext(const char *name, const char *value,
Oid srole,
GucAction action, bool changeVal, int elevel,
bool is_reload);
+extern int set_config_with_handle(const char *name, config_handle *handle,
+ const char *value,
+ GucContext context, GucSource source,
+ Oid srole,
+ GucAction action, bool changeVal,
+ int elevel, bool is_reload);
+extern config_handle *get_config_handle(const char *name);
extern void AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt);
extern char *GetConfigOptionByName(const char *name, const char **varname,
bool missing_ok);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 1053f676c38..ba41149b881 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -3247,6 +3247,7 @@ collation_cache_entry
color
colormaprange
compare_context
+config_handle
config_var_value
contain_aggs_of_level_context
contain_placeholder_references_context