Java tutorial
/* * 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); } }