Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a configuration option to allow TTL-based expires on the slave #620

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/config.c
Expand Up @@ -205,6 +205,10 @@ void loadServerConfigFromString(char *config) {
if ((server.repl_serve_stale_data = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr;
}
} else if (!strcasecmp(argv[0],"slave-allow-key-expires") && argc == 2) {
if ((server.slave_allow_key_expires = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr;
}
} else if (!strcasecmp(argv[0],"slave-read-only") && argc == 2) {
if ((server.repl_slave_ro = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr;
Expand Down Expand Up @@ -541,6 +545,11 @@ void configSetCommand(redisClient *c) {

if (yn == -1) goto badfmt;
server.repl_serve_stale_data = yn;
} else if (!strcasecmp(c->argv[2]->ptr,"slave-allow-key-expires")) {
int yn = yesnotoi(o->ptr);

if (yn == -1) goto badfmt;
server.slave_allow_key_expires = yn;
} else if (!strcasecmp(c->argv[2]->ptr,"slave-read-only")) {
int yn = yesnotoi(o->ptr);

Expand Down Expand Up @@ -761,6 +770,8 @@ void configGetCommand(redisClient *c) {
server.aof_no_fsync_on_rewrite);
config_get_bool_field("slave-serve-stale-data",
server.repl_serve_stale_data);
config_get_bool_field("slave-allow-key-expires",
server.slave_allow_key_expires);
config_get_bool_field("slave-read-only",
server.repl_slave_ro);
config_get_bool_field("stop-writes-on-bgsave-error",
Expand Down
2 changes: 1 addition & 1 deletion src/db.c
Expand Up @@ -493,7 +493,7 @@ int expireIfNeeded(redisDb *db, robj *key) {
* Still we try to return the right information to the caller,
* that is, 0 if we think the key should be still valid, 1 if
* we think the key is expired at this time. */
if (server.masterhost != NULL) {
if (server.masterhost != NULL && server.slave_allow_key_expires == 0) {
return mstime() > when;
}

Expand Down
1 change: 1 addition & 0 deletions src/redis.c
Expand Up @@ -1171,6 +1171,7 @@ void initServerConfig() {
server.repl_serve_stale_data = 1;
server.repl_slave_ro = 1;
server.repl_down_since = time(NULL);
server.slave_allow_key_expires = 0;

/* Client output buffer limits */
server.client_obuf_limits[REDIS_CLIENT_LIMIT_CLASS_NORMAL].hard_limit_bytes = 0;
Expand Down
1 change: 1 addition & 0 deletions src/redis.h
Expand Up @@ -678,6 +678,7 @@ struct redisServer {
/* Slave specific fields */
char *masterauth; /* AUTH with this password with master */
char *masterhost; /* Hostname of master */
int slave_allow_key_expires; /* True if we allow keys to expire on the slave w/o relying on replication */
int masterport; /* Port of master */
int repl_ping_slave_period; /* Master pings the salve every N seconds */
int repl_timeout; /* Timeout after N seconds of master idle */
Expand Down
51 changes: 51 additions & 0 deletions tests/integration/replication-5.tcl
@@ -0,0 +1,51 @@
start_server {tags {"repl"}} {
start_server {} {
r -1 config set slave-allow-key-expires yes

test {First server should have role slave after SLAVEOF} {
r -1 slaveof [srv 0 host] [srv 0 port]
after 1000
s -1 role
} {slave}

if {$::accurate} {set numops 50000} else {set numops 5000}

test {MASTER and SLAVE consistency with expire + allowed slave expires} {
createComplexDataset r $numops useexpire
after 4000 ;# Make sure everything expired before taking the digest
r keys * ;# Force DEL syntesizing to slave
after 1000 ;# Wait another second. Now everything should be fine.
if {[r debug digest] ne [r -1 debug digest]} {
set csv1 [csvdump r]
set csv2 [csvdump {r -1}]
set fd [open /tmp/repldump1.txt w]
puts -nonewline $fd $csv1
close $fd
set fd [open /tmp/repldump2.txt w]
puts -nonewline $fd $csv2
close $fd
puts "Master - Slave inconsistency"
puts "Run diff -u against /tmp/repldump*.txt for more info"
}
assert_equal [r debug digest] [r -1 debug digest]
}

r -1 config set slave-read-only no

test {Keys should expire on the slave with slave-allow-key-expires=yes} {
r -1 set x bar
r -1 expire x 1
after 1500
list [r -1 get x] [r -1 exists x]
} {{} 0}

r -1 config set slave-allow-key-expires no

test {Keys should not expire on the slave with slave-allow-key-expires=yes} {
r -1 set x bar
r -1 expire x 1
after 1500
list [r -1 get x] [r -1 exists x]
} {bar 1}
}
}
1 change: 1 addition & 0 deletions tests/test_helper.tcl
Expand Up @@ -30,6 +30,7 @@ set ::all_tests {
integration/replication-2
integration/replication-3
integration/replication-4
integration/replication-5
integration/aof
integration/rdb
integration/convert-zipmap-hash-on-load
Expand Down