using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
namespace Sodao.FastSocket.SocketBase.Utils
{
///
/// 一致性哈希container
///
///
public sealed class ConsistentHashContainer
{
#region Private Members
private readonly Dictionary _dic = new Dictionary();
private readonly T[] _arr = null;
private readonly uint[] _keys = null;
#endregion
#region Constructors
///
/// new
///
///
/// source is null
public ConsistentHashContainer(IDictionary source)
{
if (source == null) throw new ArgumentNullException("source");
var servers = new List();
var keys = new List();
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
///
/// Given an item key hash,
/// this method returns the Server which is closest on the server key continuum.
///
///
///
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
///
/// get
///
///
///
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
///
/// Fowler-Noll-Vo hash, variant 1, 32-bit version.
/// http://www.isthe.com/chongo/tech/comp/fnv/
///
public class FNV1_32 : HashAlgorithm
{
private static readonly uint FNV_prime = 16777619;
private static readonly uint offset_basis = 2166136261;
///
/// hash
///
protected uint hash;
///
/// new
///
public FNV1_32()
{
HashSizeValue = 32;
}
///
/// init
///
public override void Initialize()
{
hash = offset_basis;
}
///
/// hashcore
///
///
///
///
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];
}
///
/// hash final
///
///
protected override byte[] HashFinal()
{
return BitConverter.GetBytes(hash);
}
}
#endregion
#region ModifiedFNV1_32
///
/// Modified Fowler-Noll-Vo hash, 32-bit version.
/// http://home.comcast.net/~bretm/hash/6.html
///
public class ModifiedFNV1_32 : FNV1_32
{
///
/// hashFinal.
///
///
protected override byte[] HashFinal()
{
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
return BitConverter.GetBytes(hash);
}
}
#endregion
}
}