private void OnVoterConfirmation() { TransactionOperationContext context; if (_hasNewTopology.Lower()) { ClusterTopology clusterTopology; using (_engine.ContextPool.AllocateOperationContext(out context)) using (context.OpenReadTransaction()) { clusterTopology = _engine.GetTopology(context); } if (clusterTopology.Contains(_engine.LeaderTag) == false) { TaskExecutor.CompleteAndReplace(ref _newEntriesArrived); _engine.SetNewState(RachisState.Passive, this, Term, "I was kicked out of the cluster and moved to passive mode"); return; } RefreshAmbassadors(clusterTopology); } var maxIndexOnQuorum = GetMaxIndexOnQuorum(VotersMajority); if (_lastCommit >= maxIndexOnQuorum || maxIndexOnQuorum == 0) { return; // nothing to do here } bool changedFromLeaderElectToLeader; using (_engine.ContextPool.AllocateOperationContext(out context)) using (context.OpenWriteTransaction()) { _lastCommit = _engine.GetLastCommitIndex(context); if (_lastCommit >= maxIndexOnQuorum || maxIndexOnQuorum == 0) { return; // nothing to do here } if (_engine.GetTermForKnownExisting(context, maxIndexOnQuorum) < Term) { return;// can't commit until at least one entry from our term has been published } changedFromLeaderElectToLeader = _engine.TakeOffice(); maxIndexOnQuorum = _engine.Apply(context, maxIndexOnQuorum, this, Stopwatch.StartNew()); context.Transaction.Commit(); _lastCommit = maxIndexOnQuorum; } foreach (var kvp in _entries) { if (kvp.Key > _lastCommit) { continue; } if (_entries.TryRemove(kvp.Key, out CommandState value)) { TaskExecutor.Execute(o => { var tuple = (CommandState)o; if (tuple.OnNotify != null) { tuple.OnNotify(tuple.TaskCompletionSource); return; } tuple.TaskCompletionSource.TrySetResult((tuple.CommandIndex, tuple.Result)); }, value); } } if (_entries.Count != 0) { // we have still items to process, run them in 1 node cluster // and speed up the followers ambassadors if they can _newEntry.Set(); } if (changedFromLeaderElectToLeader) { _engine.LeaderElectToLeaderChanged(); } }