From 9122379abc3b15dfd2af3624586cc1e3f826eb55 Mon Sep 17 00:00:00 2001 From: Oran Agra Date: Tue, 3 Nov 2020 14:56:57 +0200 Subject: [PATCH] Propagate GETSET and SET-GET as SET (#7957) - Generates a more backwards compatible command stream - Slightly more efficient execution in replica/AOF - Add a test for coverage --- src/t_string.c | 25 ++++++++++++++++++++++++- tests/integration/replication.tcl | 21 +++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/t_string.c b/src/t_string.c index 188f27dc0..e8b37663d 100644 --- a/src/t_string.c +++ b/src/t_string.c @@ -90,7 +90,7 @@ void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire, } if (flags & OBJ_SET_GET) { - getGenericCommand(c); + getGenericCommand(c); } genericSetKey(c,c->db,key,val,flags & OBJ_SET_KEEPTTL,1); @@ -160,6 +160,24 @@ void setCommand(client *c) { c->argv[2] = tryObjectEncoding(c->argv[2]); setGenericCommand(c,flags,c->argv[1],c->argv[2],expire,unit,NULL,NULL); + + /* Propagate without the GET argument */ + if (flags & OBJ_SET_GET) { + int argc = 0; + robj **argv = zmalloc((c->argc-1)*sizeof(robj*)); + for (j=0; j < c->argc; j++) { + char *a = c->argv[j]->ptr; + /* Skip GET which may be repeated multiple times. */ + if (j >= 3 && + (a[0] == 'g' || a[0] == 'G') && + (a[1] == 'e' || a[1] == 'E') && + (a[2] == 't' || a[2] == 'T') && a[3] == '\0') + continue; + argv[argc++] = c->argv[j]; + incrRefCount(c->argv[j]); + } + replaceClientCommandVector(c, argc, argv); + } } void setnxCommand(client *c) { @@ -201,6 +219,11 @@ void getsetCommand(client *c) { setKey(c,c->db,c->argv[1],c->argv[2]); notifyKeyspaceEvent(NOTIFY_STRING,"set",c->argv[1],c->db->id); server.dirty++; + + /* Propagate as SET command */ + robj *setcmd = createStringObject("SET",3); + rewriteClientCommandArgument(c,0,setcmd); + decrRefCount(setcmd); } void setrangeCommand(client *c) { diff --git a/tests/integration/replication.tcl b/tests/integration/replication.tcl index fb0b9b965..6c437ba71 100644 --- a/tests/integration/replication.tcl +++ b/tests/integration/replication.tcl @@ -77,6 +77,27 @@ start_server {tags {"repl"}} { assert_equal [$A debug digest] [$B debug digest] } + test {GETSET replication} { + $A config resetstat + $A config set loglevel debug + $B config set loglevel debug + r set test foo + assert_equal [r getset test bar] foo + wait_for_condition 500 10 { + [$A get test] eq "bar" + } else { + fail "getset wasn't propagated" + } + assert_equal [r set test vaz get] bar + wait_for_condition 500 10 { + [$A get test] eq "vaz" + } else { + fail "set get wasn't propagated" + } + assert_match {*calls=3,*} [cmdrstat set $A] + assert_match {} [cmdrstat getset $A] + } + test {BRPOPLPUSH replication, when blocking against empty list} { $A config resetstat set rd [redis_deferring_client]