/* Remove the specified key. If 'deleted' is not NULL the pointed integer is
 * set to 0 if the key was not found, to 1 if it was found and deleted. 
 *
 * 从 zipmap 中删除包含给定 key 的节点。
 *
 * 如果 deleted 参数不为 NULL ,那么:
 *
 *  1) 如果因为 key 没找到而导致删除失败,那么将 *deleted 设为 0 。
 *
 *  2) 如果 key 找到了,并且成功将它删除了,那么将 *deleted 设为 1 。
 *
 * T = O(N^2)
 */
unsigned char *zipmapDel(unsigned char *zm, unsigned char *key, unsigned int klen, int *deleted) {

    unsigned int zmlen, freelen;

    // T = O(N^2)
    unsigned char *p = zipmapLookupRaw(zm,key,klen,&zmlen);
    if (p) {
        // 找到,进行删除

        // 计算节点的总长
        freelen = zipmapRawEntryLength(p);
        // 移动内存,覆盖被删除的数据
        // T = O(N)
        memmove(p, p+freelen, zmlen-((p-zm)+freelen+1));
        // 缩小 zipmap 
        // T = O(N)
        zm = zipmapResize(zm, zmlen-freelen);

        /* Decrease zipmap length */
        // 减少 zipmap 的节点数量
        // 注意,如果节点数量已经大于等于 ZIPMAP_BIGLEN 
        // 那么这里不会进行减少,只有在调用 zipmapLen 的时候
        // 如果有需要的话,正确的节点数量才会被设置
        // 具体请看 zipmapLen 的源码
        if (zm[0] < ZIPMAP_BIGLEN) zm[0]--;

        if (deleted) *deleted = 1;
    } else {
        if (deleted) *deleted = 0;
    }

    return zm;
}
Пример #2
0
/* Remove the specified key. If 'deleted' is not NULL the pointed integer is
 * set to 0 if the key was not found, to 1 if it was found and deleted. */
unsigned char *zipmapDel(unsigned char *zm, unsigned char *key, unsigned int klen, int *deleted) {
    unsigned char *p = zipmapLookupRaw(zm,key,klen,NULL,NULL,NULL);
    if (p) {
        unsigned int freelen = zipmapRawEntryLength(p);

        p[0] = ZIPMAP_EMPTY;
        zipmapEncodeLength(p+1,freelen);
        zm[0] |= ZIPMAP_STATUS_FRAGMENTED;
        if (deleted) *deleted = 1;
    } else {
        if (deleted) *deleted = 0;
    }
    return zm;
}
Пример #3
0
/* Remove the specified key. If 'deleted' is not NULL the pointed integer is
 * set to 0 if the key was not found, to 1 if it was found and deleted. */
unsigned char *zipmapDel(unsigned char *zm, unsigned char *key, unsigned int klen, int *deleted) {
    unsigned int zmlen, freelen;
    unsigned char *p = zipmapLookupRaw(zm,key,klen,&zmlen);
    if (p) {
        freelen = zipmapRawEntryLength(p);
        memmove(p, p+freelen, zmlen-((p-zm)+freelen+1));
        zm = zipmapResize(zm, zmlen-freelen);

        /* Decrease zipmap length */
        if (zm[0] < ZIPMAP_BIGLEN) zm[0]--;

        if (deleted) *deleted = 1;
    } else {
        if (deleted) *deleted = 0;
    }
    return zm;
}
Пример #4
0
/* 根据key删除指定的键值对 */
unsigned char *zipmapDel(unsigned char *zm, unsigned char *key, unsigned int klen, int *deleted) {
    unsigned int zmlen, freelen;
    // 看判断该键值对是否在zipmap中,如果不存在则直接返回
    unsigned char *p = zipmapLookupRaw(zm,key,klen,&zmlen);
    if (p) {
        // 下面三句代码执行删除操作,其实就是内存块的移动操作
        freelen = zipmapRawEntryLength(p);
        memmove(p, p+freelen, zmlen-((p-zm)+freelen+1));
        zm = zipmapResize(zm, zmlen-freelen);

        /* Decrease zipmap length */
        if (zm[0] < ZIPMAP_BIGLEN) zm[0]--;

        if (deleted) *deleted = 1;
    } else {
        if (deleted) *deleted = 0;
    }
    return zm;
}
Пример #5
0
/* Remove the specified key. If 'deleted' is not NULL the pointed integer is
 * set to 0 if the key was not found, to 1 if it was found and deleted. */
unsigned char *zipmapDel(unsigned char *zm, unsigned char *key, unsigned int klen, int *deleted) {
    unsigned int zmlen, freelen;
    unsigned char *p = zipmapLookupRaw(zm,key,klen,&zmlen);
    if (p) {
        // 返回当前元素的长度
        freelen = zipmapRawEntryLength(p);
        // 移动这个元素后面的内容,往前移动,连续内存的好处
        memmove(p, p+freelen, zmlen-((p-zm)+freelen+1));
        // 重新分配小的内存
        zm = zipmapResize(zm, zmlen-freelen);
        // 设置新的长度
        /* Decrease zipmap length */
        if (zm[0] < ZIPMAP_BIGLEN) zm[0]--;

        if (deleted) *deleted = 1;
    } else {
        if (deleted) *deleted = 0;
    }
    return zm;
}
Пример #6
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;
}
Пример #7
0
/* 根据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;
}