All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgroups.protocols.pbcast.CoordGmsImpl Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version

package org.jgroups.protocols.pbcast;


import org.jgroups.*;
import org.jgroups.util.*;

import java.util.*;


/**
 * Coordinator role of the Group MemberShip (GMS) protocol. Accepts JOIN and LEAVE requests and emits view changes
 * accordingly.
 * @author Bela Ban
 */
public class CoordGmsImpl extends ServerGmsImpl {
    protected static final Long  MAX_SUSPEND_TIMEOUT=30000L;

    public CoordGmsImpl(GMS g) {
        super(g);
    }


    public MergeId getMergeId() {
        return merger.getMergeId();
    }


    public void init() throws Exception {
        super.init();
        merger.cancelMerge(null);
        gms.getViewHandler().resume();
    }

    public void join(Address mbr,boolean useFlushIfPresent) {
        wrongMethod("join");
    }
    
    public void joinWithStateTransfer(Address mbr,boolean useFlushIfPresent) {
        wrongMethod("join");
    }

    /** The coordinator itself wants to leave the group */
    public void leave() {
        ViewHandler vh=gms.getViewHandler();
        vh.add(new Request(Request.COORD_LEAVE)); // https://issues.redhat.com/browse/JGRP-2293
        vh.waitUntilComplete();
    }

    public void handleCoordLeave() {
        try {
            gms.suspendViewHandler(); // clears the queue and drops subsequent requests
            leaver.leave();
        }
        finally {
            gms.initState();
        }
    }

    public void suspect(Address mbr) {
        if(mbr.equals(gms.getAddress())) {
            if(log.isWarnEnabled()) log.warn("I am the coord and I'm suspected -- will probably leave shortly");
            return;
        }        
        Collection suspected=new LinkedHashSet<>(1);
        suspected.add(new Request(Request.SUSPECT,mbr));
        handleMembershipChange(suspected);
    }


    /**
     * Fetches the digests from all members and installs them again. Used only for diagnosis and support; don't
     * use this otherwise !
     */
    void fixDigests() {
        merger.fixDigests();
    }



    public void handleMembershipChange(Collection requests) {
        boolean joinAndStateTransferInitiated=false;
        boolean useFlushIfPresent=gms.use_flush_if_present;
        Collection
new_mbrs=new LinkedHashSet<>(requests.size()); Collection
suspected_mbrs=new LinkedHashSet<>(requests.size()); Collection
leaving_mbrs=new LinkedHashSet<>(requests.size()); log.trace("%s: handleMembershipChange(%s)", gms.getAddress(), requests); boolean self_leaving=false; // is the coord leaving for(Request req: requests) { switch(req.type) { case Request.JOIN: new_mbrs.add(req.mbr); if(req.useFlushIfPresent) useFlushIfPresent=true; break; case Request.JOIN_WITH_STATE_TRANSFER: new_mbrs.add(req.mbr); joinAndStateTransferInitiated=true; if(req.useFlushIfPresent) useFlushIfPresent=true; break; case Request.LEAVE: leaving_mbrs.add(req.mbr); if(Objects.equals(gms.getAddress(), req.mbr)) self_leaving=true; break; case Request.SUSPECT: suspected_mbrs.add(req.mbr); break; } } new_mbrs.remove(gms.getAddress()); // remove myself - cannot join myself (already joined) if(gms.getViewId() == null) { // we're probably not the coord anymore (we just left ourselves), let someone else do it // (client will retry when it doesn't get a response) log.debug("gms.view_id is null, I'm not the coordinator anymore (leaving=%b); " + "the new coordinator will handle the leave request", self_leaving); return; } List
current_members=gms.members.getMembers(); leaving_mbrs.retainAll(current_members); // remove all elements of leaving_mbrs which are not current members if(suspected_mbrs.remove(gms.getAddress())) log.warn("I am the coord and I'm being suspected -- will probably leave shortly"); suspected_mbrs.retainAll(current_members); // remove all elements of suspected_mbrs which are not current members // for the members that have already joined, return the current digest and membership for(Iterator
it=new_mbrs.iterator(); it.hasNext();) { Address mbr=it.next(); if(gms.members.contains(mbr)) { // already joined: return current digest and membership log.trace("%s: %s already present; returning existing view %s", gms.getAddress(), mbr, gms.view); Tuple tuple=gms.getViewAndDigest(); if(tuple != null) gms.sendJoinResponse(new JoinRsp(tuple.getVal1(), tuple.getVal2()), mbr); else log.warn("%s: did not find a digest matching view %s; dropping JOIN-RSP", gms.getAddress(), gms.view); it.remove(); // remove it anyway, even if we didn't find a digest matching the view (joiner will retry) } } if(new_mbrs.isEmpty() && leaving_mbrs.isEmpty() && suspected_mbrs.isEmpty()) { log.trace("%s: found no members to add or remove, will not create new view", gms.getAddress()); return; } View new_view=gms.getNextView(new_mbrs, leaving_mbrs, suspected_mbrs); if(new_view.size() == 0 && gms.getAddress() != null && gms.getAddress().equals(new_view.getCreator())) { if(self_leaving) gms.initState(); // in case connect() is called again return; } log.trace("%s: joiners=%s, suspected=%s, leaving=%s, new view: %s", gms.getAddress(), new_mbrs, suspected_mbrs, leaving_mbrs, new_view); JoinRsp join_rsp=null; boolean hasJoiningMembers=!new_mbrs.isEmpty(); try { boolean successfulFlush =!useFlushIfPresent || !gms.flushProtocolInStack || gms.startFlush(new_view); if(!successfulFlush && hasJoiningMembers) { // Don't send a join response if the flush fails (https://issues.redhat.com/browse/JGRP-759) // The joiner should block until the previous FLUSH completed sendLeaveResponses(leaving_mbrs); // we still have to send potential leave responses // but let the joining client timeout and send another join request return; } // we cannot garbage collect during joining a new member *if* we're the only member // Example: {A}, B joins, after returning JoinRsp to B, A garbage collects messages higher than those // in the digest returned to the client, so the client will *not* be able to ask for retransmission // of those messages if he misses them if(hasJoiningMembers) { gms.getDownProtocol().down(new Event(Event.SUSPEND_STABLE, MAX_SUSPEND_TIMEOUT)); // create a new digest, which contains the new members, minus left members MutableDigest join_digest=new MutableDigest(new_view.getMembersRaw()).set(gms.getDigest()); for(Address member: new_mbrs) join_digest.set(member,0,0); // ... and set the new members. their first seqno will be 1 // If the digest from NAKACK doesn't include all members of the view, we try once more; if it is still // incomplete, we don't send a JoinRsp back to the joiner(s). This shouldn't be a problem as they will retry if(join_digest.allSet() || join_digest.set(gms.getDigest()).allSet()) join_rsp=new JoinRsp(new_view, join_digest); else log.warn("%s: digest does not match view (missing seqnos for %s); dropping JOIN-RSP", gms.getAddress(), Arrays.toString(join_digest.getNonSetMembers())); } sendLeaveResponses(leaving_mbrs); // no-op if no leaving members // we don't need to send the digest to existing members: https://issues.redhat.com/browse/JGRP-1317 gms.castViewChangeAndSendJoinRsps(new_view, null, new_view.getMembers(), new_mbrs, join_rsp); } finally { if(hasJoiningMembers) gms.getDownProtocol().down(new Event(Event.RESUME_STABLE)); if(!joinAndStateTransferInitiated && useFlushIfPresent) gms.stopFlush(); } } public void stop() { super.stop(); // sets leaving=false merger.stop(); } private void sendLeaveResponses(Collection
leaving_members) { for(Address address: leaving_members){ Message msg=new EmptyMessage(address).setFlag(Message.Flag.OOB, Message.Flag.NO_RELIABILITY) .putHeader(gms.getId(), new GMS.GmsHeader(GMS.GmsHeader.LEAVE_RSP)); log.trace("%s: sending LEAVE response to %s", gms.getAddress(), address); gms.getDownProtocol().down(msg); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy