Redis源码之String操作

0.前言

String操作是Redis操作中最基本的类型,包含get,set,mget,mset,append等等。下面我们会具体分析下一些命令的详细流程,特么简单的命令没有列出。

1.SET命令
2.GET命令
3.SETBIT命令
4.GETBIT命令
5.BTICOUNT命令
6.BTIPOS命令
7.BITOP命令

1.SET命令

set操作set key value [nx, xx, ex, px], 解析完命令参数后,直接调用setCommand进行相应操作

void setCommand(redisClient *c) {
    int j;
    robj *expire = NULL;
    int unit = UNIT_SECONDS;
    int flags = REDIS_SET_NO_FLAGS;
   
     /*set key value 占了三个参数,因此从第四个参数开始解析set选项nx,xx,ex,px*/
    for (j = 3; j < c->argc; j++) {
        char *a = c->argv[j]->ptr;
        robj *next = (j == c->argc-1) ? NULL : c->argv[j+1];
        
          /*解析NX,XX,EX,PX标记*/
        if ((a[0] == 'n' || a[0] == 'N') &&
            (a[1] == 'x' || a[1] == 'X') && a[2] == '\0') {
            flags |= REDIS_SET_NX;
        } else if ((a[0] == 'x' || a[0] == 'X') &&
                   (a[1] == 'x' || a[1] == 'X') && a[2] == '\0') {
            flags |= REDIS_SET_XX;
        } else if ((a[0] == 'e' || a[0] == 'E') &&
                   (a[1] == 'x' || a[1] == 'X') && a[2] == '\0' && next) {
            unit = UNIT_SECONDS;
            expire = next;
            j++;
        } else if ((a[0] == 'p' || a[0] == 'P') &&
                   (a[1] == 'x' || a[1] == 'X') && a[2] == '\0' && next) {
            unit = UNIT_MILLISECONDS;
            expire = next;
            j++;
        } else {
            addReply(c,shared.syntaxerr);
            return;
        }
    }
   
     /*尝试编码字符串,为了节省内存使用共享值或者存储为long类型,可参考《数据结构object》一文*/
    c->argv[2] = tryObjectEncoding(c->argv[2]);
	
	/*真正执行set操作函数,下面介绍此函数*/
    setGenericCommand(c,flags,c->argv[1],c->argv[2],expire,unit,NULL,NULL);
}

void setGenericCommand(redisClient *c, int flags, robj *key, robj *val, robj *expire, int unit, robj *ok_reply, robj *abort_reply) {
    long long milliseconds = 0; /* initialized to avoid any harmness warning */

    if (expire) {
          /*将object值取出保存到 milliseconds变量中*/
        if (getLongLongFromObjectOrReply(c, expire, &milliseconds, NULL) != REDIS_OK)
            return;
        if (milliseconds <= 0) {
            addReplyErrorFormat(c,"invalid expire time in %s",c->cmd->name);
            return;
        }
        if (unit == UNIT_SECONDS) milliseconds *= 1000;
    }
   
     /*通过查找key值,验证是否符合nx和xx标记,不符合条件直接返回nil*/
    if ((flags & REDIS_SET_NX && lookupKeyWrite(c->db,key) != NULL) ||
        (flags & REDIS_SET_XX && lookupKeyWrite(c->db,key) == NULL))
    {
        addReply(c, abort_reply ? abort_reply : shared.nullbulk);
        return;
    }
     /*设置key,value值,下面进行介绍*/
    setKey(c->db,key,val);
    server.dirty++;
     /*如果设置了生存周期,则设置或更新生存周期*/
    if (expire) setExpire(c->db,key,mstime()+milliseconds);
     /*向订阅键值发生变化事件的客户端,发送事件通知*/
    notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"set",key,c->db->id);
     /*向订阅命令事件的客户端,发送事件通知*/
    if (expire) notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,
        "expire",key,c->db->id);
    addReply(c, ok_reply ? ok_reply : shared.ok);
}

void setKey(redisDb *db, robj *key, robj *val) {
     /*判断是否已经存在key,存在则覆盖,不存在则添加,放入db->dict字典中*/
    if (lookupKeyWrite(db,key) == NULL) {
        dbAdd(db,key,val);
    } else {
        dbOverwrite(db,key,val);
    }
     /*增加引用*/
    incrRefCount(val);
     /*重置生存周期*/
    removeExpire(db,key);
     /*如果客户端watch此key,则设置标记,打断当前正在执行的事务,后面客户端执行exec时,则将执行失败*/
    signalModifiedKey(db,key);
}

2.GET命令

get操作get key value, 实在是太简单了,直接从db->dict中通过key取出value值,如果没有找到则返回nil。由于Redis带有生存周期key并不会在生命周期到时立即删除,
get时首先会判断生存时间是否到期,到期则直接删除,并同步给slave,返回给客户端nil。

3.SETBIT命令

setbit操作setbit key bitoffset bitval, setbit其实就是对一段内存指定的偏移量上设置一个bit位,直接调用setbitCommand函数进行处理。

void setbitCommand(redisClient *c) {
    robj *o;
    char *err = "bit is not an integer or out of range";
    size_t bitoffset;
    int byte, bit;
    int byteval, bitval;
    long on;
   
     /*bit偏移量,偏移量小于512M,取值时进行了判断*/
    if (getBitOffsetFromArgument(c,c->argv[2],&bitoffset) != REDIS_OK)
        return;
   
     /*设置值0或1*/
    if (getLongFromObjectOrReply(c,c->argv[3],&on,err) != REDIS_OK)
        return;

    /* 判断值有效性,只能0或1 */
    if (on & ~1) {
        addReplyError(c,err);
        return;
    }

    o = lookupKeyWrite(c->db,c->argv[1]);
    if (o == NULL) {
        o = createObject(REDIS_STRING,sdsempty());
        dbAdd(c->db,c->argv[1],o);
    } else {
        if (checkType(c,o,REDIS_STRING)) return;
          /*保证object独占的非共享,判断如果是共享的string,则重新创建新的string覆盖原来的string */
        o = dbUnshareStringValue(c->db,c->argv[1],o);
    }

    /*计算偏移位置,右移三位相当于对8取整*/
    byte = bitoffset >> 3;
     /*判断字符串长度是否足够,不够则增加长度并置为0*/
    o->ptr = sdsgrowzero(o->ptr,byte+1);

    /*首先取出原来位置一个字节保存的值*/
    byteval = ((uint8_t*)o->ptr)[byte];
     /*bit代表一个字节内从右向左的偏移量*/
    bit = 7 - (bitoffset & 0x7);
     /*取出原来bit位上值,后面返回给客户端*/
    bitval = byteval & (1 << bit);

    /*取出此字节上其余7bit位值*/
    byteval &= ~(1 << bit);
     /*更新客户端需要更新的bit位的值*/
    byteval |= ((on & 0x1) << bit);
    ((uint8_t*)o->ptr)[byte] = byteval;
    signalModifiedKey(c->db,c->argv[1]);
    notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"setbit",c->argv[1],c->db->id);
    server.dirty++;
    addReply(c, bitval ? shared.cone : shared.czero);
}

4.GETBIT命令

getbit操作getbit key bitoffset, 比较简单,直接从一块内存上指定的偏移量上取出bit位值

void getbitCommand(redisClient *c) {
    robj *o;
    char llbuf[32];
    size_t bitoffset;
    size_t byte, bit;
    size_t bitval = 0;

    if (getBitOffsetFromArgument(c,c->argv[2],&bitoffset) != REDIS_OK)
        return;

    if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
        checkType(c,o,REDIS_STRING)) return;
        
     /*计算bit位偏移位置*/
    byte = bitoffset >> 3;
    bit = 7 - (bitoffset & 0x7);
    if (o->encoding != REDIS_ENCODING_RAW) {
          /*非二进制编码,就是REDIS_ENCODING_INT编码,转码为字符串取值*/
        if (byte < (size_t)ll2string(llbuf,sizeof(llbuf),(long)o->ptr))
            bitval = llbuf[byte] & (1 << bit);
    } else {
          /*二进制编码直接取值*/
        if (byte < sdslen(o->ptr))
            bitval = ((uint8_t*)o->ptr)[byte] & (1 << bit);
    }

    addReply(c, bitval ? shared.cone : shared.czero);
}

5.BITCOUNT命令

bitcount操作bitcount key [start, end], 统计start到end二进制数据中,start和end的单位是字节,bit为1的个数,使用了几种算法,调用bitcountCommand函数进行处理。

void bitcountCommand(redisClient *c) {
    robj *o;
    long start, end, strlen;
    unsigned char *p;
    char llbuf[32];

    /* 通过key值查找字符串 */
    if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
        checkType(c,o,REDIS_STRING)) return;

    /* 获取字符串长度, 如果编码是REDIS_ENCODING_INT, 转换为临时字符串*/
    if (o->encoding == REDIS_ENCODING_INT) {
        p = (unsigned char*) llbuf;
        strlen = ll2string(llbuf,sizeof(llbuf),(long)o->ptr);
    } else {
        p = (unsigned char*) o->ptr;
        strlen = sdslen(o->ptr);
    }

    /* 解析用户输入的start和end参数 */
    if (c->argc == 4) {
        if (getLongFromObjectOrReply(c,c->argv[2],&start,NULL) != REDIS_OK)
            return;
        if (getLongFromObjectOrReply(c,c->argv[3],&end,NULL) != REDIS_OK)
            return;
        /* Convert negative indexes */
        if (start < 0) start = strlen+start;
        if (end < 0) end = strlen+end;
        if (start < 0) start = 0;
        if (end < 0) end = 0;
        if (end >= strlen) end = strlen-1;
    } else if (c->argc == 2) {
        /* The whole string. */
        start = 0;
        end = strlen-1;
    } else {
        /* Syntax error. */
        addReply(c,shared.syntaxerr);
        return;
    }

    if (start > end) {
        addReply(c,shared.czero);
    } else {
        long bytes = end-start+1;
         
          /*调用redisPopcount函数计算bit位1的个数, 下面介绍*/
        addReplyLongLong(c,redisPopcount(p+start,bytes));
    }
}

计算bit为1的个数函数, redis采用了查表法和平行算法, 统计bit位为1的个数算法很多也很有趣,可以参考博客

size_t redisPopcount(void *s, long count) {
    size_t bits = 0;
    unsigned char *p = s;
    uint32_t *p4;
	
	/*bit位值存储表,列出了一个字节的所有值*/
    static const unsigned char bitsinbyte[256] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};

    /* 判断指针的初始位置是否32bit对齐, 如果没有对齐首先计算没有对齐的部分, 保证32bit对齐, 提高后面算法性能 */
    while((unsigned long)p & 3 && count) {
          /*使用查表法统计bit为1的个数*/
        bits += bitsinbyte[*p++];
        count--;
    }

    /* 每次对16个字节进行统计 */
    p4 = (uint32_t*)p;
    while(count>=16) {
        uint32_t aux1, aux2, aux3, aux4;

        aux1 = *p4++;
        aux2 = *p4++;
        aux3 = *p4++;
        aux4 = *p4++;
        count -= 16;
         
          /*首先计算相邻两个bit位中1的个数*/
        aux1 = aux1 - ((aux1 >> 1) & 0x55555555);
          /*计算相邻四位bit位中1的个数*/
        aux1 = (aux1 & 0x33333333) + ((aux1 >> 2) & 0x33333333);
        aux2 = aux2 - ((aux2 >> 1) & 0x55555555);
        aux2 = (aux2 & 0x33333333) + ((aux2 >> 2) & 0x33333333);
        aux3 = aux3 - ((aux3 >> 1) & 0x55555555);
        aux3 = (aux3 & 0x33333333) + ((aux3 >> 2) & 0x33333333);
        aux4 = aux4 - ((aux4 >> 1) & 0x55555555);
        aux4 = (aux4 & 0x33333333) + ((aux4 >> 2) & 0x33333333);
                 /*
                      *(aux1 + (aux1 >> 4))计算一个字节内1的个数, 和0x0F0F0F0F进行与运算提取出每个字节中计算结果, 和0x01010101相乘相当于对每个字节进行加和,
                      *结果保存在最高一个字节中, 右移24位, 取出计算结果.
                      */
        bits += ((((aux1 + (aux1 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24) +
                ((((aux2 + (aux2 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24) +
                ((((aux3 + (aux3 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24) +
                ((((aux4 + (aux4 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24);
    }
    /* 计算剩余数据中1的个数 */
    p = (unsigned char*)p4;
    while(count--) bits += bitsinbyte[*p++];
    return bits;
}

6.BITPOS命令

bitpos命令bitpos bit [start, end], 查找一段二进制中start到end中0或者1第一次出现的位置,start和end单位是字节,调用bitposCommand函数处理。

void bitposCommand(redisClient *c) {
    robj *o;
    long bit, start, end, strlen;
    unsigned char *p;
    char llbuf[32];
    int end_given = 0;

    /* 获取查找的bit位值,0或者1*/
    if (getLongFromObjectOrReply(c,c->argv[2],&bit,NULL) != REDIS_OK)
        return;
    if (bit != 0 && bit != 1) {
        addReplyError(c, "The bit argument must be 1 or 0.");
        return;
    }

    /* 如果key不存在,查找bit为0,则返回0 ,否则返回-1*/
    if ((o = lookupKeyRead(c->db,c->argv[1])) == NULL) {
        addReplyLongLong(c, bit ? -1 : 0);
        return;
    }
    if (checkType(c,o,REDIS_STRING)) return;

	/* 获取字符串长度, 如果编码是REDIS_ENCODING_INT, 转换为临时字符串*/
    if (o->encoding == REDIS_ENCODING_INT) {
        p = (unsigned char*) llbuf;
        strlen = ll2string(llbuf,sizeof(llbuf),(long)o->ptr);
    } else {
        p = (unsigned char*) o->ptr;
        strlen = sdslen(o->ptr);
    }

    /* 解析用户输入的start和end参数,参数是字节为单位*/
    if (c->argc == 4 || c->argc == 5) {
        if (getLongFromObjectOrReply(c,c->argv[3],&start,NULL) != REDIS_OK)
            return;
        if (c->argc == 5) {
            if (getLongFromObjectOrReply(c,c->argv[4],&end,NULL) != REDIS_OK)
                return;
            end_given = 1;
        } else {
            end = strlen-1;
        }
        /* Convert negative indexes */
        if (start < 0) start = strlen+start;
        if (end < 0) end = strlen+end;
        if (start < 0) start = 0;
        if (end < 0) end = 0;
        if (end >= strlen) end = strlen-1;
    } else if (c->argc == 3) {
        /* The whole string. */
        start = 0;
        end = strlen-1;
    } else {
        /* Syntax error. */
        addReply(c,shared.syntaxerr);
        return;
    }

    if (start > end) {
        addReplyLongLong(c, -1);
    } else {
        long bytes = end-start+1;
		/*调用redisBitpos函数计算bit位位置,下面介绍*/
        long pos = redisBitpos(p+start,bytes,bit);

        if (end_given && bit == 0 && pos == bytes*8) {
            addReplyLongLong(c,-1);
            return;
        }
		
		/*最后结果要加上先前用户给出的start开始长度*/
        if (pos != -1) pos += start*8; /* Adjust for the bytes we skipped. */
        addReplyLongLong(c,pos);
    }
}

long redisBitpos(void *s, unsigned long count, int bit) {
    unsigned long *l;
    unsigned char *c;
    unsigned long skipval, word = 0, one;
    long pos = 0; /* Position of bit, to return to the caller. */
    unsigned long j;
	
	/*
	 *首先判断字节是否按sizeof(*l)对齐,不对齐则一个一个字节进行比较,直到sizeof(*l)对齐或者是count为0
	 */
    skipval = bit ? 0 : UCHAR_MAX;
    c = (unsigned char*) s;
    while((unsigned long)c & (sizeof(*l)-1) && count) {
        if (*c != skipval) break;
        c++;
        count--;
        pos += 8;
    }

    /*
	 *如果字节对齐时,count值没有为0,则按照sizeof(*l)长度进行查找,加快查找速度,特别是对大块的连续0或者1
	 */
    skipval = bit ? 0 : ULONG_MAX;
    l = (unsigned long*) c;
    while (count >= sizeof(*l)) {
        if (*l != skipval) break;
        l++;
        count -= sizeof(*l);
        pos += sizeof(*l)*8;
    }
	
	/*查找结束后,将查找最后的到值以大端形式写入word,并不一定找到*/
    c = (unsigned char*)l;
    for (j = 0; j < sizeof(*l); j++) {
        word <<= 8;
        if (count) {
            word |= *c;
            c++;
            count--;
        }
    }
	
	/*bit为1时,没有找到直接返回-1*/
    if (bit == 1 && word == 0) return -1;

	/*
	 *设置one最高位位1,其他位为0, 用于取出word中每一位
	 */
    one = ULONG_MAX; /* All bits set to 1.*/
    one >>= 1;       /* All bits set to 1 but the MSB. */
    one = ~one;      /* All bits set to 0 but the MSB. */
	
	/*
	 *依次取出word中每一位进行比较,直到找到bit
	 */
    while(one) {
		/*这里比较设计的很巧妙,节省了一个变量记录移动位数*/
        if (((one & word) != 0) == bit) return pos;
        pos++;
        one >>= 1;
    }
	
	/*
	 *这里并不会到达,上面已经把所有情况考虑到了
	 */
	
    redisPanic("End of redisBitpos() reached.");
    return 0; /* Just to avoid warnings. */
}

7.BITOP命令

bitop操作bitop operation destkey key [key ...], operation可以是and, or, xor, not,对后面列出的key二进制数据之间进行operation运算,结果保存在destkey中,操作时间复杂度O(N),数据量过大可能会非常耗时,调用bitopCommand函数处理。

void bitopCommand(redisClient *c) {
    char *opname = c->argv[1]->ptr;
    robj *o, *targetkey = c->argv[2];
    unsigned long op, j, numkeys;
    robj **objects;      /* Array of source objects. */
    unsigned char **src; /* Array of source strings pointers. */
    unsigned long *len, maxlen = 0; /* Array of length of src strings,
                                       and max len. */
    unsigned long minlen = 0;    /* Min len among the input keys. */
    unsigned char *res = NULL; /* Resulting string. */

    /* 解析运算类型,与,或,异或,非*/
    if ((opname[0] == 'a' || opname[0] == 'A') && !strcasecmp(opname,"and"))
        op = BITOP_AND;
    else if((opname[0] == 'o' || opname[0] == 'O') && !strcasecmp(opname,"or"))
        op = BITOP_OR;
    else if((opname[0] == 'x' || opname[0] == 'X') && !strcasecmp(opname,"xor"))
        op = BITOP_XOR;
    else if((opname[0] == 'n' || opname[0] == 'N') && !strcasecmp(opname,"not"))
        op = BITOP_NOT;
    else {
        addReply(c,shared.syntaxerr);
        return;
    }

    /* 操作为非时,key只能有一个*/
    if (op == BITOP_NOT && c->argc != 4) {
        addReplyError(c,"BITOP NOT must be called with a single source key.");
        return;
    }

    /* 计算key数量,然后为所有key分配一个数组,后面运算时使用 */
    numkeys = c->argc - 3;
    src = zmalloc(sizeof(unsigned char*) * numkeys);
    len = zmalloc(sizeof(long) * numkeys);
    objects = zmalloc(sizeof(robj*) * numkeys);
    for (j = 0; j < numkeys; j++) {
        o = lookupKeyRead(c->db,c->argv[j+3]);
        /* 如果找不到key对应的值,则赋值空字符串*/
        if (o == NULL) {
            objects[j] = NULL;
            src[j] = NULL;
            len[j] = 0;
            minlen = 0;
            continue;
        }
        /* 参与运行的key对应值,必须为字符串,非字符串直接返回错误 */
        if (checkType(c,o,REDIS_STRING)) {
            unsigned long i;
            for (i = 0; i < j; i++) {
                if (objects[i])
                    decrRefCount(objects[i]);
            }
            zfree(src);
            zfree(len);
            zfree(objects);
            return;
        }
        objects[j] = getDecodedObject(o);
        src[j] = objects[j]->ptr;
        len[j] = sdslen(objects[j]->ptr);
		/*利用循环直接计算出key对应的字符串最大长度和最小长度*/
        if (len[j] > maxlen) maxlen = len[j];
        if (j == 0 || len[j] < minlen) minlen = len[j];
    }

    /* 至少有一个string非空,才进行计算操作 */
    if (maxlen) {
        res = (unsigned char*) sdsnewlen(NULL,maxlen);
        unsigned char output, byte;
        unsigned long i;

        /* 如果key少于16个,为什么是16可能是经验值,就执行下面算法,算法多了一次copy操作,但循环次数变少了,一次循环运算4*sizeof(unsigned long)个字节*/
        j = 0;
        if (minlen && numkeys <= 16) {
            unsigned long *lp[16];
            unsigned long *lres = (unsigned long*) res;
			
			/*sds字符串本身8字节对齐,不用在进行对齐操作*/
            memcpy(lp,src,sizeof(unsigned long*)*numkeys);
			/*copy第一个key中value值,以备后面进行运算*/
            memcpy(res,src[0],minlen);

            /* 根据不同操作进行相应计算,每次运算4*sizeof(unsigned long)字节 */
            if (op == BITOP_AND) {
                while(minlen >= sizeof(unsigned long)*4) {
                    for (i = 1; i < numkeys; i++) {
                        lres[0] &= lp[i][0];
                        lres[1] &= lp[i][1];
                        lres[2] &= lp[i][2];
                        lres[3] &= lp[i][3];
                        lp[i]+=4;
                    }
                    lres+=4;
                    j += sizeof(unsigned long)*4;
                    minlen -= sizeof(unsigned long)*4;
                }
            } else if (op == BITOP_OR) {
                while(minlen >= sizeof(unsigned long)*4) {
                    for (i = 1; i < numkeys; i++) {
                        lres[0] |= lp[i][0];
                        lres[1] |= lp[i][1];
                        lres[2] |= lp[i][2];
                        lres[3] |= lp[i][3];
                        lp[i]+=4;
                    }
                    lres+=4;
                    j += sizeof(unsigned long)*4;
                    minlen -= sizeof(unsigned long)*4;
                }
            } else if (op == BITOP_XOR) {
                while(minlen >= sizeof(unsigned long)*4) {
                    for (i = 1; i < numkeys; i++) {
                        lres[0] ^= lp[i][0];
                        lres[1] ^= lp[i][1];
                        lres[2] ^= lp[i][2];
                        lres[3] ^= lp[i][3];
                        lp[i]+=4;
                    }
                    lres+=4;
                    j += sizeof(unsigned long)*4;
                    minlen -= sizeof(unsigned long)*4;
                }
            } else if (op == BITOP_NOT) {
                while(minlen >= sizeof(unsigned long)*4) {
                    lres[0] = ~lres[0];
                    lres[1] = ~lres[1];
                    lres[2] = ~lres[2];
                    lres[3] = ~lres[3];
                    lres+=4;
                    j += sizeof(unsigned long)*4;
                    minlen -= sizeof(unsigned long)*4;
                }
            }
        }

        /* 这里既处理上面算法中剩余的字节,也处理key数量大于16时,使用的是最原始的方式一个字节一个字节进行运算 */
        for (; j < maxlen; j++) {
            output = (len[0] <= j) ? 0 : src[0][j];
            if (op == BITOP_NOT) output = ~output;
            for (i = 1; i < numkeys; i++) {
                byte = (len[i] <= j) ? 0 : src[i][j];
                switch(op) {
                case BITOP_AND: output &= byte; break;
                case BITOP_OR:  output |= byte; break;
                case BITOP_XOR: output ^= byte; break;
                }
            }
            res[j] = output;
        }
    }
    for (j = 0; j < numkeys; j++) {
        if (objects[j])
            decrRefCount(objects[j]);
    }
    zfree(src);
    zfree(len);
    zfree(objects);

    /* 如果至少一个非空,则将结果存入targetkey中,否则在targetkey存在情况下执行删除操作 */
    if (maxlen) {
        o = createObject(REDIS_STRING,res);
        setKey(c->db,targetkey,o);
        notifyKeyspaceEvent(REDIS_NOTIFY_STRING,"set",targetkey,c->db->id);
        decrRefCount(o);
    } else if (dbDelete(c->db,targetkey)) {
        signalModifiedKey(c->db,targetkey);
        notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",targetkey,c->db->id);
    }
    server.dirty++;
	
	/*返回给客户端字符串最大长度*/
    addReplyLongLong(c,maxlen); 
}
posted @ 2015-10-28 21:47  蒲蜡  阅读(1557)  评论(0编辑  收藏  举报