diff --git a/src/sort.c b/src/sort.c index 77f4cbbc4..a8b9391b1 100644 --- a/src/sort.c +++ b/src/sort.c @@ -32,6 +32,7 @@ #include "server.h" #include "pqsort.h" /* Partial qsort for SORT+LIMIT */ #include /* isnan() */ +#include "cluster.h" zskiplistNode* zslGetElementByRank(zskiplist *zsl, unsigned long rank); @@ -235,10 +236,12 @@ void sortCommandGeneric(client *c, int readonly) { if (strchr(c->argv[j+1]->ptr,'*') == NULL) { dontsort = 1; } else { - /* If BY is specified with a real pattern, we can't accept - * it in cluster mode. */ - if (server.cluster_enabled) { - addReplyError(c,"BY option of SORT denied in Cluster mode."); + /* If BY is specified with a real pattern, we can't accept it in cluster mode, + * unless we can make sure the keys formed by the pattern are in the same slot + * as the key to sort. */ + if (server.cluster_enabled && patternHashSlot(sortby->ptr, sdslen(sortby->ptr)) != c->slot) { + addReplyError(c, "BY option of SORT denied in Cluster mode when " + "keys formed by the pattern may be in different slots."); syntax_error++; break; } @@ -252,8 +255,12 @@ void sortCommandGeneric(client *c, int readonly) { } j++; } else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) { - if (server.cluster_enabled) { - addReplyError(c,"GET option of SORT denied in Cluster mode."); + /* If GET is specified with a real pattern, we can't accept it in cluster mode, + * unless we can make sure the keys formed by the pattern are in the same slot + * as the key to sort. */ + if (server.cluster_enabled && patternHashSlot(c->argv[j+1]->ptr, sdslen(c->argv[j+1]->ptr)) != c->slot) { + addReplyError(c, "GET option of SORT denied in Cluster mode when " + "keys formed by the pattern may be in different slots."); syntax_error++; break; } diff --git a/tests/unit/sort.tcl b/tests/unit/sort.tcl index 109f6615e..eade6ea34 100644 --- a/tests/unit/sort.tcl +++ b/tests/unit/sort.tcl @@ -357,3 +357,39 @@ foreach command {SORT SORT_RO} { } } } + +start_cluster 1 0 {tags {"external:skip cluster sort"}} { + + r flushall + r lpush "{a}mylist" 1 2 3 + r set "{a}by1" 20 + r set "{a}by2" 30 + r set "{a}by3" 0 + r set "{a}get1" 200 + r set "{a}get2" 100 + r set "{a}get3" 30 + + test "sort by in cluster mode" { + catch {r sort "{a}mylist" by by*} e + assert_match {ERR BY option of SORT denied in Cluster mode when *} $e + r sort "{a}mylist" by "{a}by*" + } {3 1 2} + + test "sort get in cluster mode" { + catch {r sort "{a}mylist" by "{a}by*" get get*} e + assert_match {ERR GET option of SORT denied in Cluster mode when *} $e + r sort "{a}mylist" by "{a}by*" get "{a}get*" + } {30 200 100} + + test "sort_ro by in cluster mode" { + catch {r sort_ro "{a}mylist" by by*} e + assert_match {ERR BY option of SORT denied in Cluster mode when *} $e + r sort_ro "{a}mylist" by "{a}by*" + } {3 1 2} + + test "sort_ro get in cluster mode" { + catch {r sort_ro "{a}mylist" by "{a}by*" get get*} e + assert_match {ERR GET option of SORT denied in Cluster mode when *} $e + r sort_ro "{a}mylist" by "{a}by*" get "{a}get*" + } {30 200 100} +}