alluxio.worker.netty.NettyDataServer.java Source code

Java tutorial

Introduction

Here is the source code for alluxio.worker.netty.NettyDataServer.java

Source

/*
 * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
 * (the "License"). You may not use this work except in compliance with the License, which is
 * available at www.apache.org/licenses/LICENSE-2.0
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied, as more fully set forth in the License.
 *
 * See the NOTICE file distributed with this work for information regarding copyright ownership.
 */

package alluxio.worker.netty;

import alluxio.Configuration;
import alluxio.Constants;
import alluxio.PropertyKey;
import alluxio.network.ChannelType;
import alluxio.util.network.NettyUtils;
import alluxio.worker.AlluxioWorkerService;
import alluxio.worker.DataServer;

import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ServerChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

import javax.annotation.concurrent.NotThreadSafe;

/**
 * Runs a netty data server that responds to block requests.
 */
@NotThreadSafe
public final class NettyDataServer implements DataServer {
    private static final Logger LOG = LoggerFactory.getLogger(Constants.LOGGER_TYPE);

    private final ServerBootstrap mBootstrap;
    private final ChannelFuture mChannelFuture;
    // Use a shared handler for all pipelines.
    private final DataServerHandler mDataServerHandler;

    /**
     * Creates a new instance of {@link NettyDataServer}.
     *
     * @param address the server address
     * @param worker the Alluxio worker which contains the appropriate components to handle data
     *               operations
     */
    public NettyDataServer(final InetSocketAddress address, final AlluxioWorkerService worker) {
        mDataServerHandler = new DataServerHandler(Preconditions.checkNotNull(worker));
        mBootstrap = createBootstrap().childHandler(new PipelineHandler(mDataServerHandler));

        try {
            mChannelFuture = mBootstrap.bind(address).sync();
        } catch (InterruptedException e) {
            throw Throwables.propagate(e);
        }
    }

    @Override
    public void close() throws IOException {
        int quietPeriodSecs = Configuration.getInt(PropertyKey.WORKER_NETWORK_NETTY_SHUTDOWN_QUIET_PERIOD);
        int timeoutSecs = Configuration.getInt(PropertyKey.WORKER_NETWORK_NETTY_SHUTDOWN_TIMEOUT);

        // The following steps are needed to shut down the data server:
        //
        // 1) its channel needs to be closed
        // 2) its main EventLoopGroup needs to be shut down
        // 3) its child EventLoopGroup needs to be shut down
        //
        // Each of the above steps can time out. If 1) times out, we simply give up on closing the
        // channel. If 2) or 3) times out, the respective EventLoopGroup failed to shut down
        // gracefully and its shutdown is forced.

        boolean completed;
        completed = mChannelFuture.channel().close().awaitUninterruptibly(timeoutSecs, TimeUnit.SECONDS);
        if (!completed) {
            LOG.warn("Closing the channel timed out.");
        }
        completed = mBootstrap.group().shutdownGracefully(quietPeriodSecs, timeoutSecs, TimeUnit.SECONDS)
                .awaitUninterruptibly(timeoutSecs, TimeUnit.SECONDS);
        if (!completed) {
            LOG.warn("Forced group shutdown because graceful shutdown timed out.");
        }
        completed = mBootstrap.childGroup().shutdownGracefully(quietPeriodSecs, timeoutSecs, TimeUnit.SECONDS)
                .awaitUninterruptibly(timeoutSecs, TimeUnit.SECONDS);
        if (!completed) {
            LOG.warn("Forced child group shutdown because graceful shutdown timed out.");
        }
    }

    private ServerBootstrap createBootstrap() {
        final ServerBootstrap boot = createBootstrapOfType(
                Configuration.getEnum(PropertyKey.WORKER_NETWORK_NETTY_CHANNEL, ChannelType.class));

        // use pooled buffers
        boot.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
        boot.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);

        // set write buffer
        // this is the default, but its recommended to set it in case of change in future netty.
        boot.childOption(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK,
                (int) Configuration.getBytes(PropertyKey.WORKER_NETWORK_NETTY_WATERMARK_HIGH));
        boot.childOption(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK,
                (int) Configuration.getBytes(PropertyKey.WORKER_NETWORK_NETTY_WATERMARK_LOW));

        // more buffer settings on Netty socket option, one can tune them by specifying
        // properties, e.g.:
        // alluxio.worker.network.netty.backlog=50
        // alluxio.worker.network.netty.buffer.send=64KB
        // alluxio.worker.network.netty.buffer.receive=64KB
        if (Configuration.containsKey(PropertyKey.WORKER_NETWORK_NETTY_BACKLOG)) {
            boot.option(ChannelOption.SO_BACKLOG, Configuration.getInt(PropertyKey.WORKER_NETWORK_NETTY_BACKLOG));
        }
        if (Configuration.containsKey(PropertyKey.WORKER_NETWORK_NETTY_BUFFER_SEND)) {
            boot.option(ChannelOption.SO_SNDBUF,
                    (int) Configuration.getBytes(PropertyKey.WORKER_NETWORK_NETTY_BUFFER_SEND));
        }
        if (Configuration.containsKey(PropertyKey.WORKER_NETWORK_NETTY_BUFFER_RECEIVE)) {
            boot.option(ChannelOption.SO_RCVBUF,
                    (int) Configuration.getBytes(PropertyKey.WORKER_NETWORK_NETTY_BUFFER_RECEIVE));
        }
        return boot;
    }

    @Override
    public String getBindHost() {
        // Return value of io.netty.channel.Channel.localAddress() must be down-cast into types like
        // InetSocketAddress to get detailed info such as port.
        return ((InetSocketAddress) mChannelFuture.channel().localAddress()).getHostString();
    }

    @Override
    public int getPort() {
        // Return value of io.netty.channel.Channel.localAddress() must be down-cast into types like
        // InetSocketAddress to get detailed info such as port.
        return ((InetSocketAddress) mChannelFuture.channel().localAddress()).getPort();
    }

    @Override
    public boolean isClosed() {
        return mBootstrap.group().isShutdown();
    }

    /**
     * Creates a default {@link io.netty.bootstrap.ServerBootstrap} where the channel and groups are
     * preset.
     *
     * @param type the channel type; current channel types supported are nio and epoll
     * @return an instance of {@code ServerBootstrap}
     */
    private ServerBootstrap createBootstrapOfType(final ChannelType type) {
        final ServerBootstrap boot = new ServerBootstrap();
        final int bossThreadCount = Configuration.getInt(PropertyKey.WORKER_NETWORK_NETTY_BOSS_THREADS);
        // If number of worker threads is 0, Netty creates (#processors * 2) threads by default.
        final int workerThreadCount = Configuration.getInt(PropertyKey.WORKER_NETWORK_NETTY_WORKER_THREADS);
        final EventLoopGroup bossGroup = NettyUtils.createEventLoop(type, bossThreadCount, "data-server-boss-%d",
                false);
        final EventLoopGroup workerGroup = NettyUtils.createEventLoop(type, workerThreadCount,
                "data-server-worker-%d", false);

        final Class<? extends ServerChannel> socketChannelClass = NettyUtils.getServerChannelClass(type);
        boot.group(bossGroup, workerGroup).channel(socketChannelClass);

        return boot;
    }
}