org.jgroups.protocols.relay.RELAY3 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).
package org.jgroups.protocols.relay;
import org.jgroups.*;
import org.jgroups.Message.Flag;
import org.jgroups.annotations.*;
import org.jgroups.protocols.relay.SiteAddress.Type;
import org.jgroups.protocols.relay.SiteStatus.Status;
import org.jgroups.protocols.relay.Topology.MemberInfo;
import org.jgroups.protocols.relay.Topology.Members;
import org.jgroups.stack.AddressGenerator;
import org.jgroups.stack.IpAddress;
import org.jgroups.util.UUID;
import org.jgroups.util.*;
import java.util.*;
import java.util.function.Supplier;
import static org.jgroups.protocols.relay.RelayHeader.*;
// todo: check if copy is needed in route(), passUp() and deliver(); possibly pass a boolean as parameter (copy or not)
// todo: use CompletableFutures in routeThen(); this could parallelize routing and delivery/passsing up
// todo: check if a message can bypass RELAY2 completely when NO_RELAY is set (in up(),down())
/**
* Provides relaying of messages between autonomous sites.
* Design: ./doc/design/RELAY2.txt and at https://github.com/belaban/JGroups/blob/master/doc/design/RELAY2.txt.
* JIRA: https://issues.redhat.com/browse/JGRP-1433
* @author Bela Ban
* @since 3.2
*/
@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
//@XmlInclude(schema="relay.xsd",type=XmlInclude.Type.IMPORT,namespace="urn:jgroups:relay:1.0",alias="relay")
//@XmlElement(name="RelayConfiguration",type="relay:RelayConfigurationType")
@MBean(description="RELAY3 protocol")
public class RELAY3 extends RELAY {
// to prevent duplicate sitesUp()/sitesDown() notifications; this is needed in every member: routes are only
// maintained by site masters (relayer != null)
// todo: replace with topo once JGRP-2706 is in place
@ManagedAttribute(description="A cache maintaining a list of sites that are up")
protected final SiteStatus site_status=new SiteStatus();
public SiteStatus siteStatus() {return site_status;}
@Override public void configure() throws Exception {
super.configure();
JChannel ch=getProtocolStack().getChannel();
ch.addAddressGenerator(new AddressGenerator() {
@Override public Address generateAddress() {return generateAddress(null);}
@Override public Address generateAddress(String name) {
SiteUUID uuid=new SiteUUID(UUID.randomUUID(), name, site);
if(can_become_site_master)
uuid.setFlag(can_become_site_master_flag);
return uuid;
}
});
}
@ManagedOperation(description="Prints the topology (site masters and local members) of this site")
public String printTopology(boolean all_sites) {
if(!all_sites)
return printLocalTopology();
return topo.print();
}
@ManagedOperation(description="Prints the topology (site masters and local members) of this site")
public String printLocalTopology() {
return topo.print(this.site);
}
public Object down(Message msg) {
//if(msg.isFlagSet(Flag.NO_RELAY))
// return down_prot.down(msg);
msg.src(local_addr);
return process(true, msg);
}
public Object up(Message msg) {
// if(msg.isFlagSet(Flag.NO_RELAY))
// return up_prot.up(msg);
Message copy=msg;
RelayHeader hdr=msg.getHeader(id);
if(hdr != null) {
if(hdr.getType() == SITE_UNREACHABLE) {
triggerSiteUnreachableEvent((SiteAddress)hdr.final_dest);
return null;
}
//todo: check if copy is needed!
copy=copy(msg).dest(hdr.final_dest).src(hdr.original_sender).putHeader(id, hdr);
}
return process(false, copy);
}
public void up(MessageBatch batch) {
List unreachable_sites=null;
for(Iterator it=batch.iterator(); it.hasNext();) {
Message msg=it.next(), copy=msg;
// if(msg.isFlagSet(Flag.NO_RELAY))
// continue;
RelayHeader hdr=msg.getHeader(id);
it.remove();
if(hdr != null) {
if(hdr.getType() == SITE_UNREACHABLE) {
SiteAddress site_addr=(SiteAddress)hdr.final_dest;
String site_name=site_addr.getSite();
if(unreachable_sites == null)
unreachable_sites=new ArrayList<>();
boolean contains=unreachable_sites.stream().anyMatch(sa -> sa.getSite().equals(site_name));
if(!contains)
unreachable_sites.add(site_addr);
continue;
}
copy=copy(msg).dest(hdr.final_dest).src(hdr.original_sender).putHeader(id, hdr);
}
process(false, copy);
}
if(unreachable_sites != null) {
for(SiteAddress sa: unreachable_sites)
triggerSiteUnreachableEvent(sa); // https://issues.redhat.com/browse/JGRP-2586
}
if(!batch.isEmpty())
up_prot.up(batch);
}
protected void sendResponseFor(List mbrs, Address dest) {
Members m=new Members(this.site);
for(Address mbr: mbrs) {
SiteAddress addr=mbr instanceof SiteMaster? new SiteMaster(((SiteMaster)mbr).getSite())
: new SiteUUID((UUID)mbr, NameCache.get(mbr), site);
MemberInfo mi=new MemberInfo(this.site, addr, (IpAddress)getPhysicalAddress(mbr),
site_masters.contains(mbr));
m.addJoined(mi);
}
Message rsp=new ObjectMessage(dest, m).putHeader(this.id, new RelayHeader(TOPO_RSP));
down(rsp);
}
public void handleView(View view) {
members=view.getMembers(); // First, save the members for routing received messages to local members
int max_num_site_masters=max_site_masters;
if(site_masters_ratio > 0)
max_num_site_masters=(int)Math.max(max_site_masters, site_masters_ratio * view.size());
List old_site_masters=site_masters;
List new_site_masters=determineSiteMasters(view, max_num_site_masters);
boolean become_site_master=new_site_masters.contains(local_addr)
&& (old_site_masters == null || !old_site_masters.contains(local_addr));
boolean cease_site_master=old_site_masters != null
&& old_site_masters.contains(local_addr) && !new_site_masters.contains(local_addr);
site_masters=new_site_masters;
if(!site_masters.isEmpty() && site_masters.get(0).equals(local_addr))
broadcast_route_notifications=true;
if(become_site_master) {
is_site_master=true;
final String bridge_name="_" + NameCache.get(local_addr);
if(relayer != null)
relayer.stop();
relayer=new Relayer3(this, log);
final Relayer3 tmp=(Relayer3)relayer;
if(async_relay_creation)
timer.execute(() -> startRelayer(tmp, bridge_name));
else
startRelayer(tmp, bridge_name);
notifySiteMasterListener(true);
}
else {
if(cease_site_master) { // ceased being the site master: stop the relayer
is_site_master=false;
notifySiteMasterListener(false);
log.trace(local_addr + ": ceased to be site master; closing bridges");
if(relayer != null)
relayer.stop();
}
}
suppress_log_no_route.removeExpired(suppress_time_no_route_errors);
topo().adjust(this.site, view.getMembers());
}
/** Called to handle a message received from a different site (via a bridge channel) */
protected void handleRelayMessage(Message msg) {
RelayHeader hdr=msg.getHeader(id);
if(hdr == null) {
log.warn("%s: received a message without a relay header; discarding it", local_addr);
return;
}
Message copy=copy(msg).dest(hdr.final_dest).src(hdr.original_sender).putHeader(id, hdr);
// todo: check if copy is needed!
process(true, copy);
}
/** Handles SITES_UP/SITES_DOWN/TOPO_REQ/TOPO_RSP messages */
protected boolean handleAdminMessage(RelayHeader hdr, Message msg) {
switch(hdr.type) {
case SITES_UP:
case SITES_DOWN:
Set tmp_sites=new HashSet<>();
if(hdr.hasSites())
tmp_sites.addAll(hdr.getSites());
tmp_sites.remove(this.site);
if(tmp_sites != null && !tmp_sites.isEmpty()) {
Status status=hdr.type == SITES_UP? Status.up : Status.down;
Set tmp=site_status.add(tmp_sites, status);
if(status == Status.down)
topo.removeAll(tmp_sites);
if(route_status_listener != null && !tmp.isEmpty()) {
String[] t=tmp.toArray(new String[]{});
if(hdr.type == SITES_UP)
route_status_listener.sitesUp(t);
else
route_status_listener.sitesDown(t);
}
}
return true;
case TOPO_REQ:
sendResponseFor(members, msg.src());
return true;
case TOPO_RSP:
Members mbrs=msg.getObject();
if(mbrs != null)
topo.handleResponse(mbrs);
return true;
}
return false;
}
// todo: use CompletableFutures and possibly thenRunAsync() to parallelize (e.g.) routing and local delivery
protected Object routeThen(Message msg, List sites, Supplier