예제 #1
0
        /// <summary>
        /// Removes a node from the hash ring.
        ///
        /// Note that <see cref="ConsistentHash{T}"/> is immutable and
        /// this operation returns a new instance.
        /// </summary>
        public static ConsistentHash <T> operator -(ConsistentHash <T> hash, T node)
        {
            var nodeHash = ConsistentHash.HashFor(node.ToString());

            return(new ConsistentHash <T>(hash._nodes.CopyAndRemove(Enumerable.Range(1, hash._virtualNodesFactor).Select(r => new KeyValuePair <int, T>(ConsistentHash.ConcatenateNodeHash(nodeHash, r), node))),
                                          hash._virtualNodesFactor));
        }
예제 #2
0
        /// <summary>
        /// Get the node responsible for the data key.
        /// Can only be used if nodes exist in the node ring.
        /// Otherwise throws <see cref="ArgumentException"/>.
        /// </summary>
        public T NodeFor(string key)
        {
            if (IsEmpty)
            {
                throw new InvalidOperationException(string.Format("Can't get node for [{0}] from an empty node ring", key));
            }

            return(NodeRing[Idx(Array.BinarySearch(NodeHashRing, ConsistentHash.HashFor(key)))]);
        }
예제 #3
0
        /// <summary>
        /// Get the node responsible for the data key.
        /// Can only be used if nodes exist in the node ring.
        /// </summary>
        /// <exception cref="InvalidOperationException">
        /// This exception is thrown if the node ring is empty.
        /// </exception>
        public T NodeFor(byte[] key)
        {
            if (IsEmpty)
            {
                throw new InvalidOperationException($"Can't get node for [{key}] from an empty node ring");
            }

            return(NodeRing[Idx(Array.BinarySearch(NodeHashRing, ConsistentHash.HashFor(key)))]);
        }
예제 #4
0
        public override Routee Select(object message, Routee[] routees)
        {
            if (message == null || routees == null || routees.Length == 0)
            {
                return(Routee.NoRoutee);
            }

            Func <ConsistentHash <ConsistentRoutee> > updateConsistentHash = () =>
            {
                // update consistentHash when routees are changed
                // changes to routees are rare when no changes this is a quick operation
                var oldConsistHashTuple = _consistentHashRef.Value;
                var oldRoutees          = oldConsistHashTuple.Item1;
                var oldConsistentHash   = oldConsistHashTuple.Item2;

                if (oldRoutees == null || !routees.SequenceEqual(oldRoutees))
                {
                    // when other instance, same content, no need to re-hash, but try to set routees
                    var consistentHash = routees == oldRoutees
                        ? oldConsistentHash
                        : ConsistentHash.Create(routees.Select(x => new ConsistentRoutee(x, _selfAddress)), _vnodes);
                    //ignore, don't update, in case of CAS failure
                    _consistentHashRef.CompareAndSet(oldConsistHashTuple, Tuple.Create(routees, consistentHash));
                    return(consistentHash);
                }
                return(oldConsistentHash);
            };

            Func <object, Routee> target = hashData =>
            {
                try
                {
                    var currentConsistentHash = updateConsistentHash();
                    if (currentConsistentHash.IsEmpty)
                    {
                        return(Routee.NoRoutee);
                    }
                    else
                    {
                        if (hashData is byte[])
                        {
                            return(currentConsistentHash.NodeFor(hashData as byte[]).Routee);
                        }
                        if (hashData is string)
                        {
                            return(currentConsistentHash.NodeFor(hashData as string).Routee);
                        }
                        return
                            (currentConsistentHash.NodeFor(
                                 _system.Serialization.FindSerializerFor(hashData).ToBinary(hashData)).Routee);
                    }
                }
                catch (Exception ex)
                {
                    //serialization failed
                    _log.Value.Warning("Couldn't route message with consistent hash key [{0}] due to [{1}]", hashData,
                                       ex.Message);
                    return(Routee.NoRoutee);
                }
            };

            if (_hashMapping(message) != null)
            {
                return(target(ConsistentHash.ToBytesOrObject(_hashMapping(message))));
            }
            else if (message is IConsistentHashable)
            {
                var hashable = (IConsistentHashable)message;
                return(target(ConsistentHash.ToBytesOrObject(hashable.ConsistentHashKey)));
            }
            else
            {
                _log.Value.Warning(
                    "Message [{0}] must be handled by hashMapping, or implement [{1}] or be wrapped in [{2}]",
                    message.GetType().Name, typeof(IConsistentHashable).Name, typeof(ConsistentHashableEnvelope).Name);
                return(Routee.NoRoutee);
            }
        }