Skip to content

Commit

Permalink
Support setlocale via CONFIG operation. (redis#11059)
Browse files Browse the repository at this point in the history
Till now Redis officially supported tuning it via environment variable see redis#1074.
But we had other requests to allow changing it at runtime, see redis#799, and redis#11041.

Note that `strcoll()` is used as Lua comparison function and also for comparison of
certain string objects in Redis, which leads to a problem that, in different regions,
for some characters, the result may be different. Below is an example.
```
127.0.0.1:6333> SORT test alpha
1) "<"
2) ">"
3) ","
4) "*"
127.0.0.1:6333> CONFIG GET locale-collate
1) "locale-collate"
2) ""
127.0.0.1:6333> CONFIG SET locale-collate 1
(error) ERR CONFIG SET failed (possibly related to argument 'locale')
127.0.0.1:6333> CONFIG SET locale-collate C
OK
127.0.0.1:6333> SORT test alpha
1) "*"
2) ","
3) "<"
4) ">"
```
That will cause accidental code compatibility issues for Lua scripts and some
Redis commands. This commit creates a new config parameter to control the
local environment which only affects `Collate` category. Above shows how it
affects `SORT` command, and below shows the influence on Lua scripts.
```
127.0.0.1:6333> CONFIG GET locale-collate
1) " locale-collate"
2) "C"
127.0.0.1:6333> EVAL "return ',' < '*'" 0
(nil)
127.0.0.1:6333> CONFIG SET locale-collate ""
OK
127.0.0.1:6333> EVAL "return ',' < '*'" 0
(integer) 1
```

Co-authored-by: calvincjli <calvincjli@tencent.com>
Co-authored-by: Oran Agra <oran@redislabs.com>
  • Loading branch information
3 people committed Aug 21, 2022
1 parent 31ef410 commit ca6aead
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 1 deletion.
5 changes: 5 additions & 0 deletions redis.conf
Expand Up @@ -409,6 +409,11 @@ set-proc-title yes
#
proc-title-template "{title} {listen-addr} {server-mode}"

# Set the local environment which is used for string comparison operations, and
# also affect the performance of Lua scripts. Empty String indicates the locale
# is derived from the environment variables.
locale-collate ""

################################ SNAPSHOTTING ################################

# Save the DB to disk.
Expand Down
11 changes: 11 additions & 0 deletions src/config.c
Expand Up @@ -35,6 +35,7 @@
#include <sys/stat.h>
#include <glob.h>
#include <string.h>
#include <locale.h>

/*-----------------------------------------------------------------------------
* Config file name-value maps.
Expand Down Expand Up @@ -2400,6 +2401,15 @@ static int isValidProcTitleTemplate(char *val, const char **err) {
return 1;
}

static int updateLocaleCollate(const char **err) {
const char *s = setlocale(LC_COLLATE, server.locale_collate);
if (s == NULL) {
*err = "Invalid locale name";
return 0;
}
return 1;
}

static int updateProcTitleTemplate(const char **err) {
if (redisSetProcTitle(NULL) == C_ERR) {
*err = "failed to set process title";
Expand Down Expand Up @@ -2995,6 +3005,7 @@ standardConfig static_configs[] = {
createStringConfig("proc-title-template", NULL, MODIFIABLE_CONFIG, ALLOW_EMPTY_STRING, server.proc_title_template, CONFIG_DEFAULT_PROC_TITLE_TEMPLATE, isValidProcTitleTemplate, updateProcTitleTemplate),
createStringConfig("bind-source-addr", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.bind_source_addr, NULL, NULL, NULL),
createStringConfig("logfile", NULL, IMMUTABLE_CONFIG, ALLOW_EMPTY_STRING, server.logfile, "", NULL, NULL),
createStringConfig("locale-collate", NULL, MODIFIABLE_CONFIG, ALLOW_EMPTY_STRING, server.locale_collate, "", NULL, updateLocaleCollate),

/* SDS Configs */
createSDSConfig("masterauth", NULL, MODIFIABLE_CONFIG | SENSITIVE_CONFIG, EMPTY_STRING_IS_NULL, server.masterauth, NULL, NULL, NULL),
Expand Down
7 changes: 6 additions & 1 deletion src/server.c
Expand Up @@ -2440,6 +2440,12 @@ void initServer(void) {
server.reply_buffer_resizing_enabled = 1;
resetReplicationBuffer();

/* Make sure the locale is set on startup based on the config file. */
if (setlocale(LC_COLLATE,server.locale_collate) == NULL) {
serverLog(LL_WARNING, "Failed to configure LOCALE for invalid locale name.");
exit(1);
}

if ((server.tls_port || server.tls_replication || server.tls_cluster)
&& tlsConfigure(&server.tls_ctx_config) == C_ERR) {
serverLog(LL_WARNING, "Failed to configure TLS. Check logs for more info.");
Expand Down Expand Up @@ -6910,7 +6916,6 @@ int main(int argc, char **argv) {
#ifdef INIT_SETPROCTITLE_REPLACEMENT
spt_init(argc, argv);
#endif
setlocale(LC_COLLATE,"");
tzset(); /* Populates 'timezone' global. */
zmalloc_set_oom_handler(redisOutOfMemoryHandler);

Expand Down
2 changes: 2 additions & 0 deletions src/server.h
Expand Up @@ -1944,6 +1944,8 @@ struct redisServer {
is down, doesn't affect pubsub global. */
long reply_buffer_peak_reset_time; /* The amount of time (in milliseconds) to wait between reply buffer peak resets */
int reply_buffer_resizing_enabled; /* Is reply buffer resizing enabled (1 by default) */
/* Local environment */
char *locale_collate;
};

#define MAX_KEYS_BUFFER 256
Expand Down

0 comments on commit ca6aead

Please sign in to comment.