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

bboss.org.jgroups.util.FIFOMessageQueue Maven / Gradle / Ivy

The newest version!
package bboss.org.jgroups.util;

import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import bboss.org.jgroups.Address;

/**
 * Blocking queue which can only process 1 message per service concurrently, establishing FIFO order per sender. Example:
 * if message A1, A2, A3, B1, B2 (where A and B are service names for services on top of a Multiplexer) arrive at the
 * same time, then this class will deliver A1 and B1 concurrently (ie. pass them up to the thread pool for processing).
 * Only when A1 is done will A2 be processed, same for B2: it will get processed when B1 is done. Thus, messages
 * for different services are processed concurrently; messages from the same service are processed FIFO.
 * @author Bela Ban
 * @version $Id: FIFOMessageQueue.java,v 1.9 2009/06/22 14:34:26 belaban Exp $
 * @deprecated Will be removed together with the Multiplexer in 3.0
 */
@Deprecated
public class FIFOMessageQueue {
    /** Used for consolidated takes */
    final BlockingQueue                       queue=new LinkedBlockingQueue();

    /** One queue per sender and destination. This is a two level hashmap, with sender's addresses as keys and hashmaps
     * as values. Those hashmaps have destinations (K) as keys and Entries (list of Vs) as values */
    final ConcurrentMap>> queues=new ConcurrentHashMap>>();

    private final AtomicInteger size=new AtomicInteger(0);


    public V take() throws InterruptedException {
        V retval=queue.take();
        if(retval != null)
            size.decrementAndGet();
        return retval;
    }


    public V poll(long timeout) throws InterruptedException {
        V retval=queue.poll(timeout, TimeUnit.MILLISECONDS);
        if(retval != null)
            size.decrementAndGet();
        return retval;
    }



    public void put(Address sender, K dest, V el) throws InterruptedException {
        if(sender == null) {
            size.incrementAndGet();
            queue.add(el);
            return;
        }

        ConcurrentMap> dests=queues.get(sender);
        if(dests == null) {
            dests=new ConcurrentHashMap>();
            if(queues.putIfAbsent(sender, dests) != null) // already existed (someone else inserted the key/value mapping)
                dests=queues.get(sender);
        }

        Entry entry=dests.get(dest);
        if(entry == null) {
            entry=new Entry();
            if(dests.putIfAbsent(dest, entry) != null)
                entry=dests.get(dest);
        }

        synchronized(entry) {
            size.incrementAndGet();
            if(entry.ready) {
                entry.ready=false;
                queue.add(el);
            }
            else {
                entry.list.add(el);
            }
        }
    }


    public void done(Address sender, K dest) {
        if(sender == null)
            return;
        Map> dests=queues.get(sender);
        if(dests == null) return;

        Entry entry=dests.get(dest);
        if(entry != null) {
            V el=null;
            synchronized(entry) {
                if(!entry.list.isEmpty()) {
                    el=entry.list.removeFirst();
                    queue.add(el);
                }
                else {
                    entry.ready=true;
                }
            }
        }
    }

    public int size() {
        return size.get();
    }

    public String toString() {
        StringBuilder sb=new StringBuilder();
        sb.append("queue: ").append(queue).append("\nqueues:\n");
        for(ConcurrentMap.Entry>> entry: queues.entrySet()) {
            sb.append("sender ").append(entry.getKey()).append(":\n");
            for(Map.Entry> entry2: entry.getValue().entrySet()) {
                sb.append(entry2.getKey()).append(": ").append(entry2.getValue().list).append("\n");
            }
        }
        return sb.toString();
    }



    static class Entry {
        boolean ready=true;
        LinkedList list=new LinkedList();
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy