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

org.jgroups.protocols.tom.DeliveryManagerImpl 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.Beta1
Show newest version
package org.jgroups.protocols.tom;

import org.jgroups.Address;
import org.jgroups.Message;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * The implementation of the Delivery Manager
 *
 * @author Pedro Ruivo
 * @since 3.1
 */
public class DeliveryManagerImpl implements DeliveryManager {
    private final SortedSet deliverySet = new TreeSet<>();
    private final ConcurrentMap messageCache = new ConcurrentHashMap<>(8192, .75f, 64);
    private final SequenceNumberManager sequenceNumberManager = new SequenceNumberManager();

    public long addLocalMessageToDeliver(MessageID messageID, Message message, ToaHeader header) {
        MessageInfo messageInfo;
        long sequenceNumber;
        synchronized (deliverySet) {
            sequenceNumber = sequenceNumberManager.getAndIncrement();
            header.setSequencerNumber(sequenceNumber);
            messageInfo = new MessageInfo(messageID, message, sequenceNumber);
            deliverySet.add(messageInfo);
        }
        messageCache.put(messageID, messageInfo);
        return sequenceNumber;
    }

    public long addRemoteMessageToDeliver(MessageID messageID, Message message, long remoteSequenceNumber) {
        MessageInfo messageInfo;
        long sequenceNumber;
        synchronized (deliverySet) {
            sequenceNumber = sequenceNumberManager.updateAndGet(remoteSequenceNumber);
            messageInfo = new MessageInfo(messageID, message, sequenceNumber);
            deliverySet.add(messageInfo);
        }
        messageCache.put(messageID, messageInfo);
        return sequenceNumber;
    }

    public void updateSequenceNumber(long sequenceNumber) {
        synchronized (deliverySet) {
            sequenceNumberManager.update(sequenceNumber);
        }
    }

    /**
     * marks the message as ready to deliver and set the final sequence number (to be ordered)
     *
     * @param messageID           the message ID
     * @param finalSequenceNumber the final sequence number
     */
    public void markReadyToDeliver(MessageID messageID, long finalSequenceNumber) {
        markReadyToDeliverV2(messageID, finalSequenceNumber);
    }

    private void markReadyToDeliverV2(MessageID messageID, long finalSequenceNumber) {
        MessageInfo messageInfo = messageCache.remove(messageID);

        if (messageInfo == null) {
            throw new IllegalStateException("Message ID not found in to deliver list. this can't happen. " +
                    "Message ID is " + messageID);
        }

        boolean needsUpdatePosition = messageInfo.isUpdatePositionNeeded(finalSequenceNumber);

        synchronized (deliverySet) {
            sequenceNumberManager.update(finalSequenceNumber);
            if (needsUpdatePosition) {
                deliverySet.remove(messageInfo);
                messageInfo.updateAndmarkReadyToDeliver(finalSequenceNumber);
                deliverySet.add(messageInfo);
            } else {
                messageInfo.updateAndmarkReadyToDeliver(finalSequenceNumber);
            }

            if (deliverySet.first().isReadyToDeliver()) {
                deliverySet.notify();
            }
        }
    }

    public final void removeLeavers(Collection
leavers) { if (leavers == null) { return; } List toRemove = new LinkedList<>(); synchronized (deliverySet) { for (MessageInfo messageInfo : deliverySet) { if (leavers.contains(messageInfo.getMessage().getSrc()) && !messageInfo.isReadyToDeliver()) { toRemove.add(messageInfo); } } deliverySet.removeAll(toRemove); if (!deliverySet.isEmpty() && deliverySet.first().isReadyToDeliver()) { deliverySet.notify(); } } for (MessageInfo removed : toRemove) { messageCache.remove(removed.messageID); } } //see the interface javadoc @Override public List getNextMessagesToDeliver() throws InterruptedException { LinkedList toDeliver = new LinkedList<>(); synchronized (deliverySet) { while (deliverySet.isEmpty() || !deliverySet.first().isReadyToDeliver()) { deliverySet.wait(); } Iterator iterator = deliverySet.iterator(); while (iterator.hasNext()) { MessageInfo messageInfo = iterator.next(); if (messageInfo.isReadyToDeliver()) { toDeliver.add(messageInfo.getMessage()); iterator.remove(); } else { break; } } } return toDeliver; } /** * remove all the pending messages */ public void clear() { synchronized (deliverySet) { deliverySet.clear(); messageCache.clear(); } } /** * delivers a message that has only as destination member this node * * @param msg the message */ public void deliverSingleDestinationMessage(Message msg, MessageID messageID) { synchronized (deliverySet) { long sequenceNumber = sequenceNumberManager.get(); MessageInfo messageInfo = new MessageInfo(messageID, msg, sequenceNumber); messageInfo.updateAndmarkReadyToDeliver(sequenceNumber); deliverySet.add(messageInfo); if (deliverySet.first().isReadyToDeliver()) { deliverySet.notify(); } } } /** * Keeps the state of a message */ private static class MessageInfo implements Comparable { private MessageID messageID; private Message message; private volatile long sequenceNumber; private volatile boolean readyToDeliver; public MessageInfo(MessageID messageID, Message message, long sequenceNumber) { if (messageID == null) { throw new NullPointerException("Message ID can't be null"); } this.messageID = messageID; this.message = message.copy(true, true); this.sequenceNumber = sequenceNumber; this.readyToDeliver = false; this.message.setSrc(messageID.getAddress()); } private Message getMessage() { return message; } private void updateAndmarkReadyToDeliver(long finalSequenceNumber) { this.readyToDeliver = true; this.sequenceNumber = finalSequenceNumber; } private boolean isReadyToDeliver() { return readyToDeliver; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null) { return false; } boolean isMessageID = o.getClass() == MessageID.class; if (o.getClass() != getClass() && !isMessageID) { return false; } if (isMessageID) { return messageID.equals(o); } MessageInfo that = (MessageInfo) o; return messageID.equals(that.messageID); } @Override public int hashCode() { return messageID.hashCode(); } @Override public String toString() { return "MessageInfo{" + "messageID=" + messageID + ", sequenceNumber=" + sequenceNumber + ", readyToDeliver=" + readyToDeliver + '}'; } public boolean isUpdatePositionNeeded(long finalSequenceNumber) { return sequenceNumber != finalSequenceNumber; } @Override public int compareTo(MessageInfo o) { if (o == null) { throw new NullPointerException(); } int sameId = messageID.compareTo(o.messageID); if (sameId == 0) { return 0; } return sequenceNumber < o.sequenceNumber ? -1 : sequenceNumber == o.sequenceNumber ? sameId : 1; } } /** * It is used for testing (see the messages in JMX) * * @return unmodifiable set of messages */ public Set getMessageSet() { synchronized (deliverySet) { return Collections.unmodifiableSet(deliverySet); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy