Ejemplo n.º 1
0
/* *
 * slotsdel slot1 [slot2 ...]
 * */
void
slotsdelCommand(redisClient *c) {
    int slots_slot[HASH_SLOTS_SIZE];
    int n = 0;
    if (c->argc <= 1) {
        addReplyErrorFormat(c, "wrong number of arguments for 'slotsdel' command");
        return;
    }
    int i;
    for (i = 1; i < c->argc; i ++) {
        int slot;
        if (parse_slot(c, c->argv[i], &slot) != 0) {
            return;
        }
        slots_slot[n] = slot;
        n ++;
    }
    for (i = 0; i < n; i ++) {
        dict *d = c->db->hash_slots[slots_slot[i]];
        int s = dictSize(d);
        if (s == 0) {
            continue;
        }
        list *l = listCreate();
        listSetFreeMethod(l, decrRefCountVoid);
        unsigned long cursor = 0;
        do {
            cursor = dictScan(d, cursor, slotsScanSdsKeyCallback, l);
        } while (cursor != 0);
        while (1) {
            listNode *head = listFirst(l);
            if (head == NULL) {
                break;
            }
            robj *key = listNodeValue(head);
            robj *keys[] = {key};
            slotsremove(c, keys, 1, 0);
            listDelNode(l, head);
        }
        listRelease(l);
    }
    addReplyMultiBulkLen(c, n);
    for (i = 0; i < n; i ++) {
        int n = slots_slot[i];
        int s = dictSize(c->db->hash_slots[n]);
        addReplyMultiBulkLen(c, 2);
        addReplyLongLong(c, n);
        addReplyLongLong(c, s);
    }
}
Ejemplo n.º 2
0
/* This command implements SCAN, HSCAN and SSCAN commands.
 * If object 'o' is passed, then it must be a Hash or Set object, otherwise
 * if 'o' is NULL the command will operate on the dictionary associated with
 * the current database.
 *
 * When 'o' is not NULL the function assumes that the first argument in
 * the client arguments vector is a key so it skips it before iterating
 * in order to parse options.
 *
 * In the case of a Hash object the function returns both the field and value
 * of every element on the Hash. */
void scanGenericCommand(client *c, robj *o, unsigned long cursor) {
    int i, j;
    list *keys = listCreate();
    listNode *node, *nextnode;
    long count = 10;
    sds pat = NULL;
    int patlen = 0, use_pattern = 0;
    dict *ht;

    /* Object must be NULL (to iterate keys names), or the type of the object
     * must be Set, Sorted Set, or Hash. */
    serverAssert(o == NULL || o->type == OBJ_SET || o->type == OBJ_HASH ||
                o->type == OBJ_ZSET);

    /* Set i to the first option argument. The previous one is the cursor. */
    i = (o == NULL) ? 2 : 3; /* Skip the key argument if needed. */

    /* Step 1: Parse options. */
    while (i < c->argc) {
        j = c->argc - i;
        if (!strcasecmp(c->argv[i]->ptr, "count") && j >= 2) {
            if (getLongFromObjectOrReply(c, c->argv[i+1], &count, NULL)
                != C_OK)
            {
                goto cleanup;
            }

            if (count < 1) {
                addReply(c,shared.syntaxerr);
                goto cleanup;
            }

            i += 2;
        } else if (!strcasecmp(c->argv[i]->ptr, "match") && j >= 2) {
            pat = c->argv[i+1]->ptr;
            patlen = sdslen(pat);

            /* The pattern always matches if it is exactly "*", so it is
             * equivalent to disabling it. */
            use_pattern = !(pat[0] == '*' && patlen == 1);

            i += 2;
        } else {
            addReply(c,shared.syntaxerr);
            goto cleanup;
        }
    }

    /* Step 2: Iterate the collection.
     *
     * Note that if the object is encoded with a ziplist, intset, or any other
     * representation that is not a hash table, we are sure that it is also
     * composed of a small number of elements. So to avoid taking state we
     * just return everything inside the object in a single call, setting the
     * cursor to zero to signal the end of the iteration. */

    /* Handle the case of a hash table. */
    ht = NULL;
    if (o == NULL) {
        ht = c->db->dict;
    } else if (o->type == OBJ_SET && o->encoding == OBJ_ENCODING_HT) {
        ht = o->ptr;
    } else if (o->type == OBJ_HASH && o->encoding == OBJ_ENCODING_HT) {
        ht = o->ptr;
        count *= 2; /* We return key / value for this type. */
    } else if (o->type == OBJ_ZSET && o->encoding == OBJ_ENCODING_SKIPLIST) {
        zset *zs = o->ptr;
        ht = zs->dict;
        count *= 2; /* We return key / value for this type. */
    }

    if (ht) {
        void *privdata[2];
        /* We set the max number of iterations to ten times the specified
         * COUNT, so if the hash table is in a pathological state (very
         * sparsely populated) we avoid to block too much time at the cost
         * of returning no or very few elements. */
        long maxiterations = count*10;

        /* We pass two pointers to the callback: the list to which it will
         * add new elements, and the object containing the dictionary so that
         * it is possible to fetch more data in a type-dependent way. */
        privdata[0] = keys;
        privdata[1] = o;
        do {
            cursor = dictScan(ht, cursor, scanCallback, privdata);
        } while (cursor &&
              maxiterations-- &&
              listLength(keys) < (unsigned long)count);
    } else if (o->type == OBJ_SET) {
        int pos = 0;
        int64_t ll;

        while(intsetGet(o->ptr,pos++,&ll))
            listAddNodeTail(keys,createStringObjectFromLongLong(ll));
        cursor = 0;
    } else if (o->type == OBJ_HASH || o->type == OBJ_ZSET) {
        unsigned char *p = ziplistIndex(o->ptr,0);
        unsigned char *vstr;
        unsigned int vlen;
        long long vll;

        while(p) {
            ziplistGet(p,&vstr,&vlen,&vll);
            listAddNodeTail(keys,
                (vstr != NULL) ? createStringObject((char*)vstr,vlen) :
                                 createStringObjectFromLongLong(vll));
            p = ziplistNext(o->ptr,p);
        }
        cursor = 0;
    } else {
        serverPanic("Not handled encoding in SCAN.");
    }

    /* Step 3: Filter elements. */
    node = listFirst(keys);
    while (node) {
        robj *kobj = listNodeValue(node);
        nextnode = listNextNode(node);
        int filter = 0;

        /* Filter element if it does not match the pattern. */
        if (!filter && use_pattern) {
            if (sdsEncodedObject(kobj)) {
                if (!stringmatchlen(pat, patlen, kobj->ptr, sdslen(kobj->ptr), 0))
                    filter = 1;
            } else {
                char buf[LONG_STR_SIZE];
                int len;

                serverAssert(kobj->encoding == OBJ_ENCODING_INT);
                len = ll2string(buf,sizeof(buf),(long)kobj->ptr);
                if (!stringmatchlen(pat, patlen, buf, len, 0)) filter = 1;
            }
        }

        /* Filter element if it is an expired key. */
        if (!filter && o == NULL && expireIfNeeded(c->db, kobj)) filter = 1;

        /* Remove the element and its associted value if needed. */
        if (filter) {
            decrRefCount(kobj);
            listDelNode(keys, node);
        }

        /* If this is a hash or a sorted set, we have a flat list of
         * key-value elements, so if this element was filtered, remove the
         * value, or skip it if it was not filtered: we only match keys. */
        if (o && (o->type == OBJ_ZSET || o->type == OBJ_HASH)) {
            node = nextnode;
            nextnode = listNextNode(node);
            if (filter) {
                kobj = listNodeValue(node);
                decrRefCount(kobj);
                listDelNode(keys, node);
            }
        }
        node = nextnode;
    }

    /* Step 4: Reply to the client. */
    addReplyMultiBulkLen(c, 2);
    addReplyBulkLongLong(c,cursor);

    addReplyMultiBulkLen(c, listLength(keys));
    while ((node = listFirst(keys)) != NULL) {
        robj *kobj = listNodeValue(node);
        addReplyBulk(c, kobj);
        decrRefCount(kobj);
        listDelNode(keys, node);
    }

cleanup:
    listSetFreeMethod(keys,decrRefCountVoid);
    listRelease(keys);
}
Ejemplo n.º 3
0
/* *
 * do migrate mutli key-value(s) for {slotsmgrt/slotsmgrtone}with tag commands
 * return value:
 *    -1 - error happens
 *   >=0 - # of success migration
 * */
static int
slotsmgrttag_command(redisClient *c, sds host, sds port, int timeout, robj *key) {
    int taglen;
    void *tag = slots_tag(key->ptr, &taglen);
    if (tag == NULL) {
        return slotsmgrtone_command(c, host, port, timeout, key);
    }

    int fd = slotsmgrt_get_socket(c, host, port, timeout);
    if (fd == -1) {
        return -1;
    }

    list *l = listCreate();
    listSetFreeMethod(l, decrRefCountVoid);
    do {
        uint32_t crc;
        int slot = slots_num(key->ptr, &crc);
        dict *d = c->db->hash_slots[slot];
        long long cursor = 0;
        void *args[] = {l, tag, &taglen, (void *)(long)crc};
        do {
            cursor = dictScan(d, cursor, slotsScanSdsKeyTagCallback, args);
        } while (cursor != 0);
    } while (0);

    int max = listLength(l);
    if (max == 0) {
        listRelease(l);
        return 0;
    }

    robj **keys = zmalloc(sizeof(robj *) * max);
    robj **vals = zmalloc(sizeof(robj *) * max);

    int n = 0;
    for (int i = 0; i < max; i ++) {
        listNode *head = listFirst(l);
        robj *key = listNodeValue(head);
        robj *val = lookupKeyWrite(c->db, key);
        if (val != NULL) {
            keys[n] = key;
            vals[n] = val;
            n ++;
            incrRefCount(key);
        }
        listDelNode(l, head);
    }

    int ret = 0;
    if (n != 0) {
        if (slotsmgrt(c, host, port, fd, c->db->id, timeout, keys, vals, n) != 0) {
            slotsmgrt_close_socket(host, port);
            ret = -1;
        } else {
            slotsremove(c, keys, n, 1);
            ret = n;
        }
    }

    listRelease(l);
    for (int i = 0; i < n; i ++) {
        decrRefCount(keys[i]);
    }
    zfree(keys);
    zfree(vals);
    return ret;
}
Ejemplo n.º 4
0
/* *
 * slotscheck
 * */
void
slotscheckCommand(redisClient *c) {
    sds bug = NULL;
    int i;
    for (i = 0; i < HASH_SLOTS_SIZE && bug == NULL; i ++) {
        dict *d = c->db->hash_slots[i];
        if (dictSize(d) == 0) {
            continue;
        }
        list *l = listCreate();
        listSetFreeMethod(l, decrRefCountVoid);
        unsigned long cursor = 0;
        do {
            cursor = dictScan(d, cursor, slotsScanSdsKeyCallback, l);
            while (1) {
                listNode *head = listFirst(l);
                if (head == NULL) {
                    break;
                }
                robj *key = listNodeValue(head);
                if (lookupKey(c->db, key) == NULL) {
                    if (bug == NULL) {
                        bug = sdsdup(key->ptr);
                    }
                }
                listDelNode(l, head);
            }
        } while (cursor != 0 && bug == NULL);
        listRelease(l);
    }
    if (bug != NULL) {
        addReplyErrorFormat(c, "step 1, miss = '%s'", bug);
        sdsfree(bug);
        return;
    }
    do {
        dict *d = c->db->dict;
        if (dictSize(d) == 0) {
            break;
        }
        list *l = listCreate();
        listSetFreeMethod(l, decrRefCountVoid);
        unsigned long cursor = 0;
        do {
            cursor = dictScan(d, cursor, slotsScanSdsKeyCallback, l);
            while (1) {
                listNode *head = listFirst(l);
                if (head == NULL) {
                    break;
                }
                robj *key = listNodeValue(head);
                int slot = slots_num(key->ptr, NULL);
                if (dictFind(c->db->hash_slots[slot], key->ptr) == NULL) {
                    if (bug == NULL) {
                        bug = sdsdup(key->ptr);
                    }
                }
                listDelNode(l, head);
            }
        } while (cursor != 0 && bug == NULL);
        listRelease(l);
    } while (0);
    if (bug != NULL) {
        addReplyErrorFormat(c, "step 2, miss = '%s'", bug);
        sdsfree(bug);
        return;
    }
    addReply(c, shared.ok);
}
Ejemplo n.º 5
0
/*
 * main function.
 */
int main()
{
    struct timeval tv;

    srand(time(NULL)^getpid());
    gettimeofday(&tv,NULL);


    // rand seed or fixed seed.
    unsigned int mod = tv.tv_sec^tv.tv_usec^getpid(); 
    printf("%u\n", mod);
    //dictSetHashFunctionSeed(mod);
    dictSetHashFunctionSeed(12391);



    // create <k,v> = <str, str>.
    dictType myType = {
        myHash,                 /* hash function */
        NULL,                   /* key dup */
        NULL,                   /* val dup */
        myCompare,              /* key compare */
        myDestructor,           /* key destructor */
        NULL                    /* val destructor */
    };


    // step 1: create.
    dict* myDict = dictCreate(&myType, NULL);
    assert(myDict != NULL);

    printf("-------------------\n");
    printState(myDict);

    char* key[10] = {"hello0", "hello1", "hello2", "hello3", "hello4", 
                "hello5", "hello6", "hello7", "hello8", "hello9"};

    char* val[10] = {"h0", "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "h9"};


    for(int i=0; i<10; i++)
    {
        unsigned int hash = myHash(key[i]);
        unsigned int idx = hash & 3;
        printf("real key: %u, real idx=%d\n", hash, idx);
    }



    // step 2: add
    printf("----------add first 5-----------------\n");
    for(int i = 0; i<5; i++)
    {
        printf("add %d\n", i);
        int ret = dictAdd(myDict, key[i], val[i]);
        printState(myDict);
        assert(ret==0);
    }

    printf("----------start rehashing..------------\n");
    for(int i=0; i<5; i++)
    {
        dictRehash(myDict, 1);
        printState(myDict);
    }

    printf("----------add  last 5.-----------------\n");
    for(int i = 5; i<10; i++)
    {
        printf("add %d\n", i);
        int ret = dictAdd(myDict, key[i], val[i]);
        printState(myDict);
        assert(ret==0);
    }




    // index.
    printf("------------index---------------\n");
    for(int i = 0; i < 10; i++)
    {
        printf("i=%d\n", i);
        char* v = dictFetchValue(myDict, key[i]);
        int ret = strcmp(v, val[i]); 
        assert(ret == 0);
    }

    char* v = dictFetchValue(myDict, "hello world2");
    assert(v == NULL);
    

    // foreach dict.
    unsigned long cur = 0;
    while(1) 
    {
        cur = dictScan(myDict, cur, dictScanCallback, NULL); 
        if(cur == 0)
        {
            break;
        }
    }

    // release. 
    dictRelease(myDict);

    return 0;
}