csharp/1100100/Uragano/src/Uragano.Abstract/ConsistentHash/ConsistentHash.cs

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

namespace Uragano.Abstractions.ConsistentHash
{
    public clast ConsistentHash : IConsistentHash
    {
        private SortedDictionary Ring { get; } = new SortedDictionary();

        private int VirtualReplication { get; set; }

        public ConsistentHash(int virtualReplication = 200)
        {
            VirtualReplication = virtualReplication;
        }

        public void SetVirtualReplicationCount(int count)
        {
            VirtualReplication = count;
        }

        public List GetAllNodes()
        {
            return Ring.Select(p => p.Value).Distinct().ToList();
        }

        public void AddNode(T node, string key)
        {
            for (var i = 0; i < VirtualReplication; i++)
            {
                var hash = HashAlgorithm.Hash(key + i);
                Ring.Add(hash, node);
            }
        }

        public void RemoveNode(string key)
        {
            for (var i = 0; i < VirtualReplication; i++)
            {
                var hash = HashAlgorithm.Hash(key + i);
                Ring.Remove(hash);
            }
        }

        public T GetNodeForKey(string key)
        {
            if (!Ring.Any())
                throw new InvalidOperationException("Can not find the available nodes, please call the AddNode method to add nodes.");

            var hash = HashAlgorithm.Hash(key);
            if (Ring.ContainsKey(hash))
                return Ring[hash];
            var node = Ring.Where(p => p.Key > hash).OrderBy(i => i.Key).Select(p => p.Value).FirstOrDefault();
            if (node != null)
                return node;
            return Ring.FirstOrDefault().Value;
        }
    }

    internal clast HashAlgorithm
    {
        private const uint m = 0x5bd1e995;
        private const int r = 24;
        public static int Hash(byte[] data, uint seed = 0xc58f1a7b)
        {
            var length = data.Length;
            if (length == 0)
                return 0;

            var h = seed ^ (uint)length;
            var c = 0;
            while (length >= 4)
            {
                var k = (uint)(
                    data[c++]
                    | data[c++]  15;
            return (int)h;
        }

        public static int Hash(string data, uint seed = 0xc58f1a7b)
        {
            return Hash(Encoding.UTF8.GetBytes(data), seed);
        }
    }
}