![JAR search and dependency download from the Maven repository](/logo.png)
org.jgroups.protocols.SHARED_LOOPBACK Maven / Gradle / Ivy
package org.jgroups.protocols;
import org.jgroups.Address;
import org.jgroups.Event;
import org.jgroups.PhysicalAddress;
import org.jgroups.View;
import org.jgroups.annotations.ManagedAttribute;
import org.jgroups.annotations.ManagedOperation;
import org.jgroups.stack.IpAddress;
import org.jgroups.util.AsciiString;
import org.jgroups.util.NameCache;
import org.jgroups.util.Util;
import java.net.InetAddress;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Loopback transport shared by all channels within the same VM. Property for testing is that no messages are lost.
* Allows us to test various protocols at maximum speed.
* @author Bela Ban
*/
public class SHARED_LOOPBACK extends TP {
protected short port=1;
protected PhysicalAddress physical_addr;
@ManagedAttribute(description="The current view")
protected volatile View curr_view;
protected volatile boolean is_server=false, is_coord=false;
/**
* Map of cluster names and address-protocol mappings. Used for routing messages to all or single members
*/
protected static final Map> routing_table=new HashMap<>();
protected static final Function> FUNC=n -> new HashMap<>();
public boolean supportsMulticasting() {return true;} // kind of...
public View getView() {return curr_view;}
public boolean isServer() {return is_server;}
public boolean isCoord() {return is_coord;}
public SHARED_LOOPBACK coord(boolean b) {this.is_coord=is_server=b; return this;}
public String toString() {return "SHARED_LOOPBACK(local address: " + local_addr + ')';}
@ManagedOperation(description="Dumps the contents of the routing table")
public static String dumpRoutingTable() {
StringBuilder sb=new StringBuilder();
synchronized(routing_table) {
for(Map.Entry> entry : routing_table.entrySet()) {
AsciiString cluster_name=entry.getKey();
Set mbrs=entry.getValue().keySet();
sb.append(cluster_name).append(": ").append(mbrs).append("\n");
}
}
return sb.toString();
}
@Override
public void sendToAll(byte[] data, int offset, int length) throws Exception {
List targets;
synchronized(routing_table) {
Map dests=routing_table.get(this.cluster_name);
if(dests == null) {
log.trace("no destination found for " + this.cluster_name);
return;
}
targets=dests.entrySet().stream().filter(e -> !Objects.equals(local_addr, e.getKey()))
.map(Map.Entry::getValue).collect(Collectors.toList());
}
targets.forEach(target -> {
try {
target.receive(local_addr, data, offset, length);
}
catch(Throwable t) {
log.error(Util.getMessage("FailedSendingMessageTo") + target.getAddress(), t);
}
});
}
public void sendUnicast(PhysicalAddress dest, byte[] data, int offset, int length) throws Exception {
sendTo(dest, data, offset, length);
}
protected void sendTo(Address dest, byte[] buf, int offset, int length) throws Exception {
SHARED_LOOPBACK target;
synchronized(routing_table) {
Map dests=routing_table.get(cluster_name);
if(dests == null) {
log.trace("no destination found for " + cluster_name);
return;
}
target=dests.get(dest);
if(target == null) {
log.trace("%s: destination address %s not found, routing table:\n%s\n", local_addr, dest, dumpRoutingTable());
return;
}
}
target.receive(local_addr, buf, offset, length);
}
public static List getDiscoveryResponsesFor(String cluster_name) {
if(cluster_name == null)
return null;
List rsps=new ArrayList<>();
synchronized(routing_table) {
Map mbrs=routing_table.get(new AsciiString(cluster_name));
if(mbrs != null) {
for(Map.Entry entry: mbrs.entrySet()) {
Address addr=entry.getKey();
SHARED_LOOPBACK l=entry.getValue();
PingData data=new PingData(addr, l.isServer(), NameCache.get(addr), null).coord(l.isCoord());
rsps.add(data);
}
}
}
return rsps;
}
public String getInfo() {
return toString();
}
protected PhysicalAddress getPhysicalAddress() {
return physical_addr;
}
/*------------------------------ Protocol interface ------------------------------ */
public Object down(Event evt) {
Object retval=super.down(evt);
switch(evt.getType()) {
case Event.CONNECT:
case Event.CONNECT_WITH_STATE_TRANSFER:
case Event.CONNECT_USE_FLUSH:
case Event.CONNECT_WITH_STATE_TRANSFER_USE_FLUSH:
register(cluster_name, local_addr, this);
break;
case Event.DISCONNECT:
unregister(cluster_name, local_addr);
break;
case Event.BECOME_SERVER: // called after client has joined and is fully working group member
is_server=true;
break;
case Event.VIEW_CHANGE:
case Event.TMP_VIEW:
handleViewChange(evt.getArg());
break;
case Event.GET_PING_DATA:
return getDiscoveryResponsesFor(evt.getArg()); // don't pass further down
case Event.GET_PHYSICAL_ADDRESS:
if(cluster_name == null)
return retval;
Address mbr=evt.getArg();
synchronized(routing_table) {
Map map=routing_table.get(cluster_name);
SHARED_LOOPBACK lp=map != null? map.get(mbr) : null;
return lp != null? lp.getPhysicalAddress() : null;
}
}
return retval;
}
public void init() throws Exception {
super.init();
physical_addr=new IpAddress(InetAddress.getLoopbackAddress(), port++);
}
public void stop() {
super.stop();
is_server=is_coord=false;
unregister(cluster_name, local_addr);
}
public void destroy() {
super.destroy();
// We cannot clear the routing table, as it is shared between channels, and so we would clear the routing for
// a different channel, too !
unregister(cluster_name, local_addr);
}
protected void handleViewChange(View v) {
curr_view=v;
is_coord=Objects.equals(local_addr, v.getCoord());
}
protected static void register(AsciiString cluster, Address local_addr, SHARED_LOOPBACK shared_loopback) {
synchronized(routing_table) {
Map map=routing_table.computeIfAbsent(cluster, FUNC);
if(map.isEmpty()) {
// the first member will become coord (may be changed by view changes/merges later)
// https://issues.redhat.com/browse/JGRP-2395
shared_loopback.coord(true);
}
map.putIfAbsent(local_addr, shared_loopback);
}
}
protected static void unregister(AsciiString cluster, Address local_addr) {
synchronized(routing_table) {
Map map=cluster != null? routing_table.get(cluster) : null;
if(map != null && map.remove(local_addr) != null && map.isEmpty())
routing_table.remove(cluster);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy