From cc04253b1de1cbf657d9f9b1429fad96b54c9072 Mon Sep 17 00:00:00 2001 From: Paul Spooren Date: Tue, 9 Jun 2020 16:53:14 -0400 Subject: [PATCH] LRANK: Add command (the command will be renamed LPOS). The `LRANK` command returns the index (position) of a given element within a list. Using the `direction` argument it is possible to specify going from head to tail (acending, 1) or from tail to head (decending, -1). Only the first found index is returend. The complexity is O(N). When using lists as a queue it can be of interest at what position a given element is, for instance to monitor a job processing through a work queue. This came up within the Python `rq` project which is based on Redis[0]. [0]: https://github.com/rq/rq/issues/1197 Signed-off-by: Paul Spooren --- src/help.h | 5 +++++ src/server.c | 4 ++++ src/server.h | 1 + src/t_list.c | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+) diff --git a/src/help.h b/src/help.h index 6d3eb33ed..9b4e90f9f 100644 --- a/src/help.h +++ b/src/help.h @@ -668,6 +668,11 @@ struct commandHelp { "Remove elements from a list", 2, "1.0.0" }, + { "LRANK", + "key direction element", + "Return first index of element in list based on direction", + 2, + "9.9.9" }, { "LSET", "key index element", "Set the value of an element in a list by its index", diff --git a/src/server.c b/src/server.c index e8e711240..767d3374f 100644 --- a/src/server.c +++ b/src/server.c @@ -326,6 +326,10 @@ struct redisCommand redisCommandTable[] = { "write @list", 0,NULL,1,1,1,0,0,0}, + {"lrank",lrankCommand,4, + "read-only fast @list", + 0,NULL,1,1,1,0,0,0}, + {"lrem",lremCommand,4, "write @list", 0,NULL,1,1,1,0,0,0}, diff --git a/src/server.h b/src/server.h index a08585292..68932f656 100644 --- a/src/server.h +++ b/src/server.h @@ -2269,6 +2269,7 @@ void flushdbCommand(client *c); void flushallCommand(client *c); void sortCommand(client *c); void lremCommand(client *c); +void lrankCommand(client *c); void rpoplpushCommand(client *c); void infoCommand(client *c); void mgetCommand(client *c); diff --git a/src/t_list.c b/src/t_list.c index 4770a2272..899a20f47 100644 --- a/src/t_list.c +++ b/src/t_list.c @@ -487,6 +487,40 @@ void ltrimCommand(client *c) { addReply(c,shared.ok); } +void lrankCommand(client *c) { + robj *subject, *obj; + obj = c->argv[3]; + long direction = 0; + long index = 0; + + if ((getLongFromObjectOrReply(c, c->argv[2], &direction, NULL) != C_OK)) + return; + + subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero); + if (subject == NULL || checkType(c,subject,OBJ_LIST)) return; + + listTypeIterator *li; + if (direction < 0) { + direction = -1; + li = listTypeInitIterator(subject,-1,LIST_HEAD); + } else { + direction = 1; + li = listTypeInitIterator(subject,0,LIST_TAIL); + } + + listTypeEntry entry; + while (listTypeNext(li,&entry)) { + if (listTypeEqual(&entry,obj)) { + break; + } + index++; + } + + listTypeReleaseIterator(li); + + addReplyLongLong(c,index * direction); +} + void lremCommand(client *c) { robj *subject, *obj; obj = c->argv[3];