001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 * 018 */ 019 020package org.apache.hadoop.hbase.ipc; 021 022import static org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType.REGION_NAME; 023import java.io.IOException; 024import java.io.InterruptedIOException; 025 026import org.apache.hadoop.hbase.DoNotRetryIOException; 027import org.apache.hadoop.hbase.HConstants; 028import org.apache.yetus.audience.InterfaceAudience; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031import org.apache.hadoop.hbase.exceptions.UnknownProtocolException; 032import org.apache.hadoop.hbase.protobuf.generated.ClientProtos; 033import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations; 034import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter; 035import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.CoprocessorServiceCall; 036import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.CoprocessorServiceRequest; 037import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.RegionSpecifier.RegionSpecifierType; 038import org.apache.hadoop.util.StringUtils; 039 040import com.google.protobuf.RpcCallback; 041import com.google.protobuf.RpcController; 042import com.google.protobuf.Descriptors; 043import com.google.protobuf.Descriptors.MethodDescriptor; 044import com.google.protobuf.Descriptors.ServiceDescriptor; 045import com.google.protobuf.Message; 046import com.google.protobuf.Service; 047 048import edu.umd.cs.findbugs.annotations.Nullable; 049 050/** 051 * Utilities for handling coprocessor rpc service calls. 052 */ 053@InterfaceAudience.Private 054public final class CoprocessorRpcUtils { 055 private static final Logger LOG = LoggerFactory.getLogger(CoprocessorRpcUtils.class); 056 /** 057 * We assume that all HBase protobuf services share a common package name 058 * (defined in the .proto files). 059 */ 060 private static final String hbaseServicePackage; 061 static { 062 Descriptors.ServiceDescriptor clientService = ClientProtos.ClientService.getDescriptor(); 063 hbaseServicePackage = clientService.getFullName() 064 .substring(0, clientService.getFullName().lastIndexOf(clientService.getName())); 065 } 066 067 private CoprocessorRpcUtils() { 068 // private for utility class 069 } 070 071 /** 072 * Returns the name to use for coprocessor service calls. For core HBase services 073 * (in the hbase.pb protobuf package), this returns the unqualified name in order to provide 074 * backward compatibility across the package name change. For all other services, 075 * the fully-qualified service name is used. 076 */ 077 public static String getServiceName(Descriptors.ServiceDescriptor service) { 078 if (service.getFullName().startsWith(hbaseServicePackage)) { 079 return service.getName(); 080 } 081 return service.getFullName(); 082 } 083 084 public static CoprocessorServiceRequest getCoprocessorServiceRequest( 085 final Descriptors.MethodDescriptor method, final Message request) { 086 return getCoprocessorServiceRequest(method, request, HConstants.EMPTY_BYTE_ARRAY, 087 HConstants.EMPTY_BYTE_ARRAY); 088 } 089 090 public static CoprocessorServiceRequest getCoprocessorServiceRequest( 091 final Descriptors.MethodDescriptor method, final Message request, final byte [] row, 092 final byte [] regionName) { 093 return CoprocessorServiceRequest.newBuilder().setCall( 094 getCoprocessorServiceCall(method, request, row)). 095 setRegion(RequestConverter.buildRegionSpecifier(REGION_NAME, regionName)).build(); 096 } 097 098 private static CoprocessorServiceCall getCoprocessorServiceCall( 099 final Descriptors.MethodDescriptor method, final Message request, final byte [] row) { 100 return CoprocessorServiceCall.newBuilder() 101 .setRow(org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations.unsafeWrap(row)) 102 .setServiceName(CoprocessorRpcUtils.getServiceName(method.getService())) 103 .setMethodName(method.getName()) 104 // TODO!!!!! Come back here after!!!!! This is a double copy of the request if I read 105 // it right copying from non-shaded to shaded version!!!!!! FIXXXXX!!!!! 106 .setRequest(org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations. 107 unsafeWrap(request.toByteArray())).build(); 108 } 109 110 public static MethodDescriptor getMethodDescriptor(final String methodName, 111 final ServiceDescriptor serviceDesc) 112 throws UnknownProtocolException { 113 Descriptors.MethodDescriptor methodDesc = serviceDesc.findMethodByName(methodName); 114 if (methodDesc == null) { 115 throw new UnknownProtocolException("Unknown method " + methodName + " called on service " + 116 serviceDesc.getFullName()); 117 } 118 return methodDesc; 119 } 120 121 public static Message getRequest(Service service, 122 Descriptors.MethodDescriptor methodDesc, 123 org.apache.hbase.thirdparty.com.google.protobuf.ByteString shadedRequest) 124 throws IOException { 125 Message.Builder builderForType = 126 service.getRequestPrototype(methodDesc).newBuilderForType(); 127 org.apache.hadoop.hbase.protobuf.ProtobufUtil.mergeFrom(builderForType, 128 // TODO: COPY FROM SHADED TO NON_SHADED. DO I HAVE TOO? 129 shadedRequest.toByteArray()); 130 return builderForType.build(); 131 } 132 133 public static Message getResponse( 134 org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.CoprocessorServiceResponse 135 result, 136 com.google.protobuf.Message responsePrototype) 137 throws IOException { 138 Message response; 139 if (result.getValue().hasValue()) { 140 Message.Builder builder = responsePrototype.newBuilderForType(); 141 builder.mergeFrom(result.getValue().getValue().newInput()); 142 response = builder.build(); 143 } else { 144 response = responsePrototype.getDefaultInstanceForType(); 145 } 146 if (LOG.isTraceEnabled()) { 147 LOG.trace("Master Result is value=" + response); 148 } 149 return response; 150 } 151 152 public static org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos. 153 CoprocessorServiceResponse getResponse(final Message result, final byte [] regionName) { 154 org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos. 155 CoprocessorServiceResponse.Builder builder = 156 org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.CoprocessorServiceResponse. 157 newBuilder(); 158 builder.setRegion(RequestConverter.buildRegionSpecifier(RegionSpecifierType.REGION_NAME, 159 regionName)); 160 // TODO: UGLY COPY IN HERE!!!! 161 builder.setValue(builder.getValueBuilder().setName(result.getClass().getName()) 162 .setValue(org.apache.hbase.thirdparty.com.google.protobuf.ByteString. 163 copyFrom(result.toByteArray()))); 164 return builder.build(); 165 } 166 167 /** 168 * Simple {@link RpcCallback} implementation providing a 169 * {@link java.util.concurrent.Future}-like {@link BlockingRpcCallback#get()} method, which 170 * will block util the instance's {@link BlockingRpcCallback#run(Object)} method has been called. 171 * {@code R} is the RPC response type that will be passed to the {@link #run(Object)} method. 172 */ 173 @InterfaceAudience.Private 174 // Copy of BlockingRpcCallback but deriving from RpcCallback non-shaded. 175 public static class BlockingRpcCallback<R> implements RpcCallback<R> { 176 private R result; 177 private boolean resultSet = false; 178 179 /** 180 * Called on completion of the RPC call with the response object, or {@code null} in the case of 181 * an error. 182 * @param parameter the response object or {@code null} if an error occurred 183 */ 184 @Override 185 public void run(R parameter) { 186 synchronized (this) { 187 result = parameter; 188 resultSet = true; 189 this.notifyAll(); 190 } 191 } 192 193 /** 194 * Returns the parameter passed to {@link #run(Object)} or {@code null} if a null value was 195 * passed. When used asynchronously, this method will block until the {@link #run(Object)} 196 * method has been called. 197 * @return the response object or {@code null} if no response was passed 198 */ 199 public synchronized R get() throws IOException { 200 while (!resultSet) { 201 try { 202 this.wait(); 203 } catch (InterruptedException ie) { 204 InterruptedIOException exception = new InterruptedIOException(ie.getMessage()); 205 exception.initCause(ie); 206 throw exception; 207 } 208 } 209 return result; 210 } 211 } 212 213 /** 214 * Stores an exception encountered during RPC invocation so it can be passed back 215 * through to the client. 216 * @param controller the controller instance provided by the client when calling the service 217 * @param ioe the exception encountered 218 */ 219 public static void setControllerException(RpcController controller, IOException ioe) { 220 if (controller == null) { 221 return; 222 } 223 if (controller instanceof org.apache.hadoop.hbase.ipc.ServerRpcController) { 224 ((ServerRpcController)controller).setFailedOn(ioe); 225 } else { 226 controller.setFailed(StringUtils.stringifyException(ioe)); 227 } 228 } 229 230 /** 231 * Retreivies exception stored during RPC invocation. 232 * @param controller the controller instance provided by the client when calling the service 233 * @return exception if any, or null; Will return DoNotRetryIOException for string represented 234 * failure causes in controller. 235 */ 236 @Nullable 237 public static IOException getControllerException(RpcController controller) throws IOException { 238 if (controller == null || !controller.failed()) { 239 return null; 240 } 241 if (controller instanceof ServerRpcController) { 242 return ((ServerRpcController)controller).getFailedOn(); 243 } 244 return new DoNotRetryIOException(controller.errorText()); 245 } 246}