summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJonah H. Harris <jonah.harris@gmail.com>2021-08-03 04:45:27 -0400
committerGitHub <noreply@github.com>2021-08-03 11:45:27 +0300
commit432c92d8df179a6a1aeae2df553c6b3fc810be76 (patch)
tree7fb64e93ee532ebe6f508c68f8f108b68a6606dd /src
parentbdbf5eedae55a1eea869cc5a31832d0c35113c66 (diff)
downloadredis-432c92d8df179a6a1aeae2df553c6b3fc810be76.tar.gz
Add SINTERCARD/ZINTERCARD Commands (#8946)
Add SINTERCARD and ZINTERCARD commands that are similar to ZINTER and SINTER but only return the cardinality with minimum processing and memory overheads. Co-authored-by: Oran Agra <oran@redislabs.com>
Diffstat (limited to 'src')
-rw-r--r--src/server.c8
-rw-r--r--src/server.h2
-rw-r--r--src/t_set.c26
-rw-r--r--src/t_zset.c36
4 files changed, 52 insertions, 20 deletions
diff --git a/src/server.c b/src/server.c
index 9138e4756..37fa6a996 100644
--- a/src/server.c
+++ b/src/server.c
@@ -404,6 +404,10 @@ struct redisCommand redisCommandTable[] = {
"read-only to-sort @set",
0,NULL,1,-1,1,0,0,0},
+ {"sintercard",sinterCardCommand,-2,
+ "read-only @set",
+ 0,NULL,1,-1,1,0,0,0},
+
{"sinterstore",sinterstoreCommand,-3,
"write use-memory @set",
0,NULL,1,-1,1,0,0,0},
@@ -476,6 +480,10 @@ struct redisCommand redisCommandTable[] = {
"read-only @sortedset",
0,zunionInterDiffGetKeys,0,0,0,0,0,0},
+ {"zintercard",zinterCardCommand,-3,
+ "read-only @sortedset",
+ 0,zunionInterDiffGetKeys,0,0,0,0,0,0},
+
{"zdiff",zdiffCommand,-3,
"read-only @sortedset",
0,zunionInterDiffGetKeys,0,0,0,0,0,0},
diff --git a/src/server.h b/src/server.h
index cab2aaf12..72e8a0103 100644
--- a/src/server.h
+++ b/src/server.h
@@ -2583,6 +2583,7 @@ void scardCommand(client *c);
void spopCommand(client *c);
void srandmemberCommand(client *c);
void sinterCommand(client *c);
+void sinterCardCommand(client *c);
void sinterstoreCommand(client *c);
void sunionCommand(client *c);
void sunionstoreCommand(client *c);
@@ -2662,6 +2663,7 @@ void zinterstoreCommand(client *c);
void zdiffstoreCommand(client *c);
void zunionCommand(client *c);
void zinterCommand(client *c);
+void zinterCardCommand(client *c);
void zrangestoreCommand(client *c);
void zdiffCommand(client *c);
void zscanCommand(client *c);
diff --git a/src/t_set.c b/src/t_set.c
index 88c5c7994..57a29a98f 100644
--- a/src/t_set.c
+++ b/src/t_set.c
@@ -850,7 +850,7 @@ int qsortCompareSetsByRevCardinality(const void *s1, const void *s2) {
}
void sinterGenericCommand(client *c, robj **setkeys,
- unsigned long setnum, robj *dstkey) {
+ unsigned long setnum, robj *dstkey, int cardinality_only) {
robj **sets = zmalloc(sizeof(robj*)*setnum);
setTypeIterator *si;
robj *dstset = NULL;
@@ -888,6 +888,8 @@ void sinterGenericCommand(client *c, robj **setkeys,
server.dirty++;
}
addReply(c,shared.czero);
+ } else if (cardinality_only) {
+ addReplyLongLong(c,cardinality);
} else {
addReply(c,shared.emptyset[c->resp]);
}
@@ -903,12 +905,12 @@ void sinterGenericCommand(client *c, robj **setkeys,
* the intersection set size, so we use a trick, append an empty object
* to the output list and save the pointer to later modify it with the
* right length */
- if (!dstkey) {
- replylen = addReplyDeferredLen(c);
- } else {
+ if (dstkey) {
/* If we have a target key where to store the resulting set
* create this key with an empty set inside */
dstset = createIntsetObject();
+ } else if (!cardinality_only) {
+ replylen = addReplyDeferredLen(c);
}
/* Iterate all the elements of the first (smallest) set, and test
@@ -944,7 +946,9 @@ void sinterGenericCommand(client *c, robj **setkeys,
/* Only take action when all sets contain the member */
if (j == setnum) {
- if (!dstkey) {
+ if (cardinality_only) {
+ cardinality++;
+ } else if (!dstkey) {
if (encoding == OBJ_ENCODING_HT)
addReplyBulkCBuffer(c,elesds,sdslen(elesds));
else
@@ -963,7 +967,9 @@ void sinterGenericCommand(client *c, robj **setkeys,
}
setTypeReleaseIterator(si);
- if (dstkey) {
+ if (cardinality_only) {
+ addReplyLongLong(c,cardinality);
+ } else if (dstkey) {
/* Store the resulting set into the target, if the intersection
* is not an empty set. */
if (setTypeSize(dstset) > 0) {
@@ -989,12 +995,16 @@ void sinterGenericCommand(client *c, robj **setkeys,
/* SINTER key [key ...] */
void sinterCommand(client *c) {
- sinterGenericCommand(c,c->argv+1,c->argc-1,NULL);
+ sinterGenericCommand(c,c->argv+1,c->argc-1,NULL,0);
+}
+
+void sinterCardCommand(client *c) {
+ sinterGenericCommand(c,c->argv+1,c->argc-1,NULL,1);
}
/* SINTERSTORE destination key [key ...] */
void sinterstoreCommand(client *c) {
- sinterGenericCommand(c,c->argv+2,c->argc-2,c->argv[1]);
+ sinterGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],0);
}
#define SET_OP_UNION 0
diff --git a/src/t_zset.c b/src/t_zset.c
index 679477a6f..71344f135 100644
--- a/src/t_zset.c
+++ b/src/t_zset.c
@@ -2548,14 +2548,17 @@ dictType setAccumulatorDictType = {
};
/* The zunionInterDiffGenericCommand() function is called in order to implement the
- * following commands: ZUNION, ZINTER, ZDIFF, ZUNIONSTORE, ZINTERSTORE, ZDIFFSTORE.
+ * following commands: ZUNION, ZINTER, ZDIFF, ZUNIONSTORE, ZINTERSTORE, ZDIFFSTORE,
+ * ZINTERCARD.
*
* 'numkeysIndex' parameter position of key number. for ZUNION/ZINTER/ZDIFF command,
* this value is 1, for ZUNIONSTORE/ZINTERSTORE/ZDIFFSTORE command, this value is 2.
*
* 'op' SET_OP_INTER, SET_OP_UNION or SET_OP_DIFF.
+ * 'cardinality_only' is currently only applicable when 'op' is SET_OP_INTER.
*/
-void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, int op) {
+void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, int op,
+ int cardinality_only) {
int i, j;
long setnum;
int aggregate = REDIS_AGGR_SUM;
@@ -2567,6 +2570,7 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
zset *dstzset;
zskiplistNode *znode;
int withscores = 0;
+ unsigned long cardinality = 0;
/* expect setnum input keys to be given */
if ((getLongFromObjectOrReply(c, c->argv[numkeysIndex], &setnum, NULL) != C_OK))
@@ -2613,7 +2617,7 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
int remaining = c->argc - j;
while (remaining) {
- if (op != SET_OP_DIFF &&
+ if (op != SET_OP_DIFF && !cardinality_only &&
remaining >= (setnum + 1) &&
!strcasecmp(c->argv[j]->ptr,"weights"))
{
@@ -2626,7 +2630,7 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
return;
}
}
- } else if (op != SET_OP_DIFF &&
+ } else if (op != SET_OP_DIFF && !cardinality_only &&
remaining >= 2 &&
!strcasecmp(c->argv[j]->ptr,"aggregate"))
{
@@ -2644,7 +2648,7 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
}
j++; remaining--;
} else if (remaining >= 1 &&
- !dstkey &&
+ !dstkey && !cardinality_only &&
!strcasecmp(c->argv[j]->ptr,"withscores"))
{
j++; remaining--;
@@ -2694,7 +2698,9 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
}
/* Only continue when present in every input. */
- if (j == setnum) {
+ if (j == setnum && cardinality_only) {
+ cardinality++;
+ } else if (j == setnum) {
tmp = zuiNewSdsFromValue(&zval);
znode = zslInsert(dstzset->zsl,score,tmp);
dictAdd(dstzset->dict,tmp,&znode->score);
@@ -2791,6 +2797,8 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
server.dirty++;
}
}
+ } else if (cardinality_only) {
+ addReplyLongLong(c, cardinality);
} else {
unsigned long length = dstzset->zsl->length;
zskiplist *zsl = dstzset->zsl;
@@ -2815,27 +2823,31 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
}
void zunionstoreCommand(client *c) {
- zunionInterDiffGenericCommand(c, c->argv[1], 2, SET_OP_UNION);
+ zunionInterDiffGenericCommand(c, c->argv[1], 2, SET_OP_UNION, 0);
}
void zinterstoreCommand(client *c) {
- zunionInterDiffGenericCommand(c, c->argv[1], 2, SET_OP_INTER);
+ zunionInterDiffGenericCommand(c, c->argv[1], 2, SET_OP_INTER, 0);
}
void zdiffstoreCommand(client *c) {
- zunionInterDiffGenericCommand(c, c->argv[1], 2, SET_OP_DIFF);
+ zunionInterDiffGenericCommand(c, c->argv[1], 2, SET_OP_DIFF, 0);
}
void zunionCommand(client *c) {
- zunionInterDiffGenericCommand(c, NULL, 1, SET_OP_UNION);
+ zunionInterDiffGenericCommand(c, NULL, 1, SET_OP_UNION, 0);
}
void zinterCommand(client *c) {
- zunionInterDiffGenericCommand(c, NULL, 1, SET_OP_INTER);
+ zunionInterDiffGenericCommand(c, NULL, 1, SET_OP_INTER, 0);
+}
+
+void zinterCardCommand(client *c) {
+ zunionInterDiffGenericCommand(c, NULL, 1, SET_OP_INTER, 1);
}
void zdiffCommand(client *c) {
- zunionInterDiffGenericCommand(c, NULL, 1, SET_OP_DIFF);
+ zunionInterDiffGenericCommand(c, NULL, 1, SET_OP_DIFF, 0);
}
typedef enum {