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);
            }
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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();
        }
Beispiel #5
0
        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();
                        }
                    });
                }
            });
        }