暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Redis Set数据结构

Different Java 2021-10-18
631

Set

无序集合,其中的元素不重复。

内存数据结构

Set在Redis中以intset或hashtable存储。hashtable中的value永远为NULL。当set中只包含整数型元素时,采用intset实现

intset

  1. typedef struct intset{

  2.    uint32_t encoding;

  3.    uint32_t length;

  4.    int8_t contents[];

  5. } intset;

intset的核心元素是一个字节数组,其中从小到大地有序存放着set的元素,length表示元素个数,encoding表示每个元素的编码方式。其中编码方式指定了一个整数元素占用多少个contents数组位

由于元素有序排列,所以set的获取操作采用二分查找方式实现,复杂度O(log(N))。

进行插入操作时,首先通过二分查找得到本次插入的位置,再对元素进行扩容,再将预计插入位置之后的所有元素向后移动一个位置,最后插入元素。插入复杂度为O(N)。

存储在content中的元素应该是定长的,即所有的元素占用content数组相同的格子。因此对于一个所有元素为小整数的intset突然插入一个大整数,intset中原有的所有元素都需要将所占有的字节升级为更多的字节。这个过程涉及全集合的移动。由于引起升级的新元素一定大于(或小于)全部已有元素,所以新的元素的插入位置要么在头要么在尾

原有元素从后面的元素开始移动,由于每个元素的新位置一定大于旧位置,移动过程不会发生覆盖

intset针对小整数进行了性能优化,对不同类型的整数采用变长的存储,在元素均不大的情况下减少了内存开销。

升级实例

假设有一个intset,里面有三个int16_t保存的数值,分别是1、2、3,结构如下:

  1. encoding=INTSET_ENC_INT16;

  2. length=3;

  3. contents=[1,2,3];

其中intset中contents在内存中的排列如下:

现在需要将一个长度为int32_t的值65535加入到集合中,intset需要进行以下步骤:

1.将encoding设置为INTSETENCINT32;

2.根据encoding的值,对contents数组进行内存重分配。重分配完成后,contents在内存中的排列如下:

3.因为原来的3个int16_t值还在contents前面48个位里,所以程序需要移动它们并转换类型,让她们适应集合的新编码方式。

首先移动3:

接着移动2:

最后移动1:

4.最后将新值65535添加到数组,将length设置为4:

至此,集合的升级和新增操作完成,现在的结构如下:

  1. encoding=INTSET_ENC_INT32;

  2. length=4;

  3. contents=[1,2,3,65535];


文章转载自Different Java,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论