Skip to content

Commit

Permalink
Make varcache dynamically configurable. (#867)
Browse files Browse the repository at this point in the history
This change enables caching other postgres parameters in addition to the static list `{"client_encoding", "DateStyle", "TimeZone", "standard_conforming_strings", "application_name"}` that is already supported.

This also starts tracking IntervalStyle using this new mechanism by default.
 
Related to #452 and #482
Fixes #470
Fixes #821
  • Loading branch information
emelsimsek committed Jul 4, 2023
1 parent 084310c commit 8c18fc4
Show file tree
Hide file tree
Showing 14 changed files with 237 additions and 37 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
@@ -1,3 +1,6 @@
[submodule "lib"]
path = lib
url = https://github.com/libusual/libusual.git
[submodule "uthash"]
path = uthash
url = https://github.com/troydhanson/uthash.git
8 changes: 7 additions & 1 deletion Makefile
Expand Up @@ -59,7 +59,9 @@ pgbouncer_SOURCES = \
include/common/unicode_norm.h \
include/common/unicode_norm_table.h

UTHASH = uthash
pgbouncer_CPPFLAGS = -Iinclude $(CARES_CFLAGS) $(LIBEVENT_CFLAGS) $(TLS_CPPFLAGS)
pgbouncer_CPPFLAGS += -I$(UTHASH)/src

# include libusual sources directly
AM_FEATURES = libusual
Expand All @@ -84,7 +86,8 @@ EXTRA_DIST = AUTHORS COPYRIGHT Makefile config.mak.in config.sub config.guess \
install-sh autogen.sh configure configure.ac \
etc/mkauth.py etc/optscan.sh etc/example.debian.init.sh \
win32/Makefile \
$(LIBUSUAL_DIST)
$(LIBUSUAL_DIST) \
$(UTHASH_DIST) \

# libusual files (FIXME: list should be provided by libusual...)
LIBUSUAL_DIST = $(filter-out %/config.h, $(sort $(wildcard \
Expand All @@ -98,6 +101,9 @@ LIBUSUAL_DIST = $(filter-out %/config.h, $(sort $(wildcard \
lib/README lib/COPYRIGHT \
lib/find_modules.sh )))

UTHASH_DIST = $(UTHASH)/src/uthash.h \
$(UTHASH)/LICENSE

pgbouncer_LDFLAGS := $(TLS_LDFLAGS)
pgbouncer_LDADD := $(CARES_LIBS) $(LIBEVENT_LIBS) $(TLS_LIBS) $(LIBS)
LIBS :=
Expand Down
19 changes: 19 additions & 0 deletions doc/config.md
Expand Up @@ -200,6 +200,25 @@ achieving uniform load.

Default: 0

### track_extra_parameters

By default, PgBouncer tracks `client_encoding`, `datestyle`, `timezone`, `standard_conforming_strings`
and `application_name` parameters per client. To allow other parameters to be tracked, they can be
specified here, so that PgBouncer knows that they should be maintained in the client variable cache
and restored in the server whenever the client becomes active.

If you need to specify multiple values, use a comma-separated list (e.g.
`default_transaction_readonly, IntervalStyle`)

Note: Most parameters cannot be tracked this way. The only parameters that can be tracked are ones that
Postgres reports to the client. Postgres has
[an official list of parameters that it reports to the client](https://www.postgresql.org/docs/15/protocol-flow.html#PROTOCOL-ASYNC).
Postgres extensions can change this list though, they can add parameters themselves that they also report,
and they can start reporting already existing paremeters that Postgres does not report.
Notably Citus 12.0+ causes Postgres to also report `search_path`.

Default: IntervalStyle

### ignore_startup_parameters

By default, PgBouncer allows only parameters it can keep track of in startup
Expand Down
5 changes: 5 additions & 0 deletions etc/pgbouncer.ini
Expand Up @@ -161,6 +161,11 @@ auth_file = /etc/pgbouncer/userlist.txt
;; is off, server_reset_query is used only for session-pooling.
;server_reset_query_always = 0

;; Comma-separated list of parameters to track per client. The Postgres
;; parameters listed here will be cached per client by pgbouncer and
;; restored in server everytime the client runs a query.
;track_extra_parameters = IntervalStyle
;
;; Comma-separated list of parameters to ignore when given in startup
;; packet. Newer JDBC versions require the extra_float_digits here.
;ignore_startup_parameters = extra_float_digits
Expand Down
1 change: 1 addition & 0 deletions include/objects.h
Expand Up @@ -32,6 +32,7 @@ extern struct Slab *peer_pool_cache;
extern struct Slab *pool_cache;
extern struct Slab *user_cache;
extern struct Slab *iobuf_cache;
extern struct Slab *var_list_cache;

PgDatabase *find_peer(int peer_id);
PgDatabase *find_database(const char *name);
Expand Down
4 changes: 3 additions & 1 deletion include/varcache.h
Expand Up @@ -12,9 +12,11 @@ enum VarCacheIdx {
typedef struct VarCache VarCache;

struct VarCache {
struct PStr *var_list[NumVars];
struct PStr **var_list;
};

void init_var_lookup(const char *cf_track_extra_parameters);
int get_num_var_cached(void);
bool varcache_set(VarCache *cache, const char *key, const char *value) /* _MUSTCHECK */;
bool varcache_apply(PgSocket *server, PgSocket *client, bool *changes_p) _MUSTCHECK;
void varcache_fill_unset(VarCache *src, PgSocket *dst);
Expand Down
2 changes: 1 addition & 1 deletion lib
Submodule lib updated 2 files
+0 −24 .appveyor.yml
+4 −5 .cirrus.yml
2 changes: 2 additions & 0 deletions src/janitor.c
Expand Up @@ -761,6 +761,7 @@ void kill_pool(PgPool *pool)
list_del(&pool->map_head);
statlist_remove(&pool_list, &pool->head);
varcache_clean(&pool->orig_vars);
slab_free(var_list_cache, pool->orig_vars.var_list);
slab_free(pool_cache, pool);
}

Expand All @@ -778,6 +779,7 @@ void kill_peer_pool(PgPool *pool)
list_del(&pool->map_head);
statlist_remove(&peer_pool_list, &pool->head);
varcache_clean(&pool->orig_vars);
slab_free(var_list_cache, pool->orig_vars.var_list);
slab_free(peer_pool_cache, pool);
}

Expand Down
5 changes: 5 additions & 0 deletions src/main.c
Expand Up @@ -116,6 +116,7 @@ char *cf_auth_hba_file;
char *cf_auth_user;
char *cf_auth_query;
char *cf_auth_dbname;
char *cf_track_extra_parameters;

int cf_max_client_conn;
int cf_default_pool_size;
Expand Down Expand Up @@ -314,6 +315,7 @@ CF_ABS("tcp_keepidle", CF_INT, cf_tcp_keepidle, 0, "0"),
CF_ABS("tcp_keepintvl", CF_INT, cf_tcp_keepintvl, 0, "0"),
CF_ABS("tcp_socket_buffer", CF_INT, cf_tcp_socket_buffer, 0, "0"),
CF_ABS("tcp_user_timeout", CF_INT, cf_tcp_user_timeout, 0, "0"),
CF_ABS("track_extra_parameters", CF_STR, cf_track_extra_parameters, CF_NO_RELOAD, "IntervalStyle"),
CF_ABS("unix_socket_dir", CF_STR, cf_unix_socket_dir, CF_NO_RELOAD, DEFAULT_UNIX_SOCKET_DIR),
#ifndef WIN32
CF_ABS("unix_socket_group", CF_STR, cf_unix_socket_group, CF_NO_RELOAD, ""),
Expand Down Expand Up @@ -893,6 +895,8 @@ static void cleanup(void)
xfree((char **)&cf_logfile);
xfree((char **)&cf_syslog_ident);
xfree((char **)&cf_syslog_facility);

xfree(&cf_track_extra_parameters);
}

/* boot everything */
Expand Down Expand Up @@ -973,6 +977,7 @@ int main(int argc, char *argv[])
init_objects();
load_config();
main_config.loaded = true;
init_var_lookup(cf_track_extra_parameters);
init_caches();
logging_prefix_cb = log_socket_prefix;

Expand Down
10 changes: 10 additions & 0 deletions src/objects.c
Expand Up @@ -60,6 +60,7 @@ struct Slab *peer_pool_cache;
struct Slab *pool_cache;
struct Slab *user_cache;
struct Slab *iobuf_cache;
struct Slab *var_list_cache;

/*
* libevent may still report events when event_del()
Expand Down Expand Up @@ -91,6 +92,7 @@ static void construct_client(void *obj)
memset(client, 0, sizeof(PgSocket));
list_init(&client->head);
sbuf_init(&client->sbuf, client_proto);
client->vars.var_list = slab_alloc(var_list_cache);
client->state = CL_FREE;
}

Expand All @@ -101,6 +103,7 @@ static void construct_server(void *obj)
memset(server, 0, sizeof(PgSocket));
list_init(&server->head);
sbuf_init(&server->sbuf, server_proto);
server->vars.var_list = slab_alloc(var_list_cache);
server->state = SV_FREE;
}

Expand Down Expand Up @@ -146,6 +149,7 @@ void init_caches(void)
server_cache = slab_create("server_cache", sizeof(PgSocket), 0, construct_server, USUAL_ALLOC);
client_cache = slab_create("client_cache", sizeof(PgSocket), 0, construct_client, USUAL_ALLOC);
iobuf_cache = slab_create("iobuf_cache", IOBUF_SIZE, 0, do_iobuf_reset, USUAL_ALLOC);
var_list_cache = slab_create("var_list_cache", sizeof(struct PStr*) * get_num_var_cached(), 0, NULL, USUAL_ALLOC);
}

/* state change means moving between lists */
Expand Down Expand Up @@ -191,6 +195,7 @@ void change_client_state(PgSocket *client, SocketState newstate)
switch (client->state) {
case CL_FREE:
varcache_clean(&client->vars);
slab_free(var_list_cache, client->vars.var_list);
slab_free(client_cache, client);
break;
case CL_JUSTFREE:
Expand Down Expand Up @@ -261,6 +266,7 @@ void change_server_state(PgSocket *server, SocketState newstate)
switch (server->state) {
case SV_FREE:
varcache_clean(&server->vars);
slab_free(var_list_cache, server->vars.var_list);
slab_free(server_cache, server);
break;
case SV_JUSTFREE:
Expand Down Expand Up @@ -583,6 +589,7 @@ static PgPool *new_pool(PgDatabase *db, PgUser *user)

list_init(&pool->head);
list_init(&pool->map_head);
pool->orig_vars.var_list = slab_alloc(var_list_cache);

pool->user = user;
pool->db = db;
Expand Down Expand Up @@ -625,6 +632,7 @@ static PgPool *new_peer_pool(PgDatabase *db)

list_init(&pool->head);
list_init(&pool->map_head);
pool->orig_vars.var_list = slab_alloc(var_list_cache);

pool->db = db;

Expand Down Expand Up @@ -2242,4 +2250,6 @@ void objects_cleanup(void)
user_cache = NULL;
slab_destroy(iobuf_cache);
iobuf_cache = NULL;
slab_destroy(var_list_cache);
var_list_cache = NULL;
}

0 comments on commit 8c18fc4

Please sign in to comment.