Package xbird.server.services

Source Code of xbird.server.services.RemotePagingService

/*
* @(#)$Id: codetemplate_xbird.xml 943 2006-09-13 07:03:37Z yui $
*
* Copyright 2006-2008 Makoto YUI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
*     Makoto YUI - initial implementation
*/
package xbird.server.services;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.util.concurrent.ConcurrentMap;

import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.mina.integration.jmx.IoServiceMBean;
import org.apache.mina.transport.socket.DatagramSessionConfig;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.apr.AprSocketAcceptor;
import org.apache.mina.transport.socket.nio.NioDatagramAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

import xbird.config.Settings;
import xbird.server.ServiceException;
import xbird.storage.io.RemoteVarSegments;
import xbird.storage.io.RemoteVarSegments.TrackReadRequestMessage;
import xbird.storage.io.VarSegments.IDescriptor;
import xbird.util.concurrent.ExecutorFactory;
import xbird.util.concurrent.jsr166.ConcurrentReferenceHashMap;
import xbird.util.concurrent.jsr166.ConcurrentReferenceHashMap.ReferenceType;
import xbird.util.concurrent.reference.FinalizableSoftValueReferenceMap;
import xbird.util.concurrent.reference.ReferenceMap;
import xbird.util.concurrent.reference.ReferentFinalizer;
import xbird.util.io.IOUtils;
import xbird.util.nio.RemoteMemoryMappedFile;
import xbird.util.nio.RemoteMemoryMappedFile.ReadRequestMessage;
import xbird.util.primitive.Primitives;
import xbird.util.system.SystemUtils;

/**
*
* <DIV lang="en"></DIV>
* <DIV lang="ja"></DIV>
*
* @author Makoto YUI (yuin405+xbird@gmail.com)
*/
public final class RemotePagingService extends ServiceBase {
    private static final Log LOG = LogFactory.getLog(RemotePagingService.class);

    public static final String SRV_NAME = "RemotePaging";
    public static final int MAX_COMMAND_BUFLEN = 1024;
    public static final int COMMAND_READ = 1;
    public static final int COMMAND_TRACK_READ = 2;
    public static final int PORT = Integer.parseInt(Settings.get("xbird.remote.paging_serv.port", "8900"));
    public static final String CONN_TYPE = Settings.get("xbird.remote.paging_serv.connection.type", "").toUpperCase();

    private static final int SND_BUFSIZE = Integer.parseInt(Settings.get("xbird.remote.paging_serv.connection.so_sndbufsize", "8192"));
    private static final int SO_IDLETIME = Integer.parseInt(Settings.get("xbird.remote.paging_serv.idletime", "30"));
    private static final int SO_WRITE_TIMEOUT = Integer.parseInt(Settings.get("xbird.remote.paging_serv.write_timeout", "120"));
    private static final boolean JMX_MONITOR_ENABLED = Boolean.parseBoolean(Settings.get("xbird.remote.paging_serv.jmx_monitoring"));
    private static final int NUM_IO_PROCESSORS;

    public static final int SWEEP_INTERVAL;
    public static final int TIME_TO_LIVE;
    public static final int SO_RCVBUF_SIZE;

    static {
        final String numIoProcs = Settings.get("xbird.remote.paging_serv.io_processors", "-1");
        if("-1".equals(numIoProcs)) {
            NUM_IO_PROCESSORS = SystemUtils.availableProcessors() + 1;
        } else {
            NUM_IO_PROCESSORS = Integer.parseInt(numIoProcs);
        }
        String sweep = Settings.get("xbird.remote.paging_serv.connection.sweep_interval");
        String ttl = Settings.get("xbird.remote.paging_serv.connection.ttl");
        String rcvbuf = Settings.get("xbird.remote.paging_serv.connection.so_rcvbufsize");
        SWEEP_INTERVAL = Primitives.parseInt(sweep, 60000);
        TIME_TO_LIVE = Primitives.parseInt(ttl, 30000);
        SO_RCVBUF_SIZE = Primitives.parseInt(rcvbuf, 4096);
    }

    private final ReferenceMap<String, FileChannel> _fdCacheMap;
    private final ConcurrentMap<String, IDescriptor> _directoryCache;

    public RemotePagingService() {
        super(SRV_NAME);
        this._fdCacheMap = new FinalizableSoftValueReferenceMap<String, FileChannel>(new ReferentFinalizer<String, FileChannel>() {
            public void finalize(String key, FileChannel reclaimed) {
                IOUtils.closeQuietly(reclaimed);
            }
        });
        this._directoryCache = new ConcurrentReferenceHashMap<String, IDescriptor>(32, ReferenceType.STRONG, ReferenceType.SOFT);
    }

    public void start() throws ServiceException {
        try {
            acceptConnections();
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * We add the ExecutorFilter after the ProtocolCodecFilter implementation.
     * It is because the performance characteristic of most protocol codec implementations
     * is CPU-bound, which should not be in same thread with I/O processor.
     *
     * @link http://mina.apache.org/configuring-thread-model.html
     */
    private void acceptConnections() throws IOException {
        IoAcceptor accepter = setupAcceptor();
        accepter.setHandler(new IOHandler());

        DefaultIoFilterChainBuilder filterChainBuilder = accepter.getFilterChain();
        // Add CPU-bound job first,
        ProtocolCodecFilter protocolFiler = new ProtocolCodecFilter(new ResponseEncoder(), new RequestDecoder());
        filterChainBuilder.addLast("protocol", protocolFiler);
        // and then a thread pool. REVIEWME
        filterChainBuilder.addLast("execFilter", new ExecutorFilter(ExecutorFactory.newCachedThreadPool("execFilter")));

        InetAddress host = InetAddress.getLocalHost();
        InetSocketAddress sockAddr = new InetSocketAddress(host, PORT);
        accepter.bind(sockAddr);

        if(JMX_MONITOR_ENABLED) {
            setupMonitor(accepter);
        }
    }

    private static IoAcceptor setupAcceptor() {
        if("NIODATAGRAM".equals(CONN_TYPE)) {
            LOG.info("NioDatagramAcceptor is used for RemotePaging");
            NioDatagramAcceptor datagramAcceptor = new NioDatagramAcceptor(); // connection less
            DatagramSessionConfig config = datagramAcceptor.getSessionConfig();
            config.setReuseAddress(true);
            config.setReadBufferSize(1024);
            config.setSendBufferSize(SND_BUFSIZE);
            config.setBothIdleTime(SO_IDLETIME);
            config.setWriteTimeout(SO_WRITE_TIMEOUT);
            config.setBroadcast(false);
            return datagramAcceptor;
        } else {
            final SocketAcceptor acceptor;
            if("APRSOCKET".equals(CONN_TYPE)) {
                LOG.info("AprSocketAcceptor is used for RemotePaging");
                acceptor = new AprSocketAcceptor(NUM_IO_PROCESSORS);
            } else {
                LOG.info("NioSocketAcceptor is used for RemotePaging");
                acceptor = new NioSocketAcceptor(NUM_IO_PROCESSORS);
            }
            SocketSessionConfig config = acceptor.getSessionConfig();
            config.setReuseAddress(true);
            config.setReadBufferSize(1024);
            config.setSendBufferSize(SND_BUFSIZE);
            config.setBothIdleTime(SO_IDLETIME);
            config.setWriteTimeout(SO_WRITE_TIMEOUT);
            //config.setTcpNoDelay(true); // Disable Nagle's algorithm
            return acceptor;
        }
    }

    private static void setupMonitor(IoAcceptor service) {
        final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        try {
            server.registerMBean(new IoServiceMBean(service), new ObjectName("org.apache.mina:type=service,name="
                    + SRV_NAME));
        } catch (InstanceAlreadyExistsException iaee) {
            throw new IllegalStateException(iaee);
        } catch (MBeanRegistrationException mre) {
            throw new IllegalStateException(mre);
        } catch (NotCompliantMBeanException ncme) {
            throw new IllegalStateException(ncme);
        } catch (MalformedObjectNameException mone) {
            throw new IllegalStateException(mone);
        } catch (NullPointerException npe) {
            throw new IllegalStateException(npe);
        }
    }

    private static final class IOHandler extends IoHandlerAdapter {

        IOHandler() {
            super();
        }

        @Override
        public void messageReceived(IoSession session, Object message) throws Exception {
            session.write(message);
        }

        @Override
        public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
            LOG.error(cause);
            //session.close();
        }

    }

    private static final class RequestDecoder extends CumulativeProtocolDecoder {

        public RequestDecoder() {
            super();
        }

        protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
                throws Exception {
            // Remember the initial position.
            final int start = in.position();
            if(in.remaining() < 4) {
                return false;
            }
            final int cmdLen = in.getInt();
            final int remaining = in.remaining();
            if(remaining < cmdLen) {
                in.position(start);
                return false;
            }
            final int cmd = in.getInt();
            final RequestMessage reqMsg;
            switch(cmd) {
                case COMMAND_READ:
                    reqMsg = ReadRequestMessage.decode(in);
                    break;
                case COMMAND_TRACK_READ:
                    reqMsg = TrackReadRequestMessage.decode(in);
                    break;
                default:
                    throw new IllegalStateException("Unknown command: " + cmd);
            }
            out.write(reqMsg);
            return true;
        }

    }

    private final class ResponseEncoder extends ProtocolEncoderAdapter {

        public ResponseEncoder() {
            super();
        }

        public void encode(IoSession session, Object message, ProtocolEncoderOutput out)
                throws Exception {
            final RequestMessage requestMsg = (RequestMessage) message;
            switch(requestMsg.cmdSign) {
                case COMMAND_READ:
                    RemoteMemoryMappedFile.handleResponse((ReadRequestMessage) requestMsg, out, _fdCacheMap);
                    break;
                case COMMAND_TRACK_READ:
                    RemoteVarSegments.handleResponse((TrackReadRequestMessage) requestMsg, out, _fdCacheMap, _directoryCache);
                    break;
                default:
                    throw new IllegalStateException("Unknown command: " + requestMsg.cmdSign);
            }
        }

    }

    public static class RequestMessage {

        protected final int cmdSign;

        public RequestMessage(int cmdSign) {
            this.cmdSign = cmdSign;
        }

    }

    public void stop() throws ServiceException {
        _fdCacheMap.clear();
    }

}
TOP

Related Classes of xbird.server.services.RemotePagingService

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.