diff options
author | Jonah H. Harris <jonah.harris@gmail.com> | 2021-08-03 04:45:27 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-03 11:45:27 +0300 |
commit | 432c92d8df179a6a1aeae2df553c6b3fc810be76 (patch) | |
tree | 7fb64e93ee532ebe6f508c68f8f108b68a6606dd /src | |
parent | bdbf5eedae55a1eea869cc5a31832d0c35113c66 (diff) | |
download | redis-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.c | 8 | ||||
-rw-r--r-- | src/server.h | 2 | ||||
-rw-r--r-- | src/t_set.c | 26 | ||||
-rw-r--r-- | src/t_zset.c | 36 |
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 { |