Beispiel #1
0
void pushGenericCommand(redisClient *c, int where) {
    robj *lobj = lookupKeyWrite(c->db,c->argv[1]);
    c->argv[2] = tryObjectEncoding(c->argv[2]);
    if (lobj == NULL) {
        if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) {
            addReply(c,shared.cone);
            return;
        }
        lobj = createZiplistObject();
        dbAdd(c->db,c->argv[1],lobj);
    } else {
        if (lobj->type != REDIS_LIST) {
            addReply(c,shared.wrongtypeerr);
            return;
        }
        if (handleClientsWaitingListPush(c,c->argv[1],c->argv[2])) {
            touchWatchedKey(c->db,c->argv[1]);
            addReply(c,shared.cone);
            return;
        }
    }
    listTypePush(lobj,c->argv[2],where);
    addReplyLongLong(c,listTypeLength(lobj));
    touchWatchedKey(c->db,c->argv[1]);
    server.dirty++;
}
Beispiel #2
0
void rpoplpushHandlePush(redisClient *origclient, redisClient *c, robj *dstkey, robj *dstobj, robj *value) {
    if (!handleClientsWaitingListPush(origclient,dstkey,value)) {
        /* Create the list if the key does not exist */
        if (!dstobj) {
            dstobj = createZiplistObject();
            dbAdd(c->db,dstkey,dstobj);
        } else {
            signalModifiedKey(c->db,dstkey);
        }
        listTypePush(dstobj,value,REDIS_HEAD);
        /* Additionally propagate this PUSH operation together with
         * the operation performed by the command. */
        {
            robj **argv = zmalloc(sizeof(robj*)*3);
            argv[0] = createStringObject("LPUSH",5);
            argv[1] = dstkey;
            argv[2] = value;
            incrRefCount(argv[1]);
            incrRefCount(argv[2]);
            alsoPropagate(server.lpushCommand,c->db->id,argv,3,
                          REDIS_PROPAGATE_AOF|REDIS_PROPAGATE_REPL);
        }
    }
    /* Always send the pushed value to the client. */
    addReplyBulk(c,value);
}
Beispiel #3
0
void rpoplpushHandlePush(redisClient *origclient, redisClient *c, robj *dstkey, robj *dstobj, robj *value) {
    robj *aux;

    if (!handleClientsWaitingListPush(c,dstkey,value)) {
        /* Create the list if the key does not exist */
        if (!dstobj) {
            dstobj = createZiplistObject();
            dbAdd(c->db,dstkey,dstobj);
        } else {
            signalModifiedKey(c->db,dstkey);
        }
        listTypePush(dstobj,value,REDIS_HEAD);
        /* If we are pushing as a result of LPUSH against a key
         * watched by BLPOPLPUSH, we need to rewrite the command vector.
         * But if this is called directly by RPOPLPUSH (either directly
         * or via a BRPOPLPUSH where the popped list exists)
         * we should replicate the BRPOPLPUSH command itself. */
        if (c != origclient) {
            aux = createStringObject("LPUSH",5);
            rewriteClientCommandVector(origclient,3,aux,dstkey,value);
            decrRefCount(aux);
        } else {
            /* Make sure to always use RPOPLPUSH in the replication / AOF,
             * even if the original command was BRPOPLPUSH. */
            aux = createStringObject("RPOPLPUSH",9);
            rewriteClientCommandVector(origclient,3,aux,c->argv[1],c->argv[2]);
            decrRefCount(aux);
        }
        server.dirty++;
    }

    /* Always send the pushed value to the client. */
    addReplyBulk(c,value);
}
Beispiel #4
0
void pushGenericCommand(redisClient *c, int where) {
    int j, addlen = 0, pushed = 0;
    robj *lobj = lookupKeyWrite(c->db,c->argv[1]);
    int may_have_waiting_clients = (lobj == NULL);

    if (lobj && lobj->type != REDIS_LIST) {
        addReply(c,shared.wrongtypeerr);
        return;
    }

    for (j = 2; j < c->argc; j++) {
        c->argv[j] = tryObjectEncoding(c->argv[j]);
        if (may_have_waiting_clients) {
            if (handleClientsWaitingListPush(c,c->argv[1],c->argv[j])) {
                addlen++;
                continue;
            } else {
                may_have_waiting_clients = 0;
            }
        }
        if (!lobj) {
            lobj = createZiplistObject();
            dbAdd(c->db,c->argv[1],lobj);
        }
        listTypePush(lobj,c->argv[j],where);
        pushed++;
    }
    addReplyLongLong(c,addlen + (lobj ? listTypeLength(lobj) : 0));
    if (pushed) signalModifiedKey(c->db,c->argv[1]);
    server.dirty += pushed;
}
Beispiel #5
0
/* This is the semantic of this command:
 *  RPOPLPUSH srclist dstlist:
 *   IF LLEN(srclist) > 0
 *     element = RPOP srclist
 *     LPUSH dstlist element
 *     RETURN element
 *   ELSE
 *     RETURN nil
 *   END
 *  END
 *
 * The idea is to be able to get an element from a list in a reliable way
 * since the element is not just returned but pushed against another list
 * as well. This command was originally proposed by Ezra Zygmuntowicz.
 */
void rpoplpushcommand(redisClient *c) {
    robj *sobj, *value;
    if ((sobj = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
        checkType(c,sobj,REDIS_LIST)) return;

    if (listTypeLength(sobj) == 0) {
        addReply(c,shared.nullbulk);
    } else {
        robj *dobj = lookupKeyWrite(c->db,c->argv[2]);
        if (dobj && checkType(c,dobj,REDIS_LIST)) return;
        value = listTypePop(sobj,REDIS_TAIL);

        /* Add the element to the target list (unless it's directly
         * passed to some BLPOP-ing client */
        if (!handleClientsWaitingListPush(c,c->argv[2],value)) {
            /* Create the list if the key does not exist */
            if (!dobj) {
                dobj = createZiplistObject();
                dbAdd(c->db,c->argv[2],dobj);
            }
            listTypePush(dobj,value,REDIS_HEAD);
        }

        /* Send the element to the client as reply as well */
        addReplyBulk(c,value);

        /* listTypePop returns an object with its refcount incremented */
        decrRefCount(value);

        /* Delete the source list when it is empty */
        if (listTypeLength(sobj) == 0) dbDelete(c->db,c->argv[1]);
        touchWatchedKey(c->db,c->argv[1]);
        server.dirty++;
    }
}
Beispiel #6
0
void rpoplpushHandlePush(redisClient *c, robj *dstkey, robj *dstobj, robj *value) {
    if (!handleClientsWaitingListPush(c,dstkey,value)) {
        /* Create the list if the key does not exist */
        if (!dstobj) {
            dstobj = createZiplistObject();
            dbAdd(c->db,dstkey,dstobj);
        } else {
            touchWatchedKey(c->db,dstkey);
            server.dirty++;
        }
        listTypePush(dstobj,value,REDIS_HEAD);
    }

    /* Always send the pushed value to the client. */
    addReplyBulk(c,value);
}
Beispiel #7
0
void pushGenericCommand(redisClient *c, int where) {
    int j, waiting = 0, pushed = 0;
    robj *lobj = lookupKeyWrite(c->db,c->argv[1]);
    int may_have_waiting_clients = (lobj == NULL);

    if (lobj && lobj->type != REDIS_LIST) {
        addReply(c,shared.wrongtypeerr);
        return;
    }

    for (j = 2; j < c->argc; j++) {
        c->argv[j] = tryObjectEncoding(c->argv[j]);
        if (may_have_waiting_clients) {
            if (handleClientsWaitingListPush(c,c->argv[1],c->argv[j])) {
                waiting++;
                continue;
            } else {
                may_have_waiting_clients = 0;
            }
        }
        if (!lobj) {
            lobj = createZiplistObject();
            dbAdd(c->db,c->argv[1],lobj);
        }
        listTypePush(lobj,c->argv[j],where);
        pushed++;
    }
    addReplyLongLong(c, waiting + (lobj ? listTypeLength(lobj) : 0));
    if (pushed) signalModifiedKey(c->db,c->argv[1]);
    server.dirty += pushed;

    /* Alter the replication of the command accordingly to the number of
     * list elements delivered to clients waiting into a blocking operation.
     * We do that only if there were waiting clients, and only if still some
     * element was pushed into the list (othewise dirty is 0 and nothign will
     * be propagated). */
    if (waiting && pushed) {
        /* CMD KEY a b C D E */
        for (j = 0; j < waiting; j++) decrRefCount(c->argv[j+2]);
        memmove(c->argv+2,c->argv+2+waiting,sizeof(robj*)*pushed);
        c->argc -= waiting;
    }
}