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

org.jgroups.protocols.ABP Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and Jakarta Messaging 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).

There is a newer version: 35.0.0.Final
Show newest version
package org.jgroups.protocols;

import org.jgroups.*;
import org.jgroups.annotations.Experimental;
import org.jgroups.annotations.MBean;
import org.jgroups.annotations.Property;
import org.jgroups.annotations.Unsupported;
import org.jgroups.stack.Protocol;
import org.jgroups.util.ConcurrentLinkedBlockingQueue;
import org.jgroups.util.TimeScheduler;
import org.jgroups.util.Util;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * Alternating Bit Protocol. Use without any UNICASTX protocol. Place it somewhere below NAKACKX. Provides reliable
 * p2p unicasting. Design is in ./doc/design/ABP.txt
 * @author Bela Ban
 * @since  3.6.3
 * @deprecated Mainly used as a design study of Pluscal / TLA+
 */
@Experimental @Unsupported @Deprecated
@MBean(description="Alternating Bit Protocol, for reliable p2p unicasts")
public class ABP extends Protocol {

    @Property(description="Interval (in ms) at which a sent msg is resent")
    protected long resend_interval=1000;

    protected final ConcurrentHashMap send_map=new ConcurrentHashMap<>(),
                                                     recv_map=new ConcurrentHashMap<>();
    protected TimeScheduler timer;
    protected Address       local_addr;

    public void init() throws Exception {
        super.init();
        timer=getTransport().getTimer();
    }

    public Object down(Event evt) {
        switch(evt.getType()) {
            case Event.VIEW_CHANGE:
                View view=evt.getArg();
                send_map.keySet().retainAll(view.getMembers());
                recv_map.keySet().retainAll(view.getMembers());
                break;
            case Event.SET_LOCAL_ADDRESS:
                local_addr=evt.getArg();
                break;
        }
        return down_prot.down(evt);
    }

    public Object down(Message msg) {
        Address dest;
        if((dest=msg.dest()) == null) // we only handle unicast messages
            return down_prot.down(msg);
        Entry entry=getEntry(send_map, dest);
        entry.send(msg);
        return null;
    }

    public Object up(Message msg) {
        Address dest=msg.dest(), sender=msg.src();
        if(dest == null) // we don't handle multicast messages
            return up_prot.up(msg);

        ABPHeader hdr=msg.getHeader(id);
        if(hdr == null)
            return up_prot.up(msg);
        switch(hdr.type) {
            case data:
                Entry entry=getEntry(recv_map, sender);
                log.trace("%s: <-- %s.msg(%d)", local_addr, sender, hdr.bit);
                if(entry.handleMessage(sender, hdr.bit)) {
                    // deliver
                    return up_prot.up(msg);
                }
                break;
            case ack:
                log.trace("%s: <-- %s.ack(%d)", local_addr, sender, hdr.bit);
                entry=getEntry(send_map, sender);
                entry.handleAck(hdr.bit);
                break;
        }
        return null;
    }

    protected Entry getEntry(ConcurrentMap map, Address dest) {
        Entry entry=map.get(dest);
        if(entry == null) {
            Entry existing=map.putIfAbsent(dest, entry=new Entry());
            if(existing != null)
                entry=existing;
        }
        return entry;
    }

    protected enum Type {data, ack};

    protected class Entry implements Runnable {
        protected byte                         bit=0;
        protected final BlockingQueue send_queue=new ConcurrentLinkedBlockingQueue<>(500);
        protected Thread                       xmit_task;

        protected void send(Message msg) {
            synchronized(send_queue) {
                send_queue.add(msg);
            }
            startTask();
        }

        protected synchronized boolean handleMessage(Address sender, byte msg_bit) {
            boolean retval=false;
            if(this.bit == msg_bit) {
                this.bit^=1;
                retval=true;
            }

            byte ack_bit=(byte)(this.bit ^ 1);
            Message ack=new Message(sender).putHeader(id, new ABPHeader(Type.ack, ack_bit));
            log.trace("%s: --> %s.ack(%d)", local_addr, sender, ack_bit);
            down_prot.down(ack);
            return retval;
        }

        protected synchronized void handleAck(byte ack_bit) {
            if(this.bit == ack_bit) {
                this.bit^=1;
                if(!send_queue.isEmpty())
                    send_queue.remove(0);
            }
        }

        protected synchronized void startTask() {
            if(xmit_task == null || !xmit_task.isAlive()) {
                xmit_task=new Thread(this, "ABP.XmitTask");
                xmit_task.setDaemon(true);
                xmit_task.start();
            }
        }


        public void run() {
            Message msg=null, copy;
            while(true) {
                synchronized(this) {
                    try {
                        msg=send_queue.poll(1000, TimeUnit.MILLISECONDS);
                        if(msg == null) {
                            Util.sleep(1000);
                            continue;
                        }
                    }
                    catch(InterruptedException e) {
                        return;
                    }

                    copy=msg.copy().putHeader(id, new ABPHeader(Type.data, bit));
                }
                log.trace("%s: --> %s.msg(%d). Msg: %s", local_addr, copy.dest(), bit, copy.printHeaders());
                down_prot.down(copy);
            }
        }
    }

    protected static class ABPHeader extends Header {
        protected Type type;
        protected byte bit;  // either 1 or 0

        public ABPHeader() {}

        public ABPHeader(Type type, byte bit) {
            this.type=type;
            this.bit=bit;
        }
        public short getMagicId() {return 87;}
        @Override
        public Supplier create() {return ABPHeader::new;}

        @Override
        public int serializedSize() {
            return Global.BYTE_SIZE *2;
        }

        @Override
        public void writeTo(DataOutput out) throws IOException {
            out.writeByte(type.ordinal());
            out.writeByte(bit);
        }

        @Override
        public void readFrom(DataInput in) throws IOException {
            type=Type.values()[in.readByte()];
            bit=in.readByte();
        }

        @Override
        public String toString() {
            return "ABP (" + bit + ")";
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy