/// <summary> /// /// </summary> /// <param name="result"></param> private Dictionary<Uri, UpdateResult> UpdateMembers(NodeInformation[] nodesInformation) { var results = new Dictionary<Uri, UpdateResult>(); foreach (var n in nodesInformation) { if (n != null && n.Address != null) results[n.Address] = UpdateMember(n); } return results; }
public NodeInformation[] Ping(Uri targetUri, NodeInformation[] membersInformation) { if (Fail) throw new Exception(string.Format("Node {0} is failed", LocalUri)); if (_env.RandomFailure()) throw new Exception("Network exception (local)"); var transport = _env.Transports[targetUri] as GossipEmulatorTransport; return transport.IncomingPingCallback(transport.LocalUri, membersInformation); }
/// <summary> /// /// </summary> /// <param name="newNodeInfo"></param> private UpdateResult UpdateMember(NodeInformation newNodeInfo) { if (newNodeInfo.Address == _localUri) return UpdateResult.IsOrigianl; MemberInfo localNodeInfo; if (_membersList.TryGetValue(newNodeInfo.Address, out localNodeInfo) == false) { AddNewNode(newNodeInfo.Address, newNodeInfo.Hearbeat); return UpdateResult.IsNew; } if (localNodeInfo.Heartbeat < newNodeInfo.Hearbeat) { localNodeInfo.Heartbeat = newNodeInfo.Hearbeat; localNodeInfo.Timestamp = _timeStamp; if (localNodeInfo.State != MemberState.Ok) { localNodeInfo.State = MemberState.Ok; return UpdateResult.IsNew; } return UpdateResult.IsUpdated; } return UpdateResult.IsOrigianl; }
/// <summary> /// /// </summary> /// <param name="nodeUri"></param> private NodeInformation[] SendPing(Uri nodeUri, NodeInformation[] membersInformation) { _log.DebugFormat("{0} \t sending ping request to {1}", _localUri, nodeUri); try { return _transport.Ping(nodeUri, membersInformation); } catch (Exception ex) { _log.Debug(string.Format("Failed to ping node {0}", nodeUri), ex); return null; } }
/// <summary> /// /// </summary> /// <param name="nodesInformation"></param> /// <param name="processFailedNodes"></param> private void ProcessUpdates(NodeInformation[] nodesInformation, bool processFailedNodes = false) { lock (_syncRoot) { var membersState = UpdateMembers(nodesInformation); Node[] newMembers = membersState.Where(a => a.Value == UpdateResult.IsNew).Select(a => _membersList[a.Key].NodeData).ToArray(); Node[] failedMembers = null; if (processFailedNodes) { // process not responding nodes -> mark as failed var toMarkAsFail = _membersList.Where(a => a.Value.Timestamp < _timeStamp - _configuration.FailTimeout).Select(a => a.Value); foreach (var v in toMarkAsFail) v.State = MemberState.Failed; failedMembers = toMarkAsFail.Select(a => a.NodeData).ToArray(); // process nodes to remove var toRemove = _membersList.Where(a => a.Value.Timestamp < _timeStamp - _configuration.RemoveTimeout).Select(a => a.Value.NodeData.Address).ToArray(); foreach (var uri in toRemove) { MemberInfo info; _membersList.TryRemove(uri, out info); } } Task.Run(() => RaiseNotifications(newMembers, failedMembers)); } }
/// <summary> /// /// </summary> /// <param name="nodesInformation"></param> /// <returns></returns> private NodeInformation[] OnPingReceived(Uri senderUri, NodeInformation[] membersInformation) { if (membersInformation == null) throw new ArgumentNullException("membersInformation"); _log.DebugFormat("{0} \t received ping request from {1}", _localUri, senderUri); Interlocked.Increment(ref _heartbeat); ProcessUpdates(membersInformation); if (_configuration.InformationExchangePattern == InformationExchangePattern.Pull || _configuration.InformationExchangePattern == InformationExchangePattern.PushPull) return GetMembersInformation(includingLocal: true); else return new NodeInformation[] { GetLocalNodeInformation() }; }
/// <summary> /// Ping nodes and collect updates. /// </summary> /// <returns>Collected updates from all nodes.</returns> private NodeInformation[] GetUpdates() { var pingNodes = GetRandomNodes(); var updatesQueue = new Queue<NodeInformation>(); NodeInformation[] membersInformation = null; if (_configuration.InformationExchangePattern == InformationExchangePattern.Push || _configuration.InformationExchangePattern == InformationExchangePattern.PushPull) membersInformation = GetMembersInformation(includingLocal: true); else membersInformation = new NodeInformation[] { GetLocalNodeInformation() }; // ping nodes foreach (var uri in pingNodes) { var result = SendPing(uri, membersInformation); if (result != null) updatesQueue.EnqueueAll(result); } // process results Dictionary<Uri, long> updates = new Dictionary<Uri, long>(); while (updatesQueue.Count > 0) { NodeInformation r = updatesQueue.Dequeue(); if (updates.ContainsKey(r.Address) == false) updates[r.Address] = r.Hearbeat; else if (updates[r.Address] < r.Hearbeat) updates[r.Address] = r.Hearbeat; } return updates.Select(a => new NodeInformation() { Address = a.Key, Hearbeat = a.Value }).ToArray(); }