Package org.jgroups.protocols.pbcast

Source Code of org.jgroups.protocols.pbcast.STATE_SOCK$StateProviderAcceptor

package org.jgroups.protocols.pbcast;

import org.jgroups.Address;
import org.jgroups.Event;
import org.jgroups.Global;
import org.jgroups.View;
import org.jgroups.annotations.LocalAddress;
import org.jgroups.annotations.MBean;
import org.jgroups.annotations.Property;
import org.jgroups.conf.PropertyConverters;
import org.jgroups.stack.IpAddress;
import org.jgroups.util.StateTransferResult;
import org.jgroups.util.Util;

import java.io.*;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;

/**
* <code>STATE_SOCK</code> has the state provider create a server socket to which the state
* requester connects and from which the latter reads the state.
* <p/>
* When implementing {@link org.jgroups.MessageListener#getState(java.io.OutputStream)}, the state should be written in
* sizeable chunks, because the underlying output stream sends 1 message / write over the socket. So if there are 1000
* writes of 1 byte each, this would generate 1000 messages ! We suggest using a {@link java.io.BufferedOutputStream}
* over the output stream handed to the application as argument of the callback.
* <p/>
* When implementing the {@link org.jgroups.MessageListener#setState(java.io.InputStream)} callback, there is no need to use a
* {@link java.io.BufferedOutputStream}, as the input stream handed to the application already buffers incoming data
* internally.
* @author Vladimir Blagojevic
* @author Bela Ban
* @see STATE_TRANSFER
* @since 3.0
*/
@MBean(description="State trasnfer protocol based on streaming state transfer")
public class STATE_SOCK extends StreamingStateTransfer {

    /*
     * ----------------------------------------------Properties -----------------------------------
     */
    @LocalAddress
    @Property(description="The interface (NIC) used to accept state requests. " +
      "The following special values are also recognized: GLOBAL, SITE_LOCAL, LINK_LOCAL and NON_LOOPBACK",
              systemProperty={Global.BIND_ADDR},
              defaultValueIPv4=Global.NON_LOOPBACK_ADDRESS, defaultValueIPv6=Global.NON_LOOPBACK_ADDRESS)
    protected InetAddress bind_addr;

    @Property(name="bind_interface", converter=PropertyConverters.BindInterface.class,
              description="The interface (NIC) which should be used by this transport", dependsUpon="bind_addr")
    protected String bind_interface_str=null;

    @Property(description="The port listening for state requests. Default value of 0 binds to any (ephemeral) port")
    protected int bind_port=0;


    /*
    * --------------------------------------------- Fields ---------------------------------------
    */

    /**
     * Runnable that listens for state requests and spawns threads to serve those requests if socket transport is used
     */
    protected volatile StateProviderAcceptor spawner;


    public STATE_SOCK() {
        super();
    }


    public void stop() {
        super.stop();
        if(spawner != null)
            spawner.stop();
    }


    /*
    * --------------------------- Private Methods ------------------------------------------------
    */

    protected StateProviderAcceptor createAcceptor() {
        StateProviderAcceptor retval=new StateProviderAcceptor(thread_pool,
                                                               Util.createServerSocket(getSocketFactory(),
                                                                                       Global.STATE_SERVER_SOCK,
                                                                                       bind_addr, bind_port));
        Thread t=getThreadFactory().newThread(retval, "STATE server socket acceptor");
        t.start();
        return retval;
    }


    protected void modifyStateResponseHeader(StateHeader hdr) {
        if(spawner != null)
            hdr.bind_addr=spawner.getServerSocketAddress();
    }


    protected void createStreamToRequester(Address requester) {
        ;
    }

    protected void createStreamToProvider(Address provider, StateHeader hdr) {
        IpAddress address=hdr.bind_addr;
        InputStream bis=null;
        Socket socket=new Socket();
        try {
            socket.bind(new InetSocketAddress(bind_addr, 0));
            socket.setReceiveBufferSize(buffer_size);
            Util.connect(socket, new InetSocketAddress(address.getIpAddress(), address.getPort()), 0);
            if(log.isDebugEnabled())
                log.debug(local_addr + ": connected to state provider " + address.getIpAddress() + ":" + address.getPort());

            // write out our state_id and address
            ObjectOutputStream out=new ObjectOutputStream(socket.getOutputStream());
            out.writeObject(local_addr);
            // bis=new BufferedInputStream(new StreamingInputStreamWrapper(socket), buffer_size);
            bis=new BufferedInputStream(socket.getInputStream(), buffer_size);
            setStateInApplication(provider, bis, hdr.getDigest());
        }
        catch(IOException e) {
            if(log.isWarnEnabled())
                log.warn(local_addr + ": state reader socket thread spawned abnormally", e);
            handleException(e);
        }
        finally {
            Util.close(bis);
            Util.close(socket);
        }
    }


    protected void handleStateReq(Address requester) {
        if(spawner == null || !spawner.isRunning())
            spawner=createAcceptor();
        super.handleStateReq(requester);
    }


    protected void handleViewChange(View v) {
        super.handleViewChange(v);
        if(state_provider != null && !v.getMembers().contains(state_provider)) {
            openBarrierAndResumeStable();
            Exception ex=new EOFException("state provider " + state_provider + " left");
            up_prot.up(new Event(Event.STATE_TRANSFER_INPUTSTREAM_CLOSED, new StateTransferResult(ex)));
        }
    }




    /*
    * ------------------------ End of Private Methods --------------------------------------------
    */

    protected class StateProviderAcceptor implements Runnable {
        protected final ExecutorService pool;
        protected final ServerSocket    serverSocket;
        protected final IpAddress       address;
        protected volatile boolean      running=true;

        public StateProviderAcceptor(ExecutorService pool, ServerSocket stateServingSocket) {
            super();
            this.pool=pool;
            this.serverSocket=stateServingSocket;
            this.address=new IpAddress(STATE_SOCK.this.bind_addr, serverSocket.getLocalPort());
        }

        public IpAddress getServerSocketAddress() {return address;}
        public boolean   isRunning()              {return running;}

        public void run() {
            if(log.isDebugEnabled())
                log.debug(local_addr + ": StateProviderAcceptor listening at " + getServerSocketAddress());
            while(running) {
                try {
                    final Socket socket=serverSocket.accept();
                    try {
                        pool.execute(new Runnable() {
                            public void run() {
                                process(socket);
                            }
                        });
                    }
                    catch(RejectedExecutionException rejected) {
                        Util.close(socket);
                    }
                }
                catch(Throwable e) {
                    if(serverSocket.isClosed())
                        running=false;
                }
            }
        }

        protected void process(Socket socket) {
            OutputStream      output=null;
            ObjectInputStream ois=null;
            try {
                socket.setSendBufferSize(buffer_size);
                if(log.isDebugEnabled())
                    log.debug(local_addr + ": accepted request for state transfer from " + socket.getInetAddress() + ":" + socket.getPort());

                ois=new ObjectInputStream(socket.getInputStream());
                Address stateRequester=(Address)ois.readObject();
                output=new BufferedOutputStream(socket.getOutputStream(), buffer_size);
                getStateFromApplication(stateRequester, output, false);
            }
            catch(Throwable e) {
                if(log.isWarnEnabled())
                    log.warn(local_addr + ": failed handling request from requester", e);
            }
            // getStateFromApplication() is run in the same thread; it closes the output stream, and we close the socket
            finally {
                Util.close(socket);
            }
        }



        public void stop() {
            running=false;
            try {
                getSocketFactory().close(serverSocket);
            }
            catch(Exception ignored) {
            }
        }
    }


}
TOP

Related Classes of org.jgroups.protocols.pbcast.STATE_SOCK$StateProviderAcceptor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.