/** * Determines whether this member is the new coordinator given a list of suspected members. This is * computed as follows: the list of currently suspected members (suspected_mbrs) is removed from the current * membership. If the first member of the resulting list is equals to the local_addr, then it is true, * otherwise false. Example: own address is B, current membership is {A, B, C, D}, suspected members are {A, * D}. The resulting list is {B, C}. The first member of {B, C} is B, which is equal to the * local_addr. Therefore, true is returned. */ boolean wouldIBeCoordinator(Collection<Address> leaving_mbrs) { List<Address> mbrs=gms.computeNewMembership(gms.members.getMembers(), null, leaving_mbrs, suspected_mbrs); if(mbrs.isEmpty()) return false; Address new_coord=mbrs.get(0); return gms.local_addr.equals(new_coord); }
/** * Old default implementation for a merge. Adds all members into a list, sorts the list and returns it * @param subviews A list of membership lists, e.g. [{A,B,C}, {M,N,O,P}, {X,Y,Z}]. This is a merge between * 3 subviews. Guaranteed to be non-null (but may be empty) * @return The new membership. Needs to be non-null and cannot contain duplicates */ public static List<Address> getNewMembershipOld(final Collection<Collection<Address>> subviews) { Membership mbrs=new Membership(); subviews.forEach(mbrs::add); return mbrs.sort().getMembers(); }
/** * Called when a merge happened. The largest subview wins. */ public List<Address> getNewMembership(final Collection<Collection<Address>> subviews) { ArrayList<Collection<Address>> aSubviews=new ArrayList<>(subviews); int sLargest = 0; int iLargest = 0; for (int i = 0; i < aSubviews.size(); i++) { int size = aSubviews.get(i).size(); if (size > sLargest) { sLargest = size; iLargest = i; } } Membership mbrs = new Membership(aSubviews.get(iLargest)); for (int i = 0; i < aSubviews.size(); i++) if (i != iLargest) mbrs.add(aSubviews.get(i)); return mbrs.getMembers(); }
/** * Clears the membership and adds all members of a given membership parameter. Prior to setting * membership this method will clear out all the old members of this membership by invoking the * {@code clear} method. * @param m a membership containing all the members this membership will contain */ public Membership set(Membership m) { clear(); if(m != null) add(m.getMembers()); return this; }
/** * Computes the next view. Returns a copy that has {@code leavers} and * {@code suspected_mbrs} removed and {@code joiners} added. */ public View getNextView(Collection<Address> joiners, Collection<Address> leavers, Collection<Address> suspected_mbrs) { synchronized(members) { ViewId view_id=view != null? view.getViewId() : null; if(view_id == null) { log.error(Util.getMessage("ViewidIsNull")); return null; // this should *never* happen ! } long vid=Math.max(view_id.getId(), ltime) + 1; ltime=vid; List<Address> mbrs=computeNewMembership(tmp_members.getMembers(), joiners, leavers, suspected_mbrs); Address new_coord=!mbrs.isEmpty()? mbrs.get(0) : local_addr; View v=new View(new_coord, vid, mbrs); // Update membership (see DESIGN for explanation): tmp_members.set(mbrs); // Update joining list (see DESIGN for explanation) if(joiners != null) joiners.stream().filter(tmp_mbr -> !joining.contains(tmp_mbr)).forEach(joining::add); // Update leaving list (see DESIGN for explanations) if(leavers != null) leavers.stream().filter(addr -> !leaving.contains(addr)).forEach(leaving::add); if(suspected_mbrs != null) suspected_mbrs.stream().filter(addr -> !leaving.contains(addr)).forEach(leaving::add); return v; } }
/** * Default implementation for a merge. Picks the new coordinator among the coordinators of the old subviews * by getting all coords, sorting them and picking the first. Then the coord is added to the new list, and * all subviews are subsequently added.<p/> * Tries to minimize coordinatorship moving around between different members * @param subviews A list of membership lists, e.g. [{A,B,C}, {M,N,O,P}, {X,Y,Z}]. This is a merge between * 3 subviews. Guaranteed to be non-null (but may be empty) * @return The new membership. Needs to be non-null and cannot contain duplicates */ public List<Address> getNewMembership(final Collection<Collection<Address>> subviews) { // add the coord of each subview Membership coords=new Membership(); subviews.stream().filter(subview -> !subview.isEmpty()).forEach(subview -> coords.add(subview.iterator().next())); // pick the first coord of the sorted list as the new coord coords.sort(); Membership new_mbrs=new Membership().add(coords.elementAt(0)); // add all other members in the order in which they occurred in their subviews - dupes are not added subviews.forEach(new_mbrs::add); return new_mbrs.getMembers(); } }
/** * Takes the existing membership list and removes suspected and left members, then adds new * members to the end of the list * @param current_members The list of current members. Guaranteed to be non-null (but may be empty) * @param joiners The joining members. Guaranteed to be non-null (but may be empty) * @param leavers Members that are leaving. Guaranteed to be non-null (but may be empty) * @param suspects Members which are suspected. Guaranteed to be non-null (but may be empty) * @return The new membership. Needs to be non-null and cannot contain duplicates */ public List<Address> getNewMembership(final Collection<Address> current_members, final Collection<Address> joiners, final Collection<Address> leavers, final Collection<Address> suspects) { Membership mbrs=new Membership(current_members).remove(leavers).remove(suspects).add(joiners); return mbrs.getMembers(); }
List<Address> current_members=gms.members.getMembers();
/** * 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)) { log.trace("%s: merge_ids (mine: %s, received: %s) don't match; merge view %s is discarded", gms.local_addr, this.merge_id, merge_id, data.view.getViewId()); 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> expected_acks=gms.members.getMembers(); try { gms.castViewChangeAndSendJoinRsps(data.view, data.digest, expected_acks, null, null); // 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) .putHeader(gms.getId(), new GMS.GmsHeader(GMS.GmsHeader.INSTALL_MERGE_VIEW_OK)); gms.getDownProtocol().down(ack); } } finally { cancelMerge(merge_id); } }
/** * Determines whether this member is the new coordinator given a list of suspected members. This is * computed as follows: the list of currently suspected members (suspected_mbrs) is removed from the current * membership. If the first member of the resulting list is equals to the local_addr, then it is true, * otherwise false. Example: own address is B, current membership is {A, B, C, D}, suspected members are {A, * D}. The resulting list is {B, C}. The first member of {B, C} is B, which is equal to the * local_addr. Therefore, true is returned. */ boolean wouldIBeCoordinator(Collection<Address> leaving_mbrs) { List<Address> mbrs=gms.computeNewMembership(gms.members.getMembers(), null, leaving_mbrs, suspected_mbrs); if(mbrs.isEmpty()) return false; Address new_coord=mbrs.get(0); return gms.local_addr.equals(new_coord); }
/** * Determines whether this member is the new coordinator given a list of suspected members. This is * computed as follows: the list of currently suspected members (suspected_mbrs) is removed from the current * membership. If the first member of the resulting list is equals to the local_addr, then it is true, * otherwise false. Example: own address is B, current membership is {A, B, C, D}, suspected members are {A, * D}. The resulting list is {B, C}. The first member of {B, C} is B, which is equal to the * local_addr. Therefore, true is returned. */ boolean wouldIBeCoordinator() { Address new_coord; Vector mbrs=gms.members.getMembers(); // getMembers() returns a *copy* of the membership vector mbrs.removeAll(suspected_mbrs); if(mbrs.size() < 1) return false; new_coord=(Address)mbrs.elementAt(0); return gms.local_addr.equals(new_coord); }
/** * Old default implementation for a merge. Adds all members into a list, sorts the list and returns it * @param subviews A list of membership lists, e.g. [{A,B,C}, {M,N,O,P}, {X,Y,Z}]. This is a merge between * 3 subviews. Guaranteed to be non-null (but may be empty) * @return The new membership. Needs to be non-null and cannot contain duplicates */ public static List<Address> getNewMembershipOld(final Collection<Collection<Address>> subviews) { Membership mbrs=new Membership(); subviews.forEach(mbrs::add); return mbrs.sort().getMembers(); }
/** * Called when a merge happened. The largest subview wins. */ public List<Address> getNewMembership(final Collection<Collection<Address>> subviews) { ArrayList<Collection<Address>> aSubviews=new ArrayList<>(subviews); int sLargest = 0; int iLargest = 0; for (int i = 0; i < aSubviews.size(); i++) { int size = aSubviews.get(i).size(); if (size > sLargest) { sLargest = size; iLargest = i; } } Membership mbrs = new Membership(aSubviews.get(iLargest)); for (int i = 0; i < aSubviews.size(); i++) if (i != iLargest) mbrs.add(aSubviews.get(i)); return mbrs.getMembers(); }
/** * Clears the membership and adds all members of a given membership parameter. Prior to setting * membership this method will clear out all the old members of this membership by invoking the * {@code clear} method. * @param m a membership containing all the members this membership will contain */ public Membership set(Membership m) { clear(); if(m != null) add(m.getMembers()); return this; }
/** * Clear the membership and adds all members of v * This method will clear out all the old members of this membership by * invoking the <code>Clear</code> method. * Then it will add all the all members provided in the vector v * * @param m - a membership containing all the members this membership will contain */ public void set(Membership m) { clear(); if(m != null) { add(m.getMembers()); } }
/** * Default implementation for a merge. Picks the new coordinator among the coordinators of the old subviews * by getting all coords, sorting them and picking the first. Then the coord is added to the new list, and * all subviews are subsequently added.<p/> * Tries to minimize coordinatorship moving around between different members * @param subviews A list of membership lists, e.g. [{A,B,C}, {M,N,O,P}, {X,Y,Z}]. This is a merge between * 3 subviews. Guaranteed to be non-null (but may be empty) * @return The new membership. Needs to be non-null and cannot contain duplicates */ public List<Address> getNewMembership(final Collection<Collection<Address>> subviews) { // add the coord of each subview Membership coords=new Membership(); subviews.stream().filter(subview -> !subview.isEmpty()).forEach(subview -> coords.add(subview.iterator().next())); // pick the first coord of the sorted list as the new coord coords.sort(); Membership new_mbrs=new Membership().add(coords.elementAt(0)); // add all other members in the order in which they occurred in their subviews - dupes are not added subviews.forEach(new_mbrs::add); return new_mbrs.getMembers(); } }
private MergeData getMergeResponse(Address sender, ViewId merge_id) { Digest digest; View view; MergeData retval; if(sender == null) { if(log.isErrorEnabled()) log.error("sender == null; cannot send back a response"); return null; } if(merging) { if(log.isErrorEnabled()) log.error("merge already in progress"); retval=new MergeData(sender, null, null); retval.merge_rejected=true; return retval; } merging=true; setMergeId(merge_id); if(log.isDebugEnabled()) log.debug("sender=" + sender + ", merge_id=" + merge_id); try { digest=gms.getDigest(); view=new View(gms.view_id.copy(), gms.members.getMembers()); retval=new MergeData(sender, view, digest); retval.view=view; retval.digest=digest; } catch(NullPointerException null_ex) { return null; } return retval; }
/** * Get the view and digest and send back both (MergeData) in the form of a MERGE_RSP to the sender. * If a merge is already in progress, send back a MergeData with the merge_rejected field set to true. */ public void handleMergeRequest(Address sender, ViewId merge_id) { Digest digest; View view; if(sender == null) { if(log.isErrorEnabled()) log.error("sender == null; cannot send back a response"); return; } if(merging) { if(log.isErrorEnabled()) log.error("merge already in progress"); sendMergeRejectedResponse(sender, merge_id); return; } merging=true; /* Clears the view handler queue and discards all JOIN/LEAVE/MERGE requests until after the MERGE */ gms.getViewHandler().suspend(merge_id); setMergeId(merge_id); if(log.isDebugEnabled()) log.debug("sender=" + sender + ", merge_id=" + merge_id); digest=gms.getDigest(); view=new View(gms.view_id.copy(), gms.members.getMembers()); sendMergeResponse(sender, view, digest); }
/** * Takes the existing membership list and removes suspected and left members, then adds new * members to the end of the list * @param current_members The list of current members. Guaranteed to be non-null (but may be empty) * @param joiners The joining members. Guaranteed to be non-null (but may be empty) * @param leavers Members that are leaving. Guaranteed to be non-null (but may be empty) * @param suspects Members which are suspected. Guaranteed to be non-null (but may be empty) * @return The new membership. Needs to be non-null and cannot contain duplicates */ public List<Address> getNewMembership(final Collection<Address> current_members, final Collection<Address> joiners, final Collection<Address> leavers, final Collection<Address> suspects) { Membership mbrs=new Membership(current_members).remove(leavers).remove(suspects).add(joiners); return mbrs.getMembers(); }
/** * 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)) { log.trace("%s: merge_ids (mine: %s, received: %s) don't match; merge view %s is discarded", gms.local_addr, this.merge_id, merge_id, data.view.getViewId()); 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> expected_acks=gms.members.getMembers(); try { gms.castViewChangeAndSendJoinRsps(data.view, data.digest, expected_acks, null, null); // 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) .putHeader(gms.getId(), new GMS.GmsHeader(GMS.GmsHeader.INSTALL_MERGE_VIEW_OK)); gms.getDownProtocol().down(ack); } } finally { cancelMerge(merge_id); } }