Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/cluster_migrateslots.c
Original file line number Diff line number Diff line change
Expand Up @@ -1448,8 +1448,8 @@ int slotExportTryDoPause(slotMigrationJob *job) {
return C_ERR;
}
serverLog(LL_NOTICE,
"Pausing writes to allow slot migration %s to finalize failover.",
job->description);
"Pausing writes (remaining_repl_size is %lld) to allow slot migration %s to finalize failover.",
job->client->reply_bytes, job->description);
job->mf_end = mstime() + server.cluster_mf_timeout * CLUSTER_MF_PAUSE_MULT;
pauseActions(PAUSE_DURING_SLOT_MIGRATION, job->mf_end,
PAUSE_ACTIONS_CLIENT_WRITE_SET);
Expand Down
25 changes: 24 additions & 1 deletion src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -2168,6 +2168,13 @@ static int numericParseString(standardConfig *config, sds value, const char **er
int memerr;
*res = memtoull(value, &memerr);
if (!memerr) return 1;

/* memtoull rejects negative values, but some memory configs accept
* special negative values (e.g. -1 to disable a limit). Fall back
* to plain integer parsing for those. */
if (config->data.numeric.flags & SIGNED_MEMORY_CONFIG) {
if (string2ll(value, sdslen(value), res)) return 1;
}
}

/* Attempt to parse as percent */
Expand Down Expand Up @@ -2241,6 +2248,8 @@ static sds numericConfigGet(standardConfig *config) {
int len = ll2string(buf, sizeof(buf), -value);
buf[len] = '%';
buf[len + 1] = '\0';
} else if (config->data.numeric.flags & SIGNED_MEMORY_CONFIG && value < 0) {
ll2string(buf, sizeof(buf), value);
} else if (config->data.numeric.flags & MEMORY_CONFIG) {
ull2string(buf, sizeof(buf), value);
} else if (config->data.numeric.flags & OCTAL_CONFIG) {
Expand All @@ -2260,6 +2269,8 @@ static void numericConfigRewrite(standardConfig *config, const char *name, struc

if (config->data.numeric.flags & PERCENT_CONFIG && value < 0) {
rewriteConfigPercentOption(state, name, -value, config->data.numeric.default_value);
} else if (config->data.numeric.flags & SIGNED_MEMORY_CONFIG && value < 0) {
rewriteConfigNumericalOption(state, name, value, config->data.numeric.default_value);
} else if (config->data.numeric.flags & MEMORY_CONFIG) {
rewriteConfigBytesOption(state, name, value, config->data.numeric.default_value);
} else if (config->data.numeric.flags & OCTAL_CONFIG) {
Expand Down Expand Up @@ -3452,7 +3463,7 @@ standardConfig static_configs[] = {
createSizeTConfig("tracking-table-max-keys", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX, server.tracking_table_max_keys, 1000000, INTEGER_CONFIG, NULL, NULL), /* Default: 1 million keys max. */
createSizeTConfig("client-query-buffer-limit", NULL, DEBUG_CONFIG | MODIFIABLE_CONFIG, 1024 * 1024, LONG_MAX, server.client_max_querybuf_len, 1024 * 1024 * 1024, MEMORY_CONFIG, NULL, NULL), /* Default: 1GB max query buffer. */
createSSizeTConfig("maxmemory-clients", NULL, MODIFIABLE_CONFIG, -100, SSIZE_MAX, server.maxmemory_clients, 0, MEMORY_CONFIG | PERCENT_CONFIG, NULL, applyClientMaxMemoryUsage),
createSSizeTConfig("slot-migration-max-failover-repl-bytes", NULL, MODIFIABLE_CONFIG, -1, SSIZE_MAX, server.slot_migration_max_failover_repl_bytes, 0, MEMORY_CONFIG, NULL, NULL),
createSSizeTConfig("slot-migration-max-failover-repl-bytes", NULL, MODIFIABLE_CONFIG, -1, SSIZE_MAX, server.slot_migration_max_failover_repl_bytes, 0, MEMORY_CONFIG | SIGNED_MEMORY_CONFIG, NULL, NULL),
Comment thread
enjoy-binbin marked this conversation as resolved.

/* Other configs */
createTimeTConfig("repl-backlog-ttl", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX, server.repl_backlog_time_limit, 60 * 60, INTEGER_CONFIG, NULL, NULL), /* Default: 1 hour */
Expand Down Expand Up @@ -3519,6 +3530,18 @@ void initConfigValues(void) {
dictExpand(configs, sizeof(static_configs) / sizeof(standardConfig));
for (standardConfig *config = static_configs; config->name != NULL; config++) {
if (config->interface.init) config->interface.init(config);

if (config->type == NUMERIC_CONFIG) {
/* SIGNED_MEMORY_CONFIG must be used together with MEMORY_CONFIG. */
serverAssert(!((config->data.numeric.flags & SIGNED_MEMORY_CONFIG) &&
!(config->data.numeric.flags & MEMORY_CONFIG)));
Comment thread
enjoy-binbin marked this conversation as resolved.
Outdated

/* PERCENT_CONFIG and SIGNED_MEMORY_CONFIG both use negative values
* with different semantics, so they must not be combined. */
serverAssert(!((config->data.numeric.flags & PERCENT_CONFIG) &&
(config->data.numeric.flags & SIGNED_MEMORY_CONFIG)));
}

/* Add the primary config to the dictionary. */
int ret = registerConfigValue(config->name, config, 0);
serverAssert(ret);
Expand Down
12 changes: 7 additions & 5 deletions src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -3640,11 +3640,13 @@ sds keyspaceEventsFlagsToString(int flags);
* to apply the configuration change even if the new config value is the same as \
* the old. */

#define INTEGER_CONFIG 0 /* No flags means a simple integer configuration */
#define MEMORY_CONFIG (1 << 0) /* Indicates if this value can be loaded as a memory value */
#define PERCENT_CONFIG (1 << 1) /* Indicates if this value can be loaded as a percent (and stored as a negative int) */
#define OCTAL_CONFIG (1 << 2) /* This value uses octal representation */
#define UNSIGNED_CONFIG (1 << 3) /* This value uses unsigned representation */
/* Numeric Flags */
#define INTEGER_CONFIG 0 /* No flags means a simple integer configuration */
#define MEMORY_CONFIG (1 << 0) /* Indicates if this value can be loaded as a memory value */
#define PERCENT_CONFIG (1 << 1) /* Indicates if this value can be loaded as a percent (and stored as a negative int) */
#define OCTAL_CONFIG (1 << 2) /* This value uses octal representation */
#define UNSIGNED_CONFIG (1 << 3) /* This value uses unsigned representation */
#define SIGNED_MEMORY_CONFIG (1 << 4) /* A MEMORY_CONFIG that also accepts plain negative integers */

/* Enum Configs contain an array of configEnum objects that match a string with an integer. */
typedef struct configEnum {
Expand Down
45 changes: 44 additions & 1 deletion tests/unit/cluster/cluster-migrateslots.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -2450,7 +2450,7 @@ start_cluster 3 0 {tags {logreqres:skip external:skip cluster} overrides {cluste
set 16383_slot_tag "{6ZJ}"
set_debug_prevent_pause 1

# Move 16383 from R0 to R2
# Move 16383 from R2 to R0.
assert_match "OK" [R 2 CLUSTER MIGRATESLOTS SLOTSRANGE 16383 16383 NODE [R 0 CLUSTER MYID]]
set jobname [get_job_name 2 16383]
wait_for_migration_field 2 $jobname state waiting-to-pause
Expand Down Expand Up @@ -2482,5 +2482,48 @@ start_cluster 3 0 {tags {logreqres:skip external:skip cluster} overrides {cluste
set export_migration [get_migration_by_name 2 $jobname]
assert_equal [dict get $export_migration remaining_repl_size] 0
assert_equal [dict get $import_migration remaining_repl_size] 0

# Check the remaining_repl_size log is OK.
verify_log_message -2 "*Pausing writes (remaining_repl_size is 0) to allow slot migration*" 0
}
}

start_cluster 3 0 {tags {logreqres:skip external:skip cluster} overrides {cluster-require-full-coverage no slot-migration-max-failover-repl-bytes -1}} {
test "slot-migration-max-failover-repl-bytes -1 disables repl bytes limit" {
set 16383_slot_tag "{6ZJ}"

# Use PREVENT-PAUSE to hold the migration at the waiting-to-pause
# state so we can fill the replication buffer first.
R 2 DEBUG SLOTMIGRATION PREVENT-PAUSE 1

# Move slot 16383 from R2 to R0.
assert_match "OK" [R 2 CLUSTER MIGRATESLOTS SLOTSRANGE 16383 16383 NODE [R 0 CLUSTER MYID]]
set jobname [get_job_name 2 16383]
wait_for_migration_field 2 $jobname state waiting-to-pause

# Pause the target (R0) process and generate data to fill the
# replication buffer on the source (R2).
pause_process [srv 0 pid]
set bigstr [string repeat x 1024000]
for {set j 0} {$j < 50} {incr j} {
R 2 set "$16383_slot_tag:key:$j" $bigstr
}

# Confirm the replication buffer has accumulated data.
set export_migration [get_migration_by_name 2 $jobname]
set remaining_repl_size [dict get $export_migration remaining_repl_size]
assert_morethan $remaining_repl_size [expr 1024000 * 25]

# Resume the PREVENT-PAUSE.
# With slot-migration-max-failover-repl-bytes -1, the source (R2) should proceed
# to pause writes regardless of the large remaining_repl_size.
R 2 DEBUG SLOTMIGRATION PREVENT-PAUSE 0
wait_for_log_messages -2 {"*Pausing writes*"} 0 1000 10
set pattern "*Pausing writes (remaining_repl_size is $remaining_repl_size) to allow slot migration*"
verify_log_message -2 $pattern 0

# Resume R0 and wait for R0 to finish the migration.
resume_process [srv 0 pid]
wait_for_migration 0 16383
}
}
14 changes: 13 additions & 1 deletion tests/unit/introspection.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -1964,10 +1964,22 @@ test {CONFIG REWRITE handles alias config properly} {
}
} {} {external:skip}

test {SIGNED MEMORY CONFIG allows negative number} {
start_server {tags {"introspection"}} {
r config set slot-migration-max-failover-repl-bytes -1
assert_equal [lindex [r config get slot-migration-max-failover-repl-bytes] 1] -1
assert_error {*argument must be between -1 and *} {r config set slot-migration-max-failover-repl-bytes -2}

r config rewrite
restart_server 0 true false
assert_equal [lindex [r config get slot-migration-max-failover-repl-bytes] 1] -1
}
} {} {external:skip}

test {CONFIG hash-seed is immutable and settable at startup} {
start_server {tags {"introspection"} overrides {hash-seed aabbccddeeffgghh}} {
assert_error "ERR CONFIG SET failed (possibly related to argument 'hash-seed') - can't set immutable config*" {
r config set hash-seed newseed
}
}
} {} {external:skip}
} {} {external:skip}
Loading