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

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

package org.jgroups.protocols.pbcast;


import org.jgroups.Address;
import org.jgroups.Event;
import org.jgroups.Message;
import org.jgroups.View;
import org.jgroups.protocols.PingData;
import org.jgroups.util.Digest;
import org.jgroups.util.Promise;
import org.jgroups.util.Responses;
import org.jgroups.util.Util;

import java.util.*;


/**
 * Client part of GMS. Whenever a new member wants to join a group, it starts in the CLIENT role.
 * No multicasts to the group will be received and processed until the member has been joined and
 * turned into a SERVER (either coordinator or participant, mostly just participant). This class
 * only implements Join (called by clients who want to join a certain group, and
 * ViewChange which is called by the coordinator that was contacted by this client, to
 * tell the client what its initial membership is.
 * @author Bela Ban
 * @version $Revision: 1.78 $
 */
public class ClientGmsImpl extends GmsImpl {
    protected final Promise join_promise=new Promise<>();


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

    public void init() throws Exception {
        super.init();
        join_promise.reset();
    }

    public void join(Address address,boolean useFlushIfPresent) {
        joinInternal(address, false,useFlushIfPresent);
    }

    public void joinWithStateTransfer(Address local_addr, boolean useFlushIfPresent) {
        joinInternal(local_addr,true,useFlushIfPresent);
    }
    
    /**
     * Joins this process to a group. Determines the coordinator and sends a
     * unicast handleJoin() message to it. The coordinator returns a JoinRsp and
     * then broadcasts the new view, which contains a message digest and the
     * current membership (including the joiner). The joiner is then supposed to
     * install the new view and the digest and starts accepting mcast messages.
     * Previous mcast messages were discarded (this is done in PBCAST).
     * 

* If successful, impl is changed to an instance of ParticipantGmsImpl. * Otherwise, we continue trying to send join() messages to the coordinator, * until we succeed (or there is no member in the group. In this case, we * create our own singleton group). *

* When GMS.disable_initial_coord is set to true, then we won't become * coordinator on receiving an initial membership of 0, but instead will * retry (forever) until we get an initial membership of > 0. * * @param mbr Our own address (assigned through SET_LOCAL_ADDRESS) */ protected void joinInternal(Address mbr, boolean joinWithStateTransfer, boolean useFlushIfPresent) { long join_attempts=0; leaving=false; join_promise.reset(); while(!leaving) { if(installViewIfValidJoinRsp(join_promise, false)) return; long start=System.currentTimeMillis(); Responses responses=(Responses)gms.getDownProtocol().down(Event.FIND_INITIAL_MBRS_EVT); // Sept 2008 (bela): break if we got a belated JoinRsp (https://jira.jboss.org/jira/browse/JGRP-687) if(installViewIfValidJoinRsp(join_promise, false)) return; responses.waitFor(gms.join_timeout); responses.done(); long diff=System.currentTimeMillis() - start; if(responses.isEmpty()) { log.trace("%s: no members discovered after %d ms: creating cluster as first member", gms.local_addr, diff); becomeSingletonMember(mbr); return; } log.trace("%s: discovery took %d ms, members: %s", gms.local_addr, diff, responses); List

coords=getCoords(responses); // We didn't get any coord responses; all responses were clients. If I'm the first of the sorted clients // I'll become coordinator. The others will wait and then retry the discovery and join process if(coords == null) { // e.g. because we have all clients only if(firstOfAllClients(mbr, responses)) return; continue; } if(coords.size() > 1) { log.debug("%s: found multiple coords: %s", gms.local_addr, coords); Collections.shuffle(coords); // so the code below doesn't always pick the same coord } join_attempts++; for(Address coord: coords) { log.debug("%s: sending JOIN(%s) to %s", gms.local_addr, mbr, coord); sendJoinMessage(coord, mbr, joinWithStateTransfer, useFlushIfPresent); if(installViewIfValidJoinRsp(join_promise, true)) return; log.warn("%s: JOIN(%s) sent to %s timed out (after %d ms), on try %d", gms.local_addr, mbr, coord, gms.join_timeout, join_attempts); } if(gms.max_join_attempts != 0 && join_attempts >= gms.max_join_attempts) { log.warn("%s: too many JOIN attempts (%d): becoming singleton", gms.local_addr, join_attempts); becomeSingletonMember(mbr); return; } } } public void leave(Address mbr) { leaving=true; wrongMethod("leave"); } public void handleJoinResponse(JoinRsp join_rsp) { join_promise.setResult(join_rsp); // will wake up join() method } /* --------------------------- Private Methods ------------------------------------ */ // Installs a new view and sends an ack if (1) the join rsp is not null, (2) it is valid and (3) the view // installation is successful. If true is returned, the JOIN process can be terminated, else it needs to // go through discovery and JOIN-REQ again in a next iteration protected boolean installViewIfValidJoinRsp(final Promise join_promise, boolean block_for_rsp) { boolean success=false; JoinRsp rsp=null; try { if(join_promise.hasResult()) rsp=join_promise.getResult(1, true); else if(block_for_rsp) rsp=join_promise.getResult(gms.join_timeout, true); return success=rsp != null && isJoinResponseValid(rsp) && installView(rsp.getView(), rsp.getDigest()); } finally { if(success) sendViewAck(rsp.getView().getCreator()); } } /** Handles the case where no coord responses were received. Returns true if we became the coord * (caller needs to terminate the join() call), or false when the caller needs to continue */ protected boolean firstOfAllClients(final Address joiner, final Responses rsps) { log.trace("%s: could not determine coordinator from rsps %s", gms.local_addr, rsps); // so the member to become singleton member (and thus coord) is the first of all clients SortedSet
clients=new TreeSet<>(); clients.add(joiner); // add myself again (was removed by findInitialMembers()) for(PingData response: rsps) clients.add(response.getAddress()); log.trace("%s: nodes to choose new coord from are: %s", gms.local_addr, clients); Address new_coord=clients.first(); if(new_coord.equals(joiner)) { log.trace("%s: I (%s) am the first of the nodes, will become coordinator", gms.local_addr, joiner); becomeSingletonMember(joiner); return true; } log.trace("%s: I (%s) am not the first of the nodes, waiting for another client to become coordinator", gms.local_addr, joiner); Util.sleep(500); return false; } protected boolean isJoinResponseValid(final JoinRsp rsp) { if(rsp.getFailReason() != null) throw new SecurityException(rsp.getFailReason()); Digest tmp_digest=rsp.getDigest(); if(tmp_digest == null || tmp_digest.capacity() == 0) { log.warn("%s: digest is empty: digest=%s", gms.local_addr, rsp.getDigest()); return false; } if(!tmp_digest.contains(gms.local_addr)) { log.error("%s: digest in JOIN_RSP does not contain myself; join response: %s", gms.local_addr, rsp); return false; } if(rsp.getView() == null) { log.error("%s: JoinRsp has a null view, skipping it", gms.local_addr); return false; } return true; } /** * Called by join(). Installs the view returned by calling Coord.handleJoin() and becomes coordinator. */ private boolean installView(View new_view, Digest digest) { if(!new_view.containsMember(gms.local_addr)) { log.error("%s: I'm not member of %s, will not install view", gms.local_addr, new_view); return false; } gms.installView(new_view, digest); if(gms.impl == null || gms.impl instanceof ClientGmsImpl) // installView() should have set the role (impl) gms.becomeParticipant(); gms.getUpProtocol().up(new Event(Event.BECOME_SERVER)); gms.getDownProtocol().down(new Event(Event.BECOME_SERVER)); return true; } protected static String print(List rsps) { StringBuilder sb=new StringBuilder(); for(PingData rsp: rsps) sb.append(rsp.getAddress() + " "); return sb.toString(); } protected static String print(Responses rsps) { StringBuilder sb=new StringBuilder(); for(PingData rsp: rsps) sb.append(rsp.getAddress() + " "); return sb.toString(); } void sendJoinMessage(Address coord, Address mbr,boolean joinWithTransfer, boolean useFlushIfPresent) { Message msg=new Message(coord).setFlag(Message.Flag.OOB, Message.Flag.INTERNAL); GMS.GmsHeader hdr=joinWithTransfer? new GMS.GmsHeader(GMS.GmsHeader.JOIN_REQ_WITH_STATE_TRANSFER, mbr,useFlushIfPresent) : new GMS.GmsHeader(GMS.GmsHeader.JOIN_REQ, mbr,useFlushIfPresent); msg.putHeader(gms.getId(), hdr); gms.getDownProtocol().down(new Event(Event.MSG, msg)); } void sendViewAck(Address coord) { Message view_ack=new Message(coord).setFlag(Message.Flag.OOB, Message.Flag.INTERNAL) .putHeader(gms.getId(), new GMS.GmsHeader(GMS.GmsHeader.VIEW_ACK)); gms.getDownProtocol().down(new Event(Event.MSG, view_ack)); // send VIEW_ACK to sender of view } /** Returns all members whose PingData is flagged as coordinator */ private static List
getCoords(Iterable mbrs) { if(mbrs == null) return null; List
coords=null; for(PingData mbr: mbrs) { if(mbr.isCoord()) { if(coords == null) coords=new ArrayList<>(); if(!coords.contains(mbr.getAddress())) coords.add(mbr.getAddress()); } } return coords; } void becomeSingletonMember(Address mbr) { View new_view=View.create(mbr, 0, mbr); // create singleton view with mbr as only member // set the initial digest (since I'm the first member) Digest initial_digest=new Digest(mbr, 0, 0); gms.installView(new_view, initial_digest); gms.becomeCoordinator(); // not really necessary - installView() should do it gms.getUpProtocol().up(new Event(Event.BECOME_SERVER)); gms.getDownProtocol().down(new Event(Event.BECOME_SERVER)); log.debug("%s: created cluster (first member). My view is %s, impl is %s", gms.getLocalAddress(), gms.getViewId(), gms.getImpl().getClass().getName()); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy