/// <summary> /// Attempts to commit changing the configuration if a consensus exists at this point. /// Otherwise a join is performed. /// If a consensus is lost before the desired configuration was reached, it is instantly applied. /// /// </summary> /// <param name="cfg"></param> public void ChangeConfiguration(Configuration cfg) { DoSerialized(() => { if (IsInConsensus) { cfgChange = new ConfigurationChange(cfg); cfgChangeAt = DateTime.Now; Schedule(cfgChange); } else { cfgChange = null; Join(cfg); } }); }
internal void Join(Configuration cfg) { List <Connection> doDispose = new List <Connection>(); DoSerialized(() => { if (cfgChange != null && cfgChange.NewCFG == cfg) { LogMinorEvent("Recognized requested cfg"); cfgChange = null; } if (cfg == config) { return; } LogEvent("Implementing consensus configuration " + cfg); int at; if (!cfg.ToIndex(MemberID, out at)) { LogError("Local member ID " + MemberID + " is not part of new consensus configuration " + cfg + ". Closing down node"); OnOutOfConfig(cfg); Dispose(); throw new ArgumentException("Local member ID " + MemberID + " is not part of new consensus configuration " + cfg); } MemberID = cfg.Members[at]; MyLinearIndex = at; var newMembers = new Connection[cfg.Size]; if (remoteMembers != null) { foreach (var m in remoteMembers) { if (m == null) { continue; } int linear; if (cfg.ToIndex(m.RemoteIdentifier, out linear) && m.IsActive == linear > MyLinearIndex && m.RemoteIdentifier == cfg.Members[linear]) { if (at == linear) { throw new InvalidOperationException("Found self among remotes"); } newMembers[linear] = m; } else { doDispose.Add(m); } } } config = cfg; for (int i = MyLinearIndex + 1; i < cfg.Size; i++) { if (newMembers[i] == null) { newMembers[i] = new ActiveConnection(this, cfg.Members[i]); } } remoteMembers = newMembers; if (IsLeader) { if (!MemberID.CanBeLeader) { Yield(); } } else { var l = leader as Connection; int linear; if (l != null && (!cfg.ToIndex(l.RemoteIdentifier, out linear) || !cfg.Members[linear].CanBeLeader)) { Yield(); } } }); foreach (var d in doDispose) { d.Dispose(); } }