private void MulticastStartViewChange() { IMessage message = new StartViewChange(this.replicaState.ServerId, this.viewNumber, this.configuration); Uri[] currentConfiguration = this.replicaState.ReplicasUrl.ToArray(); IResponses responses = this.messageServiceClient.RequestMulticast( message, currentConfiguration, this.replicaState.Configuration.Count / 2, (int)(Timeout.TIMEOUT_VIEW_CHANGE), true); IResponse[] responsesVector = responses.ToArray(); // There was no quorum to accept the view change if (responsesVector.Length < this.numberToWait) { Log.Debug($"There was no quorum for view change. " + $"Just received {responsesVector.Length} from at least {this.numberToWait}"); this.replicaState.ChangeToNormalState(); return; } // In case I'm the leader, wait for f DoViewChange if (this.imTheLeader) { this.CheckNumberAndSetNewConfiguration(); } else { // Else, send DoViewChange to leader Uri leader = this.configuration.Values.ToArray()[0]; IMessage doViewMessage = new DoViewChange( this.replicaState.ServerId, this.viewNumber, this.replicaState.ViewNumber, this.configuration, this.replicaState.Logger, this.replicaState.OpNumber, this.replicaState.CommitNumber); this.messageServiceClient.Request(doViewMessage, leader, -1); } }
public ClientHandShakeResponse DoHandShake() { // Do the handshake Uri[] servers = System.IO.File.ReadAllLines(SERVERS_LIST).ToList() .ConvertAll <Uri>(server => new Uri(server)) .ToArray(); IResponses responses = this.MessageServiceClient.RequestMulticast( new ClientHandShakeRequest(this.Id), servers, 1, -1, true); ClientHandShakeResponse response = (ClientHandShakeResponse)responses.ToArray()[0]; this.ViewNumber = response.ViewNumber; this.ViewServers = response.ViewConfiguration; this.Leader = response.Leader; return(response); }
private void InitProtocol() { Uri[] servers = System.IO.File.ReadAllLines(SERVERS_LIST).ToList() .ConvertAll <Uri>(server => new Uri(server)) .Where(server => !server.Equals(this.replicaState.MyUrl)) .ToArray(); IMessage message = new ServerHandShakeRequest(this.replicaState.ServerId, Protocol.StateMachineReplication); IResponses responses = this.messageServiceClient.RequestMulticast(message, servers, 1, Timeout.TIMEOUT_SERVER_HANDSHAKE, true); IResponse[] filteredResponses = responses.ToArray(); // I'm the first server if (filteredResponses.Length == 0) { Log.Info("No servers found for handshake."); this.replicaState.SetNewConfiguration( new SortedDictionary <string, Uri> { { this.replicaState.ServerId, this.replicaState.MyUrl } }, new Uri[] { }, this.replicaState.ViewNumber + 1); this.replicaState.ChangeToNormalState(); return; } // Else multicast joinView to everyone Uri[] configuration = ((ServerHandShakeResponse)filteredResponses[0]).ViewConfiguration; IMessage joinViewMessage = new JoinView(this.replicaState.ServerId, this.replicaState.MyUrl); this.messageServiceClient.RequestMulticast( joinViewMessage, configuration, configuration.Length, Timeout.TIMEOUT_INIT, false); }
private void RecoveryProtocol() { // Multicast recovery message IMessage message = new Recovery( this.replicaState.ServerId, this.replicaState.ViewNumber, this.replicaState.OpNumber, this.replicaState.CommitNumber); IResponses responses = this.messageServiceClient.RequestMulticast( message, this.replicaState.ReplicasUrl.ToArray(), this.replicaState.Configuration.Count / 2, -1, true); Log.Debug($"Recovery Protocol: got {responses.Count()} responses."); if (responses.Count() == 0) { this.replicaState.ChangeToInitializationState(); return; } RecoveryResponse betterResponse = null; foreach (IResponse response in responses.ToArray()) { RecoveryResponse recoveryResponse = (RecoveryResponse)response; if (recoveryResponse.ViewNumber > this.replicaState.ViewNumber) { this.replicaState.ChangeToInitializationState(); return; } if (recoveryResponse.ViewNumber == this.replicaState.ViewNumber) { if (betterResponse == null) { betterResponse = recoveryResponse; continue; } if (recoveryResponse.OpNumber > betterResponse.OpNumber) { betterResponse = recoveryResponse; } } } if (betterResponse != null && betterResponse.OpNumber > this.replicaState.OpNumber) { Log.Debug($"Better Response: OpNumber = {betterResponse.OpNumber}, " + $"CommitNumber = {betterResponse.CommitNumber} ({this.replicaState.CommitNumber})"); this.replicaState.Logger.AddRange(betterResponse.SuffixLogger); this.replicaState.UpdateOpNumber(); this.replicaState.ExecuteFromUntil(this.replicaState.CommitNumber, betterResponse.CommitNumber); } Log.Debug($"Recovery Protocol: Changing to Normal State."); this.replicaState.ChangeToNormalState(); }
public ReplicaState(MessageServiceClient messageServiceClient, Uri url, string serverId) { this.MessageServiceClient = messageServiceClient; this.ServerId = serverId; this.MyUrl = url; this.Configuration = new SortedDictionary <string, Uri> { { this.ServerId, url } }; this.ReplicasUrl = new List <Uri>(); this.ClientTable = new Dictionary <string, Tuple <int, ClientResponse> >(); this.State = new InitializationStateMessageProcessor(this, this.MessageServiceClient); this.ViewNumber = 0; this.TupleSpace = new TupleSpace.TupleSpace(); this.HeartBeats = new SortedDictionary <string, DateTime>(); this.RequestsExecutor = new RequestsExecutor(this); // Handlers this.HandlerStateChanged = new EventWaitHandle(false, EventResetMode.ManualReset); this.HandlersClient = new ConcurrentDictionary <string, EventWaitHandle>(); // Task that checks HeartBeats Task.Factory.StartNew(() => { while (true) { Thread.Sleep(Timeout.TIMEOUT_VIEW_CHANGE); foreach (KeyValuePair <string, DateTime> entry in this.HeartBeats) { if (entry.Value < DateTime.Now.AddMilliseconds(-Timeout.TIMEOUT_HEART_BEAT_XL * 1.1)) { int newViewNumber = this.ViewNumber + 1; SortedDictionary <string, Uri> newConfiguration = new SortedDictionary <string, Uri>( this.Configuration .Where(kvp => !kvp.Key.Equals(entry.Key)) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value)); Log.Debug($"Server {entry.Key} is presumably dead as the HeartBeat timeout expired."); this.ChangeToViewChange(newViewNumber, newConfiguration); break; } } } }); // Task that sends the HeartBeats Task.Factory.StartNew(() => { while (true) { Thread.Sleep(Timeout.TIMEOUT_HEART_BEAT_XL); if (!(this.State is NormalStateMessageProcessor)) { continue; } Task.Factory.StartNew(() => { IResponses responses = this.MessageServiceClient.RequestMulticast( new HeartBeat(this.ServerId), this.ReplicasUrl.ToArray(), this.ReplicasUrl.Count, -1, false); IResponse[] filteredResponses = responses.ToArray() .Where(response => ((HeartBeatResponse)response).ViewNumber > ViewNumber) .ToArray(); if (filteredResponses.Length > 0) { this.ChangeToInitializationState(); } }); } }); }