public INode Locate(Key key) { var keyArray = key.Array; if (keyArray == null) throw new ArgumentNullException("key"); switch (nodes.Length) { case 0: return AlreadyFailedNode.Instance; case 1: return nodes[0]; default: var retval = LocateNode(GetKeyHash(keyArray, key.Length)); // if the result is not alive then try to mutate the item key and find another node // this way we do not have to reinitialize every time a node dies/comes back // (DefaultServerPool will resurrect the nodes in the background without affecting the hashring) // // Key mutation logic is taken from spymemcached (https://code.google.com/p/spymemcached/) if (!retval.IsAlive) { var alteredKey = new byte[key.Length + 1]; Buffer.BlockCopy(keyArray, 0, alteredKey, 1, key.Length); for (var i = (byte)'0'; i < (byte)'7'; i++) { // -- this is from spymemcached alteredKey[0] = i; var tmpKey = (ulong)GetKeyHash(alteredKey, alteredKey.Length); tmpKey += (uint)(tmpKey ^ (tmpKey >> 32)); tmpKey &= 0xffffffffL; /* truncate to 32-bits */ retval = LocateNode((uint)tmpKey); // -- end if (retval.IsAlive) return retval; } } return retval; } }
public bool Equals(Key obj) { return obj.array == array && obj.length == length; }