schangxiang@126.com
2025-11-04 f5ed29dc26c7cd952d56ec5721a2efc43cd25992
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
 
namespace Sodao.FastSocket.SocketBase.Utils
{
    /// <summary>
    /// 一致性哈希container
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public sealed class ConsistentHashContainer<T>
    {
        #region Private Members
        private readonly Dictionary<uint, T> _dic = new Dictionary<uint, T>();
        private readonly T[] _arr = null;
        private readonly uint[] _keys = null;
        #endregion
 
        #region Constructors
        /// <summary>
        /// new
        /// </summary>
        /// <param name="source"></param>
        /// <exception cref="ArgumentNullException">source is null</exception>
        public ConsistentHashContainer(IDictionary<string, T> source)
        {
            if (source == null) throw new ArgumentNullException("source");
 
            var servers = new List<T>();
            var keys = new List<uint>();
 
            foreach (var child in source)
            {
                for (int i = 0; i < 250; i++)
                {
                    uint key = BitConverter.ToUInt32(new ModifiedFNV1_32().ComputeHash(Encoding.ASCII.GetBytes(child.Key + "-" + i)), 0);
                    if (!this._dic.ContainsKey(key))
                    {
                        this._dic[key] = child.Value;
                        keys.Add(key);
                    }
                }
                servers.Add(child.Value);
            }
 
            this._arr = servers.ToArray();
            keys.Sort();
            this._keys = keys.ToArray();
        }
        #endregion
 
        #region Private Methods
        /// <summary>
        /// Given an item key hash, 
        /// this method returns the Server which is closest on the server key continuum.
        /// </summary>
        /// <param name="consistentKey"></param>
        /// <returns></returns>
        private T Get(uint consistentKey)
        {
            int i = Array.BinarySearch(this._keys, consistentKey);
 
            //If not exact match...
            if (i < 0)
            {
                //Get the index of the first item bigger than the one searched for.
                i = ~i;
                //If i is bigger than the last index, it was bigger than the last item = use the first item.
                if (i >= this._keys.Length) i = 0;
            }
            return this._dic[this._keys[i]];
        }
        #endregion
 
        #region Public Methods
        /// <summary>
        /// get
        /// </summary>
        /// <param name="consistentKey"></param>
        /// <returns></returns>
        public T Get(byte[] consistentKey)
        {
            if (this._arr.Length == 0) return default(T);
            //Quick return if we only have one.
            if (this._arr.Length == 1) return this._arr[0];
            return Get(BitConverter.ToUInt32(new ModifiedFNV1_32().ComputeHash(consistentKey), 0));
        }
        #endregion
 
        #region FNV1_32
        /// <summary>
        /// Fowler-Noll-Vo hash, variant 1, 32-bit version.
        /// http://www.isthe.com/chongo/tech/comp/fnv/
        /// </summary>
        public class FNV1_32 : HashAlgorithm
        {
            private static readonly uint FNV_prime = 16777619;
            private static readonly uint offset_basis = 2166136261;
            /// <summary>
            /// hash
            /// </summary>
            protected uint hash;
 
            /// <summary>
            /// new
            /// </summary>
            public FNV1_32()
            {
                HashSizeValue = 32;
            }
            /// <summary>
            /// init
            /// </summary>
            public override void Initialize()
            {
                hash = offset_basis;
            }
            /// <summary>
            /// hashcore
            /// </summary>
            /// <param name="array"></param>
            /// <param name="ibStart"></param>
            /// <param name="cbSize"></param>
            protected override void HashCore(byte[] array, int ibStart, int cbSize)
            {
                int length = ibStart + cbSize;
                for (int i = ibStart; i < length; i++) hash = (hash * FNV_prime) ^ array[i];
            }
            /// <summary>
            /// hash final
            /// </summary>
            /// <returns></returns>
            protected override byte[] HashFinal()
            {
                return BitConverter.GetBytes(hash);
            }
        }
        #endregion
 
        #region ModifiedFNV1_32
        /// <summary>
        /// Modified Fowler-Noll-Vo hash, 32-bit version.
        /// http://home.comcast.net/~bretm/hash/6.html
        /// </summary>
        public class ModifiedFNV1_32 : FNV1_32
        {
            /// <summary>
            /// hashFinal.
            /// </summary>
            /// <returns></returns>
            protected override byte[] HashFinal()
            {
                hash += hash << 13;
                hash ^= hash >> 7;
                hash += hash << 3;
                hash ^= hash >> 17;
                hash += hash << 5;
                return BitConverter.GetBytes(hash);
            }
        }
        #endregion
    }
}