字符串sdssds(simpledynamicstring)链表字典rehash过程:intset整数集合升级降级
字符串sdssds(simpledynamicstring)目前使用最多的一种存储方式
typedefchar*sds;//sds头信息structsdshdr{intlen;intfree;charbuf[];};
sds变量指的是sdshdr.buf;取len和free值时,直接使用len=(int)(buf-sizeof(int)-sizeof(int));free=(int)(buf-sizeof(int))。
动态分配空间。字符串空间分配原则:
//已分配空间小于1M,每次翻倍,大于1M,每次增加1M。if(len1M){free=len;}else{free=1M;}
释放是惰性释放原则。有sds的value需要缩短字符串时,不会立马把多余的空间释放,而是保留,同时改变free值。在有需要的时候释放。在对一个sds进行操作前会调用tryObjectEncoding函数,该函数里会判断是否要释放多余空间。
//伪代码,首先满足编码为REDIS_ENCODING_RAWif(sdsavail(s)sdslen(s)/10){sdsRemoveFreeSpace(s);}
特别说明:redis4.0版本sdshdr结构变化较大,实现了多种类型的len/free,包括uint8_t/uint16_t/uint32_t/uint64_t等。这种做法为了适配不同长度的字符串,节省更多的内存。
链表redis的链表使用了双向链表作为存储结构
//链表节点structlistNode{structlistNode*prev;structlistNode*next;void*value;}
为了操作方便,能很快找到头、尾,redis使用list结构来持有多个listNode。
structlist{listNode*head;listNode*tail;usignedlonglen;void*(*dup)(void*ptr);void(*free)(void*ptr);void(*match)(void*ptr,void*key);}
head指向链表的头,tail指向链表的尾,len记录链表的长度。dup/free/match对应的是自定义的拷贝、释放、匹配函数,默认都为NULL。
字典用来保存键值对的数据结构字典的实现用的是哈希表。槽位:用来解决哈希冲突,哈希表不可能容纳所有的哈希值,所以在取哈希值时会有截断,导致总会有哈希冲突。截断后相同值的key落在同一个槽位。槽位内部不同的节点以单向链表形式存放。哈希表的节点结构是dictEntry.
//字典的节点结构structdictEntry{void*key;union{void*val;uint64_tu64;int64_ts64;}v;structdictEntry*next;}
key对应的就是键值对中的"键";v对应键值对的"值",v可以是三种类型实现动态存储;next指向所在槽位的下一个哈希表节点,最终每个槽位下是一个链表结构。
上边所说的是一个节点,节点是由dictht结构来持有并且保存各种信息。
structdictht{dictEntry**table;unsignedlongsize;usignedlongsizemask;unsignedlongused;}
table可以看成是槽位的数组(槽位是虚拟的一个结构),而每个槽位里是dictEntry的链表。size是槽位数组的大小。sizemask的长度是size-1,纯粹是为了方便做“与操作”(相当于对size求模操作)。减少了每次使用size-1的计算。used记录了字典中保存的节点个数。dictht是一个真正的字典结构,而redis的字典有一个功能:重哈希,所以dictht并不是被直接使用的结构。而是被dict结构所持有。做进一步的封装。
structdict{dictType*type;void*privdata;dicththt[2];intrehashidx;}structdictType{unsignedint(*hashFunction)(constvoid*key);void*(*keyDup)(void*privdata,constvoid*key);void*(*valDup)(void*privdata,constvoid*obj);int(*keyCompare)(void*privdata,constvoid*key1,constvoid*key2);void(*keyDestructor)(void*privdata,void*key);void(*valDestructor)(void*privdata,void*obj);}
type的类型是dictType,是为了实现多态,可以存放不同的类型,因而使用各自的比较、拷贝、销毁函数。这个性能在c++中特别容易实现。可以不用特别有效治疗白癜风白癜风治疗的方法