/** * Removed rejected merge requests from merge_rsps and coords. This method has a lock on * merge_rsps */ private void removeRejectedMergeRequests(Collection<Address> coords) { for (Map.Entry<Address, MergeData> entry : merge_rsps.getResults().entrySet()) { Address member = entry.getKey(); MergeData data = entry.getValue(); if (data.merge_rejected) { if (data.getSender() != null) coords.remove(data.getSender()); merge_rsps.remove(member); } } }
/** * Merge all digests into one. For each sender, the new value is max(highest_delivered), * max(highest_received). This method has a lock on merge_rsps */ private Digest consolidateDigests(List<MergeData> merge_rsps, int num_mbrs) { MutableDigest retval = new MutableDigest(num_mbrs); for (MergeData data : merge_rsps) { Digest tmp_digest = data.getDigest(); if (tmp_digest == null) continue; retval.merge(tmp_digest); } return retval.copy(); }
/** * Merge all digests into one. For each sender, the new value is min(low_seqno), * max(high_seqno), max(high_seqno_seen). This method has a lock on merge_rsps */ private Digest consolidateDigests(Vector<MergeData> merge_rsps, int num_mbrs) { MutableDigest retval = new MutableDigest(num_mbrs); for (MergeData data : merge_rsps) { Digest tmp_digest = data.getDigest(); if (tmp_digest == null) { if (log.isErrorEnabled()) log.error("tmp_digest == null; skipping"); continue; } retval.merge(tmp_digest); } return retval.copy(); }
/** * 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. This method has a lock on merge_rsps. * * @param merge_rsps 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. */ private MergeData consolidateMergeData(Vector<MergeData> merge_rsps) { long logical_time = 0; // for new_vid Membership new_mbrs = new Membership(); Vector<View> subgroups = new Vector<View>(11); // contains a list of Views, each View is a subgroup for (MergeData tmp_data : merge_rsps) { View tmp_view = tmp_data.getView(); if (tmp_view != null) { ViewId tmp_vid = tmp_view.getVid(); if (tmp_vid != null) { // compute the new view id (max of all vids +1) logical_time = Math.max(logical_time, tmp_vid.getId()); } // merge all membership lists into one (prevent duplicates) new_mbrs.add(tmp_view.getMembers()); subgroups.addElement((View) tmp_view.clone()); } } // the new coordinator is the first member of the consolidated & sorted membership list new_mbrs.sort(); Address new_coord = new_mbrs.size() > 0 ? new_mbrs.elementAt(0) : null; if (new_coord == null) { if (log.isErrorEnabled()) log.error("new_coord == null"); return null; } // should be the highest view ID seen up to now plus 1 ViewId new_vid = new ViewId(new_coord, logical_time + 1); // determine the new view MergeView new_view = new MergeView(new_vid, new_mbrs.getMembers(), subgroups); // determine the new digest Digest new_digest = consolidateDigests(merge_rsps, new_mbrs.size()); if (new_digest == null) { if (log.isErrorEnabled()) log.error("Merge leader " + gms.local_addr + ": could not consolidate digest for merge"); return null; } if (log.isDebugEnabled()) log.debug( "Merge leader " + gms.local_addr + ": consolidated view=" + new_view + "\nconsolidated digest=" + new_digest); return new MergeData(gms.local_addr, new_view, new_digest); }
/** * 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. This method has a lock on merge_rsps. * * @param merge_rsps 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. */ private MergeData consolidateMergeData(List<MergeData> merge_rsps) { long logical_time = 0; // for new_vid List<View> subgroups = new ArrayList<View>(11); // contains a list of Views, each View is a subgroup Collection<Collection<Address>> sub_mbrships = new ArrayList<Collection<Address>>(); for (MergeData tmp_data : merge_rsps) { View tmp_view = tmp_data.getView(); if (tmp_view != null) { ViewId tmp_vid = tmp_view.getVid(); if (tmp_vid != null) { // compute the new view id (max of all vids +1) logical_time = Math.max(logical_time, tmp_vid.getId()); } // merge all membership lists into one (prevent duplicates) sub_mbrships.add(new ArrayList<Address>(tmp_view.getMembers())); subgroups.add(tmp_view.copy()); } } // determine the new digest Digest new_digest = consolidateDigests(merge_rsps, merge_rsps.size()); if (new_digest == null) return null; // remove all members from the new member list that are not in the digest Collection<Address> digest_mbrs = new_digest.getMembers(); for (Collection<Address> coll : sub_mbrships) coll.retainAll(digest_mbrs); List<Address> merged_mbrs = gms.computeNewMembership(sub_mbrships); // the new coordinator is the first member of the consolidated & sorted membership list Address new_coord = merged_mbrs.isEmpty() ? null : merged_mbrs.get(0); if (new_coord == null) return null; // should be the highest view ID seen up to now plus 1 ViewId new_vid = new ViewId(new_coord, logical_time + 1); // determine the new view MergeView new_view = new MergeView(new_vid, merged_mbrs, subgroups); if (log.isTraceEnabled()) log.trace( gms.local_addr + ": consolidated view=" + new_view + "\nconsolidated digest=" + new_digest); return new MergeData(gms.local_addr, new_view, new_digest); }
/** * If merge_id is not equal to this.merge_id then discard. Else cast the view/digest to all * members of this group. */ public void handleMergeView(final MergeData data, final MergeId merge_id) { if (!matchMergeId(merge_id)) { if (log.isErrorEnabled()) log.error("merge_ids don't match (or are null); merge view discarded"); return; } // only send to our *current* members, if we have A and B being merged (we are B), then we would // *not* // receive a VIEW_ACK from A because A doesn't see us in the pre-merge view yet and discards the // view // [JGRP-700] - FLUSH: flushing should span merge // we have to send new view only to current members and we should not wait // for view acks from newly merged mebers List<Address> newViewMembers = new Vector<Address>(data.view.getMembers()); newViewMembers.removeAll(gms.members.getMembers()); gms.castViewChangeWithDest(data.view, data.digest, null, newViewMembers); // if we have flush in stack send ack back to merge coordinator if (gms.flushProtocolInStack) { Message ack = new Message(data.getSender(), null, null); ack.setFlag(Message.OOB); GMS.GmsHeader ack_hdr = new GMS.GmsHeader(GMS.GmsHeader.INSTALL_MERGE_VIEW_OK); ack.putHeader(gms.getId(), ack_hdr); gms.getDownProtocol().down(new Event(Event.MSG, ack)); } cancelMerge(merge_id); }
public void handleMergeResponse(MergeData data, MergeId merge_id) { if (!matchMergeId(merge_id)) { if (log.isTraceEnabled()) log.trace( gms.local_addr + ": this.merge_id (" + this.merge_id + ") is different from merge_id " + merge_id + " sent by " + data.getSender() + " as merge response, discarding it"); return; } merge_rsps.add(data.getSender(), data); }
/** * Removed rejected merge requests from merge_rsps and coords. This method has a lock on * merge_rsps */ private void removeRejectedMergeRequests(Collection<Address> coords) { int num_removed = 0; for (Iterator<Map.Entry<Address, MergeData>> it = merge_rsps.getResults().entrySet().iterator(); it.hasNext(); ) { Map.Entry<Address, MergeData> entry = it.next(); MergeData data = entry.getValue(); if (data.merge_rejected) { if (data.getSender() != null) coords.remove(data.getSender()); it.remove(); num_removed++; } } if (num_removed > 0) { if (log.isTraceEnabled()) log.trace(gms.local_addr + ": removed " + num_removed + " rejected merge responses"); } }
public void handleMergeResponse(MergeData data, MergeId merge_id) { if (!matchMergeId(merge_id)) { if (log.isErrorEnabled()) log.error( gms.local_addr + ": this.merge_id (" + this.merge_id + ") is different from merge_id (" + merge_id + ')'); return; } merge_rsps.add(data.getSender(), data); }
/** * If merge_id is not equal to this.merge_id then discard. Else cast the view/digest to all * members of this group. */ public void handleMergeView(final MergeData data, final MergeId merge_id) { if (!matchMergeId(merge_id)) { if (log.isTraceEnabled()) log.trace( gms.local_addr + ": merge_ids (mine: " + this.merge_id + ", received: " + merge_id + ") don't match; merge view " + data.view.getViewId() + " is discarded"); return; } // only send to our *current* members, if we have A and B being merged (we are B), then we would // *not* // want to block on a VIEW_ACK from A because A doesn't see us in the pre-merge view yet and // discards the view List<Address> newViewMembers = new ArrayList<Address>(data.view.getMembers()); newViewMembers.removeAll(gms.members.getMembers()); try { gms.castViewChange(data.view, data.digest, null, newViewMembers); // if we have flush in stack send ack back to merge coordinator if (gms.flushProtocolInStack) { // [JGRP-700] - FLUSH: flushing should span merge Message ack = new Message(data.getSender()).setFlag(Message.Flag.OOB, Message.Flag.INTERNAL); GMS.GmsHeader ack_hdr = new GMS.GmsHeader(GMS.GmsHeader.INSTALL_MERGE_VIEW_OK); ack.putHeader(gms.getId(), ack_hdr); gms.getDownProtocol().down(new Event(Event.MSG, ack)); } } finally { cancelMerge(merge_id); } }