重写Redis字典

转载请注明:http://blog.csdn.net/hel_wor/article/details/50358539

关于Redis的博客和教程网上都很多,比较全面的是黄建宏的Redis设计与实现

看了书,作者是怎么思考的似乎明白了。但抽象出来的结论又好像和实现的方式不同,所以在看了Redis字典的源代码后,我觉得可以试试用Java或者C#来写一写。看懂了书中表达的,但又像实际没看懂,所以决定自己实现一个。

Redis的字典是通过哈希表来实现的,冲突通过链地址法解决,Redis作为内存数据库也就是通过在内存中构建数据结构来保存数据,就如同搭积木一样,从低向上一步一步就把我们想要的样子搭建出来了,当我们打算保存数据到Redis中时,我们传入键和值,对于键,会先通过hash算法计算键的hash值,在Redis中使用的hash算法是MurmurHash2,我们需要一个映射表,把这个hash值和键,值封装成的对象对应起来,或者会有想法对应的时候是否不需要键,直接把hash值和值对应起来就可以了?保存这个键的目的是在有hash冲突时,这个键是作为查找条件用来遍历链表的,如果能保证计算出来的hash值是分布的,那么我们将所有hash值同时除以某个数结果也是相同分布的,而同时除以某个数可以保证我们得到的hash值与未除前的哈希值有相同的效果并且已经限制在一个范围内。在Redis中是通过&操作来完成的。

在自己写的DLL里,实现了哈希表扩容,步进Rahash和强制Rehash,定义了新增和保存的接口DicSave,移除键值DicRemove,获取值DicGet,字典是否为空IsEmpty,主键是否存在IsExist。

整个程序的结构就如同上图,Dic存放两个哈希表ht[0],ht[1],1表在Rehash时使用,未Rehash时使用0表,存入的键经过MurmurHash2算法获取到hashKey与哈希表中的masksize&操作得到存入哈希节点索引,要保存到字典中的键和值就存放在hashEntry中,即哈希节点,当发现hash冲突时,把新节点放在最前面,这一切通过指针来完成,也就是链地址法。

在自己实现的时候,才发现下面这个结构的实现挺奇妙的。

因为数组,我们保存数据的时候要考虑到数组索引超界的问题,链表的长度是可以扩展的,但这里我们放进数组的不是链表,而是我们自己定义的一个固定大小的类,链表的操作被我们定义在类中的next指针实现了,这样在数组中我们存放了自定义类的地址,在这个地址中有包含了下一个自定义类的地址,这样就把这个结构实现了,并且我们不必将这个结构定义成Array[List(HashEntry)]的格式。虽然我猜测C#中的可能也是这么实现的,不过是不是得看源码才知道了。

在Dic类中:
重写Redis字典_第1张图片

要说说这个lastRehashOverFlag标志(上次Rehash执行完毕标志),我定义它的是为了避免在单步Rehash时由于步进过小导致上一次Rehash未完成时又ht[0]又满足Rehash条件,这样会导致第一次Rehash时扩容的ht[1]未替换掉ht[0]又创建了一个哈希表ht,有了这个标志可以使下一次rehash延迟到上一次rehash结束后再进行。
但这个标志后来证实没有用处,因为不会出现上面说的情况,扩容是按2倍的比例执行的,如果rehash之前的表size为n,那么rehash扩容后的表size则为2n,在代码中将ht[0]上的值搬移到ht[1]上是以一个数组索引为单位的,也就是说每步rehash会搬移ht[0]上的哈希节点数组的某个索引上的所有值(包括解决hash冲突产生的链表)到ht[1]上,如果这个索引上的值为null,就跳过去找下一个值不为null的数组索引,因此在2倍的条件下,将ht[0]中的数据完成搬到ht[1]中所需的单步rehash次数会<=n,每次新增的时候rehash一次,那么最终在n次新增过程内,rehash是一定能完成的。只有在表扩展的增量小于原来表的size时才需要这个标志。

因为先执行把数据搬移一次到ht[1],再执行rehash过程中键值加到ht[1],链表的实现使得这两个过程不会产生冲突。如果自动rehash开关为关,那么满足强制rehash条件后就要执行强制rehash,这时候主线程会被阻塞到直到rehash完成,还有一种情况,就是上面说的表扩展的增量小于原来表的size,一段时间后used/size的比例会满足强制rehash条件,但代码中没有考虑这一点。

        /// <summary>
        /// 保存成员(添加/修改)
        /// </summary>
        /// <param name="key">主键</param>
        /// <param name="value"></param>
        /// <returns>是否成功</returns>
        public bool DicSave(string key, string value)
        {
            //// 散列比例
            float radio = ht[0].used / float.Parse(ht[0].size.ToString());
            if (autoRehashFlag && radio > 1 && lastRehashOverFlag)
            {
                //// 如果单步Rehash步进过小导致二次散列比例超界,等待第一次超界处理流程执行完
                rehashIndex = 0;
                lastRehashOverFlag = false;
            }

            if (rehashIndex != -1)
            {
                //// 单步Rehash
                if (this.DictRehash(1))
                {
                    Console.WriteLine("单步Rehash完成");
                }
            }
            else
            {
                //// 否则超界后的下一次添加才会扩容 因为比例不再是维持在1左右所有必须加等号
                if (radio >= forceRehashBoundary)
                {
                    //// 强制Rehash
                    rehashIndex = 0;
                    forceExpendHashTableFlag = true;
                    if (this.DictRehash(ht[0].used))
                    {
                        Console.WriteLine("强制Rehash完成");
                    }
                }
            }

            //// 这里逻辑不与上面合并的原因,因为Rehash后rehashIndex已置为-1 但合并的话会导致键值仍会保存到ht[1]保存而非ht[0],而此时ht[1]的哈希节点数组为null,会报异常。
            if (rehashIndex == -1)
            {
                return this.HashEntrySave(ht[0], key, value);
            }
            else
            {
                return this.HashEntrySave(ht[1], key, value);
            }
        }

rehashIndex是用来记录上一次rehash执行到的索引位置,但rehashIndex == sizemask时,就表示Rehash已完成,可以用ht[1]表替换ht[0],并将ht[1]表重置,rehashIndex置为-1, 等待下次Rehash。
rehash代码如下:

        /// <summary>
        /// 重新散列
        /// </summary>
        /// <param name="n">此参数控制Rehash步长</param>
        /// <returns>是否成功</returns>
        private bool DictRehash(int n)
        {
            try
            {
                //// rehashIndex == 0作为扩容标志
                if (rehashIndex == 0)
                {
                    //// 强制扩容
                    if (forceExpendHashTableFlag == true)
                    {
                        ht[1] = HashTable.ForceExpendHashTable(ht[0].used);
                    }
                    else 
                    {
                        ht[1] = HashTable.ExpendHashTable(ht[0].size);
                    }
                }

                while (n-- != 0)
                {
                    //// 只需要处理哈希节点不为空的数组索引
                    while (ht[0].hashEntryArr[rehashIndex] == null)
                    {
                        rehashIndex++;
                    }

                    HashEntry entry = ht[0].hashEntryArr[rehashIndex];
                    HashEntry nextEntry = null;

                    //// 对每个节点都做处理
                    while (entry != null)
                    {
                        //// 每个节点取出来单独处理,保存下一个节点的地址
                        nextEntry = entry.next;
                        entry.next = null;
                        int hashKey = HashTable.DictGenHashFunction(entry.key);
                        if (ht[1].hashEntryArr[hashKey & ht[1].sizemask] == null)
                        {
                            ht[1].hashEntryArr[hashKey & ht[1].sizemask] = entry;
                        }
                        else
                        {
                            HashEntry temp = ht[1].hashEntryArr[hashKey & ht[1].sizemask];
                            entry.next = temp;
                            ht[1].hashEntryArr[hashKey & ht[1].sizemask] = entry;
                        }

                        //// 更新已占用的数值
                        ht[1].used++;
                        ht[0].used--;
                        entry = nextEntry;
                    }

                    //// 处理完一条索引下滑1
                    rehashIndex++;

                    //// 循环结束条件
                    if (ht[0].used == 0)
                    {
                        //// 更新标志 重置哈希表
                        rehashIndex = -1;

                        //// 上次Rehash执行结束
                        lastRehashOverFlag = true;
                        ht[0] = ht[1];
                        ht[1] = null;
                        return true;
                    }
                }

                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

异常直接抛出了,其作为组件的作用已经完成。异常就丢给调用方去处理。

增,删,改,查,在写DicRemove处理指针时遇到一个问题。

 public bool DicRemove(string key) 
        {
            int count = 0;
            bool removeFlag = false;
            int hashKey = HashTable.DictGenHashFunction(key);
            HashEntry temp = ht[0].hashEntryArr[hashKey & ht[0].sizemask];
            HashEntry lastEntry = null;
            while (temp != null)
            {
                if (temp.key == key)
                {
                    //// 如果刚好排在第一个位置
                    if (count == 0) 
                    {
                        ht[0].hashEntryArr[hashKey & ht[0].sizemask] = temp.next;

                        //// 处理引用关系,使其能被GC回收
                        temp.next = null;
                        removeFlag = true;
                        break;
                    }

                    if (temp.next == null) 

当时写错了代码。
ht[0].hashEntryArr[hashKey & ht[0].sizemask] = temp.next;
写成了
ht[0].hashEntryArr[hashKey & ht[0].sizemask].next = temp.next;
我本想实现的是这个功能:
重写Redis字典_第2张图片
但最后出来的结果是该删掉的第一个哈希节点还在,但这个hash节点next指针原本存在的节点现在却成了null。
原因抽象出来是这样:
这里写图片描述

虽然我现在都没弄清楚为什么当时会想到数组会有next指针,next指针才会指向第一个hash节点,明明是数组封装的hash节点才有next指针,而后这个节点就是第一个hash节点。现在不晓得当时咋想的。

下面的都是源代码,只是我看了redis字典的源码认为自己大致理解了其原理自己写的一个,虽然代码的功能我的测试过了实现了,但如果要阅读,我还是建议去读redis的源码。

Dict类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Dict
{
    public class Dict
    {
        /// <summary>
        /// 哈希表
        /// </summary>
        public static HashTable[] ht = new HashTable[2];

        /// <summary>
        /// 强制rehash边界
        /// </summary>
        private static int forceRehashBoundary = 2;

        /// <summary>
        /// 重新散列记录 默认值表示未进行rehash
        /// </summary>
        private static int rehashIndex;

        /// <summary>
        /// 上次Rehash执行完毕标志 首次执行默认为true
        /// </summary>
        private static bool lastRehashOverFlag = true;

        /// <summary>
        /// 判断是否存在时保存的value值,避免获取时二次查询
        /// </summary>
        private static string getValue;

        /// <summary>
        /// 自动rehash开关 默认为开
        /// </summary>
        private bool autoRehashFlag = true;

        /// <summary>
        /// 强制扩展hash表标志
        /// </summary>
        private bool forceExpendHashTableFlag = false;

        /// <summary>
        /// 哈希表
        /// </summary>
        public HashTable[] Ht
        {
            get { return ht; }
            private set { ht = value; }
        }

        /// <summary>
        /// 自动rehash开关
        /// </summary>
        public bool AutoRehashFlag
        {
            get { return this.autoRehashFlag; }
            set { this.autoRehashFlag = value; }
        }

        /// <summary>
        /// 创建字典
        /// </summary>
        /// <returns>字典</returns>
        public static Dict NewInstance()
        {
            Dict dic = new Dict();
            rehashIndex = -1;
            dic.autoRehashFlag = false;
            dic.Ht[0] = HashTable.NewInstance();
            return dic;
        }

        /// <summary>
        /// 字典是否为空
        /// </summary>
        /// <returns>结果</returns>
        public bool IsEmpty()
        {
            return ht[0].used == 0;
        }

        /// <summary>
        /// 保存成员(添加/修改)
        /// </summary>
        /// <param name="key">主键</param>
        /// <param name="value"></param>
        /// <returns>是否成功</returns>
        public bool DicSave(string key, string value)
        {
            //// 散列比例
            float radio = ht[0].used / float.Parse(ht[0].size.ToString());
            if (autoRehashFlag && radio > 1 && lastRehashOverFlag)
            {
                //// 如果单步Rehash步进过小导致二次散列比例超界,等待第一次超界处理流程执行完
                rehashIndex = 0;
                lastRehashOverFlag = false;
            }

            if (rehashIndex != -1)
            {
                //// 单步Rehash
                if (this.DictRehash(1))
                {
                    Console.WriteLine("单步Rehash完成");
                }
            }
            else
            {
                //// 否则超界后的下一次添加才会扩容 因为比例不再是维持在1左右所有必须加等号
                if (radio >= forceRehashBoundary)
                {
                    //// 强制Rehash
                    rehashIndex = 0;
                    forceExpendHashTableFlag = true;
                    if (this.DictRehash(ht[0].used))
                    {
                        Console.WriteLine("强制Rehash完成");
                    }
                }
            }

            //// 这里逻辑不与上面合并的原因,因为Rehash后rehashIndex已置为1 如果合并的话会导致走是ht[1]保存而非ht[0]
            if (rehashIndex == -1)
            {
                return this.HashEntrySave(ht[0], key, value);
            }
            else
            {
                return this.HashEntrySave(ht[1], key, value);
            }
        }

        /// <summary>
        /// 主键是否存在
        /// </summary>
        /// <returns>treu/false</returns>
        public bool IsExist(string key)
        {
            bool existFlag = false;
            int hashKey = HashTable.DictGenHashFunction(key);
            HashEntry temp = ht[0].hashEntryArr[hashKey & ht[0].sizemask];
            while (temp != null)
            {
                if (temp.key == key)
                {
                    existFlag = true;
                    getValue = temp.value;
                    break;
                }

                //// 可能有哈希冲突 对每个成员做判断
                temp = temp.next;
            }

            if (existFlag == false)
            {
                //// 如果正在执行Rehash 再去ht[1]中查找
                if (rehashIndex != -1)
                {
                    temp = ht[1].hashEntryArr[hashKey & ht[1].sizemask];
                    while (temp != null)
                    {
                        if (temp.key == key)
                        {
                            existFlag = true;
                            getValue = temp.value;
                            break;
                        }

                        temp = temp.next;
                    }
                }
            }

            return existFlag;
        }

        /// <summary>
        /// 移除键值
        /// </summary>
        /// <param name="key">主键</param>
        /// <returns>true/false</returns>
        public bool DicRemove(string key) 
        {
            int count = 0;
            bool removeFlag = false;
            int hashKey = HashTable.DictGenHashFunction(key);
            HashEntry temp = ht[0].hashEntryArr[hashKey & ht[0].sizemask];
            HashEntry lastEntry = null;
            while (temp != null)
            {
                if (temp.key == key)
                {
                    //// 如果是第一个
                    if (count == 0) 
                    {
                        ht[0].hashEntryArr[hashKey & ht[0].sizemask] = temp.next;

                        //// 处理引用关系,使其能被GC回收
                        temp.next = null;
                        removeFlag = true;
                        break;
                    }

                    if (temp.next == null) 
                    {
                        //// 如果是唯一的一个
                        if (count == 0) 
                        {
                            ht[0].hashEntryArr[hashKey & ht[0].sizemask] = null;
                            removeFlag = true;
                            break;
                        }

                        //// 如果是最后一个
                        if (count > 0) 
                        {
                            lastEntry.next = null;
                            removeFlag = true;
                            break;
                        }
                    }

                    //// 如果在中间
                    lastEntry.next = temp.next;
                    temp.next = null;
                    removeFlag = true;
                    break;
                }

                //// 保存上一个节点
                lastEntry = temp;

                //// 可能有哈希冲突 对每个成员做判断
                temp = temp.next;
                count++;
            }

            if (removeFlag == false)
            {
                //// 如果正在执行Rehash 再去ht[1]中查找
                if (rehashIndex != -1)
                {
                    count = 0;
                    temp = ht[1].hashEntryArr[hashKey & ht[1].sizemask];
                    while (temp != null)
                    {
                        if (temp.key == key)
                        {
                            //// 如果是第一个
                            if (count == 0)
                            {
                                ht[1].hashEntryArr[hashKey & ht[1].sizemask] = temp.next;
                                temp.next = null;
                                removeFlag = true;
                                break;
                            }

                            if (temp.next == null)
                            {
                                //// 如果是唯一的一个
                                if (count == 0)
                                {
                                    ht[1].hashEntryArr[hashKey & ht[1].sizemask] = null;
                                    removeFlag = true;
                                    break;
                                }

                                //// 如果是最后一个
                                if (count > 0)
                                {
                                    lastEntry.next = null;
                                    removeFlag = true;
                                    break;
                                }
                            }

                            //// 如果在中间
                            lastEntry.next = temp.next;
                            temp.next = null;
                            removeFlag = true;
                            break;
                        }

                        lastEntry = temp;
                        temp = temp.next;
                        count++;
                    }
                }

                if (removeFlag)
                {
                    //// 更新已存入节点数
                    ht[1].used--;
                }
            }
            else 
            {
                ht[0].used--;
            }

            return removeFlag;
        }

        /// <summary>
        /// 获取值
        /// </summary>
        /// <param name="key">主键</param>
        /// <returns>value值</returns>
        public string DicGet(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                return null;
            }

            if (!this.IsExist(key))
            {
                return "DicGet ERROR : 字典中不存在此主键";
            }

            return getValue;
        }

        /// <summary>
        /// 保存哈希节点(新增/修改)
        /// </summary>
        /// <param name="ht">哈希表</param>
        /// <param name="key">主键</param>
        /// <param name="value"></param>
        /// <returns>添加结果</returns>
        private bool HashEntrySave(HashTable ht, string key, string value)
        {
            try
            {
                //// 这种情况会出现在误用ht[1]上
                if (ht == null)
                {
                    return false;
                }

                bool isExist = false;
                int hash = HashTable.DictGenHashFunction(key);
                if (ht.hashEntryArr[hash & ht.sizemask] == null)
                {
                    HashEntry node = HashEntry.NewInstance(key, value, null);
                    ht.hashEntryArr[hash & ht.sizemask] = node;
                    ht.used += 1;
                    return true;
                }
                else
                {
                    HashEntry temp = ht.hashEntryArr[hash & ht.sizemask];
                    while (temp != null) 
                    {
                        if (temp.key == key) 
                        {
                            isExist = true;
                            temp.value = value;
                        }

                        temp = temp.next;
                    }

                    //// 存在就修改 不存在则添加
                    if (isExist)
                    {
                        return true;
                    }
                    else 
                    {
                        HashEntry node = HashEntry.NewInstance(key, value, null);
                        HashEntry elder = ht.hashEntryArr[hash & ht.sizemask];
                        ht.hashEntryArr[hash & ht.sizemask] = node;
                        node.next = elder;
                        ht.used += 1;
                        return true;
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 重新散列
        /// </summary>
        /// <param name="n">此参数控制Rehash步长</param>
        /// <returns>是否成功</returns>
        private bool DictRehash(int n)
        {
            try
            {
                //// rehashIndex == 0作为扩容标志
                if (rehashIndex == 0)
                {
                    //// 强制扩容
                    if (forceExpendHashTableFlag == true)
                    {
                        ht[1] = HashTable.ForceExpendHashTable(ht[0].used);
                    }
                    else 
                    {
                        ht[1] = HashTable.ExpendHashTable(ht[0].size);
                    }
                }

                while (n-- != 0)
                {
                    //// 只需要处理哈希节点不为空的数组索引
                    while (ht[0].hashEntryArr[rehashIndex] == null)
                    {
                        rehashIndex++;
                    }

                    HashEntry entry = ht[0].hashEntryArr[rehashIndex];
                    HashEntry nextEntry = null;

                    //// 对每个节点都做处理
                    while (entry != null)
                    {
                        //// 每个节点取出来单独处理,保存下一个节点的地址
                        nextEntry = entry.next;
                        entry.next = null;
                        int hashKey = HashTable.DictGenHashFunction(entry.key);
                        if (ht[1].hashEntryArr[hashKey & ht[1].sizemask] == null)
                        {
                            ht[1].hashEntryArr[hashKey & ht[1].sizemask] = entry;
                        }
                        else
                        {
                            HashEntry temp = ht[1].hashEntryArr[hashKey & ht[1].sizemask];
                            entry.next = temp;
                            ht[1].hashEntryArr[hashKey & ht[1].sizemask] = entry;
                        }

                        //// 更新已占用的数值
                        ht[1].used++;
                        ht[0].used--;
                        entry = nextEntry;
                    }

                    //// 处理完一条索引下滑1
                    rehashIndex++;

                    //// 循环结束条件
                    if (ht[0].used == 0)
                    {
                        //// 更新标志 重置哈希表
                        rehashIndex = -1;

                        //// 上次Rehash执行结束
                        lastRehashOverFlag = true;
                        ht[0] = ht[1];
                        ht[1] = null;
                        return true;
                    }
                }

                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}

hashTable类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace Dict
{
    /// <summary>
    /// 哈希表
    /// </summary>
    public class HashTable
    {
        /// <summary>
        /// 哈希变长度
        /// </summary>
        public int size;

        /// <summary>
        /// 哈希掩码
        /// </summary>
        public int sizemask;

        /// <summary>
        /// 已添加的节点数
        /// </summary>
        public int used;

        /// <summary>
        /// 哈希节点数组
        /// </summary>
        public HashEntry[] hashEntryArr;

        /// <summary>
        /// 创建hash表
        /// </summary>
        /// <returns></returns>
        public static HashTable NewInstance() 
        {
            HashTable instance = new HashTable();
            instance.size = 4;
            instance.sizemask = instance.size - 1;
            instance.used = 0;
            instance.hashEntryArr = new HashEntry[4];
            return instance;
        }

        /// <summary>
        /// 扩展hash表
        /// </summary>
        /// <param name="size">扩展前的hash表大小</param>
        /// <returns>hash表</returns>
        public static HashTable ExpendHashTable(int size)
        {
            int i = 0;
            while (Math.Pow(2, i) < size * 2) 
            {
                i++;
            }

            HashTable instance = new HashTable();
            instance.size = int.Parse(Math.Pow(2, i).ToString());
            instance.sizemask = instance.size - 1;
            instance.used = 0;
            instance.hashEntryArr = new HashEntry[instance.size];
            return instance;
        }

        /// <summary>
        /// 强制扩展hash表
        /// </summary>
        /// <param name="size">扩展前已装入的成员数</param>
        /// <returns>hash表</returns>
        public static HashTable ForceExpendHashTable(int used)
        {
            int i = 0;
            while (Math.Pow(2, i) < used)
            {
                i++;
            }

            HashTable instance = new HashTable();
            instance.size = int.Parse(Math.Pow(2, i).ToString());
            instance.sizemask = instance.size - 1;
            instance.used = 0;
            instance.hashEntryArr = new HashEntry[instance.size];
            return instance;
        }

        /// <summary>
        /// Thomas Wang's 32
        /// </summary>
        /// <param name="key">待计算HASH主键</param>
        /// <returns>哈希值</returns>
        public int DictIntHashFunction(int key)
        {
            key += ~(key << 15);
            key ^=  (key >> 10);
            key +=  (key << 3);
            key ^=  (key >> 6);
            key += ~(key << 11);
            key ^=  (key >> 16);
            return key;
        }

        /// <summary>
        /// 获取字符串的hash值
        /// </summary>
        /// <param name="key">字符串主键</param>
        /// <param name="len">散列因子</param>
        /// <returns>hash值</returns>
        public static int DictGenHashFunction(string key)
        {
            int seed = 5381;
            int m = 0x5bd1e995; 
            int r = 24;  
            byte[] data = Encoding.ASCII.GetBytes(key);
            int length = data.Length;
            if (length == 0)
            {
                 return 0;
            }

            int h = seed ^ (int)length;
            int currentIndex = 0;
            int[] hackArray = new int[length];
            int i = 0;
            foreach (var item in data) 
            {
                hackArray[i] = int.Parse(item.ToString());
                i++;
            }

            while (length >= 4)
            {
                int k = hackArray[currentIndex++];
                k *= m;
                k ^= k >> r;
                k *= m;

                h *= m;
                h ^= k;
                length -= 4;
            }
            currentIndex *= 4; // fix the length 
            switch (length)
            {
                case 3:
                    h ^= (int)(data[currentIndex++] | data[currentIndex++] << 8);
                    h ^= (int)data[currentIndex] << 16;
                    h *= m;
                    break;
                case 2:
                    h ^= (int)(data[currentIndex++] | data[currentIndex] << 8);
                    h *= m;
                    break;
                case 1:
                    h ^= data[currentIndex];
                    h *= m;
                    break;
                default:
                    break;
            }

            // Do a few final mixes of the hash to ensure the last few 
            // bytes are well-incorporated. 

            h ^= h >> 13;
            h *= m;
            h ^= h >> 15;

            return h;  
        }
    }
}

hashEntry类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Dict
{
    /// <summary>
    /// 哈希节点
    /// </summary>
    public class HashEntry
    {
        /// <summary>
        /// 主键
        /// </summary>
        public string key;

        /// <summary>
        ///
        /// </summary>
        public string value;

        /// <summary>
        /// 下一个哈希节点
        /// </summary>
        public HashEntry next;

        /// <summary>
        /// 返回特定实例
        /// </summary>
        /// <param name="key">主键</param>
        /// <param name="value"></param>
        /// <param name="next">下一节点</param>
        /// <returns>特定实例</returns>
        public static HashEntry NewInstance(string key, string value, HashEntry next) 
        {
            HashEntry node = new HashEntry();
            node.key = key;
            node.value = value;
            node.next = next;
            return node;
        }

        /// <summary>
        /// 返回默认实例
        /// </summary>
        /// <returns>默认实例</returns>
        public static HashEntry NewInstance() 
        {
            HashEntry node = new HashEntry();
            node.key = string.Empty;
            node.value = string.Empty;
            node.next = null;
            return node;
        }
    }
}

你可能感兴趣的:(redis,内存数据库)