org.apache.giraph.comm.netty.handler.RequestServerHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.giraph.comm.netty.handler.RequestServerHandler.java

Source

/*
 * 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 org.apache.giraph.comm.netty.handler;

import org.apache.giraph.comm.requests.WritableRequest;
import org.apache.giraph.conf.ImmutableClassesGiraphConfiguration;
import org.apache.giraph.graph.TaskInfo;
import org.apache.giraph.time.SystemTime;
import org.apache.giraph.time.Time;
import org.apache.giraph.time.Times;
import org.apache.log4j.Logger;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import static org.apache.giraph.conf.GiraphConstants.NETTY_SIMULATE_FIRST_REQUEST_CLOSED;

/**
 * Generic handler of requests.
 *
 * @param <R> Request type
 */
public abstract class RequestServerHandler<R> extends ChannelInboundHandlerAdapter {
    /** Number of bytes in the encoded response */
    public static final int RESPONSE_BYTES = 13;
    /** Time class to use */
    private static Time TIME = SystemTime.get();
    /** Class logger */
    private static final Logger LOG = Logger.getLogger(RequestServerHandler.class);
    /** Already closed first request? */
    private static volatile boolean ALREADY_CLOSED_FIRST_REQUEST = false;
    /** Close connection on first request (used for simulating failure) */
    private final boolean closeFirstRequest;
    /** Request reserved map (for exactly one semantics) */
    private final WorkerRequestReservedMap workerRequestReservedMap;
    /** My task info */
    private final TaskInfo myTaskInfo;
    /** Start nanoseconds for the processing time */
    private long startProcessingNanoseconds = -1;
    /** Handler for uncaught exceptions */
    private final Thread.UncaughtExceptionHandler exceptionHandler;

    /**
     * Constructor
     *
     * @param workerRequestReservedMap Worker request reservation map
     * @param conf Configuration
     * @param myTaskInfo Current task info
     * @param exceptionHandler Handles uncaught exceptions
     */
    public RequestServerHandler(WorkerRequestReservedMap workerRequestReservedMap,
            ImmutableClassesGiraphConfiguration conf, TaskInfo myTaskInfo,
            Thread.UncaughtExceptionHandler exceptionHandler) {
        this.workerRequestReservedMap = workerRequestReservedMap;
        closeFirstRequest = NETTY_SIMULATE_FIRST_REQUEST_CLOSED.get(conf);
        this.myTaskInfo = myTaskInfo;
        this.exceptionHandler = exceptionHandler;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (LOG.isTraceEnabled()) {
            LOG.trace("messageReceived: Got " + msg.getClass());
        }

        WritableRequest request = (WritableRequest) msg;

        // Simulate a closed connection on the first request (if desired)
        if (closeFirstRequest && !ALREADY_CLOSED_FIRST_REQUEST) {
            LOG.info("messageReceived: Simulating closing channel on first " + "request " + request.getRequestId()
                    + " from " + request.getClientId());
            setAlreadyClosedFirstRequest();
            ctx.close();
            return;
        }

        // Only execute this request exactly once
        int alreadyDone = 1;
        if (workerRequestReservedMap.reserveRequest(request.getClientId(), request.getRequestId())) {
            if (LOG.isDebugEnabled()) {
                startProcessingNanoseconds = TIME.getNanoseconds();
            }
            processRequest((R) request);
            if (LOG.isDebugEnabled()) {
                LOG.debug("messageReceived: Processing client " + request.getClientId() + ", " + "requestId "
                        + request.getRequestId() + ", " + request.getType() + " took "
                        + Times.getNanosSince(TIME, startProcessingNanoseconds) + " ns");
            }
            alreadyDone = 0;
        } else {
            LOG.info("messageReceived: Request id " + request.getRequestId() + " from client "
                    + request.getClientId() + " was already processed, " + "not processing again.");
        }

        // Send the response with the request id
        ByteBuf buffer = ctx.alloc().buffer(RESPONSE_BYTES);
        buffer.writeInt(myTaskInfo.getTaskId());
        buffer.writeLong(request.getRequestId());
        buffer.writeByte(alreadyDone);

        ctx.write(buffer);
    }

    /**
     * Set the flag indicating already closed first request
     */
    private static void setAlreadyClosedFirstRequest() {
        ALREADY_CLOSED_FIRST_REQUEST = true;
    }

    /**
     * Process request
     *
     * @param request Request to process
     */
    public abstract void processRequest(R request);

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        if (LOG.isDebugEnabled()) {
            LOG.debug("channelActive: Connected the channel on " + ctx.channel().remoteAddress());
        }
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        if (LOG.isDebugEnabled()) {
            LOG.debug("channelInactive: Closed the channel on " + ctx.channel().remoteAddress());
        }
        ctx.fireChannelInactive();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        exceptionHandler.uncaughtException(Thread.currentThread(), cause);
    }

    /**
     * Factory for {@link RequestServerHandler}
     */
    public interface Factory {
        /**
         * Create new {@link RequestServerHandler}
         *
         * @param workerRequestReservedMap Worker request reservation map
         * @param conf Configuration to use
         * @param myTaskInfo Current task info
         * @param exceptionHandler Handles uncaught exceptions
         * @return New {@link RequestServerHandler}
         */
        RequestServerHandler newHandler(WorkerRequestReservedMap workerRequestReservedMap,
                ImmutableClassesGiraphConfiguration conf, TaskInfo myTaskInfo,
                Thread.UncaughtExceptionHandler exceptionHandler);
    }
}