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

org.jgroups.protocols.relay.RELAY Maven / Gradle / Ivy

package org.jgroups.protocols.relay;

import org.jgroups.*;
import org.jgroups.annotations.*;
import org.jgroups.conf.ConfiguratorFactory;
import org.jgroups.conf.XmlNode;
import org.jgroups.protocols.relay.config.RelayConfig;
import org.jgroups.protocols.relay.config.RelayConfig.SiteConfig;
import org.jgroups.stack.Protocol;
import org.jgroups.util.ExtendedUUID;
import org.jgroups.util.SuppressLog;
import org.jgroups.util.TimeScheduler;
import org.jgroups.util.Util;

import java.io.InputStream;
import java.util.*;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Consumer;

import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static org.jgroups.conf.AttributeType.TIME;
import static org.jgroups.protocols.relay.RelayHeader.SITES_DOWN;
import static org.jgroups.protocols.relay.RelayHeader.SITES_UP;

/**
 * Common superclass for {@link RELAY2} and {@link RELAY3}
 * @author Bela Ban
 * @since  5.2.17
 */
@XmlInclude(schema="relay.xsd",type=XmlInclude.Type.IMPORT,namespace="urn:jgroups:relay:1.0",alias="relay")
@XmlElement(name="RelayConfiguration",type="relay:RelayConfigurationType")
public abstract class RELAY extends Protocol {
    // reserved flags
    public static final short              can_become_site_master_flag = 1 << 1;

    @Property(description="Name of the site; must be defined in the configuration",writable=false)
    protected String                       site;

    @Property(description="Name of the relay configuration",writable=false)
    protected String                       config;

    @Property(description="Whether or not this node can become the site master. If false, " +
      "and we become the coordinator, we won't start the bridge(s)",writable=false)
    protected boolean                      can_become_site_master=true;

    @Property(description="Maximum number of site masters. Setting this to a value greater than 1 means that we can " +
      "have multiple site masters. If the value is greater than the number of cluster nodes, everyone in the site " +
      "will be a site master (and thus join the global cluster",writable=false)
    protected int                          max_site_masters=1;

    @Property(description="Ratio of members that are site masters, out of range [0..1] (0 disables this). The number " +
      "of site masters is computes as Math.min(max_site_masters, view.size() * site_masters_ratio). " +
       "See https://issues.redhat.com/browse/JGRP-2581 for details")
    protected double                       site_masters_ratio;

    @Property(description="Fully qualified name of a class implementing SiteMasterPicker")
    protected String                       site_master_picker_impl;

    @Property(description="If true, the creation of the relay channel (and the connect()) are done in the background. " +
      "Async relay creation is recommended, so the view callback won't be blocked")
    protected boolean                      async_relay_creation=true;

    @Property(description="Time during which identical errors about no route to host will be suppressed. " +
      "0 disables this (every error will be logged).",type= TIME)
    protected long                         suppress_time_no_route_errors=60000;

    @ManagedAttribute(description="Whether this member is a site master")
    protected volatile boolean             is_site_master;

    @ManagedAttribute(description="A list of site masters in this (local) site")
    protected volatile List
site_masters; @ManagedAttribute(description="The first of all site masters broadcasts route-up/down messages to all members of " + "the local cluster") protected volatile boolean broadcast_route_notifications; protected volatile Relayer relayer; @Component(description="Maintains a cache of sites and members",name="topo") protected final Topology topo=new Topology(this); /** Number of messages forwarded to the local SiteMaster */ protected final LongAdder forward_to_site_master=new LongAdder(); protected final LongAdder forward_sm_time=new LongAdder(); /** Number of messages relayed by the local SiteMaster to a remote SiteMaster */ protected final LongAdder relayed=new LongAdder(); /** Total time spent relaying messages from the local SiteMaster to remote SiteMasters (in ns) */ protected final LongAdder relayed_time=new LongAdder(); /** Number of messages (received from a remote Sitemaster and) delivered by the local SiteMaster to a local node */ protected final LongAdder forward_to_local_mbr=new LongAdder(); protected final LongAdder forward_to_local_mbr_time=new LongAdder(); protected short[] prots_above; // protocol IDs above RELAY protected TimeScheduler timer; protected SiteMasterPicker site_master_picker; protected volatile List
members=new ArrayList<>(11); protected volatile RouteStatusListener route_status_listener; /** Listens for notifications about becoming site master (arg: true), or ceasing to be site master (arg: false) */ protected Consumer site_master_listener; /** A map containing site names (e.g. "LON") as keys and SiteConfigs as values */ protected final Map sites=new HashMap<>(); protected SiteConfig site_config; /** Log to suppress identical errors for messages to non-existing sites ('no route to site X') */ protected SuppressLog suppress_log_no_route; @ManagedAttribute(description="Number of messages forwarded to the local SiteMaster") public long getNumForwardedToSiteMaster() {return forward_to_site_master.sum();} @ManagedAttribute(description="The total time (in ms) spent forwarding messages to the local SiteMaster",type=TIME) public long getTimeForwardingToSM() {return MILLISECONDS.convert(forward_sm_time.sum(), NANOSECONDS);} @ManagedAttribute(description="The average number of messages / s for forwarding messages to the local SiteMaster") public long getAvgMsgsForwardingToSM() {return getTimeForwardingToSM() > 0? (long)(getNumForwardedToSiteMaster() / (getTimeForwardingToSM()/1000.0)) : 0;} @ManagedAttribute(description="Number of messages sent by this SiteMaster to a remote SiteMaster") public long getNumRelayed() {return relayed.sum();} @ManagedAttribute(description="The total time (ms) spent relaying messages from this SiteMaster to remote SiteMasters" ,type=TIME) public long getTimeRelaying() {return MILLISECONDS.convert(relayed_time.sum(), NANOSECONDS);} @ManagedAttribute(description="The average number of messages / s for relaying messages from this SiteMaster to remote SiteMasters") public long getAvgMsgsRelaying() {return getTimeRelaying() > 0? (long)(getNumRelayed() / (getTimeRelaying()/1000.0)) : 0;} @ManagedAttribute(description="Number of messages (received from a remote Sitemaster and) delivered " + "by this SiteMaster to a local node") public long getNumForwardedToLocalMbr() {return forward_to_local_mbr.sum();} @ManagedAttribute(description="The total time (in ms) spent forwarding messages to a member in the same site", type=TIME) public long getTimeForwardingToLocalMbr() {return MILLISECONDS.convert(forward_to_local_mbr_time.sum(), NANOSECONDS);} @ManagedAttribute(description="The average number of messages / s for forwarding messages to a member in the same site") public long getAvgMsgsForwardingToLocalMbr() {return getTimeForwardingToLocalMbr() > 0? (long)(getNumForwardedToLocalMbr() / (getTimeForwardingToLocalMbr()/1000.0)) : 0;} @ManagedAttribute(description="Number of 'no route to site X' errors") public int getNumberOfNoRouteErrors() {return suppress_log_no_route.getCache().size();} @ManagedOperation(description="Clears the 'no route to site X' cache") public T clearNoRouteCache() {suppress_log_no_route.getCache().clear(); return (T)this;} public String getSite() {return site;} public String site() {return site;} public T setSite(String s) {this.site=s; return (T)this;} public T site(String s) {site=s; return (T)this;} public Topology topo() {return topo;} public List
members() {return members;} public String config() {return config;} public T config(String cfg) {config=cfg; return (T)this;} public String getConfig() {return config;} public T setConfig(String c) {this.config=c; return (T)this;} public TimeScheduler getTimer() {return timer;} public void incrementRelayed() {relayed.increment();} public void addToRelayedTime(long d) {relayed_time.add(d);} public List
siteMasters() {return site_masters;} public boolean canBecomeSiteMaster() {return can_become_site_master;} public T canBecomeSiteMaster(boolean f) {can_become_site_master=f; return (T)this;} public int getMaxSiteMasters() {return max_site_masters;} public T setMaxSiteMasters(int m) {this.max_site_masters=m; return (T)this;} public double getSiteMastersRatio() {return site_masters_ratio;} public T setSiteMastersRatio(double r) {site_masters_ratio=r; return (T)this;} public String getSiteMasterPickerImpl() {return site_master_picker_impl;} public T setSiteMasterPickerImpl(String s) {this.site_master_picker_impl=s; return (T)this;} public T siteMasterPicker(SiteMasterPicker s) {if(s != null) this.site_master_picker=s; return (T)this;} public boolean asyncRelayCreation() {return async_relay_creation;} public T asyncRelayCreation(boolean flag) {async_relay_creation=flag; return (T)this;} public boolean broadcastRouteNotifications() {return broadcast_route_notifications;} public T broadcastRouteNotifications(boolean b) {this.broadcast_route_notifications=b; return (T)this;} public RouteStatusListener getRouteStatusListener() {return route_status_listener;} public void setRouteStatusListener(RouteStatusListener l) {this.route_status_listener=l;} public T setSiteMasterListener(Consumer l) {site_master_listener=l; return (T)this;} public T addSite(String n, SiteConfig cfg) {sites.put(n,cfg); return (T)this;} public List siteNames() {return getSites();} @ManagedAttribute(description="Whether or not this instance is a site master") public boolean isSiteMaster() {return relayer != null;} public List getSites() { return sites.isEmpty()? Collections.emptyList() : new ArrayList<>(sites.keySet()); } @ManagedOperation(description="Prints the routes that are currently up. " + "Only available if we're the current coordinator (site master)") public String printSites() { return relayer != null? Util.print(relayer.getSiteNames()) : "n/a (not site master)"; } @ManagedOperation(description="Prints the contents of the routing table. " + "Only available if we're the current coordinator (site master)") public String printRoutes() { return relayer != null? relayer.printRoutes() : "n/a (not site master)"; } /** * Returns the route to a given site * @param site_name The site name, e.g. "SFO" * @return The route to the given site, or null if no route was found or we're not the coordinator */ public Route getRoute(String site_name) { Relayer tmp=relayer; return tmp != null? tmp.getRoute(site_name): null; } /** * @return A {@link List} of sites name that are currently up or {@code null} if this node is not a Site Master (i.e. * {@link #isSiteMaster()} returns false). */ public List getCurrentSites() { // must return a List, as Infinispan expects a List (not a Collection) Relayer rel=relayer; return rel == null ? null : new ArrayList<>(rel.getSiteNames()); } /** * Returns the bridge channel to a given site * @param site_name The site name, e.g. "SFO" * @return The JChannel to the given site, or null if no route was found or we're not the coordinator */ public JChannel getBridge(String site_name) { Relayer tmp=relayer; Route route=tmp != null? tmp.getRoute(site_name): null; return route != null? route.bridge() : null; } public View getBridgeView(String cluster_name) { Relayer tmp=relayer; return tmp != null? tmp.getBridgeView(cluster_name) : null; } public void resetStats() { super.resetStats(); forward_to_site_master.reset(); forward_sm_time.reset(); relayed.reset(); relayed_time.reset(); forward_to_local_mbr.reset(); forward_to_local_mbr_time.reset(); clearNoRouteCache(); } public void init() throws Exception { super.init(); configure(); if(site_master_picker == null) { site_master_picker=new SiteMasterPicker() { public Address pickSiteMaster(List
site_masters, Address original_sender) { return Util.pickRandomElement(site_masters); } public Route pickRoute(String site, List routes, Address original_sender) { return Util.pickRandomElement(routes); } }; } if(suppress_time_no_route_errors <= 0) throw new IllegalArgumentException("suppress_time_no_route_errors has to be > 0"); suppress_log_no_route=new SuppressLog<>(log, "RelayNoRouteToSite", "SuppressMsgRelay"); } public void stop() { super.stop(); is_site_master=false; log.trace("%s: ceased to be site master; closing bridges", local_addr); if(relayer != null) relayer.stop(); } public void configure() throws Exception { timer=getTransport().getTimer(); if(site == null) throw new IllegalArgumentException("site cannot be null"); if(max_site_masters < 1) { log.warn("max_size_masters was " + max_site_masters + ", changed to 1"); max_site_masters=1; } if(site_masters_ratio < 0) { log.warn("%s: changing incorrect site_masters_ratio of %.2f to 0", local_addr, site_masters_ratio); site_masters_ratio=0.0; } else if(site_masters_ratio > 1) { log.warn("%s: changing incorrect site_masters_ratio of %.2f to 1", local_addr, site_masters_ratio); site_masters_ratio=1.0; } if(site_master_picker_impl != null) { Class clazz=(Class)Util.loadClass(site_master_picker_impl, (Class)null); this.site_master_picker=clazz.getDeclaredConstructor().newInstance(); } if(config != null) parseSiteConfiguration(sites); site_config=sites.get(site); if(site_config == null) throw new Exception("site configuration for \"" + site + "\" not found in " + config); log.trace("site configuration:\n" + site_config); prots_above=getIdsAbove(); } @Override public void parse(XmlNode node) throws Exception { RelayConfig.parse(node, sites); } public Object down(Event evt) { if(evt.getType() == Event.VIEW_CHANGE) handleView(evt.getArg()); return down_prot.down(evt); } public Object up(Event evt) { if(evt.getType() == Event.VIEW_CHANGE) handleView(evt.getArg()); return up_prot.up(evt); } public abstract void handleView(View v); protected abstract void handleRelayMessage(Message msg); public String toString() { return String.format("%s%s", getClass().getSimpleName(), local_addr != null? String.format(" (%s)", local_addr) : ""); } /** Parses the configuration by reading the config file */ protected void parseSiteConfiguration(final Map map) throws Exception { try(InputStream input=ConfiguratorFactory.getConfigStream(config)) { RelayConfig.parse(input, map); } } /** Copies the message, but only the headers above the current protocol (RELAY) (or RpcDispatcher related headers) */ protected Message copy(Message msg) { return Util.copy(msg, true, Global.BLOCKS_START_ID, this.prots_above); } protected void sitesChange(boolean down, Set sites) { if(!broadcast_route_notifications || sites == null || sites.isEmpty()) return; RelayHeader hdr=new RelayHeader(down? SITES_DOWN : SITES_UP, null, null) .addToSites(sites); down_prot.down(new EmptyMessage(null).putHeader(id, hdr)); } protected void notifySiteMasterListener(boolean flag) { if(site_master_listener != null) site_master_listener.accept(flag); } protected PhysicalAddress getPhysicalAddress(Address mbr) { return mbr != null? (PhysicalAddress)down(new Event(Event.GET_PHYSICAL_ADDRESS, mbr)) : null; } /** * Iterates over the list of members and adds every member if the member's rank is below max_site_masters. Skips * members which cannot become site masters (can_become_site_master == false). If no site master can be found, * the first member of the view will be returned (even if it has can_become_site_master == false) */ protected static List
determineSiteMasters(View view, int max_num_site_masters) { List
retval=new ArrayList<>(view.size()); int selected=0; for(Address member: view) { if(member instanceof ExtendedUUID && !((ExtendedUUID)member).isFlagSet(can_become_site_master_flag)) continue; if(selected++ < max_num_site_masters) retval.add(member); } if(retval.isEmpty()) { Address coord=view.getCoord(); if(coord != null) retval.add(coord); } return retval; } /** Returns a site master from site_masters */ protected Address pickSiteMaster(Address sender) { List
masters=site_masters; if(masters.size() == 1) return masters.get(0); return site_master_picker.pickSiteMaster(masters, sender); } protected void triggerSiteUnreachableEvent(SiteAddress remoteSite) { up_prot.up(new Event(Event.SITE_UNREACHABLE, remoteSite)); if(route_status_listener != null) route_status_listener.sitesUnreachable(remoteSite.getSite()); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy