Commit f8547e53 authored by antirez's avatar antirez
Browse files

Added GEORADIUS(BYMEMBER)_RO variants for read-only operations.

Issue #4084 shows how for a design error, GEORADIUS is a write command
because of the STORE option. Because of this it does not work
on readonly slaves, gets redirected to masters in Redis Cluster even
when the connection is in READONLY mode and so forth.

To break backward compatibility at this stage, with Redis 4.0 to be in
advanced RC state, is problematic for the user base. The API can be
fixed into the unstable branch soon if we'll decide to do so in order to
be more consistent, and reease Redis 5.0 with this incompatibility in
the future. This is still unclear.

However, the ability to scale GEO queries in slaves easily is too
important so this commit adds two read-only variants to the GEORADIUS
and GEORADIUSBYMEMBER command: GEORADIUS_RO and GEORADIUSBYMEMBER_RO.
The commands are exactly as the original commands, but they do not
accept the STORE and STOREDIST options.
parent 01a4b989
...@@ -452,13 +452,14 @@ void geoaddCommand(client *c) { ...@@ -452,13 +452,14 @@ void geoaddCommand(client *c) {
#define SORT_ASC 1 #define SORT_ASC 1
#define SORT_DESC 2 #define SORT_DESC 2
#define RADIUS_COORDS 1 #define RADIUS_COORDS (1<<0) /* Search around coordinates. */
#define RADIUS_MEMBER 2 #define RADIUS_MEMBER (1<<1) /* Search around member. */
#define RADIUS_NOSTORE (1<<2) /* Do not acceot STORE/STOREDIST option. */
/* GEORADIUS key x y radius unit [WITHDIST] [WITHHASH] [WITHCOORD] [ASC|DESC] /* GEORADIUS key x y radius unit [WITHDIST] [WITHHASH] [WITHCOORD] [ASC|DESC]
* [COUNT count] [STORE key] [STOREDIST key] * [COUNT count] [STORE key] [STOREDIST key]
* GEORADIUSBYMEMBER key member radius unit ... options ... */ * GEORADIUSBYMEMBER key member radius unit ... options ... */
void georadiusGeneric(client *c, int type) { void georadiusGeneric(client *c, int flags) {
robj *key = c->argv[1]; robj *key = c->argv[1];
robj *storekey = NULL; robj *storekey = NULL;
int storedist = 0; /* 0 for STORE, 1 for STOREDIST. */ int storedist = 0; /* 0 for STORE, 1 for STOREDIST. */
...@@ -473,11 +474,11 @@ void georadiusGeneric(client *c, int type) { ...@@ -473,11 +474,11 @@ void georadiusGeneric(client *c, int type) {
/* Find long/lat to use for radius search based on inquiry type */ /* Find long/lat to use for radius search based on inquiry type */
int base_args; int base_args;
double xy[2] = { 0 }; double xy[2] = { 0 };
if (type == RADIUS_COORDS) { if (flags & RADIUS_COORDS) {
base_args = 6; base_args = 6;
if (extractLongLatOrReply(c, c->argv + 2, xy) == C_ERR) if (extractLongLatOrReply(c, c->argv + 2, xy) == C_ERR)
return; return;
} else if (type == RADIUS_MEMBER) { } else if (flags & RADIUS_MEMBER) {
base_args = 5; base_args = 5;
robj *member = c->argv[2]; robj *member = c->argv[2];
if (longLatFromMember(zobj, member, xy) == C_ERR) { if (longLatFromMember(zobj, member, xy) == C_ERR) {
...@@ -485,7 +486,7 @@ void georadiusGeneric(client *c, int type) { ...@@ -485,7 +486,7 @@ void georadiusGeneric(client *c, int type) {
return; return;
} }
} else { } else {
addReplyError(c, "unknown georadius search type"); addReplyError(c, "Unknown georadius search type");
return; return;
} }
...@@ -522,11 +523,17 @@ void georadiusGeneric(client *c, int type) { ...@@ -522,11 +523,17 @@ void georadiusGeneric(client *c, int type) {
return; return;
} }
i++; i++;
} else if (!strcasecmp(arg, "store") && (i+1) < remaining) { } else if (!strcasecmp(arg, "store") &&
(i+1) < remaining &&
!(flags & RADIUS_NOSTORE))
{
storekey = c->argv[base_args+i+1]; storekey = c->argv[base_args+i+1];
storedist = 0; storedist = 0;
i++; i++;
} else if (!strcasecmp(arg, "storedist") && (i+1) < remaining) { } else if (!strcasecmp(arg, "storedist") &&
(i+1) < remaining &&
!(flags & RADIUS_NOSTORE))
{
storekey = c->argv[base_args+i+1]; storekey = c->argv[base_args+i+1];
storedist = 1; storedist = 1;
i++; i++;
...@@ -671,10 +678,20 @@ void georadiusCommand(client *c) { ...@@ -671,10 +678,20 @@ void georadiusCommand(client *c) {
} }
/* GEORADIUSBYMEMBER wrapper function. */ /* GEORADIUSBYMEMBER wrapper function. */
void georadiusByMemberCommand(client *c) { void georadiusbymemberCommand(client *c) {
georadiusGeneric(c, RADIUS_MEMBER); georadiusGeneric(c, RADIUS_MEMBER);
} }
/* GEORADIUS_RO wrapper function. */
void georadiusroCommand(client *c) {
georadiusGeneric(c, RADIUS_COORDS|RADIUS_NOSTORE);
}
/* GEORADIUSBYMEMBER_RO wrapper function. */
void georadiusbymemberroCommand(client *c) {
georadiusGeneric(c, RADIUS_MEMBER|RADIUS_NOSTORE);
}
/* GEOHASH key ele1 ele2 ... eleN /* GEOHASH key ele1 ele2 ... eleN
* *
* Returns an array with an 11 characters geohash representation of the * Returns an array with an 11 characters geohash representation of the
......
...@@ -291,7 +291,9 @@ struct redisCommand redisCommandTable[] = { ...@@ -291,7 +291,9 @@ struct redisCommand redisCommandTable[] = {
{"command",commandCommand,0,"lt",0,NULL,0,0,0,0,0}, {"command",commandCommand,0,"lt",0,NULL,0,0,0,0,0},
{"geoadd",geoaddCommand,-5,"wm",0,NULL,1,1,1,0,0}, {"geoadd",geoaddCommand,-5,"wm",0,NULL,1,1,1,0,0},
{"georadius",georadiusCommand,-6,"w",0,georadiusGetKeys,1,1,1,0,0}, {"georadius",georadiusCommand,-6,"w",0,georadiusGetKeys,1,1,1,0,0},
{"georadiusbymember",georadiusByMemberCommand,-5,"w",0,georadiusGetKeys,1,1,1,0,0}, {"georadius_ro",georadiusroCommand,-6,"r",0,georadiusGetKeys,1,1,1,0,0},
{"georadiusbymember",georadiusbymemberCommand,-5,"w",0,georadiusGetKeys,1,1,1,0,0},
{"georadiusbymember_ro",georadiusbymemberroCommand,-5,"r",0,georadiusGetKeys,1,1,1,0,0},
{"geohash",geohashCommand,-2,"r",0,NULL,1,1,1,0,0}, {"geohash",geohashCommand,-2,"r",0,NULL,1,1,1,0,0},
{"geopos",geoposCommand,-2,"r",0,NULL,1,1,1,0,0}, {"geopos",geoposCommand,-2,"r",0,NULL,1,1,1,0,0},
{"geodist",geodistCommand,-4,"r",0,NULL,1,1,1,0,0}, {"geodist",geodistCommand,-4,"r",0,NULL,1,1,1,0,0},
......
...@@ -1956,8 +1956,10 @@ void replconfCommand(client *c); ...@@ -1956,8 +1956,10 @@ void replconfCommand(client *c);
void waitCommand(client *c); void waitCommand(client *c);
void geoencodeCommand(client *c); void geoencodeCommand(client *c);
void geodecodeCommand(client *c); void geodecodeCommand(client *c);
void georadiusByMemberCommand(client *c); void georadiusbymemberCommand(client *c);
void georadiusbymemberroCommand(client *c);
void georadiusCommand(client *c); void georadiusCommand(client *c);
void georadiusroCommand(client *c);
void geoaddCommand(client *c); void geoaddCommand(client *c);
void geohashCommand(client *c); void geohashCommand(client *c);
void geoposCommand(client *c); void geoposCommand(client *c);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment