/// <summary> If we are leaving, we have to wait for the view change (last msg in the current view) that /// excludes us before we can leave. /// </summary> /// <param name="new_view">The view to be installed /// </param> /// <param name="digest"> If view is a MergeView, digest contains the seqno digest of all members and has to /// be set by GMS /// </param> public override void handleViewChange(View new_view, Digest digest) { if (gms.Stack.NCacheLog.IsInfoEnabled) { gms.Stack.NCacheLog.Info("ParticipentGMSImpl.handleViewChange", "received view"); } System.Collections.ArrayList mbrs = new_view.Members; gms.Stack.NCacheLog.Debug("view=");// + new_view); suspected_mbrs.Clear(); if (leaving && !mbrs.Contains(gms.local_addr)) { // received a view in which I'm not member: ignore return; } ViewId vid = gms.view_id != null?gms.view_id.Copy() : null; if (vid != null) { int rc = vid.CompareTo(new_view.Vid); if (rc < 0) { isNewMember = false; if (gms.Stack.NCacheLog.IsInfoEnabled) { gms.Stack.NCacheLog.Info("ParticipantGmsImp", "isNewMember : " + isNewMember); } } } gms.installView(new_view, digest); }
/// <summary> /// Sets the new view and sends a VIEW_CHANGE event up and down the stack. /// </summary> /// <param name="new_view">New View to install</param> public void installView(View new_view) { Address coord; int rc; ViewId vid = new_view.getVid(); ArrayList mbrs = new_view.getMembers(); lock (members) { // serialize access to views ltime = Math.Max(vid.getId(), ltime); // compute Lamport logical time /* Check for self-inclusion: if I'm not part of the new membership, I just discard it. * This ensures that messages sent in view V1 are only received by members of V1 */ if (Trace.trace) { Trace.info("GMS.installView()", "View to install contains: " + new_view.ToString()); } if (checkSelfInclusion(mbrs) == false) { if (Trace.trace) { Trace.warn("GMS.installView()", "checkSelfInclusion() failed, not a member of view " + mbrs + "; discarding view"); } if (shun) { if (Trace.trace) { Trace.warn("GMS.installView()", "I'm being shunned, will leave and rejoin group"); } passUp(new Event(Event.EXIT)); } return; } // Discards view with id lower than our own. Will be installed without check if first view if (view_id != null) { rc = vid.CompareTo(view_id); if (rc <= 0) { if (Trace.trace) { Trace.error("GMS.installView()", "received view <= current view;" + " discarding it ! (current vid: " + view_id + ", new vid: " + vid + ")"); } return; } } if (Trace.trace) { Trace.info("GMS.installView()", "view is " + new_view); } // assign new_view to view_id view_id = vid.Copy(); // Set the membership. Take into account joining members if (mbrs != null && mbrs.Count > 0) { members.set(mbrs); tmp_members.set(members); foreach (Object obj in mbrs) { joining.Remove(obj); // remove all members in mbrs from joining } tmp_members.add(joining); // adjust temporary membership } // Send VIEW_CHANGE event up and down the stack: Event view_event = new Event(Event.VIEW_CHANGE, (View)new_view.copy()); passDown(view_event); // needed e.g. by failure detector or UDP passUp(view_event); coord = determineCoordinator(); if (coord != null && coord.Equals(local_addr) && !(coord.Equals(vid.getCoordAddress()))) { becomeCoordinator(); } else { if (haveCoordinatorRole() && !local_addr.Equals(coord)) { becomeParticipant(); } } } }