示例#1
0
/* Set key to value, creating the key if it does not already exist.
 * If 'update' is not NULL, *update is set to 1 if the key was
 * already preset, otherwise to 0. */
unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen, int *update) {
    unsigned int zmlen, offset;
    unsigned int freelen, reqlen = zipmapRequiredLength(klen,vlen);
    unsigned int empty, vempty;
    unsigned char *p;

    freelen = reqlen;
    if (update) *update = 0;
    p = zipmapLookupRaw(zm,key,klen,&zmlen);
    if (p == NULL) {
        /* Key not found: enlarge */
        zm = zipmapResize(zm, zmlen+reqlen);
        p = zm+zmlen-1;
        zmlen = zmlen+reqlen;

        /* Increase zipmap length (this is an insert) */
        if (zm[0] < ZIPMAP_BIGLEN) zm[0]++;
    } else {
        /* Key found. Is there enough space for the new value? */
        /* Compute the total length: */
        if (update) *update = 1;
        freelen = zipmapRawEntryLength(p);
        if (freelen < reqlen) {
            /* Store the offset of this key within the current zipmap, so
             * it can be resized. Then, move the tail backwards so this
             * pair fits at the current position. */
            offset = p-zm;
            zm = zipmapResize(zm, zmlen-freelen+reqlen);
            p = zm+offset;

            /* The +1 in the number of bytes to be moved is caused by the
             * end-of-zipmap byte. Note: the *original* zmlen is used. */
            memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1));
            zmlen = zmlen-freelen+reqlen;
            freelen = reqlen;
        }
    }

    /* We now have a suitable block where the key/value entry can
     * be written. If there is too much free space, move the tail
     * of the zipmap a few bytes to the front and shrink the zipmap,
     * as we want zipmaps to be very space efficient. */
    empty = freelen-reqlen;
    if (empty >= ZIPMAP_VALUE_MAX_FREE) {
        /* First, move the tail <empty> bytes to the front, then resize
         * the zipmap to be <empty> bytes smaller. */
        offset = p-zm;
        memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1));
        zmlen -= empty;
        zm = zipmapResize(zm, zmlen);
        p = zm+offset;
        vempty = 0;
    } else {
        vempty = empty;
    }

    /* Just write the key + value and we are done. */
    /* Key: */
    p += zipmapEncodeLength(p,klen);
    memcpy(p,key,klen);
    p += klen;
    /* Value: */
    p += zipmapEncodeLength(p,vlen);
    *p++ = vempty;
    memcpy(p,val,vlen);
    return zm;
}
示例#2
0
文件: zipmap.c 项目: mallipeddi/redis
/* Set key to value, creating the key if it does not already exist. */
unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen) {
    unsigned int oldlen = 0, freeoff = 0, freelen;
    unsigned int reqlen = zipmapRequiredLength(klen,vlen);
    unsigned int empty, vempty;
    unsigned char *p;
   
    freelen = reqlen;
    p = zipmapLookupRaw(zm,key,klen,&oldlen,&freeoff,&freelen);
    if (p == NULL && freelen == 0) {
        printf("HERE oldlen:%u required:%u\n",oldlen,reqlen);
        /* Key not found, and not space for the new key. Enlarge */
        zm = zrealloc(zm,oldlen+reqlen);
        p = zm+oldlen-1;
        zm[oldlen+reqlen-1] = ZIPMAP_END;
        freelen = reqlen;
        printf("New total length is: %u\n", oldlen+reqlen);
    } else if (p == NULL) {
        /* Key not found, but there is enough free space. */
        p = zm+freeoff;
        /* note: freelen is already set in this case */
    } else {
        unsigned char *b = p;

        /* Key found. Is there enough space for the new value? */
        /* Compute the total length: */
        freelen = zipmapRawKeyLength(b);
        b += freelen;
        freelen += zipmapRawValueLength(b);
        if (freelen < reqlen) {
            /* Mark this entry as free and recurse */
            p[0] = ZIPMAP_EMPTY;
            zipmapEncodeLength(p+1,freelen);
            zm[0] |= ZIPMAP_STATUS_FRAGMENTED;
            return zipmapSet(zm,key,klen,val,vlen);
        }
    }

    /* Ok we have a suitable block where to write the new key/value
     * entry. */
    empty = freelen-reqlen;
    /* If there is too much free space mark it as a free block instead
     * of adding it as trailing empty space for the value, as we want
     * zipmaps to be very space efficient. */
    if (empty > ZIPMAP_VALUE_MAX_FREE) {
        unsigned char *e;

        e = p+reqlen;
        e[0] = ZIPMAP_EMPTY;
        zipmapEncodeLength(e+1,empty);
        vempty = 0;
        zm[0] |= ZIPMAP_STATUS_FRAGMENTED;
    } else {
        vempty = empty;
    }

    /* Just write the key + value and we are done. */
    /* Key: */
    p += zipmapEncodeLength(p,klen);
    memcpy(p,key,klen);
    p += klen;
    /* Value: */
    p += zipmapEncodeLength(p,vlen);
    *p++ = vempty;
    memcpy(p,val,vlen);
    return zm;
}
/* 根据key设置value,如果key不存在则创建相应的键值对,参数update用来辨别更新操作和添加操作。 */
unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen, int *update) {
    unsigned int zmlen, offset;
    // 计算存储key和value所需要的字节数
    unsigned int freelen, reqlen = zipmapRequiredLength(klen,vlen);
    unsigned int empty, vempty;
    unsigned char *p;

    /************************************************************************
     *  下面这段代码用于在zipmap留出足够的空间来容纳新插入的键值对或新的value值,尚未写入
     ************************************************************************/
    freelen = reqlen;
    if (update) *update = 0;
    // 在zipmap中查找key,函数返回后zmlen中保存了zipmap所占用的字节数。
    p = zipmapLookupRaw(zm,key,klen,&zmlen);
    if (p == NULL) {
        /* Key not found: enlarge */
        // 如果key指定的键值对不存在,则对zipmap扩容,为容纳新的键值对准备内存空间
        // zipmapResize执行的是realloc操作
        zm = zipmapResize(zm, zmlen+reqlen);
        // 此时p指向扩容前zipmap的结尾符,将从这里添加新的键值对
        p = zm+zmlen-1;
        // 更新zipmap所占用的内存空间大小
        zmlen = zmlen+reqlen;

        /* Increase zipmap length (this is an insert) */
        // 更新zipmap中保存的键值对数量,即zmlen字段
        if (zm[0] < ZIPMAP_BIGLEN) zm[0]++;

    } else {
        /* Key found. Is there enough space for the new value? */
        /* 找到可对应的键值对,执行更新操作。这里需要考虑value节点的空间大小是否能够容纳新值 */
        /* Compute the total length: */
        if (update) *update = 1;
        // 求出旧value节点的空间大小
        freelen = zipmapRawEntryLength(p);
        if (freelen < reqlen) {
            /* Store the offset of this key within the current zipmap, so
             * it can be resized. Then, move the tail backwards so this
             * pair fits at the current position. */
             // 旧节点的空间太小,需要扩容操作,zipmapResize函数会重新分配空间,所以需要记录p指针的偏移量
            offset = p-zm;
            zm = zipmapResize(zm, zmlen-freelen+reqlen);
            p = zm+offset;

            /* The +1 in the number of bytes to be moved is caused by the
             * end-of-zipmap byte. Note: the *original* zmlen is used. */
            // 移动旧value节点以后的元素以确保有足够的空间容纳新值( +1是将尾部结尾符一起移动)
            memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1));
            zmlen = zmlen-freelen+reqlen;
            freelen = reqlen;
        }
    }

    /* We now have a suitable block where the key/value entry can
     * be written. If there is too much free space, move the tail
     * of the zipmap a few bytes to the front and shrink the zipmap,
     * as we want zipmaps to be very space efficient. */
    // freelen表示经上步骤后流出来的空余空间大小,reqlen表示插入或更新键值对所需要的空间,两者的差就是free字段的
    // 的值,如果该值过大zipmap会自动调整。下面这段代码就是完成调整功能。
    empty = freelen-reqlen;
    if (empty >= ZIPMAP_VALUE_MAX_FREE) {
        /* First, move the tail <empty> bytes to the front, then resize
         * the zipmap to be <empty> bytes smaller. */
        offset = p-zm;
        memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1));
        zmlen -= empty;
        zm = zipmapResize(zm, zmlen);
        p = zm+offset;
        vempty = 0;
    } else {
        vempty = empty;
    }

    /******************************************
     *  下面的操作是讲key和value写入zipmap指定位置
     *******************************************/
    /* Just write the key + value and we are done. */
    /* Key: */
    // 对key的长度编码并写入zipmap中
    p += zipmapEncodeLength(p,klen);
    // 写入key字符串
    memcpy(p,key,klen);
    // 移动指针到value写入位置
    p += klen;
    /* Value: */
    // 对value的长度编码并写入zipmap中
    p += zipmapEncodeLength(p,vlen);
    // 写入free字段
    *p++ = vempty;
    // 写入value
    memcpy(p,val,vlen);
    return zm;
}
/* Set key to value, creating the key if it does not already exist.
 *
 * 将 key 的值设置为 value ,如果 key 不存在于 zipmap 中,那么新创建一个。
 *
 * If 'update' is not NULL, *update is set to 1 if the key was
 * already preset, otherwise to 0. 
 *
 * 如果 update 不为 NULL :
 *
 *  1) 那么在 key 已经存在时,将 *update 设为 1 。
 *
 *  2) 如果 key 未存在,将 *update 设为 0 。
 *
 * T = O(N^2)
 */
unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen, int *update) {
    unsigned int zmlen, offset;
    // 计算节点所需的长度
    unsigned int freelen, reqlen = zipmapRequiredLength(klen,vlen);
    unsigned int empty, vempty;
    unsigned char *p;
   
    freelen = reqlen;
    if (update) *update = 0;
    // 按 key 在 zipmap 中查找节点
    // T = O(N^2)
    p = zipmapLookupRaw(zm,key,klen,&zmlen);
    if (p == NULL) {

        /* Key not found: enlarge */
        // key 不存在,扩展 zipmap

        // T = O(N)
        zm = zipmapResize(zm, zmlen+reqlen);
        p = zm+zmlen-1;
        zmlen = zmlen+reqlen;

        /* Increase zipmap length (this is an insert) */
        if (zm[0] < ZIPMAP_BIGLEN) zm[0]++;
    } else {

        /* Key found. Is there enough space for the new value? */
        /* Compute the total length: */
        // 键已经存在,检查旧的值空间大小能否满足新值
        // 如果不满足的话,扩展 zipmap 并移动数据

        if (update) *update = 1;
        // T = O(1)
        freelen = zipmapRawEntryLength(p);
        if (freelen < reqlen) {

            /* Store the offset of this key within the current zipmap, so
             * it can be resized. Then, move the tail backwards so this
             * pair fits at the current position. */
            // 如果已有空间不满足新值所需空间,那么对 zipmap 进行扩展
            // T = O(N)
            offset = p-zm;
            zm = zipmapResize(zm, zmlen-freelen+reqlen);
            p = zm+offset;

            /* The +1 in the number of bytes to be moved is caused by the
             * end-of-zipmap byte. Note: the *original* zmlen is used. */
            // 向后移动数据,为节点空出足以存放新值的空间
            // T = O(N)
            memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1));
            zmlen = zmlen-freelen+reqlen;
            freelen = reqlen;
        }
    }

    /* We now have a suitable block where the key/value entry can
     * be written. If there is too much free space, move the tail
     * of the zipmap a few bytes to the front and shrink the zipmap,
     * as we want zipmaps to be very space efficient. */
    // 计算节点空余空间的长度,如果空余空间太大了,就进行缩短
    empty = freelen-reqlen;
    if (empty >= ZIPMAP_VALUE_MAX_FREE) {
        /* First, move the tail <empty> bytes to the front, then resize
         * the zipmap to be <empty> bytes smaller. */
        offset = p-zm;
        // 前移数据,覆盖空余空间
        // T = O(N)
        memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1));
        zmlen -= empty;
        // 缩小 zipmap ,移除多余的空间
        // T = O(N)
        zm = zipmapResize(zm, zmlen);
        p = zm+offset;
        vempty = 0;
    } else {
        vempty = empty;
    }

    /* Just write the key + value and we are done. */

    /* Key: */
    // 写入键
    // T = O(N)
    p += zipmapEncodeLength(p,klen);
    memcpy(p,key,klen);
    p += klen;

    /* Value: */
    // 写入值
    // T = O(N)
    p += zipmapEncodeLength(p,vlen);
    *p++ = vempty;
    memcpy(p,val,vlen);

    return zm;
}