static void sinterstoreCommand(redisClient *c);
static void sunionCommand(redisClient *c);
static void sunionstoreCommand(redisClient *c);
+static void sdiffCommand(redisClient *c);
+static void sdiffstoreCommand(redisClient *c);
static void syncCommand(redisClient *c);
static void flushdbCommand(redisClient *c);
static void flushallCommand(redisClient *c);
{"sinterstore",sinterstoreCommand,-3,REDIS_CMD_INLINE},
{"sunion",sunionCommand,-2,REDIS_CMD_INLINE},
{"sunionstore",sunionstoreCommand,-3,REDIS_CMD_INLINE},
+ {"sdiff",sdiffCommand,-2,REDIS_CMD_INLINE},
+ {"sdiffstore",sdiffstoreCommand,-3,REDIS_CMD_INLINE},
{"smembers",sinterCommand,2,REDIS_CMD_INLINE},
{"incrby",incrbyCommand,3,REDIS_CMD_INLINE},
{"decrby",decrbyCommand,3,REDIS_CMD_INLINE},
sinterGenericCommand(c,c->argv+2,c->argc-2,c->argv[1]);
}
-static void sunionGenericCommand(redisClient *c, robj **setskeys, int setsnum, robj *dstkey) {
+#define REDIS_OP_UNION 0
+#define REDIS_OP_DIFF 1
+
+static void sunionDiffGenericCommand(redisClient *c, robj **setskeys, int setsnum, robj *dstkey, int op) {
dict **dv = zmalloc(sizeof(dict*)*setsnum);
dictIterator *di;
dictEntry *de;
- robj *lenobj = NULL, *dstset = NULL;
+ robj *dstset = NULL;
int j, cardinality = 0;
- if (!dv) oom("sunionCommand");
+ if (!dv) oom("sunionDiffGenericCommand");
for (j = 0; j < setsnum; j++) {
robj *setobj;
* 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) {
- lenobj = createObject(REDIS_STRING,NULL);
- addReply(c,lenobj);
- decrRefCount(lenobj);
- } else {
+ if (dstkey) {
/* If we have a target key where to store the resulting set
* create this key with an empty set inside */
deleteKey(c->db,dstkey);
/* dictAdd will not add the same element multiple times */
ele = dictGetEntryKey(de);
- if (dictAdd(dstset->ptr,ele,NULL) == DICT_OK) {
- incrRefCount(ele);
- if (!dstkey) {
- addReplySds(c,sdscatprintf(sdsempty(),
- "$%d\r\n",sdslen(ele->ptr)));
- addReply(c,ele);
- addReply(c,shared.crlf);
+ if (op == REDIS_OP_UNION || j == 0) {
+ if (dictAdd(dstset->ptr,ele,NULL) == DICT_OK) {
+ incrRefCount(ele);
cardinality++;
}
+ } else if (op == REDIS_OP_DIFF) {
+ if (dictDelete(dstset->ptr,ele) == DICT_OK) {
+ cardinality--;
+ }
}
}
dictReleaseIterator(di);
}
+ /* Output the content of the resulting set, if not in STORE mode */
+ if (!dstkey) {
+ addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",cardinality));
+ di = dictGetIterator(dstset->ptr);
+ if (!di) oom("dictGetIterator");
+ while((de = dictNext(di)) != NULL) {
+ robj *ele;
+
+ ele = dictGetEntryKey(de);
+ addReplySds(c,sdscatprintf(sdsempty(),
+ "$%d\r\n",sdslen(ele->ptr)));
+ addReply(c,ele);
+ addReply(c,shared.crlf);
+ }
+ dictReleaseIterator(di);
+ }
+
+ /* Cleanup */
if (!dstkey) {
- lenobj->ptr = sdscatprintf(sdsempty(),"*%d\r\n",cardinality);
decrRefCount(dstset);
} else {
addReply(c,shared.ok);
}
static void sunionCommand(redisClient *c) {
- sunionGenericCommand(c,c->argv+1,c->argc-1,NULL);
+ sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_UNION);
}
static void sunionstoreCommand(redisClient *c) {
- sunionGenericCommand(c,c->argv+2,c->argc-2,c->argv[1]);
+ sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_UNION);
+}
+
+static void sdiffCommand(redisClient *c) {
+ sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_DIFF);
+}
+
+static void sdiffstoreCommand(redisClient *c) {
+ sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_DIFF);
}
static void flushdbCommand(redisClient *c) {