
org.jgroups.protocols.relay.Bridge Maven / Gradle / Ivy
package org.jgroups.protocols.relay;
import org.jgroups.*;
import org.jgroups.logging.Log;
import org.jgroups.protocols.pbcast.GMS;
import org.jgroups.stack.AddressGenerator;
import org.jgroups.util.Util;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Class which joins the bridge cluster and send and receives messages to/from other sites. Also generates
* sitesUp()/sitesDown() notifications from view changes
* @author Bela Ban
* @since 5.2.17
*/
public class Bridge implements Receiver {
protected final JChannel channel;
protected final Relayer3 rel;
protected final RELAY relay;
protected final Log log;
protected final String cluster_name;
protected View view;
protected final long join_timeout;
protected Bridge(final JChannel ch, final Relayer3 r, final String cluster_name,
String channel_name, AddressGenerator addr_generator) throws Exception {
this.channel=ch;
this.cluster_name=cluster_name;
this.rel=r;
this.relay=rel.relay();
this.log=rel.log();
channel.setName(channel_name).setReceiver(this).addAddressGenerator(addr_generator);
join_timeout=((GMS)channel.getProtocolStack().findProtocol(GMS.class)).getJoinTimeout();
}
protected void start() throws Exception {
channel.connect(cluster_name);
log.info("%s: joined bridge cluster '%s'", channel.getAddress(), cluster_name);
}
protected void stop() {
log.info("%s: leaving bridge cluster '%s'", channel.getAddress(), channel.getClusterName());
Util.close(channel);
}
public void receive(Message msg) {
relay.handleRelayMessage(msg);
}
/** The view contains a list of SiteUUIDs. Adjust the routing table based on the SiteUUIDs and site */
public void viewAccepted(View new_view) {
View old_view=this.view;
Map> sites=Util.getSites(new_view, relay.site());
List removed_routes=removedRoutes(old_view, new_view);
Set up=new HashSet<>(), down=new HashSet<>(removed_routes);
this.view=new_view;
// add new routes to routing table:
for(String r: sites.keySet()) {
if(!rel.hasRouteTo(r))
up.add(r);
}
log.trace("[Relayer " + channel.getAddress() + "] view: " + new_view);
for(Map.Entry> entry: sites.entrySet()) {
String key=entry.getKey();
List val=entry.getValue();
List existing=rel.getRoutes(key);
List newRoutes=existing != null? new ArrayList<>(existing) : new ArrayList<>();
// Remove routes not in the view anymore:
newRoutes.removeIf(r -> !val.contains(r.siteMaster()));
// Add routes that aren't yet in the routing table:
val.stream().filter(addr -> !contains(newRoutes, addr))
.forEach(addr -> newRoutes.add(new Route(addr, channel, relay, log).stats(relay.statsEnabled())));
if(newRoutes.isEmpty()) {
rel.removeRoute(key);
down.add(key);
}
else
rel.addRoutes(key, newRoutes);
}
// remove all routes which were dropped between the old and new view:
if(!removed_routes.isEmpty() && log.isTraceEnabled())
log.trace("%s: removing routes %s from routing table", channel.getAddress(), removed_routes);
removed_routes.forEach(rel::removeRoute);
if(!down.isEmpty()) {
if(relay.delaySitesDown()) {
final Relayer r=relay.relayer;
final Map cache=relay.topo().cache();
for(String s: down) {
View v=cache.get(s);
if(v == null || v.size() < 2) {
relay.sitesChange(true, Set.of(s));
continue;
}
long timeout=join_timeout*2, interval=timeout / 10;
CompletableFuture.supplyAsync(() -> Util.waitUntilTrue(timeout, interval, () -> r.hasRouteTo(s)))
.thenAccept(success -> {
if(!success)
relay.sitesChange(true, Set.of(s));
});
}
}
else
relay.sitesChange(true, down);
}
if(!up.isEmpty())
relay.sitesChange(false, up);
}
@Override
public String toString() {
return String.format("bridge %s", cluster_name);
}
protected static boolean contains(List routes, Address addr) {
return routes.stream().anyMatch(route -> route.siteMaster().equals(addr));
}
/** Returns a list of routes that were in old_view, but are no longer in new_view */
protected static List removedRoutes(View old_view, View new_view) {
List l=new ArrayList<>();
if(old_view == null)
return l;
List old_routes=Stream.of(old_view.getMembersRaw()).filter(a -> a instanceof SiteUUID)
.map(s -> ((SiteUUID)s).getSite()).collect(Collectors.toList());
List new_routes=Stream.of(new_view.getMembersRaw()).filter(a -> a instanceof SiteUUID)
.map(s -> ((SiteUUID)s).getSite()).collect(Collectors.toList());
old_routes.removeAll(new_routes);
return old_routes;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy