c5db.regionserver.RegionServerHandler.java Source code

Java tutorial

Introduction

Here is the source code for c5db.regionserver.RegionServerHandler.java

Source

/*
 * Copyright 2014 WANdisco
 *
 *  WANdisco 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 c5db.regionserver;

import c5db.client.generated.Call;
import c5db.client.generated.Get;
import c5db.client.generated.GetRequest;
import c5db.client.generated.GetResponse;
import c5db.client.generated.MultiRequest;
import c5db.client.generated.MultiResponse;
import c5db.client.generated.MutateRequest;
import c5db.client.generated.MutateResponse;
import c5db.client.generated.MutationProto;
import c5db.client.generated.RegionAction;
import c5db.client.generated.RegionActionResult;
import c5db.client.generated.Response;
import c5db.client.generated.ScanRequest;
import c5db.tablet.Region;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.jetlang.channels.Channel;
import org.jetlang.channels.MemoryChannel;
import org.jetlang.fibers.Fiber;
import org.jetlang.fibers.ThreadFiber;
import org.mortbay.log.Log;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * The main netty handler for the RegionServer functionality. Maps protocol buffer calls to an action against a HRegion
 * and then provides a response to the caller.
 */
public class RegionServerHandler extends SimpleChannelInboundHandler<Call> {
    private final RegionServerService regionServerService;
    private final ScannerManager scanManager = ScannerManager.INSTANCE;

    public RegionServerHandler(RegionServerService myService) {
        this.regionServerService = myService;
    }

    @Override
    public void channelRead0(final ChannelHandlerContext ctx, final Call call) throws Exception {
        switch (call.getCommand()) {
        case GET:
            get(ctx, call);
            break;
        case MUTATE:
            mutate(ctx, call);
            break;
        case SCAN:
            scan(ctx, call);
            break;
        case MULTI:
            multi(ctx, call);
            break;
        }
    }

    private void multi(ChannelHandlerContext ctx, Call call) throws IOException, RegionNotFoundException {
        final MultiRequest request = call.getMulti();

        List<RegionActionResult> regionActionResults = new ArrayList<>();
        if (request == null) {
            throw new IOException("Poorly specified multi. There is no actual get data in the RPC");
        }
        for (RegionAction regionAction : request.getRegionActionList()) {
            final Region region = regionServerService.getOnlineRegion(regionAction.getRegion());
            RegionActionResult regionActionResponse = region.processRegionAction(regionAction);
            regionActionResults.add(regionActionResponse);
        }
        MultiResponse multiResponse = new MultiResponse(regionActionResults);
        final Response response = new Response(Response.Command.MULTI, call.getCommandId(), null, null, null,
                multiResponse);
        ctx.writeAndFlush(response);
    }

    private void mutate(ChannelHandlerContext ctx, Call call) throws RegionNotFoundException, IOException {
        final MutateRequest mutateIn = call.getMutate();

        if (mutateIn == null) {
            throw new IOException("Poorly specified mutate. There is no actual get data in the RPC");
        }

        final Region region = regionServerService.getOnlineRegion(call.getMutate().getRegion());
        if (mutateIn.getMutation().getMutateType().equals(MutationProto.MutationType.PUT)
                && (mutateIn.getCondition() == null || mutateIn.getCondition().getRow() == null)) {
            Futures.addCallback(region.batchMutate(mutateIn.getMutation()), new FutureCallback<Boolean>() {
                @Override
                public void onSuccess(Boolean result) {
                    MutateResponse mutateResponse = new MutateResponse(new c5db.client.generated.Result(), true);
                    final Response response = new Response(Response.Command.MUTATE, call.getCommandId(), null,
                            mutateResponse, null, null);
                    ctx.writeAndFlush(response);

                }

                @Override
                public void onFailure(Throwable t) {
                    t.toString();
                }
            });
            //TODO check success

        } else {
            boolean success = region.mutate(mutateIn.getMutation(), mutateIn.getCondition());

            //TODO check success
            MutateResponse mutateResponse = new MutateResponse(new c5db.client.generated.Result(), success);

            final Response response = new Response(Response.Command.MUTATE, call.getCommandId(), null,
                    mutateResponse, null, null);
            ctx.writeAndFlush(response);
        }
    }

    private void scan(ChannelHandlerContext ctx, Call call) throws IOException, RegionNotFoundException {
        final ScanRequest scanIn = call.getScan();
        if (scanIn == null) {
            throw new IOException("Poorly specified scan. There is no actual get data in the RPC");
        }

        final long scannerId;
        scannerId = getScannerId(scanIn);
        final Integer numberOfRowsToSend = scanIn.getNumberOfRows();
        Channel<Integer> channel = scanManager.getChannel(scannerId);
        // New Scanner
        if (null == channel) {
            final Fiber fiber = new ThreadFiber();
            fiber.start();
            channel = new MemoryChannel<>();
            Region region = regionServerService.getOnlineRegion(call.getScan().getRegion());
            final ScanRunnable scanRunnable = new ScanRunnable(ctx, call, scannerId, region);
            channel.subscribe(fiber, scanRunnable);
            scanManager.addChannel(scannerId, channel);
        }
        channel.publish(numberOfRowsToSend);
    }

    private long getScannerId(ScanRequest scanIn) {
        long scannerId;
        if (scanIn.getScannerId() > 0) {
            scannerId = scanIn.getScannerId();
        } else {
            // Make a scanner with an Id not 0
            do {
                scannerId = System.currentTimeMillis();
            } while (scannerId == 0);
        }
        return scannerId;
    }

    private void get(ChannelHandlerContext ctx, Call call) throws IOException, RegionNotFoundException {
        final GetRequest getRequest = call.getGet();
        if (getRequest == null) {
            throw new IOException("Poorly specified getRequest. There is no actual get data in the RPC");
        }
        final Get getIn = getRequest.getGet();

        final Region region = regionServerService.getOnlineRegion(call.getGet().getRegion());
        if (region == null) {
            throw new IOException("Unable to find region");
        }

        if (getIn.getExistenceOnly()) {
            final boolean exists = region.exists(getRequest.getGet());
            final GetResponse getResponse = new GetResponse(
                    new c5db.client.generated.Result(new ArrayList<>(), 0, exists));
            final Response response = new Response(Response.Command.GET, call.getCommandId(), getResponse, null,
                    null, null);
            ctx.writeAndFlush(response);
        } else {
            final c5db.client.generated.Result getResult = region.get(getRequest.getGet());
            final GetResponse getResponse = new GetResponse(getResult);
            final Response response = new Response(Response.Command.GET, call.getCommandId(), getResponse, null,
                    null, null);
            ctx.writeAndFlush(response);
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        Log.warn(cause);
    }
}