Example #1
0
        public async Task LearnsOfNewTermThroughAppend()
        {
            // Start a follower in term 1.
            this.persistentState.CurrentTerm.Returns(_ => 1);
            this.journal.Entries.AddRange(new[] { new LogEntry <int>(new LogEntryId(1, 1), 27) });
            await this.role.Enter();

            // Append an entry from a new term.
            var request = new AppendRequest <int>
            {
                Term             = 2,
                PreviousLogEntry = new LogEntryId(1, 1),
                Entries          = new List <LogEntry <int> > {
                    new LogEntry <int>(new LogEntryId(2, 2), 38)
                }
            };
            var response = await this.role.Append(request);

            // Check that the call succeeded and that the log entries were written.
            response.Success.Should().BeTrue();
            response.Term.Should().Be(2);
            response.LastLogEntryId.Should().Be(this.journal.LastLogEntryId);
            await this.journal.Received().AppendOrOverwrite(Arg.Any <IEnumerable <LogEntry <int> > >());

            this.journal.Entries.Skip(1).Should().BeEquivalentTo(request.Entries);

            // Ensure that the term was updated.
            await this.persistentState.Received().UpdateTermAndVote(null, 2);
        }
        public async Task <AppendValuesResponse> AppendAsync(string range, ValueRange body)
        {
            AppendRequest request = _service.Spreadsheets.Values.Append(body, SheetId(), range);

            request.ValueInputOption = AppendRequest.ValueInputOptionEnum.USERENTERED;
            return(await request.ExecuteAsync());
        }
Example #3
0
        public Response HandleAppendMessages(BinaryStream buffer)
        {
            var request = AppendRequest.ReadFromStream(buffer);

            if (!_storage.ValidatePartitionNumber(request.Topic, request.Partition))
            {
                return(null);
            }

            for (int i = 0; i < request.Messages.Count; i++)
            {
                var message = request.Messages[i];

                //For testing purpose only
                if (message.Payload.Length < 20)
                {
                    var text = Encoding.UTF8.GetString(message.Payload);
                    if (text == "end!//")
                    {
                        Console.WriteLine("Done!");
                    }
                }

                _storage.Append(request.Topic, request.Partition, message.Payload);

                // Flushing to OS cashe
                _storage.Flush();
            }

            return(null);
        }
        public async Task DoesNotAppendEntries()
        {
            await this.role.Enter();

            this.persistentState.CurrentTerm.Returns(_ => 2);
            this.persistentState.VotedFor.Returns(_ => this.identity.Id);

            this.coordinator.ClearReceivedCalls();
            var request = new AppendRequest <int>
            {
                Term    = 1,
                Entries = new List <LogEntry <int> > {
                    new LogEntry <int>(new LogEntryId(1, 1), 8)
                }
            };

            // Check that append fails.
            var response = await this.role.Append(request);

            response.Success.Should().BeFalse();
            response.Term.Should().Be(2);

            // Check that the no entries were written to the log.
            await this.journal.DidNotReceive().AppendOrOverwrite(Arg.Any <IEnumerable <LogEntry <int> > >());

            // Check that the role did not transition into a follower.
            await this.coordinator.DidNotReceive().BecomeFollowerForTerm(Arg.Any <long>());
        }
Example #5
0
        public async Task AppendRemovesConflictingEntries()
        {
            // Start a follower with some log entries.
            this.persistentState.CurrentTerm.Returns(_ => 2);
            this.journal.Entries.AddRange(new[] { new LogEntry <int>(new LogEntryId(1, 1), 27) });
            await this.role.Enter();

            // Attempt to append an entry when the previous entry is not in the log.
            var request = new AppendRequest <int>
            {
                Term             = 2,
                PreviousLogEntry = default(LogEntryId),
                Entries          = new List <LogEntry <int> > {
                    new LogEntry <int>(new LogEntryId(2, 1), 38)
                }
            };
            var response = await this.role.Append(request);

            // Check that the call succeeded and that the old entry was replaced.
            response.Success.Should().BeTrue();
            response.Term.Should().Be(2);
            response.LastLogEntryId.Should().Be(this.journal.LastLogEntryId);
            await this.journal.Received().AppendOrOverwrite(request.Entries);

            this.journal.Entries.Count.Should().Be(1);
            this.journal.Entries[0].Should().Be(request.Entries[0]);
        }
Example #6
0
        public async Task DenyAppendIfPreviousEntryNotInLog()
        {
            // Start a follower with some log entries.
            this.persistentState.CurrentTerm.Returns(_ => 2);
            this.journal.Entries.AddRange(
                new[] { new LogEntry <int>(new LogEntryId(1, 1), 27), new LogEntry <int>(new LogEntryId(2, 2), 45) });
            await this.role.Enter();

            // Attempt to append an entry when the previous entry is not in the log.
            var request = new AppendRequest <int>
            {
                Term             = 2,
                PreviousLogEntry = new LogEntryId(2, 3),
                Entries          = new List <LogEntry <int> > {
                    new LogEntry <int>(new LogEntryId(2, 4), 38)
                }
            };
            var response = await this.role.Append(request);

            // Check that the call failed and that no new entries were added to the log.
            response.Success.Should().BeFalse();
            response.Term.Should().Be(2);
            response.LastLogEntryId.Should().Be(this.journal.LastLogEntryId);
            await this.journal.DidNotReceive().AppendOrOverwrite(Arg.Any <IEnumerable <LogEntry <int> > >());

            await this.persistentState.DidNotReceive().UpdateTermAndVote(Arg.Any <string>(), Arg.Any <long>());
        }
Example #7
0
        /// <summary>
        /// Appends some entries to the log, specifying that some entries are also committed on the leader.
        /// </summary>
        /// <returns>A <see cref="Task"/> representing the work performed.</returns>
        private async Task AppendValidEntriesWithSomeCommitted()
        {
            this.persistentState.CurrentTerm.Returns(_ => 1);
            this.journal.Entries.Add(new LogEntry <int>(new LogEntryId(1, 1), 27));

            // Become a follower
            await this.role.Enter();

            // Append some entries.
            var request = new AppendRequest <int>
            {
                Term             = 1,
                PreviousLogEntry = this.journal.LastLogEntryId,
                Entries          =
                    new List <LogEntry <int> >
                {
                    new LogEntry <int>(new LogEntryId(1, 2), 38),
                    new LogEntry <int>(new LogEntryId(1, 3), 98)
                },
                LeaderCommitIndex = 2
            };
            var response = await this.role.Append(request);

            // Check that the call succeeded and that the entries were written to the log.
            response.Success.Should().BeTrue();
            response.Term.Should().Be(1);
            await this.journal.Received().AppendOrOverwrite(Arg.Any <IEnumerable <LogEntry <int> > >());

            this.journal.Entries.Skip(1).Should().BeEquivalentTo(request.Entries);

            // If a follower is in the same term as the leader, a call to UpdateTermAndVote should not occur.
            await this.persistentState.DidNotReceive().UpdateTermAndVote(Arg.Any <string>(), Arg.Any <long>());
        }
        public AppendValuesResponse Append(string range, ValueRange body)
        {
            AppendRequest request = _service.Spreadsheets.Values.Append(body, SheetId(), range);

            request.ValueInputOption = AppendRequest.ValueInputOptionEnum.USERENTERED;
            return(request.Execute());
        }
Example #9
0
        public static void ForceExec(ForceExecOptions opts)
        {
            CoreLib.Messages.Config.SgxConfig config = null;
            if (!string.IsNullOrEmpty(opts.ConfigPath) && !TryReadConfig(opts.ConfigPath, out config))
            {
                return;
            }

            if (!TryConnectRpc(opts, out SgxDaemon.SgxDaemonClient client))
            {
                return;
            }

            Peer peer = config.Peers
                        .First(p => p.Addr.EndPoint.Port == opts.RpcPort);

            AppendRequest req = new AppendRequest
            {
                CommitIndex = 0,
                Entries     = new[]
                {
                    new Entry
                    {
                        Event = peer.Event,
                        Term  = 9999,
                        Index = 9999,
                        Tag   = new CommandTag
                        {
                            Type = CommandTag.CommandType.Exec,
                            Uid  = new Uid()
                        }
                    }
                }
            };

            string eventName = config?.Workflow.Events.First(e => e.Uid == peer.Event).Name;

            System.Console.WriteLine();
            System.Console.ForegroundColor = ConsoleColor.DarkYellow;
            System.Console.WriteLine($"exec  {req.Entries[0].Tag.Uid}");
            System.Console.ResetColor();
            System.Console.WriteLine($"euid  {peer.Event}");
            if (eventName != null)
            {
                System.Console.WriteLine($"event {eventName}");
            }

            try
            {
                client.Send(new Container
                {
                    Payload = req,
                    Sender  = peer.Uid
                }.ToWire());
            }
            catch (Exception ex)
            {
                System.Console.WriteLine($"\nError while executing: {ex.Message}");
            }
        }
Example #10
0
        /// <summary>
        /// Send binary message to specified topic with specified key, using specified partitioner.
        /// </summary>
        public void Send(String topic, byte[] payload, Object key, IPartitioner partitioner)
        {
            var partitionsNumber = GetNumberOfPartitionsForTopic(topic);
            var partition        = _partitioner.SelectPartition(null, partitionsNumber);
            var request          = new AppendRequest(topic, partition, Message.CreateMessage(payload));

            _pushSender.Push(request);
        }
 public ActionResult Append(string key, [FromBody] AppendRequest request)
 {
     if (!_valueStorage.Append(key, request.Values, request.ExpirationInSeconds))
     {
         return(Conflict());
     }
     return(Created(new Uri(key, UriKind.Relative), _valueStorage.Get(key)));
 }
        private void WriteActivityLogRowsToSheet(SheetsService service, List <IList <object> > rows)
        {
            CreateLogSheet(service);

            AppendRequest appendRequest = service.Spreadsheets.Values.Append(new ValueRange {
                Values = rows
            }, Spreadsheet, "PixelBotLog!A2:E");

            appendRequest.InsertDataOption = AppendRequest.InsertDataOptionEnum.INSERTROWS;
            appendRequest.ValueInputOption = AppendRequest.ValueInputOptionEnum.USERENTERED;
            _ = appendRequest.Execute();
        }
Example #13
0
        public async Task <AppendResponse> Append(AppendRequest <TOperation> request)
        {
            // If RPC request or response contains term T > currentTerm: set currentTerm = T, convert to follower (§5.1)
            if (await this.coordinator.StepDownIfGreaterTerm(request))
            {
                return(await this.coordinator.Role.Append(request));
            }

            this.logger.LogWarn($"Denying append from {request.Leader}.");
            return(new AppendResponse {
                Success = false, Term = this.persistentState.CurrentTerm
            });
        }
Example #14
0
        /// <summary>
        /// Adiciona os valores informados na planilha.
        /// </summary>
        /// <param name="values">Os valores da linha a ser adicionada.</param>
        /// <returns>Resposta do request da operação.</returns>
        public AppendValuesResponse AddValues(List <object> values)
        {
            ValueRange valueRange = new ValueRange();

            valueRange.Values = new List <IList <object> > {
                values
            };

            AppendRequest appendRequest = service.Spreadsheets.Values.Append(valueRange, spreadsheetId, "A:A");

            appendRequest.ValueInputOption = AppendRequest.ValueInputOptionEnum.USERENTERED;

            return(appendRequest.Execute());
        }
        public async Task <AppendResponse> Append(AppendRequest <TOperation> request)
        {
            // If AppendEntries RPC received from new leader: convert to follower.
            if (request.Term >= this.persistentState.CurrentTerm)
            {
                await this.local.BecomeFollowerForTerm(request.Term);

                return(await this.local.Role.Append(request));
            }

            // The requester is from an older term.
            this.logger.LogInfo($"Denying append from {request.Leader}.");
            return(new AppendResponse {
                Success = false, Term = this.persistentState.CurrentTerm
            });
        }
        public async Task LearnsOfNewLeaderThroughAppend()
        {
            await this.role.Enter();

            this.persistentState.CurrentTerm.Returns(_ => 1);
            this.persistentState.VotedFor.Returns(_ => this.identity.Id);

            this.coordinator.ClearReceivedCalls();
            var request = new AppendRequest <int> {
                Term = 1
            };

            await this.role.Append(request);

            await this.coordinator.Received().BecomeFollowerForTerm(1);
        }
Example #17
0
        public async Task LearnsOfNewTermThroughAppend()
        {
            await this.role.Enter();

            this.persistentState.CurrentTerm.Returns(_ => 1);
            this.persistentState.VotedFor.Returns(_ => this.identity.Id);

            this.coordinator.ClearReceivedCalls();
            var request = new AppendRequest <int> {
                Term = 2
            };

            await this.role.Append(request);

            await this.coordinator.Received().StepDownIfGreaterTerm(request);
        }
        private void CreateLogSheet(SheetsService service)
        {
            // Only run this the first time
            if (!_First)
            {
                return;
            }
            _First = false;

            var thisSpreadsheet = service.Spreadsheets.Get(Spreadsheet).Execute();

            if (!thisSpreadsheet.Sheets.Any(s => s.Properties.Title == "PixelBotLog"))
            {
                var newSheetRequest = new AddSheetRequest()
                {
                    Properties = new SheetProperties
                    {
                        Title = "PixelBotLog"
                    }
                };
                service.Spreadsheets.BatchUpdate(
                    new BatchUpdateSpreadsheetRequest
                {
                    Requests = new[] {
                        new Request {
                            AddSheet = newSheetRequest
                        }
                    }
                }, Spreadsheet).Execute();

                var newRecords = new List <IList <object> >();
                var newRow     = new List <object>();
                newRow.Add("Date");
                newRow.Add("Acting User");
                newRow.Add("Record Updated");
                newRow.Add("Command");
                newRow.Add("Pixels Changed");

                newRecords.Add(newRow);
                AppendRequest appendRequest = service.Spreadsheets.Values.Append(new ValueRange {
                    Values = newRecords
                }, Spreadsheet, "PixelBotLog!A1:E");
                appendRequest.InsertDataOption = AppendRequest.InsertDataOptionEnum.INSERTROWS;
                appendRequest.ValueInputOption = AppendRequest.ValueInputOptionEnum.USERENTERED;
                _ = appendRequest.Execute();
            }
        }
Example #19
0
        public void AppendToSheet(Note note, string spreadsheetID, string sheetRange, string attachmentsFolderLink)
        {
            string spreadsheetId = spreadsheetID;
            string range         = sheetRange;

            AppendRequest.ValueInputOptionEnum valueInputOption = AppendRequest.ValueInputOptionEnum.USERENTERED;
            AppendRequest.InsertDataOptionEnum insertDataOption = AppendRequest.InsertDataOptionEnum.INSERTROWS;

            var arr = new string[] { note.NoteType, note.NoteContent, note.NoteRecordtime, attachmentsFolderLink };

            RequestBody.Values = new List <IList <object> > {
                arr
            };

            Request = service.Spreadsheets.Values.Append(RequestBody, spreadsheetId, range);
            Request.ValueInputOption = valueInputOption;
            Request.InsertDataOption = insertDataOption;

            Request.Execute();
        }
Example #20
0
        public async Task EntrySendsHeartbeat()
        {
            // Setup: configure grains to always grant votes
            this.OnRaftGrainCreated = (id, grain) =>
            {
                grain.Append(Arg.Any <AppendRequest <int> >())
                .Returns(Task.FromResult(new AppendResponse {
                    Term = 1, Success = true
                }));
            };

            this.persistentState.CurrentTerm.Returns(4);
            this.journal.Entries.Add(new LogEntry <int>(new LogEntryId(3, 1), 4));

            await this.role.Enter();

            // A timer should have been registered for the heartbeat;
            this.timers.Registrations.Should().HaveCount(1);

            // Fire the timer.
            await this.timers[0].Callback(this.timers[0].State);

            var expectedRequest = new AppendRequest <int>
            {
                Leader            = this.identity.Id,
                Term              = this.persistentState.CurrentTerm,
                LeaderCommitIndex = this.volatileState.CommitIndex,
                PreviousLogEntry  = new LogEntryId(3, 1)
            };

            // Check that all of the followers received a heartbeat request.
            foreach (var server in this.members.OtherServers)
            {
                var grain = this.grainFactory.GetGrain <IRaftGrain <int> >(server);
                grain.ReceivedCalls().Should().ContainSingle().Which.IsSameOrEqualTo(expectedRequest);
            }
        }
Example #21
0
        public async Task DenyAppendFromPreviousTerm()
        {
            // Start a follower with some log entries.
            this.persistentState.CurrentTerm.Returns(_ => 2);
            this.journal.Entries.AddRange(new[] { new LogEntry <int>(new LogEntryId(1, 1), 27) });
            await this.role.Enter();

            // Attempt to append an entry from a deposed leader.
            var request = new AppendRequest <int>
            {
                Term             = 1,
                PreviousLogEntry = new LogEntryId(1, 1),
                Entries          = new List <LogEntry <int> > {
                    new LogEntry <int>(new LogEntryId(1, 2), 38)
                }
            };
            var response = await this.role.Append(request);

            // Check that the call failed and that no new entries were added to the log.
            response.Success.Should().BeFalse();
            response.Term.Should().Be(2);
            response.LastLogEntryId.Should().Be(this.journal.LastLogEntryId);
            await this.journal.DidNotReceive().AppendOrOverwrite(Arg.Any <IEnumerable <LogEntry <int> > >());
        }
        public async Task AppendRemovesConflictingEntries()
        {
            // Start a follower with some log entries.
            this.persistentState.CurrentTerm.Returns(_ => 2);
            this.journal.Entries.AddRange(new[] { new LogEntry<int>(new LogEntryId(1, 1), 27) });
            await this.role.Enter();

            // Attempt to append an entry when the previous entry is not in the log.
            var request = new AppendRequest<int>
            {
                Term = 2,
                PreviousLogEntry = default(LogEntryId),
                Entries = new List<LogEntry<int>> { new LogEntry<int>(new LogEntryId(2, 1), 38) }
            };
            var response = await this.role.Append(request);

            // Check that the call succeeded and that the old entry was replaced.
            response.Success.Should().BeTrue();
            response.Term.Should().Be(2);
            response.LastLogEntryId.Should().Be(this.journal.LastLogEntryId);
            await this.journal.Received().AppendOrOverwrite(request.Entries);
            this.journal.Entries.Count.Should().Be(1);
            this.journal.Entries[0].Should().Be(request.Entries[0]);
        }
        public async Task EntrySendsHeartbeat()
        {
            // Setup: configure grains to always grant votes
            this.OnRaftGrainCreated = (id, grain) =>
            {
                grain.Append(Arg.Any<AppendRequest<int>>())
                    .Returns(Task.FromResult(new AppendResponse { Term = 1, Success = true }));
            };

            this.persistentState.CurrentTerm.Returns(4);
            this.journal.Entries.Add(new LogEntry<int>(new LogEntryId(3, 1), 4));

            await this.role.Enter();

            // A timer should have been registered for the heartbeat;
            this.timers.Registrations.Should().HaveCount(1);
            
            // Fire the timer.
            await this.timers[0].Callback(this.timers[0].State);

            var expectedRequest = new AppendRequest<int>
            {
                Leader = this.identity.Id,
                Term = this.persistentState.CurrentTerm,
                LeaderCommitIndex = this.volatileState.CommitIndex,
                PreviousLogEntry = new LogEntryId(3, 1)
            };

            // Check that all of the followers received a heartbeat request.
            foreach (var server in this.members.OtherServers)
            {
                var grain = this.grainFactory.GetGrain<IRaftGrain<int>>(server);
                grain.ReceivedCalls().Should().ContainSingle().Which.IsSameOrEqualTo(expectedRequest);
            }
        }
        public async Task LearnsOfNewTermThroughAppend()
        {
            await this.role.Enter();
            this.persistentState.CurrentTerm.Returns(_ => 1);
            this.persistentState.VotedFor.Returns(_ => this.identity.Id);

            this.coordinator.ClearReceivedCalls();
            var request = new AppendRequest<int> { Term = 2 };
            await this.role.Append(request);
            await this.coordinator.Received().StepDownIfGreaterTerm(request);
        }
        public async Task DoesNotAppendEntries()
        {
            await this.role.Enter();
            this.persistentState.CurrentTerm.Returns(_ => 2);
            this.persistentState.VotedFor.Returns(_ => this.identity.Id);

            this.coordinator.ClearReceivedCalls();
            var request = new AppendRequest<int>
            {
                Term = 1,
                Entries = new List<LogEntry<int>> { new LogEntry<int>(new LogEntryId(1, 1), 8) }
            };

            // Check that append fails.
            var response = await this.role.Append(request);
            response.Success.Should().BeFalse();
            response.Term.Should().Be(2);

            // Check that the no entries were written to the log.
            await this.journal.DidNotReceive().AppendOrOverwrite(Arg.Any<IEnumerable<LogEntry<int>>>());

            // Check that the role did not transition into a follower.
            await this.coordinator.DidNotReceive().BecomeFollowerForTerm(Arg.Any<long>());
        }
Example #26
0
 public Task <AppendResponse> Append(AppendRequest <TOperation> request) => this.coordinator.Role.Append(request);
Example #27
0
        public async Task <AppendResponse> Append(AppendRequest <TOperation> request)
        {
            bool success;

            // If the request has a higher term than this follower, persist the updated term.
            if (request.Term > this.persistentState.CurrentTerm)
            {
                await this.persistentState.UpdateTermAndVote(null, request.Term);
            }

            // 1. Reply false if term < currentTerm (§5.1)
            if (request.Term < this.persistentState.CurrentTerm)
            {
                this.logger.LogWarn(
                    $"Denying append {request}: Term is older than current term, {this.persistentState.CurrentTerm}.");
                success = false;
            }
            // 2. Reply false if log doesn’t contain an entry at prevLogIndex whose term matches prevLogTerm (§5.3)
            else if (!this.journal.Contains(request.PreviousLogEntry))
            {
                this.messagesSinceLastElectionExpiry++;
                this.logger.LogWarn(
                    $"Denying append {request}: Local log does not contain previous entry. "
                    + $"Local: {this.journal.ProgressString()}");
                success = false;
            }
            else
            {
                this.messagesSinceLastElectionExpiry++;

                // Set the current leader, so that clients can be redirected.
                this.volatileState.LeaderId = request.Leader;

                if (request.Entries == null || request.Entries.Count == 0)
                {
                    //this.journalInfo($"heartbeat from {request.Leader}.");
                }
                else
                {
                    // 3. If an existing entry conflicts with a new one (same index but different terms),
                    // delete the existing entry and all that follow it (§5.3)
                    // 4. Append any new entries not already in the log.
                    await this.journal.AppendOrOverwrite(request.Entries);

                    this.logger.LogInfo($"Accepted append. Log is now: {this.journal.ProgressString()}");
                }

                // 5. If leaderCommit > commitIndex, set commitIndex = min(leaderCommit, index of last new entry).
                if (request.LeaderCommitIndex > this.volatileState.CommitIndex)
                {
                    this.volatileState.CommitIndex = Math.Min(
                        request.LeaderCommitIndex,
                        this.journal.LastLogEntryId.Index);

                    if (this.settings.ApplyEntriesOnFollowers)
                    {
                        // If commitIndex > lastApplied: increment lastApplied, apply log[lastApplied] to state machine(§5.3)
                        await this.ApplyRemainingCommittedEntries();
                    }
                }

                success = true;
            }

            return(new AppendResponse
            {
                Success = success,
                Term = this.persistentState.CurrentTerm,
                LastLogEntryId = this.journal.LastLogEntryId
            });
        }
Example #28
0
        private async Task AppendEntriesOnServer(string serverId, FollowerProgress followerProgress)
        {
            this.callTimer.Restart();
            var serverGrain = this.grainFactory.GetGrain <IRaftGrain <TOperation> >(serverId);

            while (!this.cancellation.IsCancellationRequested)
            {
                var nextIndex = followerProgress.NextIndex;
                var request   = new AppendRequest <TOperation>
                {
                    Leader            = this.identity.Id,
                    LeaderCommitIndex = this.volatileState.CommitIndex,
                    Term    = this.persistentState.CurrentTerm,
                    Entries =
                        this.journal.GetCursor((int)Math.Max(0, nextIndex - 1))
                        .Take(this.settings.MaxLogEntriesPerAppendRequest)
                        .ToList()
                };

                if (nextIndex >= 2 && this.journal.LastLogEntryId.Index > nextIndex - 2)
                {
                    request.PreviousLogEntry = this.journal.Get((int)nextIndex - 1).Id;
                }

                this.lastMessageSentTime = DateTime.UtcNow;
                if (request.Entries.Count > 0)
                {
                    this.logger.LogInfo(
                        $"Replicating to '{serverId}': prev: {request.PreviousLogEntry},"
                        + $" entries: [{string.Join(", ", request.Entries.Select(_ => _.Id))}]"
                        + $", next: {nextIndex}, match: {followerProgress.MatchIndex}");
                }

                var response = await serverGrain.Append(request);

                if (response.Success)
                {
                    // The follower's log matches the included logs.
                    var newMatchIndex = Math.Max(
                        followerProgress.MatchIndex,
                        (long)request.Entries?.LastOrDefault().Id.Index);

                    // The send was successful, so the next entry to send is the subsequent entry in the leader's log.
                    followerProgress.NextIndex = newMatchIndex + 1;

                    // For efficiency, only consider updating the committedIndex if matchIndex has changed.
                    if (newMatchIndex != followerProgress.MatchIndex)
                    {
                        this.logger.LogInfo(
                            $"Successfully appended entries {request.Entries?.FirstOrDefault().Id} to {newMatchIndex} on {serverId}");
                        followerProgress.MatchIndex = newMatchIndex;

                        this.madeProgress = true;
                    }

                    return;
                }

                this.logger.LogWarn($"Received failure response for append call with term of {response.Term}");
                if (await this.coordinator.StepDownIfGreaterTerm(response))
                {
                    // This node is no longer a leader, so retire.
                    return;
                }

                if (followerProgress.NextIndex > response.LastLogEntryId.Index)
                {
                    // If the follower is lagging, jump immediately to its last log entry.
                    followerProgress.NextIndex = response.LastLogEntryId.Index;
                    this.logger.LogInfo(
                        $"Follower's last log is {response.LastLogEntryId}, jumping nextIndex to that index.");
                }
                else if (followerProgress.NextIndex > 0)
                {
                    // Log mismatch, decrement and try again later.
                    --followerProgress.NextIndex;
                    this.logger.LogWarn(
                        $"Log mismatch must have occured on '{serverId}', decrementing nextIndex to {followerProgress.NextIndex}.");
                }

                // In an attempt to maintain fairness and retain leader status, bail out of catchup if the call has taken
                // more than the allotted time.
                if (this.callTimer.ElapsedMilliseconds
                    >= this.settings.HeartbeatTimeoutMilliseconds / (this.membershipProvider.AllServers.Count - 1))
                {
                    this.logger.LogInfo(
                        $"Bailing on '{serverId}' catch-up due to fairness. Elapsed: {this.callTimer.ElapsedMilliseconds}.");
                    break;
                }
            }
        }
        public async Task <ActionResult <List <int> > > Append([FromBody] AppendRequest request)
        {
            if (!await _authManager.HasSitePermissionsAsync(request.SiteId,
                                                            MenuUtils.SitePermissions.Channels))
            {
                return(Unauthorized());
            }

            var site = await _siteRepository.GetAsync(request.SiteId);

            if (site == null)
            {
                return(NotFound());
            }

            var parent = await _channelRepository.GetAsync(request.ParentId);

            if (parent == null)
            {
                return(this.Error("无法确定父栏目"));
            }

            var insertedChannelIdHashtable = new Hashtable {
                [1] = request.ParentId
            };                                                                         //key为栏目的级别,1为第一级栏目

            var channelTemplateId = request.ChannelTemplateId;
            var contentTemplateId = request.ContentTemplateId;

            if (request.IsParentTemplates)
            {
                channelTemplateId = parent.ChannelTemplateId;
                contentTemplateId = parent.ContentTemplateId;
            }

            var            channelNames       = request.Channels.Split('\n');
            IList <string> nodeIndexNameList  = null;
            var            expandedChannelIds = new List <int>
            {
                request.SiteId
            };

            foreach (var item in channelNames)
            {
                if (string.IsNullOrEmpty(item))
                {
                    continue;
                }

                //count为栏目的级别
                var count       = StringUtils.GetStartCount('-', item) == 0 ? StringUtils.GetStartCount('-', item) : StringUtils.GetStartCount('-', item);
                var channelName = item.Substring(count, item.Length - count);
                var indexName   = string.Empty;
                count++;

                if (!string.IsNullOrEmpty(channelName) && insertedChannelIdHashtable.Contains(count))
                {
                    if (request.IsIndexName)
                    {
                        indexName = channelName.Trim();
                    }

                    if (channelName.Contains('(') && channelName.Contains(')'))
                    {
                        var length = channelName.IndexOf(')') - channelName.IndexOf('(');
                        if (length > 0)
                        {
                            indexName   = channelName.Substring(channelName.IndexOf('(') + 1, length);
                            channelName = channelName.Substring(0, channelName.IndexOf('('));
                        }
                    }
                    channelName = channelName.Trim();
                    indexName   = indexName.Trim(' ', '(', ')');
                    if (!string.IsNullOrEmpty(indexName))
                    {
                        if (nodeIndexNameList == null)
                        {
                            nodeIndexNameList = (await _channelRepository.GetIndexNamesAsync(request.SiteId)).ToList();
                        }
                        if (nodeIndexNameList.Contains(indexName))
                        {
                            indexName = string.Empty;
                        }
                        else
                        {
                            nodeIndexNameList.Add(indexName);
                        }
                    }

                    var parentId = (int)insertedChannelIdHashtable[count];

                    var insertedChannelId = await _channelRepository.InsertAsync(request.SiteId, parentId, channelName, indexName, parent.ContentModelPluginId, channelTemplateId, contentTemplateId);

                    insertedChannelIdHashtable[count + 1] = insertedChannelId;
                    expandedChannelIds.Add(insertedChannelId);

                    await _createManager.CreateChannelAsync(request.SiteId, insertedChannelId);
                }
            }

            return(expandedChannelIds);
        }
 public Dictionary <string, object> Append(AppendRequest appendRequest)
 {
     UserData.ModifyData(DataMethod.Append, appendRequest.Key, appendRequest.Value, null);
     return(GetMessage(Status.Ok, null, string.Format("Added to '{0}' successfully", appendRequest.Key)));
 }
Example #31
0
        public void TestConstructors()
        {
            //var annotation = new Annotation (AnnotationEntry.AltSubject);
            //annotation.Properties[AnnotationAttribute.PrivateValue] = string.Format ("Alternate subject");
            //var annotations = new Annotation[] { annotation };
            var           keywords     = new string[] { "$Forwarded", "$Junk" };
            var           keywordSet   = new HashSet <string> (keywords);
            var           flags        = MessageFlags.Seen | MessageFlags.Draft;
            var           internalDate = DateTimeOffset.Now;
            var           message      = new MimeMessage();
            AppendRequest request;

            request = new AppendRequest(message);
            Assert.AreEqual(message, request.Message, "Message #1");
            Assert.AreEqual(MessageFlags.None, request.Flags, "Flags #1");
            Assert.IsNull(request.Keywords, "Keywords #1");
            Assert.IsNull(request.InternalDate, "InternalDate #1");
            Assert.IsNull(request.Annotations, "Annotations #1");

            request = new AppendRequest(message, flags);
            Assert.AreEqual(message, request.Message, "Message #2");
            Assert.AreEqual(flags, request.Flags, "Flags #2");
            Assert.IsNull(request.Keywords, "Keywords #2");
            Assert.IsNull(request.InternalDate, "InternalDate #2");
            Assert.IsNull(request.Annotations, "Annotations #2");

            request = new AppendRequest(message, flags, keywords);
            Assert.AreEqual(message, request.Message, "Message #3");
            Assert.AreEqual(flags, request.Flags, "Flags #3");
            Assert.IsInstanceOf <HashSet <string> > (request.Keywords, "Keywords Type #3");
            Assert.AreEqual(keywords.Length, request.Keywords.Count, "Keywords #3");
            Assert.IsNull(request.InternalDate, "InternalDate #3");
            Assert.IsNull(request.Annotations, "Annotations #3");

            request = new AppendRequest(message, flags, keywordSet);
            Assert.AreEqual(message, request.Message, "Message #4");
            Assert.AreEqual(flags, request.Flags, "Flags #4");
            Assert.IsInstanceOf <HashSet <string> > (request.Keywords, "Keywords Type #4");
            Assert.AreEqual(keywordSet, request.Keywords, "Keywords #4");
            Assert.IsNull(request.InternalDate, "InternalDate #4");
            Assert.IsNull(request.Annotations, "Annotations #4");

            request = new AppendRequest(message, flags, internalDate);
            Assert.AreEqual(message, request.Message, "Message #5");
            Assert.AreEqual(flags, request.Flags, "Flags #5");
            Assert.IsNull(request.Keywords, "Keywords #5");
            Assert.AreEqual(internalDate, request.InternalDate.Value, "InternalDate #5");
            Assert.IsNull(request.Annotations, "Annotations #5");

            request = new AppendRequest(message, flags, keywords, internalDate);
            Assert.AreEqual(message, request.Message, "Message #6");
            Assert.AreEqual(flags, request.Flags, "Flags #6");
            Assert.IsInstanceOf <HashSet <string> > (request.Keywords, "Keywords Type #6");
            Assert.AreEqual(keywords.Length, request.Keywords.Count, "Keywords #6");
            Assert.AreEqual(internalDate, request.InternalDate.Value, "InternalDate #6");
            Assert.IsNull(request.Annotations, "Annotations #6");

            request = new AppendRequest(message, flags, keywordSet, internalDate);
            Assert.AreEqual(message, request.Message, "Message #7");
            Assert.AreEqual(flags, request.Flags, "Flags #7");
            Assert.IsInstanceOf <HashSet <string> > (request.Keywords, "Keywords Type #7");
            Assert.AreEqual(keywordSet, request.Keywords, "Keywords #7");
            Assert.AreEqual(internalDate, request.InternalDate.Value, "InternalDate #7");
            Assert.IsNull(request.Annotations, "Annotations #7");
        }
        public async Task DenyAppendIfPreviousEntryNotInLog()
        {
            // Start a follower with some log entries.
            this.persistentState.CurrentTerm.Returns(_ => 2);
            this.journal.Entries.AddRange(
                new[] { new LogEntry<int>(new LogEntryId(1, 1), 27), new LogEntry<int>(new LogEntryId(2, 2), 45) });
            await this.role.Enter();

            // Attempt to append an entry when the previous entry is not in the log.
            var request = new AppendRequest<int>
            {
                Term = 2,
                PreviousLogEntry = new LogEntryId(2, 3),
                Entries = new List<LogEntry<int>> { new LogEntry<int>(new LogEntryId(2, 4), 38) }
            };
            var response = await this.role.Append(request);

            // Check that the call failed and that no new entries were added to the log.
            response.Success.Should().BeFalse();
            response.Term.Should().Be(2);
            response.LastLogEntryId.Should().Be(this.journal.LastLogEntryId);
            await this.journal.DidNotReceive().AppendOrOverwrite(Arg.Any<IEnumerable<LogEntry<int>>>());
            await this.persistentState.DidNotReceive().UpdateTermAndVote(Arg.Any<string>(), Arg.Any<long>());
        }
        public async Task LearnsOfNewTermThroughAppend()
        {
            // Start a follower in term 1.
            this.persistentState.CurrentTerm.Returns(_ => 1);
            this.journal.Entries.AddRange(new[] { new LogEntry<int>(new LogEntryId(1, 1), 27) });
            await this.role.Enter();

            // Append an entry from a new term.
            var request = new AppendRequest<int>
            {
                Term = 2,
                PreviousLogEntry = new LogEntryId(1, 1),
                Entries = new List<LogEntry<int>> { new LogEntry<int>(new LogEntryId(2, 2), 38) }
            };
            var response = await this.role.Append(request);

            // Check that the call succeeded and that the log entries were written.
            response.Success.Should().BeTrue();
            response.Term.Should().Be(2);
            response.LastLogEntryId.Should().Be(this.journal.LastLogEntryId);
            await this.journal.Received().AppendOrOverwrite(Arg.Any<IEnumerable<LogEntry<int>>>());
            this.journal.Entries.Skip(1).Should().BeEquivalentTo(request.Entries);

            // Ensure that the term was updated.
            await this.persistentState.Received().UpdateTermAndVote(null, 2);
        }
        public async Task DenyAppendFromPreviousTerm()
        {
            // Start a follower with some log entries.
            this.persistentState.CurrentTerm.Returns(_ => 2);
            this.journal.Entries.AddRange(new[] { new LogEntry<int>(new LogEntryId(1, 1), 27) });
            await this.role.Enter();

            // Attempt to append an entry from a deposed leader.
            var request = new AppendRequest<int>
            {
                Term = 1,
                PreviousLogEntry = new LogEntryId(1, 1),
                Entries = new List<LogEntry<int>> { new LogEntry<int>(new LogEntryId(1, 2), 38) }
            };
            var response = await this.role.Append(request);

            // Check that the call failed and that no new entries were added to the log.
            response.Success.Should().BeFalse();
            response.Term.Should().Be(2);
            response.LastLogEntryId.Should().Be(this.journal.LastLogEntryId);
            await this.journal.DidNotReceive().AppendOrOverwrite(Arg.Any<IEnumerable<LogEntry<int>>>());
        }
        /// <summary>
        /// Appends some entries to the log, specifying that some entries are also committed on the leader.
        /// </summary>
        /// <returns>A <see cref="Task"/> representing the work performed.</returns>
        private async Task AppendValidEntriesWithSomeCommitted()
        {
            this.persistentState.CurrentTerm.Returns(_ => 1);
            this.journal.Entries.Add(new LogEntry<int>(new LogEntryId(1, 1), 27));

            // Become a follower
            await this.role.Enter();

            // Append some entries.
            var request = new AppendRequest<int>
            {
                Term = 1,
                PreviousLogEntry = this.journal.LastLogEntryId,
                Entries =
                    new List<LogEntry<int>>
                    {
                        new LogEntry<int>(new LogEntryId(1, 2), 38),
                        new LogEntry<int>(new LogEntryId(1, 3), 98)
                    },
                LeaderCommitIndex = 2
            };
            var response = await this.role.Append(request);

            // Check that the call succeeded and that the entries were written to the log.
            response.Success.Should().BeTrue();
            response.Term.Should().Be(1);
            await this.journal.Received().AppendOrOverwrite(Arg.Any<IEnumerable<LogEntry<int>>>());
            this.journal.Entries.Skip(1).Should().BeEquivalentTo(request.Entries);

            // If a follower is in the same term as the leader, a call to UpdateTermAndVote should not occur.
            await this.persistentState.DidNotReceive().UpdateTermAndVote(Arg.Any<string>(), Arg.Any<long>());
        }
        public async Task LearnsOfNewLeaderThroughAppend()
        {
            await this.role.Enter();
            this.persistentState.CurrentTerm.Returns(_ => 1);
            this.persistentState.VotedFor.Returns(_ => this.identity.Id);

            this.coordinator.ClearReceivedCalls();
            var request = new AppendRequest<int> { Term = 1 };
            await this.role.Append(request);
            await this.coordinator.Received().BecomeFollowerForTerm(1);
        }