com.chicm.cmraft.rpc.RpcServer.java Source code

Java tutorial

Introduction

Here is the source code for com.chicm.cmraft.rpc.RpcServer.java

Source

/**
* Copyright 2014 The CmRaft Project
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.
*/

package com.chicm.cmraft.rpc;

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.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.chicm.cmraft.common.CmRaftConfiguration;
import com.chicm.cmraft.common.Configuration;
import com.chicm.cmraft.common.ServerInfo;
import com.chicm.cmraft.core.RaftRpcService;
import com.google.protobuf.BlockingService;

/**
 * A RpcServer is a socket server listening on specified port, accepting client's connection
 * and handle RPC requests. In order to prevent slow RPC calls blocking fast ones, It uses 2 
 * queues to process RPC requests.
 * @author chicm
 *
 */
public class RpcServer {
    static final Log LOG = LogFactory.getLog(RpcServer.class);

    private static final int DEFAULT_CONNECTION_BACKLOG = 200;
    private RaftRpcService service = null;
    private PriorityBlockingQueue<RpcCall> requestQueue = new PriorityBlockingQueue<RpcCall>();
    private PriorityBlockingQueue<RpcCall> responseQueue = new PriorityBlockingQueue<RpcCall>();
    private final static AtomicLong callCounter = new AtomicLong(0);
    private boolean tpsReportStarted = false;
    private ServerInfo serverInfo;

    public RpcServer(Configuration conf, RaftRpcService service, ServerInfo localServer) {
        this.service = service;
        this.serverInfo = localServer;
    }

    public BlockingService getService() {
        return service.getService();
    }

    public ServerInfo getServerInfo() {
        return this.serverInfo;
    }

    public boolean startRpcServer() {
        try {
            new NettyListener().start();
        } catch (InterruptedException e) {
            e.printStackTrace(System.out);
            return false;
        }
        return true;
    }

    class NettyListener {
        public void start() throws InterruptedException {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            ServerChannelHandler handler = new ServerChannelHandler(getService(), callCounter);
            ServerBootstrap boot = new ServerBootstrap();
            boot.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(handler)
                    .option(ChannelOption.SO_BACKLOG, DEFAULT_CONNECTION_BACKLOG)
                    .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            // Bind and start to accept incoming connections.
            ChannelFuture f = boot.bind(getServerInfo().getPort()).sync();

            // Wait until the server socket is closed.
            LOG.info("server started");
            //f.channel().closeFuture().sync();
        }
    }

    public void startTPSReport() {
        if (tpsReportStarted)
            return;

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    long calls = callCounter.get();
                    long starttm = System.currentTimeMillis();
                    try {
                        Thread.sleep(5000);
                    } catch (Exception e) {
                        LOG.error("exception", e);
                    }
                    long sec = (System.currentTimeMillis() - starttm) / 1000;
                    if (sec == 0)
                        sec = 1;
                    long n = callCounter.get() - calls;
                    LOG.info("TPS: " + (n / sec));
                    LOG.info("request queue: " + requestQueue.size() + " response queue: " + responseQueue.size());
                }
            }
        });
        thread.setDaemon(true);
        thread.setName("TPS report");
        thread.start();
        tpsReportStarted = true;
        LOG.info("TPS report started");
    }

    /**
     * For test purpose
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {

        if (args.length < 1) {
            System.out.println("usage: RpcServer <listening port>");
            return;
        }
        int port = Integer.parseInt(args[0]);

        Configuration conf = CmRaftConfiguration.create();

        RpcServer server = new RpcServer(conf, RaftRpcService.create(), new ServerInfo("localhost", port));
        LOG.info("starting server");
        server.startRpcServer();
        server.startTPSReport();
    }
}