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

zmq.FQ Maven / Gradle / Ivy

There is a newer version: 0.6.0
Show newest version
/*
    Copyright (c) 2009-2011 250bpm s.r.o.
    Copyright (c) 2007-2009 iMatix Corporation
    Copyright (c) 2011 VMware, Inc.
    Copyright (c) 2007-2011 Other contributors as noted in the AUTHORS file

    This file is part of 0MQ.

    0MQ is free software; you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    0MQ is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see .
*/

package zmq;

import java.util.ArrayList;
import java.util.List;

//  Class manages a set of inbound pipes. On receive it performs fair
//  queueing so that senders gone berserk won't cause denial of
//  service for decent senders.
public class FQ {

    //  Inbound pipes.
    private final List pipes;
    
    //  Number of active pipes. All the active pipes are located at the
    //  beginning of the pipes array.
    private int active;

    //  Index of the next bound pipe to read a message from.
    private int current;

    //  If true, part of a multipart message was already received, but
    //  there are following parts still waiting in the current pipe.
    private boolean more;
    
    public FQ () {
        active = 0;
        current = 0;
        more = false;
        
        pipes = new ArrayList();
    }
    
    public void attach (Pipe pipe_)
    {
        pipes.add (pipe_);
        Utils.swap (pipes, active, pipes.size () - 1);
        active++;
    }
    
    public void terminated (Pipe pipe_)
    {
        final int index = pipes.indexOf (pipe_);

        //  Remove the pipe from the list; adjust number of active pipes
        //  accordingly.
        if (index < active) {
            active--;
            Utils.swap (pipes, index, active);
            if (current == active)
                current = 0;
        }
        pipes.remove (pipe_);
    }

    public void activated (Pipe pipe_)
    {
        //  Move the pipe to the list of active pipes.
        Utils.swap(pipes, pipes.indexOf (pipe_), active);
        active++;
    }

    public Msg recv(ValueReference errno)
    {
        return recvpipe(errno, null);
    }

    public Msg recvpipe(ValueReference errno, ValueReference pipe_) {

        //  Round-robin over the pipes to get the next message.
        while (active > 0) {

            //  Try to fetch new message. If we've already read part of the message
            //  subsequent part should be immediately available.
            Msg msg_ = pipes.get(current).read();
            boolean fetched = msg_ != null;

            //  Note that when message is not fetched, current pipe is deactivated
            //  and replaced by another active pipe. Thus we don't have to increase
            //  the 'current' pointer.
            if (fetched) {
                if (pipe_ != null)
                    pipe_.set(pipes.get(current));
                more = msg_.hasMore();
                if (!more)
                    current = (current + 1) % active;
                return msg_;
            }
            
            //  Check the atomicity of the message.
            //  If we've already received the first part of the message
            //  we should get the remaining parts without blocking.
            assert (!more);
            
            active--;
            Utils.swap (pipes, current, active);
            if (current == active)
                current = 0;
        }

        //  No message is available. Initialise the output parameter
        //  to be a 0-byte message.
        errno.set(ZError.EAGAIN);
        return null;
    }

    public boolean has_in ()
    {
        //  There are subsequent parts of the partly-read message available.
        if (more)
            return true;

        //  Note that messing with current doesn't break the fairness of fair
        //  queueing algorithm. If there are no messages available current will
        //  get back to its original value. Otherwise it'll point to the first
        //  pipe holding messages, skipping only pipes with no messages available.
        while (active > 0) {
            if (pipes.get(current).check_read ())
                return true;

            //  Deactivate the pipe.
            active--;
            Utils.swap (pipes, current, active);
            if (current == active)
                current = 0;
        }

        return false;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy