private static Task SendLeaderElectionResponse(LeaderElectionState electionState, NetworkNode nodeTuple, bool responseState, bool uniqueState, bool uselessState) { var uriBuilder = new UriBuilder(Uri.UriSchemeHttp, nodeTuple.Hostname, nodeTuple.Port, "/secondYo/Response"); var reqDataString = string.Join(Environment.NewLine, electionState.Guid, electionState.CreationTime.ToString("o"), nodeGuid, responseState, uniqueState, uselessState); var reqDataBytes = Encoding.ASCII.GetBytes(reqDataString); return SendNotificationPostRequestToNode(uriBuilder.Uri, reqDataBytes); }
private static void FirstYoAdvertisementContext(HttpListenerContext http_ctx) { // Received leader election state from incoming connection leaderGuid = null; LeaderElectionState electionState; Guid electionGuid; DateTime electionTime; Guid nodeGuid, advertGuid; using (var reqReader = new StreamReader(http_ctx.Request.InputStream)) { electionGuid = Guid.Parse(reqReader.ReadLine()); electionTime = DateTime.Parse(reqReader.ReadLine()); nodeGuid = Guid.Parse(reqReader.ReadLine()); advertGuid = Guid.Parse(reqReader.ReadLine()); } http_ctx.Response.StatusCode = (int)HttpStatusCode.OK; http_ctx.Response.Close(); var inNodeKvps = incomingNodeConnections.ToArray(); var outNodeKvps = outgoingNodeConnections.ToArray(); // Attempt to find the leader election state in the ongoing leader election dict if (!leaderElections.TryGetValue(electionGuid, out electionState)) { // Ongoing leader election unknown, registering implicit request for leader election initiation electionState = new LeaderElectionState(inNodeKvps.Select(kvp => kvp.Key), outNodeKvps.Select(kvp => kvp.Key)) { Guid = electionGuid, CreationTime = electionTime }; if (!leaderElections.TryAdd(electionGuid, electionState)) electionState = leaderElections[electionGuid]; // Propagating leader election initiation request to all inward pointing connections // to ensure advertisements from all ingoing connections Task.WaitAll(inNodeKvps.Select(kvp => SendLeaderElectionAdvertisementRequest(electionState, kvp.Value)).ToArray()); } // Store advertised GUID in the list of expected advertisements electionState.FirstYoAdvertisements[nodeGuid] = advertGuid; var firstYoAdvertKvps = electionState.FirstYoAdvertisements.ToArray(); if (firstYoAdvertKvps.All(kvp => kvp.Value != null)) { // All outstaning advertisements received. // Ready to propagte minimum to all outgoing connections var minGuid = firstYoAdvertKvps.Min(kvp => kvp.Key); electionState.FirstYoMinimum = minGuid; leaderGuid = minGuid; var outNodes = outNodeKvps.Select(kvp => kvp.Value); if (outNodes.Any()) Task.WaitAll(outNodes.Select(n => SendLeaderElectionAdvertisement(electionState, n, nodeGuid)).ToArray()); else { // No outgoing connections -> current node is a sink // Sending election responses back to incoming connections var responseTaskList = new List<Task>(); var receivedAdvertSet = new HashSet<Guid>(); var receivedAdvertKvps = electionState.FirstYoAdvertisements.ToArray(); foreach (var receivedAdvertKvp in receivedAdvertKvps) { // The response is only YES if the actual minimum was received var responseState = receivedAdvertKvp.Value == electionState.FirstYoMinimum; // Only the first of all received values was a unique advertisement var uniqueAdvert = receivedAdvertSet.Add(receivedAdvertKvp.Value.GetValueOrDefault()); var receivedNodeTuple = incomingNodeConnections[receivedAdvertKvp.Key]; var uselessState = firstYoAdvertKvps.Length < 2; // Sending Response back to incoming connection responseTaskList.Add(SendLeaderElectionResponse(electionState, receivedNodeTuple, responseState, uniqueAdvert, uselessState)); } } } else if ((DateTime.Now - electionState.CreationTime) > new TimeSpan(0, 0, 8)) { // Retransmitting leader election initiation request after timeout var inKvps = electionState.FirstYoAdvertisements.ToArray().Where(kvp => kvp.Value == null); Task.WaitAll(inKvps.Select(kvp => SendLeaderElectionAdvertisementRequest(electionState, incomingNodeConnections[kvp.Key])).ToArray()); } }
private static Task SendLeaderElectionAdvertisement(LeaderElectionState electionState, NetworkNode nodeTuple, Guid advertGuid) { var uriBuilder = new UriBuilder(Uri.UriSchemeHttp, nodeTuple.Hostname, nodeTuple.Port, "/firstYo/Advertise"); var reqDataString = string.Join(Environment.NewLine, electionState.Guid, electionState.CreationTime.ToString("o"), nodeGuid, advertGuid); var reqDataBytes = Encoding.ASCII.GetBytes(reqDataString); return SendNotificationPostRequestToNode(uriBuilder.Uri, reqDataBytes); }
private static void FirstYoRequestAdvertisementContext(HttpListenerContext http_ctx) { // Received to request to initiate YO-YO leader election // Request should be propaged along all currently inward pointing edges // since this request only should be received along outgoing edges // => Leader election initiation request travel along the network graph in reverse edge order leaderGuid = null; LeaderElectionState electionState; var inNodeKvps = incomingNodeConnections.ToArray(); var outNodeKvps = outgoingNodeConnections.ToArray(); using (var reqReader = new StreamReader(http_ctx.Request.InputStream)) { var electionGuid = Guid.Parse(reqReader.ReadLine()); var electionTime = DateTime.Parse(reqReader.ReadLine()); // Create a new leader election state with all incoming node connections electionState = new LeaderElectionState(inNodeKvps.Select(kvp => kvp.Key), outNodeKvps.Select(kvp => kvp.Key)) { Guid = electionGuid, CreationTime = electionTime }; // Add the leader election state to current leader elections leaderElections[electionGuid] = electionState; } // Leader election initiation received http_ctx.Response.StatusCode = (int)HttpStatusCode.OK; http_ctx.Response.Close(); var inNodeTuples = inNodeKvps.Select(kvp => kvp.Value); if (inNodeTuples.Any()) // If there are inward pointing connections to the current, propagate leader election initiation request Task.WaitAll(inNodeTuples.Select(n => SendLeaderElectionAdvertisementRequest(electionState, n)).ToArray()); else { // No inward pointing connections, start leader election var outNodeTuples = outNodeKvps.Select(kvp => kvp.Value); // Advertise current node GUID to all outgoing connections Task.WaitAll(outNodeTuples.Select(n => SendLeaderElectionAdvertisement(electionState, n, nodeGuid)).ToArray()); } }
private static void SecondYoResponseContext(HttpListenerContext http_ctx) { // Received response to leader election advertisement Guid electionGuid; DateTime electionTime; Guid nodeGuid; bool responseState, uniqueState, uselessState; using (var reqReader = new StreamReader(http_ctx.Request.InputStream)) { electionGuid = Guid.Parse(reqReader.ReadLine()); electionTime = DateTime.Parse(reqReader.ReadLine()); nodeGuid = Guid.Parse(reqReader.ReadLine()); responseState = bool.Parse(reqReader.ReadLine()); uniqueState = bool.Parse(reqReader.ReadLine()); uselessState = bool.Parse(reqReader.ReadLine()); } http_ctx.Response.StatusCode = (int)HttpStatusCode.OK; http_ctx.Response.Close(); LeaderElectionState electionState; if (!leaderElections.TryGetValue(electionGuid, out electionState)) return; // Ongoing Leader election unknown. Disregarding // Registering response electionState.SecondYoResponses[nodeGuid] = responseState; var responseKvps = electionState.SecondYoResponses.ToArray(); if (responseKvps.All(kvp => kvp.Value != null)) { // All responses have been received if (responseKvps.Any(kvp => kvp.Value == false)) { // If any response was negative // all further responses will be negative // Propagating negative responses back over incoming connections Task.WaitAll(incomingNodeConnections.ToArray().Select(kvp => SendLeaderElectionResponse(electionState, kvp.Value, false, false, false)).ToArray()); } else { // All responses were positive // Propagating responses back over incoming connections // accoring to match with determined minimum var responseTaskList = new List<Task>(); var receivedAdvertSet = new HashSet<Guid>(); var receivedAdvertKvps = electionState.FirstYoAdvertisements.ToArray(); foreach (var receivedAdvertKvp in receivedAdvertKvps) { // The response is only YES if the actual minimum was received var subResponseState = receivedAdvertKvp.Value == electionState.FirstYoMinimum; // Only the first of all received values was a unique advertisement var uniqueAdvert = receivedAdvertSet.Add(receivedAdvertKvp.Value.GetValueOrDefault()); var receivedNodeTuple = incomingNodeConnections[receivedAdvertKvp.Key]; var subUselessState = electionState.SecondYoResponses.IsEmpty && electionState.FirstYoAdvertisements.Count < 2; // Sending Response back to incoming connection responseTaskList.Add(SendLeaderElectionResponse(electionState, receivedNodeTuple, subResponseState, uniqueAdvert, subUselessState)); } } var flipTaskList = new List<Task>(); foreach (var flipGuid in responseKvps.Where(kvp => kvp.Value == false).Select(kvp => kvp.Key)) { // Flipping the direction of all negative responded connections NetworkNode flipTuple; if (!outgoingNodeConnections.TryRemove(flipGuid, out flipTuple)) continue; else if (!incomingNodeConnections.TryAdd(flipGuid, flipTuple)) continue; // Transmitting flip directive to the other node so it does the same flipTaskList.Add(SendSecondYoFlipNode(flipTuple)); } Task.WaitAll(flipTaskList.ToArray()); var inNodeKvps = incomingNodeConnections.ToArray(); var outNodeKvps = outgoingNodeConnections.ToArray(); if (inNodeKvps.Length == 0) { if (outNodeKvps.Select(kvp => kvp.Value).All(node => node.IsUselessConnection)) { // Only useless outgoing connections and no incoming connections // This node is the leader. Leader election complete leaderGuid = electionState.FirstYoMinimum; } else { var newElectionState = new LeaderElectionState(inNodeKvps.Where(kvp => !kvp.Value.IsUselessConnection).Select(kvp => kvp.Key), outNodeKvps.Where(kvp => !kvp.Value.IsUselessConnection).Select(kvp => kvp.Key)) { Guid = Guid.NewGuid(), CreationTime = DateTime.Now, FirstYoMinimum = nodeGuid }; leaderElections[newElectionState.Guid] = newElectionState; leaderElections.TryRemove(electionGuid, out electionState); Task.WaitAll(outNodeKvps.Select(kvp => SendLeaderElectionAdvertisement(newElectionState, kvp.Value, nodeGuid)).ToArray()); } } } }
private static async void HandleHttpContext(HttpListener http_listener) { HttpListenerContext http_ctx; try { http_ctx = await http_listener.GetContextAsync(); } catch (Exception) { return; } //nodeStateLock.EnterReadLock(); try { HandleHttpContext(http_listener); var path = http_ctx.Request.Url.AbsolutePath; if (string.Equals("/getCurrentLeader", path, StringComparison.OrdinalIgnoreCase)) { var inNodeKvps = incomingNodeConnections.ToArray(); var outNodeKvps = outgoingNodeConnections.ToArray(); var newElectionState = new LeaderElectionState(inNodeKvps.Where(kvp => !kvp.Value.IsUselessConnection).Select(kvp => kvp.Key), outNodeKvps.Where(kvp => !kvp.Value.IsUselessConnection).Select(kvp => kvp.Key)) { Guid = Guid.NewGuid(), CreationTime = DateTime.Now, FirstYoMinimum = nodeGuid }; leaderElections[newElectionState.Guid] = newElectionState; SendLeaderElectionAdvertisementRequest(newElectionState, new NetworkNode { Hostname = "localhost", Port = portNumber }).Wait(); Guid? currentLeader; do { Task.Delay(42).Wait(); currentLeader = leaderGuid; } while (currentLeader == null); NetworkNode leaderNode; if (currentLeader == nodeGuid) leaderNode = new NetworkNode { Hostname = http_ctx.Request.LocalEndPoint.Address.ToString(), Port = portNumber }; else if (!incomingNodeConnections.TryGetValue(currentLeader.GetValueOrDefault(), out leaderNode)) { http_ctx.Response.StatusCode = (int)HttpStatusCode.NotFound; http_ctx.Response.Close(); } http_ctx.Response.ContentType = MediaTypeNames.Text.Plain; http_ctx.Response.ContentEncoding = Encoding.ASCII; http_ctx.Response.StatusCode = (int)HttpStatusCode.OK; http_ctx.Response.Close(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", leaderNode.Hostname, leaderNode.Port)), willBlock: false); } else if (string.Equals("/getNodes", path, StringComparison.OrdinalIgnoreCase)) { GetNodesContext(http_ctx); } else if (string.Equals("/getNodesWithGuids", path, StringComparison.OrdinalIgnoreCase)) { GetNodesContext(http_ctx, withGuids: true); } else if (string.Equals("/getGuid", path, StringComparison.OrdinalIgnoreCase)) { GetGuidContext(http_ctx); } else if (string.Equals("/connectToNodes", path, StringComparison.OrdinalIgnoreCase)) { await ConnectToNodesContext(http_ctx); } else if (string.Equals("/registerNeighbour", path, StringComparison.OrdinalIgnoreCase)) { RegisterNeighbourContext(http_ctx); } else if (string.Equals("/clearConnections", path, StringComparison.OrdinalIgnoreCase)) { ClearConnectionsContext(http_ctx); } else if (string.Equals("/deregisterNode", path, StringComparison.OrdinalIgnoreCase)) { await DeregisterNodeContext(http_ctx); } else if (string.Equals("/firstYo/Advertise", path, StringComparison.OrdinalIgnoreCase)) { FirstYoAdvertisementContext(http_ctx); } else if (string.Equals("/firstYo/RequestAdvertisement", path, StringComparison.OrdinalIgnoreCase)) { FirstYoRequestAdvertisementContext(http_ctx); } else if (string.Equals("/secondYo/Response", path, StringComparison.OrdinalIgnoreCase)) { SecondYoResponseContext(http_ctx); } else if (string.Equals("/secondYo/Flip", path, StringComparison.OrdinalIgnoreCase)) { SecondYoFlipContext(http_ctx); } else { http_ctx.Response.ContentType = MediaTypeNames.Text.Plain; http_ctx.Response.ContentEncoding = Encoding.ASCII; http_ctx.Response.StatusCode = (int)HttpStatusCode.NotFound; http_ctx.Response.Close(Encoding.ASCII.GetBytes("The requested resource could not be found."), willBlock: false); } } finally { //nodeStateLock.ExitReadLock(); } }