/// <summary> Merge all MergeData. All MergeData elements should be disjunct (both views and digests). However, /// this method is prepared to resolve duplicate entries (for the same member). Resolution strategy for /// views is to merge only 1 of the duplicate members. Resolution strategy for digests is to take the higher /// seqnos for duplicate digests.<p> /// After merging all members into a Membership and subsequent sorting, the first member of the sorted membership /// will be the new coordinator. /// </summary> /// <param name="v">A list of MergeData items. Elements with merge_rejected=true were removed before. Is guaranteed /// not to be null and to contain at least 1 member. /// </param> internal virtual MergeData consolidateMergeData(System.Collections.ArrayList v) { MergeData ret = null; MergeData tmp_data; long logical_time = 0; // for new_vid ViewId new_vid, tmp_vid; MergeView new_view; View tmp_view; Membership new_mbrs = new Membership(); int num_mbrs = 0; Digest new_digest = null; Address new_coord; System.Collections.ArrayList subgroups = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(11)); // contains a list of Views, each View is a subgroup for (int i = 0; i < v.Count; i++) { tmp_data = (MergeData)v[i]; gms.Stack.NCacheLog.Debug("merge data is " + tmp_data); tmp_view = tmp_data.View; if (tmp_view != null) { tmp_vid = tmp_view.Vid; if (tmp_vid != null) { // compute the new view id (max of all vids +1) logical_time = System.Math.Max(logical_time, tmp_vid.Id); } } // merge all membership lists into one (prevent duplicates) new_mbrs.add(tmp_view.Members); subgroups.Add(tmp_view.Clone()); } // the new coordinator is the first member of the consolidated & sorted membership list new_mbrs.sort(); num_mbrs = new_mbrs.size(); new_coord = num_mbrs > 0 ? (Address)new_mbrs.elementAt(0) : null; if (new_coord == null) { gms.Stack.NCacheLog.Error("CoordGmsImpl.consolodateMergeData", "new_coord is null."); return null; } // should be the highest view ID seen up to now plus 1 new_vid = new ViewId(new_coord, logical_time + 1); // determine the new view new_view = new MergeView(new_vid, new_mbrs.Members, subgroups); gms.Stack.NCacheLog.Debug("new merged view will be " + new_view); // determine the new digest new_digest = consolidateDigests(v, num_mbrs); if (new_digest == null) { gms.Stack.NCacheLog.Error("CoordGmsImpl.consolidateMergeData", "digest could not be consolidated."); return null; } gms.Stack.NCacheLog.Debug("consolidated digest=" + new_digest); ret = new MergeData(gms.local_addr, new_view, new_digest); return ret; }
/// <summary> Invoked upon receiving a MERGE event from the MERGE layer. Starts the merge protocol. /// See description of protocol in DESIGN. /// </summary> /// <param name="other_coords">A list of coordinators (including myself) found by MERGE protocol /// </param> public override void merge(System.Collections.ArrayList other_coords) { Membership tmp; Address leader = null; if (merging) { gms.Stack.NCacheLog.Warn("CoordGmsImpl.merge", "merge already in progress, discarded MERGE event"); return; } if (other_coords == null) { gms.Stack.NCacheLog.Warn("CoordGmsImpl.merge", "list of other coordinators is null. Will not start merge."); return; } if (other_coords.Count <= 1) { gms.Stack.NCacheLog.Error("CoordGmsImpl.merge", "number of coordinators found is " + other_coords.Count + "; will not perform merge"); return; } /* Establish deterministic order, so that coords can elect leader */ tmp = new Membership(other_coords); tmp.sort(); leader = (Address)tmp.elementAt(0); gms.Stack.NCacheLog.Debug("coordinators in merge protocol are: " + tmp); if (leader.Equals(gms.local_addr)) { gms.Stack.NCacheLog.Debug("I (" + leader + ") will be the leader. Starting the merge task"); startMergeTask(other_coords); } }